Compiler-Inlining.st 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. Smalltalk current createPackage: 'Compiler-Inlining' properties: #{}!
  2. IRAssignment subclass: #IRInlinedAssignment
  3. instanceVariableNames: ''
  4. package: 'Compiler-Inlining'!
  5. !IRInlinedAssignment methodsFor: 'testing'!
  6. isInlined
  7. ^ true
  8. ! !
  9. !IRInlinedAssignment methodsFor: 'visiting'!
  10. accept: aVisitor
  11. ^ aVisitor visitIRInlinedAssignment: self
  12. ! !
  13. IRClosure subclass: #IRInlinedClosure
  14. instanceVariableNames: ''
  15. package: 'Compiler-Inlining'!
  16. !IRInlinedClosure methodsFor: 'testing'!
  17. isInlined
  18. ^ true
  19. ! !
  20. !IRInlinedClosure methodsFor: 'visiting'!
  21. accept: aVisitor
  22. aVisitor visitIRInlinedClosure: self
  23. ! !
  24. IRReturn subclass: #IRInlinedReturn
  25. instanceVariableNames: ''
  26. package: 'Compiler-Inlining'!
  27. !IRInlinedReturn methodsFor: 'testing'!
  28. isInlined
  29. ^ true
  30. ! !
  31. !IRInlinedReturn methodsFor: 'visiting'!
  32. accept: aVisitor
  33. ^ aVisitor visitIRInlinedReturn: self
  34. ! !
  35. IRInlinedReturn subclass: #IRInlinedNonLocalReturn
  36. instanceVariableNames: ''
  37. package: 'Compiler-Inlining'!
  38. !IRInlinedNonLocalReturn methodsFor: 'testing'!
  39. isInlined
  40. ^ true
  41. ! !
  42. !IRInlinedNonLocalReturn methodsFor: 'visiting'!
  43. accept: aVisitor
  44. ^ aVisitor visitIRInlinedNonLocalReturn: self
  45. ! !
  46. IRSend subclass: #IRInlinedSend
  47. instanceVariableNames: ''
  48. package: 'Compiler-Inlining'!
  49. !IRInlinedSend methodsFor: 'testing'!
  50. isInlined
  51. ^ true
  52. ! !
  53. !IRInlinedSend methodsFor: 'visiting'!
  54. accept: aVisitor
  55. aVisitor visitInlinedSend: self
  56. ! !
  57. IRInlinedSend subclass: #IRInlinedIfFalse
  58. instanceVariableNames: ''
  59. package: 'Compiler-Inlining'!
  60. !IRInlinedIfFalse methodsFor: 'visiting'!
  61. accept: aVisitor
  62. aVisitor visitIRInlinedIfFalse: self
  63. ! !
  64. IRInlinedSend subclass: #IRInlinedIfTrue
  65. instanceVariableNames: ''
  66. package: 'Compiler-Inlining'!
  67. !IRInlinedIfTrue methodsFor: 'visiting'!
  68. accept: aVisitor
  69. aVisitor visitIRInlinedIfTrue: self
  70. ! !
  71. IRBlockSequence subclass: #IRInlinedSequence
  72. instanceVariableNames: ''
  73. package: 'Compiler-Inlining'!
  74. !IRInlinedSequence methodsFor: 'testing'!
  75. isInlined
  76. ^ true
  77. ! !
  78. !IRInlinedSequence methodsFor: 'visiting'!
  79. accept: aVisitor
  80. aVisitor visitIRInlinedSequence: self
  81. ! !
  82. IRInlinedSequence subclass: #IRAssigningInlinedSequence
  83. instanceVariableNames: 'assignTo'
  84. package: 'Compiler-Inlining'!
  85. !IRAssigningInlinedSequence methodsFor: 'accessing'!
  86. accept: aVisitor
  87. ^ aVisitor visitIRAssigningInlinedSequence: self
  88. !
  89. assignTo
  90. ^ assignTo
  91. !
  92. assignTo: anIRInstruction
  93. assignTo := anIRInstruction
  94. ! !
  95. IRInlinedSequence subclass: #IRReturningInlinedSequence
  96. instanceVariableNames: ''
  97. package: 'Compiler-Inlining'!
  98. !IRReturningInlinedSequence methodsFor: 'visiting'!
  99. accept: aVisitor
  100. ^ aVisitor visitIRReturningInlinedSequence: self
  101. ! !
  102. IRReturningInlinedSequence subclass: #IRNonLocalReturningInlinedSequence
  103. instanceVariableNames: ''
  104. package: 'Compiler-Inlining'!
  105. !IRNonLocalReturningInlinedSequence methodsFor: 'visiting'!
  106. accept: aVisitor
  107. ^ aVisitor visitIRNonLocalReturningInlinedSequence: self
  108. ! !
  109. IRVisitor subclass: #IRInliner
  110. instanceVariableNames: ''
  111. package: 'Compiler-Inlining'!
  112. !IRInliner methodsFor: 'factory'!
  113. assignmentInliner
  114. ^ IRAssignmentInliner new
  115. translator: self;
  116. yourself
  117. !
  118. nonLocalReturnInliner
  119. ^ IRNonLocalReturnInliner new
  120. translator: self;
  121. yourself
  122. !
  123. returnInliner
  124. ^ IRReturnInliner new
  125. translator: self;
  126. yourself
  127. !
  128. sendInliner
  129. ^ IRSendInliner new
  130. translator: self;
  131. yourself
  132. ! !
  133. !IRInliner methodsFor: 'testing'!
  134. shouldInlineAssignment: anIRAssignment
  135. ^ anIRAssignment isInlined not and: [
  136. anIRAssignment instructions last isSend and: [
  137. self shouldInlineSend: (anIRAssignment instructions last) ]]
  138. !
  139. shouldInlineReturn: anIRReturn
  140. ^ anIRReturn isInlined not and: [
  141. anIRReturn instructions first isSend and: [
  142. self shouldInlineSend: (anIRReturn instructions first) ]]
  143. !
  144. shouldInlineSend: anIRSend
  145. ^ anIRSend isInlined not and: [
  146. IRSendInliner shouldInline: anIRSend ]
  147. ! !
  148. !IRInliner methodsFor: 'visiting'!
  149. transformNonLocalReturn: anIRNonLocalReturn
  150. | localReturn |
  151. anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [
  152. anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.
  153. localReturn := IRReturn new
  154. scope: anIRNonLocalReturn scope;
  155. yourself.
  156. anIRNonLocalReturn instructions do: [ :each |
  157. localReturn add: each ].
  158. anIRNonLocalReturn replaceWith: localReturn.
  159. ^ localReturn ].
  160. ^ super visitIRNonLocalReturn: anIRNonLocalReturn
  161. !
  162. visitIRAssignment: anIRAssignment
  163. ^ (self shouldInlineAssignment: anIRAssignment)
  164. ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
  165. ifFalse: [ super visitIRAssignment: anIRAssignment ]
  166. !
  167. visitIRNonLocalReturn: anIRNonLocalReturn
  168. ^ (self shouldInlineReturn: anIRNonLocalReturn)
  169. ifTrue: [ self nonLocalReturnInliner inlineReturn: anIRNonLocalReturn ]
  170. ifFalse: [ self transformNonLocalReturn: anIRNonLocalReturn ]
  171. !
  172. visitIRReturn: anIRReturn
  173. ^ (self shouldInlineReturn: anIRReturn)
  174. ifTrue: [ self returnInliner inlineReturn: anIRReturn ]
  175. ifFalse: [ super visitIRReturn: anIRReturn ]
  176. !
  177. visitIRSend: anIRSend
  178. ^ (self shouldInlineSend: anIRSend)
  179. ifTrue: [ self sendInliner inlineSend: anIRSend ]
  180. ifFalse: [ super visitIRSend: anIRSend ]
  181. ! !
  182. IRJSTranslator subclass: #IRInliningJSTranslator
  183. instanceVariableNames: ''
  184. package: 'Compiler-Inlining'!
  185. !IRInliningJSTranslator methodsFor: 'visiting'!
  186. visitIRAssigningInlinedSequence: anIRInlinedSequence
  187. anIRInlinedSequence instructions allButLast do: [ :each |
  188. self stream nextPutStatementWith: [ self visit: each ]].
  189. self stream nextPutStatementWith: [
  190. anIRInlinedSequence instructions last canBeAssigned
  191. ifTrue: [
  192. self stream
  193. nextPutAll: anIRInlinedSequence assignTo variable alias;
  194. nextPutAssignment.
  195. self visit: anIRInlinedSequence instructions last ]
  196. ifFalse: [ self visit: anIRInlinedSequence instructions last ]]
  197. !
  198. visitIRInlinedAssignment: anIRInlinedAssignment
  199. self visit: anIRInlinedAssignment instructions last
  200. !
  201. visitIRInlinedClosure: anIRInlinedClosure
  202. anIRInlinedClosure instructions do: [ :each |
  203. self visit: each ]
  204. !
  205. visitIRInlinedIfFalse: anIRInlinedIfFalse
  206. self stream nextPutIf: [
  207. self stream nextPutAll: '!! smalltalk.assert('.
  208. self visit: anIRInlinedIfFalse instructions first.
  209. self stream nextPutAll: ')' ]
  210. with: [ self visit: anIRInlinedIfFalse instructions last ]
  211. !
  212. visitIRInlinedIfTrue: anIRInlinedIfTrue
  213. self stream nextPutIf: [
  214. self stream nextPutAll: 'smalltalk.assert('.
  215. self visit: anIRInlinedIfTrue instructions first.
  216. self stream nextPutAll: ')' ]
  217. with: [ self visit: anIRInlinedIfTrue instructions last ]
  218. !
  219. visitIRInlinedNonLocalReturn: anIRInlinedReturn
  220. self stream nextPutStatementWith: [
  221. self visit: anIRInlinedReturn instructions last ].
  222. self stream nextPutNonLocalReturnWith: [ ]
  223. !
  224. visitIRInlinedReturn: anIRInlinedReturn
  225. self visit: anIRInlinedReturn instructions last
  226. !
  227. visitIRInlinedSequence: anIRInlinedSequence
  228. anIRInlinedSequence instructions do: [ :each |
  229. self stream nextPutStatementWith: [ self visit: each ]]
  230. !
  231. visitIRNonLocalReturningInlinedSequence: anIRInlinedSequence
  232. anIRInlinedSequence instructions allButLast do: [ :each |
  233. self stream nextPutStatementWith: [ self visit: each ]].
  234. self stream nextPutStatementWith: [
  235. anIRInlinedSequence instructions last canBeAssigned
  236. ifTrue: [
  237. self stream nextPutNonLocalReturnWith: [
  238. self visit: anIRInlinedSequence instructions last ]]
  239. ifFalse: [ self visit: anIRInlinedSequence instructions last ]]
  240. !
  241. visitIRReturningInlinedSequence: anIRInlinedSequence
  242. anIRInlinedSequence instructions allButLast do: [ :each |
  243. self stream nextPutStatementWith: [ self visit: each ]].
  244. self stream nextPutStatementWith: [
  245. anIRInlinedSequence instructions last canBeAssigned
  246. ifTrue: [
  247. self stream nextPutReturn.
  248. self visit: anIRInlinedSequence instructions last ]
  249. ifFalse: [ self visit: anIRInlinedSequence instructions last ]]
  250. ! !
  251. Object subclass: #IRSendInliner
  252. instanceVariableNames: 'send translator'
  253. package: 'Compiler-Inlining'!
  254. !IRSendInliner commentStamp!
  255. I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods.!
  256. !IRSendInliner methodsFor: 'accessing'!
  257. send
  258. ^ send
  259. !
  260. send: anIRSend
  261. send := anIRSend
  262. !
  263. translator
  264. ^ translator
  265. !
  266. translator: anASTTranslator
  267. translator := anASTTranslator
  268. ! !
  269. !IRSendInliner methodsFor: 'error handling'!
  270. inliningError: aString
  271. InliningError signal: aString
  272. ! !
  273. !IRSendInliner methodsFor: 'factory'!
  274. inlinedClosure
  275. ^ IRInlinedClosure new
  276. !
  277. inlinedSequence
  278. ^ IRInlinedSequence new
  279. ! !
  280. !IRSendInliner methodsFor: 'inlining'!
  281. ifFalse: anIRInstruction
  282. | inlinedSend inlinedClosure |
  283. anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
  284. anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
  285. inlinedClosure := self inlineClosure: anIRInstruction.
  286. inlinedSend := IRInlinedIfFalse new.
  287. inlinedSend
  288. add: self send instructions first;
  289. add: inlinedClosure.
  290. self send replaceWith: inlinedSend.
  291. ^ inlinedSend
  292. !
  293. ifTrue: anIRInstruction
  294. | inlinedSend inlinedClosure |
  295. anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
  296. anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
  297. inlinedClosure := self inlineClosure: anIRInstruction.
  298. inlinedSend := IRInlinedIfTrue new.
  299. inlinedSend
  300. add: self send instructions first;
  301. add: inlinedClosure.
  302. self send replaceWith: inlinedSend.
  303. ^ inlinedSend
  304. !
  305. inlineClosure: anIRClosure
  306. | inlinedClosure sequence statements |
  307. inlinedClosure := self inlinedClosure.
  308. inlinedClosure scope: anIRClosure scope.
  309. "Add the possible temp declarations"
  310. anIRClosure instructions do: [ :each |
  311. each isSequence ifFalse: [
  312. inlinedClosure add: each ]].
  313. "Add a block sequence"
  314. sequence := self inlinedSequence.
  315. inlinedClosure add: sequence.
  316. "Get all the statements"
  317. statements := anIRClosure instructions last instructions.
  318. statements ifNotEmpty: [
  319. statements allButLast do: [ :each | sequence add: (self translator visit: each) ].
  320. "Inlined closures don't have implicit local returns"
  321. statements last isLocalReturn
  322. ifTrue: [ sequence add: (self translator visit: statements last instructions first) ]
  323. ifFalse: [ sequence add: (self translator visit: statements last) ]].
  324. ^ inlinedClosure
  325. !
  326. inlineSend: anIRSend
  327. self send: anIRSend.
  328. self perform: self send selector withArguments: self send instructions allButFirst
  329. ! !
  330. !IRSendInliner class methodsFor: 'accessing'!
  331. inlinedSelectors
  332. ^ #('ifTrue:' 'ifFalse:')
  333. !
  334. shouldInline: anIRInstruction
  335. (self inlinedSelectors includes: anIRInstruction selector) ifFalse: [ ^ false ].
  336. anIRInstruction instructions allButFirst do: [ :each |
  337. each isClosure ifFalse: [ ^ false ]].
  338. ^ true
  339. ! !
  340. IRSendInliner subclass: #IRAssignmentInliner
  341. instanceVariableNames: 'assignment'
  342. package: 'Compiler-Inlining'!
  343. !IRAssignmentInliner methodsFor: 'accessing'!
  344. assignment
  345. ^ assignment
  346. !
  347. assignment: aNode
  348. assignment := aNode
  349. ! !
  350. !IRAssignmentInliner methodsFor: 'factory'!
  351. inlinedSequence
  352. ^ IRAssigningInlinedSequence new
  353. assignTo: self assignment instructions first;
  354. yourself
  355. ! !
  356. !IRAssignmentInliner methodsFor: 'inlining'!
  357. inlineAssignment: anIRAssignment
  358. | inlinedAssignment |
  359. self assignment: anIRAssignment.
  360. inlinedAssignment := IRInlinedAssignment new.
  361. anIRAssignment instructions do: [ :each |
  362. inlinedAssignment add: each ].
  363. anIRAssignment replaceWith: inlinedAssignment.
  364. self inlineSend: inlinedAssignment instructions last.
  365. ^ inlinedAssignment
  366. ! !
  367. IRSendInliner subclass: #IRReturnInliner
  368. instanceVariableNames: ''
  369. package: 'Compiler-Inlining'!
  370. !IRReturnInliner methodsFor: 'factory'!
  371. inlinedReturn
  372. ^ IRInlinedReturn new
  373. !
  374. inlinedSequence
  375. ^ IRReturningInlinedSequence new
  376. ! !
  377. !IRReturnInliner methodsFor: 'inlining'!
  378. inlineReturn: anIRReturn
  379. | return |
  380. return := self inlinedReturn.
  381. anIRReturn instructions do: [ :each |
  382. return add: each ].
  383. anIRReturn replaceWith: return.
  384. self inlineSend: return instructions last.
  385. ^ return
  386. ! !
  387. IRReturnInliner subclass: #IRNonLocalReturnInliner
  388. instanceVariableNames: ''
  389. package: 'Compiler-Inlining'!
  390. !IRNonLocalReturnInliner methodsFor: 'factory'!
  391. inlinedReturn
  392. ^ IRInlinedNonLocalReturn new
  393. !
  394. inlinedSequence
  395. ^ IRNonLocalReturningInlinedSequence new
  396. ! !
  397. CodeGenerator subclass: #InliningCodeGenerator
  398. instanceVariableNames: ''
  399. package: 'Compiler-Inlining'!
  400. !InliningCodeGenerator methodsFor: 'compiling'!
  401. compileNode: aNode
  402. | ir stream |
  403. self semanticAnalyzer visit: aNode.
  404. ir := self translator visit: aNode.
  405. self inliner visit: ir.
  406. ^ self irTranslator
  407. visit: ir;
  408. contents
  409. !
  410. inliner
  411. ^ IRInliner new
  412. !
  413. irTranslator
  414. ^ IRInliningJSTranslator new
  415. ! !