peval.scm 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951
  1. ;;; Tree-IL partial evaluator
  2. ;; Copyright (C) 2011-2014,2017,2019-2024 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. (define-module (language tree-il peval)
  17. #:use-module (language tree-il)
  18. #:use-module (language tree-il primitives)
  19. #:use-module (language tree-il effects)
  20. #:use-module (ice-9 vlist)
  21. #:use-module (ice-9 match)
  22. #:use-module (srfi srfi-1)
  23. #:use-module (srfi srfi-9)
  24. #:use-module (srfi srfi-11)
  25. #:use-module (srfi srfi-26)
  26. #:use-module (system base target)
  27. #:use-module (ice-9 control)
  28. #:export (peval))
  29. ;;;
  30. ;;; Partial evaluation is Guile's most important source-to-source
  31. ;;; optimization pass. It performs copy propagation, dead code
  32. ;;; elimination, inlining, and constant folding, all while preserving
  33. ;;; the order of effects in the residual program.
  34. ;;;
  35. ;;; For more on partial evaluation, see William Cook’s excellent
  36. ;;; tutorial on partial evaluation at DSL 2011, called “Build your own
  37. ;;; partial evaluator in 90 minutes”[0].
  38. ;;;
  39. ;;; Our implementation of this algorithm was heavily influenced by
  40. ;;; Waddell and Dybvig's paper, "Fast and Effective Procedure Inlining",
  41. ;;; IU CS Dept. TR 484.
  42. ;;;
  43. ;;; [0] http://www.cs.utexas.edu/~wcook/tutorial/.
  44. ;;;
  45. ;; First, some helpers.
  46. ;;
  47. (define-syntax *logging* (identifier-syntax #f))
  48. ;; For efficiency we define *logging* to inline to #f, so that the call
  49. ;; to log* gets optimized out. If you want to log, uncomment these
  50. ;; lines:
  51. ;;
  52. ;; (define %logging #f)
  53. ;; (define-syntax *logging* (identifier-syntax %logging))
  54. ;;
  55. ;; Then you can change %logging at runtime.
  56. (define-syntax log
  57. (syntax-rules (quote)
  58. ((log 'event arg ...)
  59. (if (and *logging*
  60. (or (eq? *logging* #t)
  61. (memq 'event *logging*)))
  62. (log* 'event arg ...)))))
  63. (define (log* event . args)
  64. (let ((pp (module-ref (resolve-interface '(ice-9 pretty-print))
  65. 'pretty-print)))
  66. (pp `(log ,event . ,args))
  67. (newline)
  68. (values)))
  69. (define (tree-il-any proc exp)
  70. (let/ec k
  71. (tree-il-fold (lambda (exp res)
  72. (let ((res (proc exp)))
  73. (if res (k res) #f)))
  74. (lambda (exp res) #f)
  75. #f exp)))
  76. (define (vlist-any proc vlist)
  77. (let ((len (vlist-length vlist)))
  78. (let lp ((i 0))
  79. (and (< i len)
  80. (or (proc (vlist-ref vlist i))
  81. (lp (1+ i)))))))
  82. (define (singly-valued-expression? exp)
  83. (match exp
  84. (($ <const>) #t)
  85. (($ <void>) #t)
  86. (($ <lexical-ref>) #t)
  87. (($ <primitive-ref>) #t)
  88. (($ <module-ref>) #t)
  89. (($ <toplevel-ref>) #t)
  90. (($ <primcall> _ (? singly-valued-primitive?)) #t)
  91. (($ <primcall> _ 'values (val)) #t)
  92. (($ <lambda>) #t)
  93. (($ <conditional> _ test consequent alternate)
  94. (and (singly-valued-expression? consequent)
  95. (singly-valued-expression? alternate)))
  96. (else #f)))
  97. (define (truncate-values x)
  98. "Discard all but the first value of X."
  99. (if (singly-valued-expression? x)
  100. x
  101. (make-primcall (tree-il-srcv x) 'values (list x))))
  102. ;; Peval will do a one-pass analysis on the source program to determine
  103. ;; the set of assigned lexicals, and to identify unreferenced and
  104. ;; singly-referenced lexicals.
  105. ;;
  106. (define-record-type <var>
  107. (make-var name gensym refcount set?)
  108. var?
  109. (name var-name)
  110. (gensym var-gensym)
  111. (refcount var-refcount set-var-refcount!)
  112. (set? var-set? set-var-set?!))
  113. (define* (build-var-table exp #:optional (table vlist-null))
  114. (tree-il-fold
  115. (lambda (exp res)
  116. (match exp
  117. (($ <lexical-ref> src name gensym)
  118. (let ((var (cdr (vhash-assq gensym res))))
  119. (set-var-refcount! var (1+ (var-refcount var)))
  120. res))
  121. (($ <lambda-case> src req opt rest kw init gensyms body alt)
  122. (fold (lambda (name sym res)
  123. (vhash-consq sym (make-var name sym 0 #f) res))
  124. res
  125. (append req opt (if rest (list rest) '())
  126. (match kw
  127. ((aok? (kw name sym) ...) name)
  128. (_ '())))
  129. gensyms))
  130. (($ <let> src names gensyms vals body)
  131. (fold (lambda (name sym res)
  132. (vhash-consq sym (make-var name sym 0 #f) res))
  133. res names gensyms))
  134. (($ <letrec>)
  135. (error "unexpected letrec"))
  136. (($ <fix> src names gensyms vals body)
  137. (fold (lambda (name sym res)
  138. (vhash-consq sym (make-var name sym 0 #f) res))
  139. res names gensyms))
  140. (($ <lexical-set> src name gensym exp)
  141. (set-var-set?! (cdr (vhash-assq gensym res)) #t)
  142. res)
  143. (_ res)))
  144. (lambda (exp res) res)
  145. table exp))
  146. (define (augment-var-table-with-externally-introduced-lexicals exp table)
  147. "Take the previously computed var table TABLE and the term EXP and
  148. return a table augmented with the lexicals bound in EXP which are not
  149. present in TABLE. This is used for the result of `expand-primcalls`,
  150. which may introduce new lexicals if a subexpression needs to be
  151. referenced multiple times."
  152. (define (maybe-add-var name sym table)
  153. ;; Use a refcount of 2 to prevent the copy-single optimization.
  154. (define refcount 2)
  155. (define assigned? #f)
  156. (if (vhash-assq sym table)
  157. table
  158. (vhash-consq sym (make-var name sym refcount assigned?) table)))
  159. (tree-il-fold
  160. (lambda (exp table)
  161. (match exp
  162. (($ <lambda-case> src req opt rest kw init gensyms body alt)
  163. (fold maybe-add-var table
  164. (append req opt (if rest (list rest) '())
  165. (match kw
  166. ((aok? (kw name sym) ...) name)
  167. (_ '())))
  168. gensyms))
  169. (($ <let> src names gensyms vals body)
  170. (fold maybe-add-var table names gensyms))
  171. (($ <letrec>)
  172. (error "unexpected letrec"))
  173. (($ <fix> src names gensyms vals body)
  174. (fold maybe-add-var table names gensyms))
  175. (_ table)))
  176. (lambda (exp table) table)
  177. table exp))
  178. ;; Counters are data structures used to limit the effort that peval
  179. ;; spends on particular inlining attempts. Each call site in the source
  180. ;; program is allocated some amount of effort. If peval exceeds the
  181. ;; effort counter while attempting to inline a call site, it aborts the
  182. ;; inlining attempt and residualizes a call instead.
  183. ;;
  184. ;; As there is a fixed number of call sites, that makes `peval' O(N) in
  185. ;; the number of call sites in the source program.
  186. ;;
  187. ;; Counters should limit the size of the residual program as well, but
  188. ;; currently this is not implemented.
  189. ;;
  190. ;; At the top level, before seeing any peval call, there is no counter,
  191. ;; because inlining will terminate as there is no recursion. When peval
  192. ;; sees a call at the top level, it will make a new counter, allocating
  193. ;; it some amount of effort and size.
  194. ;;
  195. ;; This top-level effort counter effectively "prints money". Within a
  196. ;; toplevel counter, no more effort is printed ex nihilo; for a nested
  197. ;; inlining attempt to proceed, effort must be transferred from the
  198. ;; toplevel counter to the nested counter.
  199. ;;
  200. ;; Via `data' and `prev', counters form a linked list, terminating in a
  201. ;; toplevel counter. In practice `data' will be the a pointer to the
  202. ;; source expression of the procedure being inlined.
  203. ;;
  204. ;; In this way peval can detect a recursive inlining attempt, by walking
  205. ;; back on the `prev' links looking for matching `data'. Recursive
  206. ;; counters receive a more limited effort allocation, as we don't want
  207. ;; to spend all of the effort for a toplevel inlining site on loops.
  208. ;; Also, recursive counters don't need a prompt at each inlining site:
  209. ;; either the call chain folds entirely, or it will be residualized at
  210. ;; its original call.
  211. ;;
  212. (define-record-type <counter>
  213. (%make-counter effort size continuation recursive? data prev)
  214. counter?
  215. (effort effort-counter)
  216. (size size-counter)
  217. (continuation counter-continuation)
  218. (recursive? counter-recursive? set-counter-recursive?!)
  219. (data counter-data)
  220. (prev counter-prev))
  221. (define (abort-counter c)
  222. ((counter-continuation c)))
  223. (define (record-effort! c)
  224. (let ((e (effort-counter c)))
  225. (if (zero? (variable-ref e))
  226. (abort-counter c)
  227. (variable-set! e (1- (variable-ref e))))))
  228. (define (record-size! c)
  229. (let ((s (size-counter c)))
  230. (if (zero? (variable-ref s))
  231. (abort-counter c)
  232. (variable-set! s (1- (variable-ref s))))))
  233. (define (find-counter data counter)
  234. (and counter
  235. (if (eq? data (counter-data counter))
  236. counter
  237. (find-counter data (counter-prev counter)))))
  238. (define* (transfer! from to #:optional
  239. (effort (variable-ref (effort-counter from)))
  240. (size (variable-ref (size-counter from))))
  241. (define (transfer-counter! from-v to-v amount)
  242. (let* ((from-balance (variable-ref from-v))
  243. (to-balance (variable-ref to-v))
  244. (amount (min amount from-balance)))
  245. (variable-set! from-v (- from-balance amount))
  246. (variable-set! to-v (+ to-balance amount))))
  247. (transfer-counter! (effort-counter from) (effort-counter to) effort)
  248. (transfer-counter! (size-counter from) (size-counter to) size))
  249. (define (make-top-counter effort-limit size-limit continuation data)
  250. (%make-counter (make-variable effort-limit)
  251. (make-variable size-limit)
  252. continuation
  253. #t
  254. data
  255. #f))
  256. (define (make-nested-counter continuation data current)
  257. (let ((c (%make-counter (make-variable 0)
  258. (make-variable 0)
  259. continuation
  260. #f
  261. data
  262. current)))
  263. (transfer! current c)
  264. c))
  265. (define (make-recursive-counter effort-limit size-limit orig current)
  266. (let ((c (%make-counter (make-variable 0)
  267. (make-variable 0)
  268. (counter-continuation orig)
  269. #t
  270. (counter-data orig)
  271. current)))
  272. (transfer! current c effort-limit size-limit)
  273. c))
  274. ;; Operand structures allow bindings to be processed lazily instead of
  275. ;; eagerly. By doing so, hopefully we can get process them in a way
  276. ;; appropriate to their use contexts. Operands also prevent values from
  277. ;; being visited multiple times, wasting effort.
  278. ;;
  279. ;; TODO: Record value size in operand structure?
  280. ;;
  281. (define-record-type <operand>
  282. (%make-operand var sym visit source visit-count use-count
  283. copyable? residual-value constant-value alias)
  284. operand?
  285. (var operand-var)
  286. (sym operand-sym)
  287. (visit %operand-visit)
  288. (source operand-source)
  289. (visit-count operand-visit-count set-operand-visit-count!)
  290. (use-count operand-use-count set-operand-use-count!)
  291. (copyable? operand-copyable? set-operand-copyable?!)
  292. (residual-value operand-residual-value %set-operand-residual-value!)
  293. (constant-value operand-constant-value set-operand-constant-value!)
  294. (alias operand-alias set-operand-alias!))
  295. (define* (make-operand var sym #:optional source visit alias)
  296. ;; Bind SYM to VAR, with value SOURCE. Unassigned bound operands are
  297. ;; considered copyable until we prove otherwise. If we have a source
  298. ;; expression, truncate it to one value. Copy propagation does not
  299. ;; work on multiply-valued expressions.
  300. (let ((source (and=> source truncate-values)))
  301. (%make-operand var sym visit source 0 0
  302. (and source (not (var-set? var))) #f #f
  303. (and (not (var-set? var)) alias))))
  304. (define* (make-bound-operands vars syms sources visit #:optional aliases)
  305. (if aliases
  306. (map (lambda (name sym source alias)
  307. (make-operand name sym source visit alias))
  308. vars syms sources aliases)
  309. (map (lambda (name sym source)
  310. (make-operand name sym source visit #f))
  311. vars syms sources)))
  312. (define (make-unbound-operands vars syms)
  313. (map make-operand vars syms))
  314. (define (set-operand-residual-value! op val)
  315. (%set-operand-residual-value!
  316. op
  317. (match val
  318. (($ <primcall> src 'values (first))
  319. ;; The continuation of a residualized binding does not need the
  320. ;; introduced `values' node, so undo the effects of truncation.
  321. first)
  322. (else
  323. val))))
  324. (define* (visit-operand op counter ctx #:optional effort-limit size-limit)
  325. ;; Peval is O(N) in call sites of the source program. However,
  326. ;; visiting an operand can introduce new call sites. If we visit an
  327. ;; operand outside a counter -- i.e., outside an inlining attempt --
  328. ;; this can lead to divergence. So, if we are visiting an operand to
  329. ;; try to copy it, and there is no counter, make a new one.
  330. ;;
  331. ;; This will only happen at most as many times as there are lexical
  332. ;; references in the source program.
  333. (and (zero? (operand-visit-count op))
  334. (dynamic-wind
  335. (lambda ()
  336. (set-operand-visit-count! op (1+ (operand-visit-count op))))
  337. (lambda ()
  338. (and (operand-source op)
  339. (if (or counter (and (not effort-limit) (not size-limit)))
  340. ((%operand-visit op) (operand-source op) counter ctx)
  341. (let/ec k
  342. (define (abort)
  343. ;; If we abort when visiting the value in a
  344. ;; fresh context, we won't succeed in any future
  345. ;; attempt, so don't try to copy it again.
  346. (set-operand-copyable?! op #f)
  347. (k #f))
  348. ((%operand-visit op)
  349. (operand-source op)
  350. (make-top-counter effort-limit size-limit abort op)
  351. ctx)))))
  352. (lambda ()
  353. (set-operand-visit-count! op (1- (operand-visit-count op)))))))
  354. ;; A helper for constant folding.
  355. ;;
  356. (define (types-check? primitive-name args)
  357. (case primitive-name
  358. ((values) #t)
  359. ((not pair? null? list? symbol? vector? struct?)
  360. (= (length args) 1))
  361. ((eq? eqv? equal?)
  362. (= (length args) 2))
  363. ;; FIXME: add more cases?
  364. (else #f)))
  365. (define* (peval exp #:optional (cenv (current-module)) (env vlist-null)
  366. #:key
  367. (operator-size-limit 40)
  368. (operand-size-limit 20)
  369. (value-size-limit 10)
  370. (effort-limit 500)
  371. (recursive-effort-limit 100)
  372. (cross-module-inlining? #f))
  373. "Partially evaluate EXP in compilation environment CENV, with
  374. top-level bindings from ENV and return the resulting expression."
  375. ;; This is a simple partial evaluator. It effectively performs
  376. ;; constant folding, copy propagation, dead code elimination, and
  377. ;; inlining.
  378. ;; TODO:
  379. ;;
  380. ;; Propagate copies across toplevel bindings, if we can prove the
  381. ;; bindings to be immutable.
  382. ;;
  383. ;; Specialize lambda expressions with invariant arguments.
  384. (define local-toplevel-env
  385. ;; The top-level environment of the module being compiled.
  386. (let ()
  387. (define (env-folder x env)
  388. (match x
  389. (($ <toplevel-define> _ _ name)
  390. (vhash-consq name #t env))
  391. (($ <seq> _ head tail)
  392. (env-folder tail (env-folder head env)))
  393. (_ env)))
  394. (env-folder exp vlist-null)))
  395. (define (local-toplevel? name)
  396. (vhash-assq name local-toplevel-env))
  397. ;; gensym -> <var>
  398. ;; renamed-term -> original-term
  399. ;;
  400. (define store (build-var-table exp))
  401. (define (record-new-temporary! name sym refcount)
  402. (set! store (vhash-consq sym (make-var name sym refcount #f) store)))
  403. (define (lookup-var sym)
  404. (let ((v (vhash-assq sym store)))
  405. (if v (cdr v) (error "unbound var" sym (vlist->list store)))))
  406. (define (fresh-gensyms vars)
  407. (map (lambda (var)
  408. (let ((new (gensym (string-append (symbol->string (var-name var))
  409. " "))))
  410. (set! store (vhash-consq new var store))
  411. new))
  412. vars))
  413. (define (fresh-temporaries ls)
  414. (map (lambda (elt)
  415. (let ((new (gensym "tmp ")))
  416. (record-new-temporary! 'tmp new 1)
  417. new))
  418. ls))
  419. (define (assigned-lexical? sym)
  420. (var-set? (lookup-var sym)))
  421. (define (lexical-refcount sym)
  422. (var-refcount (lookup-var sym)))
  423. (define (splice-expression exp)
  424. (define vars (make-hash-table))
  425. (define (rename! old*)
  426. (match old*
  427. (() '())
  428. ((old . old*)
  429. (cons (let ((new (gensym "t")))
  430. (hashq-set! vars old new)
  431. new)
  432. (rename! old*)))))
  433. (define (new-name old) (hashq-ref vars old))
  434. (define renamed
  435. (pre-order
  436. (match-lambda
  437. (($ <lexical-ref> src name gensym)
  438. (make-lexical-ref src name (new-name gensym)))
  439. (($ <lexical-set> src name gensym exp)
  440. (make-lexical-set src name (new-name gensym) exp))
  441. (($ <lambda-case> src req opt rest kw init gensyms body alt)
  442. (let ((gensyms (rename! gensyms)))
  443. (make-lambda-case src req opt rest
  444. (match kw
  445. ((aok? (kw name sym) ...)
  446. (cons aok?
  447. (map (lambda (kw name sym)
  448. (list kw name (new-name sym)))
  449. kw name sym)))
  450. (#f #f))
  451. init gensyms body alt)))
  452. (($ <let> src names gensyms vals body)
  453. (make-let src names (rename! gensyms) vals body))
  454. (($ <letrec>)
  455. (error "unexpected letrec"))
  456. (($ <fix> src names gensyms vals body)
  457. (make-fix src names (rename! gensyms) vals body))
  458. (exp exp))
  459. exp))
  460. (set! store (build-var-table renamed store))
  461. renamed)
  462. (define (with-temporaries src exps refcount can-copy? k)
  463. (let* ((pairs (map (match-lambda
  464. ((and exp (? can-copy?))
  465. (cons #f exp))
  466. (exp
  467. (let ((sym (gensym "tmp ")))
  468. (record-new-temporary! 'tmp sym refcount)
  469. (cons sym exp))))
  470. exps))
  471. (tmps (filter car pairs)))
  472. (match tmps
  473. (() (k exps))
  474. (tmps
  475. (make-let src
  476. (make-list (length tmps) 'tmp)
  477. (map car tmps)
  478. (map cdr tmps)
  479. (k (map (match-lambda
  480. ((#f . val) val)
  481. ((sym . _)
  482. (make-lexical-ref #f 'tmp sym)))
  483. pairs)))))))
  484. (define (make-begin0 src first second)
  485. (make-let-values
  486. src
  487. first
  488. (let ((vals (gensym "vals ")))
  489. (record-new-temporary! 'vals vals 1)
  490. (make-lambda-case
  491. #f
  492. '() '() 'vals #f '() (list vals)
  493. (make-seq
  494. src
  495. second
  496. (make-primcall #f 'apply
  497. (list
  498. (make-primitive-ref #f 'values)
  499. (make-lexical-ref #f 'vals vals))))
  500. #f))))
  501. ;; ORIG has been alpha-renamed to NEW. Analyze NEW and record a link
  502. ;; from it to ORIG.
  503. ;;
  504. (define (record-source-expression! orig new)
  505. (set! store (vhash-consq new (source-expression orig) store))
  506. new)
  507. ;; Find the source expression corresponding to NEW. Used to detect
  508. ;; recursive inlining attempts.
  509. ;;
  510. (define (source-expression new)
  511. (let ((x (vhash-assq new store)))
  512. (if x (cdr x) new)))
  513. (define (record-operand-use op)
  514. (set-operand-use-count! op (1+ (operand-use-count op))))
  515. (define (unrecord-operand-uses op n)
  516. (let ((count (- (operand-use-count op) n)))
  517. (when (zero? count)
  518. (set-operand-residual-value! op #f))
  519. (set-operand-use-count! op count)))
  520. (define* (residualize-lexical op #:optional ctx val)
  521. (log 'residualize op)
  522. (record-operand-use op)
  523. (if (memq ctx '(value values))
  524. (set-operand-residual-value! op val))
  525. (make-lexical-ref #f (var-name (operand-var op)) (operand-sym op)))
  526. (define (fold-constants src name args ctx)
  527. (define (apply-primitive name args)
  528. ;; todo: further optimize commutative primitives
  529. (catch #t
  530. (lambda ()
  531. (define mod (resolve-interface (primitive-module name)))
  532. (call-with-values
  533. (lambda ()
  534. (apply (module-ref mod name) args))
  535. (lambda results
  536. (values #t results))))
  537. (lambda _
  538. (values #f '()))))
  539. (define (make-values src values)
  540. (match values
  541. ((single) single) ; 1 value
  542. ((_ ...) ; 0, or 2 or more values
  543. (make-primcall src 'values values))))
  544. (define (residualize-call)
  545. (make-primcall src name args))
  546. (cond
  547. ((every const? args)
  548. (let-values (((success? values)
  549. (apply-primitive name (map const-exp args))))
  550. (log 'fold success? values name args)
  551. (if success?
  552. (case ctx
  553. ((effect) (make-void src))
  554. ((test)
  555. ;; Values truncation: only take the first
  556. ;; value.
  557. (if (pair? values)
  558. (make-const src (car values))
  559. (make-values src '())))
  560. (else
  561. (make-values src (map (cut make-const src <>) values))))
  562. (residualize-call))))
  563. ((and (eq? ctx 'effect) (types-check? name args))
  564. (make-void #f))
  565. (else
  566. (residualize-call))))
  567. (define (inline-values src exp nmin nmax consumer)
  568. (let loop ((exp exp))
  569. (match exp
  570. ;; Some expression types are always singly-valued.
  571. ((or ($ <const>)
  572. ($ <void>)
  573. ($ <lambda>)
  574. ($ <lexical-ref>)
  575. ($ <toplevel-ref>)
  576. ($ <module-ref>)
  577. ($ <primitive-ref>)
  578. ($ <lexical-set>) ; FIXME: these set! expressions
  579. ($ <toplevel-set>) ; could return zero values in
  580. ($ <toplevel-define>) ; the future
  581. ($ <module-set>) ;
  582. ($ <primcall> src (? singly-valued-primitive?)))
  583. (and (<= nmin 1) (or (not nmax) (>= nmax 1))
  584. (make-call src (make-lambda #f '() consumer) (list exp))))
  585. ;; Statically-known number of values.
  586. (($ <primcall> src 'values vals)
  587. (and (<= nmin (length vals)) (or (not nmax) (>= nmax (length vals)))
  588. (make-call src (make-lambda #f '() consumer) vals)))
  589. ;; Not going to copy code into both branches.
  590. (($ <conditional>) #f)
  591. ;; Bail on other applications.
  592. (($ <call>) #f)
  593. (($ <primcall>) #f)
  594. ;; Bail on prompt and abort.
  595. (($ <prompt>) #f)
  596. (($ <abort>) #f)
  597. ;; Propagate to tail positions.
  598. (($ <let> src names gensyms vals body)
  599. (let ((body (loop body)))
  600. (and body
  601. (make-let src names gensyms vals body))))
  602. (($ <fix> src names gensyms vals body)
  603. (let ((body (loop body)))
  604. (and body
  605. (make-fix src names gensyms vals body))))
  606. (($ <let-values> src exp
  607. ($ <lambda-case> src2 req opt rest kw inits gensyms body #f))
  608. (let ((body (loop body)))
  609. (and body
  610. (make-let-values src exp
  611. (make-lambda-case src2 req opt rest kw
  612. inits gensyms body #f)))))
  613. (($ <seq> src head tail)
  614. (let ((tail (loop tail)))
  615. (and tail (make-seq src head tail)))))))
  616. (define compute-effects
  617. (make-effects-analyzer assigned-lexical?))
  618. (define (constant-expression? x)
  619. ;; Return true if X is constant, for the purposes of copying or
  620. ;; elision---i.e., if it is known to have no effects, does not
  621. ;; allocate storage for a mutable object, and does not access
  622. ;; mutable data (like `car' or toplevel references).
  623. (constant? (compute-effects x)))
  624. (define (prune-bindings ops in-order? body counter ctx build-result)
  625. ;; This helper handles both `let' and `letrec'/`fix'. In the latter
  626. ;; cases we need to make sure that if referenced binding A needs
  627. ;; as-yet-unreferenced binding B, that B is processed for value.
  628. ;; Likewise if C, when processed for effect, needs otherwise
  629. ;; unreferenced D, then D needs to be processed for value too.
  630. ;;
  631. (define (referenced? op)
  632. ;; When we visit lambdas in operator context, we just copy them,
  633. ;; as we will process their body later. However this does have
  634. ;; the problem that any free var referenced by the lambda is not
  635. ;; marked as needing residualization. Here we hack around this
  636. ;; and treat all bindings as referenced if we are in operator
  637. ;; context.
  638. (or (eq? ctx 'operator)
  639. (not (zero? (operand-use-count op)))))
  640. ;; values := (op ...)
  641. ;; effects := (op ...)
  642. (define (residualize values effects)
  643. ;; Note, values and effects are reversed.
  644. (cond
  645. (in-order?
  646. (let ((values (filter operand-residual-value ops)))
  647. (if (null? values)
  648. body
  649. (build-result (map (compose var-name operand-var) values)
  650. (map operand-sym values)
  651. (map operand-residual-value values)
  652. body))))
  653. (else
  654. (let ((body
  655. (if (null? effects)
  656. body
  657. (let ((effect-vals (map operand-residual-value effects)))
  658. (list->seq #f (reverse (cons body effect-vals)))))))
  659. (if (null? values)
  660. body
  661. (let ((values (reverse values)))
  662. (build-result (map (compose var-name operand-var) values)
  663. (map operand-sym values)
  664. (map operand-residual-value values)
  665. body)))))))
  666. ;; old := (bool ...)
  667. ;; values := (op ...)
  668. ;; effects := ((op . value) ...)
  669. (let prune ((old (map referenced? ops)) (values '()) (effects '()))
  670. (let lp ((ops* ops) (values values) (effects effects))
  671. (cond
  672. ((null? ops*)
  673. (let ((new (map referenced? ops)))
  674. (if (not (equal? new old))
  675. (prune new values '())
  676. (residualize values
  677. (map (lambda (op val)
  678. (set-operand-residual-value! op val)
  679. op)
  680. (map car effects) (map cdr effects))))))
  681. (else
  682. (let ((op (car ops*)))
  683. (cond
  684. ((memq op values)
  685. (lp (cdr ops*) values effects))
  686. ((operand-residual-value op)
  687. (lp (cdr ops*) (cons op values) effects))
  688. ((referenced? op)
  689. (set-operand-residual-value! op (visit-operand op counter 'value))
  690. (lp (cdr ops*) (cons op values) effects))
  691. (else
  692. (lp (cdr ops*)
  693. values
  694. (let ((effect (visit-operand op counter 'effect)))
  695. (if (void? effect)
  696. effects
  697. (acons op effect effects))))))))))))
  698. (define (small-expression? x limit)
  699. (let/ec k
  700. (tree-il-fold
  701. (lambda (x res) ; down
  702. (1+ res))
  703. (lambda (x res) ; up
  704. (if (< res limit)
  705. res
  706. (k #f)))
  707. 0 x)
  708. #t))
  709. (define (extend-env sym op env)
  710. (vhash-consq (operand-sym op) op (vhash-consq sym op env)))
  711. (let loop ((exp exp)
  712. (env vlist-null) ; vhash of gensym -> <operand>
  713. (counter #f) ; inlined call stack
  714. (ctx 'values)) ; effect, value, values, test, operator, or call
  715. (define (lookup var)
  716. (cond
  717. ((vhash-assq var env) => cdr)
  718. (else (error "unbound var" var))))
  719. ;; Find a value referenced a specific number of times. This is a hack
  720. ;; that's used for propagating fresh data structures like rest lists and
  721. ;; prompt tags. Usually we wouldn't copy consed data, but we can do so in
  722. ;; some special cases like `apply' or prompts if we can account
  723. ;; for all of its uses.
  724. ;;
  725. ;; You don't want to use this in general because it introduces a slight
  726. ;; nonlinearity by running peval again (though with a small effort and size
  727. ;; counter).
  728. ;;
  729. (define (find-definition x n-aliases)
  730. (cond
  731. ((lexical-ref? x)
  732. (cond
  733. ((lookup (lexical-ref-gensym x))
  734. => (lambda (op)
  735. (if (var-set? (operand-var op))
  736. (values #f #f)
  737. (let ((y (or (operand-residual-value op)
  738. (visit-operand op counter 'value 10 10)
  739. (operand-source op))))
  740. (cond
  741. ((and (lexical-ref? y)
  742. (= (lexical-refcount (lexical-ref-gensym x)) 1))
  743. ;; X is a simple alias for Y. Recurse, regardless of
  744. ;; the number of aliases we were expecting.
  745. (find-definition y n-aliases))
  746. ((= (lexical-refcount (lexical-ref-gensym x)) n-aliases)
  747. ;; We found a definition that is aliased the right
  748. ;; number of times. We still recurse in case it is a
  749. ;; lexical.
  750. (values (find-definition y 1)
  751. op))
  752. (else
  753. ;; We can't account for our aliases.
  754. (values #f #f)))))))
  755. (else
  756. ;; A formal parameter. Can't say anything about that.
  757. (values #f #f))))
  758. ((= n-aliases 1)
  759. ;; Not a lexical: success, but only if we are looking for an
  760. ;; unaliased value.
  761. (values x #f))
  762. (else (values #f #f))))
  763. (define (visit exp ctx)
  764. (loop exp env counter ctx))
  765. (define (for-value exp) (visit exp 'value))
  766. (define (for-values exp) (visit exp 'values))
  767. (define (for-test exp) (visit exp 'test))
  768. (define (for-effect exp) (visit exp 'effect))
  769. (define (for-call exp) (visit exp 'call))
  770. (define (for-tail exp) (visit exp ctx))
  771. (if counter
  772. (record-effort! counter))
  773. (log 'visit ctx (and=> counter effort-counter)
  774. (unparse-tree-il exp))
  775. (match exp
  776. (($ <const>)
  777. (case ctx
  778. ((effect) (make-void #f))
  779. (else exp)))
  780. (($ <void>)
  781. (case ctx
  782. ((test) (make-const #f #t))
  783. (else exp)))
  784. (($ <lexical-ref> _ _ gensym)
  785. (log 'begin-copy gensym)
  786. (let lp ((op (lookup gensym)))
  787. (cond
  788. ((eq? ctx 'effect)
  789. (log 'lexical-for-effect gensym)
  790. (make-void #f))
  791. ((operand-alias op)
  792. ;; This is an unassigned operand that simply aliases some
  793. ;; other operand. Recurse to avoid residualizing the leaf
  794. ;; binding.
  795. => lp)
  796. ((eq? ctx 'call)
  797. ;; Don't propagate copies if we are residualizing a call.
  798. (log 'residualize-lexical-call gensym op)
  799. (residualize-lexical op))
  800. ((var-set? (operand-var op))
  801. ;; Assigned lexicals don't copy-propagate.
  802. (log 'assigned-var gensym op)
  803. (residualize-lexical op))
  804. ((not (operand-copyable? op))
  805. ;; We already know that this operand is not copyable.
  806. (log 'not-copyable gensym op)
  807. (residualize-lexical op))
  808. ((and=> (operand-constant-value op)
  809. (lambda (x) (or (const? x) (void? x) (primitive-ref? x))))
  810. ;; A cache hit.
  811. (let ((val (operand-constant-value op)))
  812. (log 'memoized-constant gensym val)
  813. (for-tail val)))
  814. ((visit-operand op counter (if (eq? ctx 'values) 'value ctx)
  815. recursive-effort-limit operand-size-limit)
  816. =>
  817. ;; If we end up deciding to residualize this value instead of
  818. ;; copying it, save that residualized value.
  819. (lambda (val)
  820. (cond
  821. ((not (constant-expression? val))
  822. (log 'not-constant gensym op)
  823. ;; At this point, ctx is operator, test, or value. A
  824. ;; value that is non-constant in one context will be
  825. ;; non-constant in the others, so it's safe to record
  826. ;; that here, and avoid future visits.
  827. (set-operand-copyable?! op #f)
  828. (residualize-lexical op ctx val))
  829. ((or (const? val)
  830. (void? val)
  831. (primitive-ref? val))
  832. ;; Always propagate simple values that cannot lead to
  833. ;; code bloat.
  834. (log 'copy-simple gensym val)
  835. ;; It could be this constant is the result of folding.
  836. ;; If that is the case, cache it. This helps loop
  837. ;; unrolling get farther.
  838. (if (or (eq? ctx 'value) (eq? ctx 'values))
  839. (begin
  840. (log 'memoize-constant gensym val)
  841. (set-operand-constant-value! op val)))
  842. val)
  843. ((= 1 (var-refcount (operand-var op)))
  844. ;; Always propagate values referenced only once.
  845. (log 'copy-single gensym val)
  846. val)
  847. ;; FIXME: do demand-driven size accounting rather than
  848. ;; these heuristics.
  849. ((eq? ctx 'operator)
  850. ;; A pure expression in the operator position. Inline
  851. ;; if it's a lambda that's small enough.
  852. (if (and (lambda? val)
  853. (small-expression? val operator-size-limit))
  854. (begin
  855. (log 'copy-operator gensym val)
  856. val)
  857. (begin
  858. (log 'too-big-for-operator gensym val)
  859. (residualize-lexical op ctx val))))
  860. (else
  861. ;; A pure expression, processed for call or for value.
  862. ;; Don't inline lambdas, because they will probably won't
  863. ;; fold because we don't know the operator.
  864. (if (and (small-expression? val value-size-limit)
  865. (not (tree-il-any lambda? val)))
  866. (begin
  867. (log 'copy-value gensym val)
  868. val)
  869. (begin
  870. (log 'too-big-or-has-lambda gensym val)
  871. (residualize-lexical op ctx val)))))))
  872. (else
  873. ;; Visit failed. Either the operand isn't bound, as in
  874. ;; lambda formal parameters, or the copy was aborted.
  875. (log 'unbound-or-aborted gensym op)
  876. (residualize-lexical op)))))
  877. (($ <lexical-set> src name gensym exp)
  878. (let ((op (lookup gensym)))
  879. (if (zero? (var-refcount (operand-var op)))
  880. (let ((exp (for-effect exp)))
  881. (if (void? exp)
  882. exp
  883. (make-seq src exp (make-void #f))))
  884. (begin
  885. (record-operand-use op)
  886. (make-lexical-set src name (operand-sym op) (for-value exp))))))
  887. (($ <let> src
  888. (names ... rest)
  889. (gensyms ... rest-sym)
  890. (vals ... ($ <primcall> _ 'list rest-args))
  891. ($ <primcall> asrc 'apply
  892. (proc args ...
  893. ($ <lexical-ref> _
  894. (? (cut eq? <> rest))
  895. (? (lambda (sym)
  896. (and (eq? sym rest-sym)
  897. (= (lexical-refcount sym) 1))))))))
  898. (let* ((tmps (make-list (length rest-args) 'tmp))
  899. (tmp-syms (fresh-temporaries tmps)))
  900. (for-tail
  901. (make-let src
  902. (append names tmps)
  903. (append gensyms tmp-syms)
  904. (append vals rest-args)
  905. (make-call
  906. asrc
  907. proc
  908. (append args
  909. (map (cut make-lexical-ref #f <> <>)
  910. tmps tmp-syms)))))))
  911. (($ <let> src names gensyms vals body)
  912. (define (lookup-alias exp)
  913. ;; It's very common for macros to introduce something like:
  914. ;;
  915. ;; ((lambda (x y) ...) x-exp y-exp)
  916. ;;
  917. ;; In that case you might end up trying to inline something like:
  918. ;;
  919. ;; (let ((x x-exp) (y y-exp)) ...)
  920. ;;
  921. ;; But if x-exp is itself a lexical-ref that aliases some much
  922. ;; larger expression, perhaps it will fail to inline due to
  923. ;; size. However we don't want to introduce a useless alias
  924. ;; (in this case, x). So if the RHS of a let expression is a
  925. ;; lexical-ref, we record that expression. If we end up having
  926. ;; to residualize X, then instead we residualize X-EXP, as long
  927. ;; as it isn't assigned.
  928. ;;
  929. (match exp
  930. (($ <lexical-ref> _ _ sym)
  931. (let ((op (lookup sym)))
  932. (and (not (var-set? (operand-var op))) op)))
  933. (_ #f)))
  934. (let* ((vars (map lookup-var gensyms))
  935. (new (fresh-gensyms vars))
  936. (ops (make-bound-operands vars new vals
  937. (lambda (exp counter ctx)
  938. (loop exp env counter ctx))
  939. (map lookup-alias vals)))
  940. (env (fold extend-env env gensyms ops))
  941. (body (loop body env counter ctx)))
  942. (match body
  943. (($ <const>)
  944. (for-tail (list->seq src (append vals (list body)))))
  945. (($ <lexical-ref> _ _ (? (lambda (sym) (memq sym new)) sym))
  946. (let ((pairs (map cons new vals)))
  947. ;; (let ((x foo) (y bar) ...) x) => (begin bar ... foo)
  948. (for-tail
  949. (list->seq
  950. src
  951. (append (map cdr (alist-delete sym pairs eq?))
  952. (list (assq-ref pairs sym)))))))
  953. ((and ($ <conditional> src*
  954. ($ <lexical-ref> _ _ sym) ($ <lexical-ref> _ _ sym) alt)
  955. (? (lambda (_)
  956. (case ctx
  957. ((test effect)
  958. (and (equal? (list sym) new)
  959. (= (lexical-refcount sym) 2)))
  960. (else #f)))))
  961. ;; (let ((x EXP)) (if x x ALT)) -> (if EXP #t ALT) in test context
  962. (make-conditional src* (visit-operand (car ops) counter 'test)
  963. (make-const src* #t) alt))
  964. (_
  965. ;; Only include bindings for which lexical references
  966. ;; have been residualized.
  967. (prune-bindings ops #f body counter ctx
  968. (lambda (names gensyms vals body)
  969. (if (null? names) (error "what!" names))
  970. (make-let src names gensyms vals body)))))))
  971. (($ <fix> src names gensyms vals body)
  972. ;; Note the difference from the `let' case: here we use letrec*
  973. ;; so that the `visit' procedure for the new operands closes over
  974. ;; an environment that includes the operands. Also we don't try
  975. ;; to elide aliases, because we can't sensibly reduce something
  976. ;; like (letrec ((a b) (b a)) a).
  977. (letrec* ((visit (lambda (exp counter ctx)
  978. (loop exp env* counter ctx)))
  979. (vars (map lookup-var gensyms))
  980. (new (fresh-gensyms vars))
  981. (ops (make-bound-operands vars new vals visit))
  982. (env* (fold extend-env env gensyms ops))
  983. (body* (visit body counter ctx)))
  984. (if (const? body*)
  985. body*
  986. (prune-bindings ops #f body* counter ctx
  987. (lambda (names gensyms vals body)
  988. (make-fix src names gensyms vals body))))))
  989. (($ <let-values> lv-src producer consumer)
  990. ;; Peval the producer, then try to inline the consumer into
  991. ;; the producer. If that succeeds, peval again. Otherwise
  992. ;; reconstruct the let-values, pevaling the consumer.
  993. (let ((producer (for-values producer)))
  994. (or (match consumer
  995. ((and ($ <lambda-case> src () () rest #f () (rest-sym) body #f)
  996. (? (lambda _ (singly-valued-expression? producer))))
  997. (let ((tmp (gensym "tmp ")))
  998. (record-new-temporary! 'tmp tmp 1)
  999. (for-tail
  1000. (make-let
  1001. src (list 'tmp) (list tmp) (list producer)
  1002. (make-let
  1003. src (list rest) (list rest-sym)
  1004. (list
  1005. (make-primcall #f 'list
  1006. (list (make-lexical-ref #f 'tmp tmp))))
  1007. body)))))
  1008. (($ <lambda-case> src req opt rest #f inits gensyms body #f)
  1009. (let* ((nmin (length req))
  1010. (nmax (and (not rest) (+ nmin (length opt)))))
  1011. (cond
  1012. ((inline-values lv-src producer nmin nmax consumer)
  1013. => for-tail)
  1014. (else #f))))
  1015. (_ #f))
  1016. (make-let-values lv-src producer (for-tail consumer)))))
  1017. (($ <toplevel-ref> src mod (? effect-free-primitive? name))
  1018. exp)
  1019. (($ <toplevel-ref>)
  1020. ;; todo: open private local bindings.
  1021. exp)
  1022. (($ <module-ref> src module (? effect-free-primitive? name) #f)
  1023. (let ((module (false-if-exception
  1024. (resolve-module module #:ensure #f))))
  1025. (if (module? module)
  1026. (let ((var (module-variable module name)))
  1027. (if (eq? var (module-variable the-scm-module name))
  1028. (make-primitive-ref src name)
  1029. exp))
  1030. exp)))
  1031. (($ <module-ref> src module name public?)
  1032. (cond
  1033. ((and cross-module-inlining?
  1034. public?
  1035. (and=> (resolve-module module #:ensure #f)
  1036. (lambda (module)
  1037. (and=> (module-public-interface module)
  1038. (lambda (iface)
  1039. (and=> (module-inlinable-exports iface)
  1040. (lambda (proc) (proc name))))))))
  1041. => (lambda (inlined)
  1042. ;; Similar logic to lexical-ref, but we can't enumerate
  1043. ;; uses, and don't know about aliases.
  1044. (log 'begin-xm-copy exp inlined)
  1045. (cond
  1046. ((eq? ctx 'effect)
  1047. (log 'xm-effect)
  1048. (make-void #f))
  1049. ((eq? ctx 'call)
  1050. ;; Don't propagate copies if we are residualizing a call.
  1051. (log 'residualize-xm-call exp)
  1052. exp)
  1053. ((or (const? inlined) (void? inlined) (primitive-ref? inlined))
  1054. ;; Always propagate simple values that cannot lead to
  1055. ;; code bloat.
  1056. (log 'copy-xm-const)
  1057. (for-tail inlined))
  1058. ;; Inline in operator position if it's a lambda that's
  1059. ;; small enough. Normally the inlinable-exports pass
  1060. ;; will only make small lambdas available for inlining,
  1061. ;; but you never know.
  1062. ((and (eq? ctx 'operator) (lambda? inlined)
  1063. (small-expression? inlined operator-size-limit))
  1064. (log 'copy-xm-operator exp inlined)
  1065. (splice-expression inlined))
  1066. (else
  1067. (log 'xm-copy-failed)
  1068. ;; Could copy small lambdas in value context. Something
  1069. ;; to revisit.
  1070. exp))))
  1071. (else exp)))
  1072. (($ <module-set> src mod name public? exp)
  1073. (make-module-set src mod name public? (for-value exp)))
  1074. (($ <toplevel-define> src mod name exp)
  1075. (make-toplevel-define src mod name (for-value exp)))
  1076. (($ <toplevel-set> src mod name exp)
  1077. (make-toplevel-set src mod name (for-value exp)))
  1078. (($ <primitive-ref>)
  1079. (case ctx
  1080. ((effect) (make-void #f))
  1081. ((test) (make-const #f #t))
  1082. (else exp)))
  1083. (($ <conditional> src condition subsequent alternate)
  1084. (define (call-with-failure-thunk exp proc)
  1085. (match exp
  1086. (($ <call> _ _ ()) (proc exp))
  1087. (($ <primcall> _ _ ()) (proc exp))
  1088. (($ <const>) (proc exp))
  1089. (($ <void>) (proc exp))
  1090. (($ <lexical-ref>) (proc exp))
  1091. (_
  1092. (let ((t (gensym "failure-")))
  1093. (record-new-temporary! 'failure t 2)
  1094. (make-let
  1095. src (list 'failure) (list t)
  1096. (list
  1097. (make-lambda
  1098. #f '()
  1099. (make-lambda-case #f '() '() #f #f '() '() exp #f)))
  1100. (proc (make-call #f (make-lexical-ref #f 'failure t)
  1101. '())))))))
  1102. (define (simplify-conditional c)
  1103. (match c
  1104. ;; Swap the arms of (if (not FOO) A B), to simplify.
  1105. (($ <conditional> src ($ <primcall> _ 'not (pred))
  1106. subsequent alternate)
  1107. (simplify-conditional
  1108. (make-conditional src pred alternate subsequent)))
  1109. ;; In the following four cases, we try to expose the test to
  1110. ;; the conditional. This will let the CPS conversion avoid
  1111. ;; reifying boolean literals in some cases.
  1112. (($ <conditional> src ($ <let> src* names vars vals body)
  1113. subsequent alternate)
  1114. (make-let src* names vars vals
  1115. (simplify-conditional
  1116. (make-conditional src body subsequent alternate))))
  1117. (($ <conditional> src ($ <fix> src* names vars vals body)
  1118. subsequent alternate)
  1119. (make-fix src* names vars vals
  1120. (simplify-conditional
  1121. (make-conditional src body subsequent alternate))))
  1122. (($ <conditional> src ($ <seq> src* head tail)
  1123. subsequent alternate)
  1124. (make-seq src* head
  1125. (simplify-conditional
  1126. (make-conditional src tail subsequent alternate))))
  1127. ;; Special cases for common tests in the predicates of chains
  1128. ;; of if expressions.
  1129. (($ <conditional> src
  1130. ($ <conditional> src* outer-test inner-test ($ <const> _ #f))
  1131. inner-subsequent
  1132. alternate)
  1133. (let lp ((alternate alternate))
  1134. (match alternate
  1135. ;; Lift a common repeated test out of a chain of if
  1136. ;; expressions.
  1137. (($ <conditional> _ (? (cut tree-il=? outer-test <>))
  1138. other-subsequent alternate)
  1139. (make-conditional
  1140. src outer-test
  1141. (simplify-conditional
  1142. (make-conditional src* inner-test inner-subsequent
  1143. other-subsequent))
  1144. alternate))
  1145. ;; Likewise, but punching through any surrounding
  1146. ;; failure continuations.
  1147. (($ <let> let-src (name) (sym) ((and thunk ($ <lambda>))) body)
  1148. (make-let
  1149. let-src (list name) (list sym) (list thunk)
  1150. (lp body)))
  1151. ;; Otherwise, rotate AND tests to expose a simple
  1152. ;; condition in the front. Although this may result in
  1153. ;; lexically binding failure thunks, the thunks will be
  1154. ;; compiled to labels allocation, so there's no actual
  1155. ;; code growth.
  1156. (_
  1157. (call-with-failure-thunk
  1158. alternate
  1159. (lambda (failure)
  1160. (make-conditional
  1161. src outer-test
  1162. (simplify-conditional
  1163. (make-conditional src* inner-test inner-subsequent failure))
  1164. failure)))))))
  1165. (_ c)))
  1166. (match (for-test condition)
  1167. (($ <const> _ val)
  1168. (if val
  1169. (for-tail subsequent)
  1170. (for-tail alternate)))
  1171. (c
  1172. (simplify-conditional
  1173. (make-conditional src c (for-tail subsequent)
  1174. (for-tail alternate))))))
  1175. (($ <primcall> src 'call-with-values
  1176. (producer
  1177. ($ <lambda> _ _
  1178. (and consumer
  1179. ;; No optional or kwargs.
  1180. ($ <lambda-case>
  1181. _ req () rest #f () gensyms body #f)))))
  1182. (for-tail (make-let-values src (make-call src producer '())
  1183. consumer)))
  1184. (($ <primcall> src 'dynamic-wind (w thunk u))
  1185. (for-tail
  1186. (with-temporaries
  1187. src (list w u) 2 constant-expression?
  1188. (match-lambda
  1189. ((w u)
  1190. (make-seq
  1191. src
  1192. (make-seq
  1193. src
  1194. (make-conditional
  1195. src
  1196. ;; fixme: introduce logic to fold thunk?
  1197. (make-primcall src 'thunk? (list u))
  1198. (make-call src w '())
  1199. (make-primcall src 'raise-type-error
  1200. (list (make-const #f #("dynamic-wind" 3 "thunk"))
  1201. u)))
  1202. (make-primcall src 'wind (list w u)))
  1203. (make-begin0 src
  1204. (make-call src thunk '())
  1205. (make-seq src
  1206. (make-primcall src 'unwind '())
  1207. (make-call src u '())))))))))
  1208. (($ <primcall> src 'with-fluid* (f v thunk))
  1209. (for-tail
  1210. (with-temporaries
  1211. src (list f v thunk) 1 constant-expression?
  1212. (match-lambda
  1213. ((f v thunk)
  1214. (make-seq src
  1215. (make-primcall src 'push-fluid (list f v))
  1216. (make-begin0 src
  1217. (make-call src thunk '())
  1218. (make-primcall src 'pop-fluid '()))))))))
  1219. (($ <primcall> src 'with-dynamic-state (state thunk))
  1220. (for-tail
  1221. (with-temporaries
  1222. src (list state thunk) 1 constant-expression?
  1223. (match-lambda
  1224. ((state thunk)
  1225. (make-seq src
  1226. (make-primcall src 'push-dynamic-state (list state))
  1227. (make-begin0 src
  1228. (make-call src thunk '())
  1229. (make-primcall src 'pop-dynamic-state
  1230. '()))))))))
  1231. (($ <primcall> src 'values exps)
  1232. (match exps
  1233. (()
  1234. (case ctx
  1235. ((effect) (make-void #f))
  1236. ((values) exp)
  1237. ;; Zero values returned to continuation expecting a value:
  1238. ;; ensure that we raise an error.
  1239. (else (make-primcall src 'values (list exp)))))
  1240. ((($ <primcall> _ 'values ())) exp)
  1241. (_
  1242. (let ((vals (map for-value exps)))
  1243. (if (and (case ctx
  1244. ((value test effect) #t)
  1245. (else (null? (cdr vals))))
  1246. (every singly-valued-expression? vals))
  1247. (for-tail (list->seq src (append (cdr vals) (list (car vals)))))
  1248. (make-primcall src 'values vals))))))
  1249. (($ <primcall> src 'apply (proc args ... tail))
  1250. (let lp ((tail* (find-definition tail 1)) (speculative? #t))
  1251. (define (copyable? x)
  1252. ;; Inlining a result from find-definition effectively copies it,
  1253. ;; relying on the let-pruning to remove its original binding. We
  1254. ;; shouldn't copy non-constant expressions.
  1255. (or (not speculative?) (constant-expression? x)))
  1256. (match tail*
  1257. (($ <const> _ (args* ...))
  1258. (let ((args* (map (cut make-const #f <>) args*)))
  1259. (for-tail (make-call src proc (append args args*)))))
  1260. (($ <primcall> _ 'cons
  1261. ((and head (? copyable?)) (and tail (? copyable?))))
  1262. (for-tail (make-primcall src 'apply
  1263. (cons proc
  1264. (append args (list head tail))))))
  1265. (($ <primcall> _ 'list
  1266. (and args* ((? copyable?) ...)))
  1267. (for-tail (make-call src proc (append args args*))))
  1268. (tail*
  1269. (if speculative?
  1270. (lp (for-value tail) #f)
  1271. (let ((args (append (map for-value args) (list tail*))))
  1272. (make-primcall src 'apply
  1273. (cons (for-value proc) args))))))))
  1274. (($ <primcall> src 'append (x z))
  1275. (let ((x (for-value x)))
  1276. (match x
  1277. ((or ($ <const> _ ())
  1278. ($ <primcall> _ 'list ()))
  1279. (for-value z))
  1280. ((or ($ <const> _ (_ . _))
  1281. ($ <primcall> _ 'cons)
  1282. ($ <primcall> _ 'list))
  1283. (for-tail
  1284. (let lp ((x x))
  1285. (match x
  1286. ((or ($ <const> csrc ())
  1287. ($ <primcall> csrc 'list ()))
  1288. ;; Defer visiting z in value context to for-tail.
  1289. z)
  1290. (($ <const> csrc (x . y))
  1291. (let ((x (make-const csrc x))
  1292. (y (make-const csrc y)))
  1293. (make-primcall src 'cons (list x (lp y)))))
  1294. (($ <primcall> csrc 'cons (x y))
  1295. (make-primcall src 'cons (list x (lp y))))
  1296. (($ <primcall> csrc 'list (x . y))
  1297. (let ((y (make-primcall csrc 'list y)))
  1298. (make-primcall src 'cons (list x (lp y)))))
  1299. (x (make-primcall src 'append (list x z)))))))
  1300. (else
  1301. (make-primcall src 'append (list x (for-value z)))))))
  1302. (($ <primcall> src (? constructor-primitive? name) args)
  1303. (cond
  1304. ((and (memq ctx '(effect test))
  1305. (match (cons name args)
  1306. ((or ('cons _ _)
  1307. ('list . _)
  1308. ('vector . _)
  1309. ('make-prompt-tag)
  1310. ('make-prompt-tag ($ <const> _ (? string?))))
  1311. #t)
  1312. (_ #f)))
  1313. (let ((res (if (eq? ctx 'effect)
  1314. (make-void #f)
  1315. (make-const #f #t))))
  1316. (for-tail (list->seq src (append (map for-value args)
  1317. (list res))))))
  1318. (else
  1319. (match (cons name (map for-value args))
  1320. (('cons x ($ <const> _ (? (cut eq? <> '()))))
  1321. (make-primcall src 'list (list x)))
  1322. (('cons x ($ <primcall> _ 'list elts))
  1323. (make-primcall src 'list (cons x elts)))
  1324. (('list)
  1325. (make-const src '()))
  1326. (('vector)
  1327. (make-const src '#()))
  1328. ((name . args)
  1329. (make-primcall src name args))))))
  1330. (($ <primcall> src 'thunk? (proc))
  1331. (case ctx
  1332. ((effect)
  1333. (for-tail (make-seq src proc (make-void src))))
  1334. (else
  1335. (match (for-value proc)
  1336. (($ <lambda> _ _ ($ <lambda-case> _ req))
  1337. (for-tail (make-const src (null? req))))
  1338. (proc
  1339. (match (find-definition proc 2)
  1340. (($ <lambda> _ _ ($ <lambda-case> _ req))
  1341. (for-tail (make-const src (null? req))))
  1342. (_
  1343. (make-primcall src 'thunk? (list proc)))))))))
  1344. (($ <primcall> src name args)
  1345. (match (cons name (map for-value args))
  1346. ;; FIXME: these for-tail recursions could take place outside
  1347. ;; an effort counter.
  1348. (('car ($ <primcall> src 'cons (head tail)))
  1349. (for-tail (make-seq src tail head)))
  1350. (('cdr ($ <primcall> src 'cons (head tail)))
  1351. (for-tail (make-seq src head tail)))
  1352. (('car ($ <primcall> src 'list (head . tail)))
  1353. (for-tail (list->seq src (append tail (list head)))))
  1354. (('cdr ($ <primcall> src 'list (head . tail)))
  1355. (for-tail (make-seq src head (make-primcall #f 'list tail))))
  1356. (('car ($ <const> src (head . tail)))
  1357. (for-tail (make-const src head)))
  1358. (('cdr ($ <const> src (head . tail)))
  1359. (for-tail (make-const src tail)))
  1360. (((or 'memq 'memv) k ($ <const> _ (elts ...)))
  1361. ;; FIXME: factor
  1362. (case ctx
  1363. ((effect)
  1364. (for-tail
  1365. (make-seq src k (make-void #f))))
  1366. ((test)
  1367. (cond
  1368. ((const? k)
  1369. ;; A shortcut. The `else' case would handle it, but
  1370. ;; this way is faster.
  1371. (let ((member (case name ((memq) memq) ((memv) memv))))
  1372. (make-const #f (and (member (const-exp k) elts) #t))))
  1373. ((null? elts)
  1374. (for-tail
  1375. (make-seq src k (make-const #f #f))))
  1376. (else
  1377. (let ((t (gensym "t "))
  1378. (eq (if (eq? name 'memq) 'eq? 'eqv?)))
  1379. (record-new-temporary! 't t (length elts))
  1380. (for-tail
  1381. (make-let
  1382. src (list 't) (list t) (list k)
  1383. (let lp ((elts elts))
  1384. (define test
  1385. (make-primcall #f eq
  1386. (list (make-lexical-ref #f 't t)
  1387. (make-const #f (car elts)))))
  1388. (if (null? (cdr elts))
  1389. test
  1390. (make-conditional src test
  1391. (make-const #f #t)
  1392. (lp (cdr elts)))))))))))
  1393. (else
  1394. (cond
  1395. ((const? k)
  1396. (let ((member (case name ((memq) memq) ((memv) memv))))
  1397. (make-const #f (member (const-exp k) elts))))
  1398. ((null? elts)
  1399. (for-tail (make-seq src k (make-const #f #f))))
  1400. (else
  1401. (make-primcall src name (list k (make-const #f elts))))))))
  1402. (((? equality-primitive?) a (and b ($ <const> _ v)))
  1403. (cond
  1404. ((const? a)
  1405. ;; Constants will be deduplicated later, but eq? folding can
  1406. ;; happen now. Anticipate the deduplication by using equal?
  1407. ;; instead of eq? or eqv?.
  1408. (for-tail (make-const src (equal? (const-exp a) v))))
  1409. ((eq? name 'eq?)
  1410. ;; Already in a reduced state.
  1411. (make-primcall src 'eq? (list a b)))
  1412. ((or (memq v '(#f #t () #nil)) (symbol? v) (char? v)
  1413. ;; Only fold to eq? value is a fixnum on target and
  1414. ;; host, as constant folding may have us compare on host
  1415. ;; as well.
  1416. (and (exact-integer? v)
  1417. (<= (max (target-most-negative-fixnum)
  1418. most-negative-fixnum)
  1419. v
  1420. (min (target-most-positive-fixnum)
  1421. most-positive-fixnum))))
  1422. ;; Reduce to eq?. Note that in Guile, characters are
  1423. ;; comparable with eq?.
  1424. (make-primcall src 'eq? (list a b)))
  1425. ((number? v)
  1426. ;; equal? and eqv? on non-fixnum numbers is the same as
  1427. ;; eqv?, and can't be reduced beyond that.
  1428. (make-primcall src 'eqv? (list a b)))
  1429. ((eq? name 'eqv?)
  1430. ;; eqv? on anything else is the same as eq?.
  1431. (make-primcall src 'eq? (list a b)))
  1432. (else
  1433. ;; FIXME: inline a specialized implementation of equal? for
  1434. ;; V here.
  1435. (make-primcall src name (list a b)))))
  1436. (((? equality-primitive?) (and a ($ <const>)) b)
  1437. (for-tail (make-primcall src name (list b a))))
  1438. (((? equality-primitive?) ($ <lexical-ref> _ _ sym)
  1439. ($ <lexical-ref> _ _ sym))
  1440. (for-tail (make-const src #t)))
  1441. (('logbit? ($ <const> src2
  1442. (? (lambda (bit)
  1443. (and (exact-integer? bit)
  1444. (<= 0 bit (logcount most-positive-fixnum))))
  1445. bit))
  1446. val)
  1447. (for-tail
  1448. (make-primcall src 'logtest
  1449. (list (make-const src2 (ash 1 bit)) val))))
  1450. (('logtest a b)
  1451. (for-tail
  1452. (make-primcall
  1453. src
  1454. 'not
  1455. (list
  1456. (make-primcall src 'eq?
  1457. (list (make-primcall src 'logand (list a b))
  1458. (make-const src 0)))))))
  1459. (((? effect-free-primitive?) . args)
  1460. (fold-constants src name args ctx))
  1461. ((name . args)
  1462. (if (and (eq? ctx 'effect) (effect-free-primcall? name args))
  1463. (if (null? args)
  1464. (make-void src)
  1465. (for-tail (list->seq src args)))
  1466. (make-primcall src name args)))))
  1467. (($ <call> src orig-proc orig-args)
  1468. (define (residualize-call)
  1469. (make-call src (for-call orig-proc) (map for-value orig-args)))
  1470. (define (singly-referenced-lambda? proc)
  1471. (match proc
  1472. (($ <lambda>) #t)
  1473. (($ <lexical-ref> _ _ sym)
  1474. (and (not (assigned-lexical? sym))
  1475. (= (lexical-refcount sym) 1)
  1476. (singly-referenced-lambda?
  1477. (operand-source (lookup sym)))))
  1478. (_ #f)))
  1479. (define (attempt-inlining proc names syms vals body)
  1480. (define inline-key (source-expression proc))
  1481. (define existing-counter (find-counter inline-key counter))
  1482. (define inlined-exp (make-let src names syms vals body))
  1483. (cond
  1484. ((and=> existing-counter counter-recursive?)
  1485. ;; A recursive call. Process again in tail context.
  1486. ;; Mark intervening counters as recursive, so we can
  1487. ;; handle a toplevel counter that recurses mutually with
  1488. ;; some other procedure. Otherwise, the next time we see
  1489. ;; the other procedure, the effort limit would be clamped
  1490. ;; to 100.
  1491. (let lp ((counter counter))
  1492. (unless (eq? counter existing-counter)
  1493. (set-counter-recursive?! counter #t)
  1494. (lp (counter-prev counter))))
  1495. (log 'inline-recurse inline-key)
  1496. (loop inlined-exp env counter ctx))
  1497. ((singly-referenced-lambda? orig-proc)
  1498. ;; A lambda in the operator position of the source
  1499. ;; expression. Process again in tail context.
  1500. (log 'inline-beta inline-key)
  1501. (loop inlined-exp env counter ctx))
  1502. (else
  1503. ;; An integration at the top-level, the first
  1504. ;; recursion of a recursive procedure, or a nested
  1505. ;; integration of a procedure that hasn't been seen
  1506. ;; yet.
  1507. (log 'inline-begin exp)
  1508. (let/ec k
  1509. (define (abort)
  1510. (log 'inline-abort exp)
  1511. (k (residualize-call)))
  1512. (define new-counter
  1513. (cond
  1514. ;; These first two cases will transfer effort from
  1515. ;; the current counter into the new counter.
  1516. (existing-counter
  1517. (make-recursive-counter recursive-effort-limit
  1518. operand-size-limit
  1519. existing-counter counter))
  1520. (counter
  1521. (make-nested-counter abort inline-key counter))
  1522. ;; This case opens a new account, effectively
  1523. ;; printing money. It should only do so once for
  1524. ;; each call site in the source program.
  1525. (else
  1526. (make-top-counter effort-limit operand-size-limit
  1527. abort inline-key))))
  1528. (define result
  1529. (loop inlined-exp env new-counter ctx))
  1530. (when counter
  1531. ;; The nested inlining attempt succeeded. Deposit the
  1532. ;; unspent effort and size back into the current
  1533. ;; counter.
  1534. (transfer! new-counter counter))
  1535. (log 'inline-end result exp)
  1536. result))))
  1537. (let revisit-proc ((proc (visit orig-proc 'operator)))
  1538. (match proc
  1539. (($ <primitive-ref> _ name)
  1540. (let ((exp (expand-primcall (make-primcall src name orig-args))))
  1541. (set! store
  1542. (augment-var-table-with-externally-introduced-lexicals
  1543. exp store))
  1544. (for-tail exp)))
  1545. (($ <lambda> _ _ clause)
  1546. ;; A lambda. Attempt to find the matching clause, if
  1547. ;; possible.
  1548. (define (inline-clause req opt rest kw inits gensyms body
  1549. arity-mismatch)
  1550. (define (bind name sym val binds)
  1551. (cons (vector name sym val) binds))
  1552. (define (has-binding? binds sym)
  1553. (match binds
  1554. (() #f)
  1555. ((#(n s v) . binds)
  1556. (or (eq? s sym) (has-binding? binds sym)))))
  1557. ;; The basic idea is that we are going to transform an
  1558. ;; expression like ((lambda (param ...) body) arg ...)
  1559. ;; into (let ((param arg) ...) body). However, we have to
  1560. ;; consider order of effects and scope: the args are
  1561. ;; logically parallel, whereas initializer expressions for
  1562. ;; params that don't have arguments are evaluated in
  1563. ;; order, after the arguments. Therefore we have a set of
  1564. ;; parallel bindings, abbreviated pbinds, which proceed
  1565. ;; from the call site, and a set of serial bindings, the
  1566. ;; sbinds, which result from callee initializers. We
  1567. ;; collect these in reverse order as we parse arguments.
  1568. ;; The result is an outer let for the parallel bindings
  1569. ;; containing a let* of the serial bindings and then the
  1570. ;; body.
  1571. (define (process-req req syms args pbinds sbinds)
  1572. (match req
  1573. (() (process-opt (or opt '()) syms inits args pbinds sbinds))
  1574. ((name . req)
  1575. (match syms
  1576. ((sym . syms)
  1577. (match args
  1578. (() (arity-mismatch))
  1579. ((arg . args)
  1580. (process-req req syms args
  1581. (bind name sym arg pbinds)
  1582. sbinds))))))))
  1583. (define (keyword-arg? exp)
  1584. (match exp
  1585. (($ <const> _ (? keyword?)) #t)
  1586. (_ #f)))
  1587. (define (not-keyword-arg? exp)
  1588. (match exp
  1589. ((or ($ <const> _ (not (? keyword?)))
  1590. ($ <void>)
  1591. ($ <primitive-ref>)
  1592. ($ <lambda>))
  1593. #t)
  1594. (_ #f)))
  1595. (define (process-opt opt syms inits args pbinds sbinds)
  1596. (match opt
  1597. (() (process-rest syms inits args pbinds sbinds))
  1598. ((name . opt)
  1599. (match inits
  1600. ((init . inits)
  1601. (match syms
  1602. ((sym . syms)
  1603. (cond
  1604. (kw
  1605. (match args
  1606. ((or () ((? keyword-arg?) . _))
  1607. ;; Optargs and kwargs; stop optarg dispatch at
  1608. ;; first keyword.
  1609. (process-opt opt syms inits args pbinds
  1610. (bind name sym init sbinds)))
  1611. (((? not-keyword-arg? arg) . args)
  1612. ;; Arg is definitely not a keyword; it is an
  1613. ;; optarg.
  1614. (process-opt opt syms inits args
  1615. (bind name sym arg pbinds)
  1616. sbinds))
  1617. (_
  1618. ;; We can't tell whether the arg is a keyword
  1619. ;; or not! Annoying semantics, this.
  1620. (residualize-call))))
  1621. (else
  1622. ;; No kwargs.
  1623. (match args
  1624. (()
  1625. (process-opt opt syms inits args pbinds
  1626. (bind name sym init sbinds)))
  1627. ((arg . args)
  1628. (process-opt opt syms inits args
  1629. (bind name sym arg pbinds)
  1630. sbinds))))))))))))
  1631. (define (process-rest syms inits args pbinds sbinds)
  1632. (match rest
  1633. (#f
  1634. (match kw
  1635. ((#f . kw)
  1636. (process-kw kw syms inits args pbinds sbinds))
  1637. (#f
  1638. (unless (and (null? syms) (null? inits))
  1639. (error "internal error"))
  1640. (match args
  1641. (() (finish pbinds sbinds body))
  1642. (_ (arity-mismatch))))))
  1643. (rest
  1644. (match syms
  1645. ((sym . syms)
  1646. (let ((rest-val (make-primcall src 'list args)))
  1647. (unless (and (null? syms) (null? inits))
  1648. (error "internal error"))
  1649. (finish pbinds (bind rest sym rest-val sbinds)
  1650. body)))))))
  1651. (define (process-kw kw syms inits args pbinds sbinds)
  1652. ;; Require that the ordered list of the keywords'
  1653. ;; syms is the same as the remaining gensyms to bind.
  1654. ;; Psyntax emits tree-il with this property, and it
  1655. ;; is required by (and checked by) other parts of the
  1656. ;; compiler, e.g. tree-il-to-cps lowering.
  1657. (unless (equal? syms (match kw (((k name sym) ...) sym)))
  1658. (error "internal error: unexpected kwarg syms" kw syms))
  1659. (define (process-kw-args positional? args pbinds)
  1660. (match args
  1661. (()
  1662. (process-kw-inits kw inits pbinds sbinds))
  1663. ((($ <const> _ (? keyword? keyword)) arg . args)
  1664. (match (assq keyword kw)
  1665. ((keyword name sym)
  1666. ;; Because of side effects, we don't
  1667. ;; optimize passing the same keyword arg
  1668. ;; multiple times.
  1669. (if (has-binding? pbinds sym)
  1670. (residualize-call)
  1671. (process-kw-args #f args
  1672. (bind name sym arg pbinds))))
  1673. (#f (residualize-call))))
  1674. (((? not-keyword-arg?) . args)
  1675. (if positional?
  1676. (arity-mismatch)
  1677. (residualize-call)))
  1678. (_ (residualize-call))))
  1679. (define (process-kw-inits kw inits pbinds sbinds)
  1680. (match kw
  1681. (()
  1682. (unless (null? inits) (error "internal error"))
  1683. (finish pbinds sbinds body))
  1684. (((keyword name sym) . kw)
  1685. (match inits
  1686. ((init . inits)
  1687. (process-kw-inits kw inits pbinds
  1688. (if (has-binding? pbinds sym)
  1689. sbinds
  1690. (bind name sym init sbinds))))))))
  1691. (process-kw-args #t args pbinds))
  1692. (define (finish pbinds sbinds body)
  1693. (match sbinds
  1694. (()
  1695. (match (reverse pbinds)
  1696. ((#(name sym val) ...)
  1697. (attempt-inlining proc name sym val body))))
  1698. ((#(name sym val) . sbinds)
  1699. (finish pbinds sbinds
  1700. (make-let src (list name) (list sym) (list val)
  1701. body)))))
  1702. ;; Limitations:
  1703. ;;
  1704. ;; - #:key or #:rest, but not both.
  1705. ;; - #:allow-other-keys unsupported.
  1706. (cond
  1707. ((and kw (or rest (match kw ((aok? . _) aok?))))
  1708. (residualize-call))
  1709. (else
  1710. (process-req req gensyms orig-args '() '()))))
  1711. (let lp ((clause clause))
  1712. (match clause
  1713. ;; No clause matches.
  1714. (#f (residualize-call))
  1715. (($ <lambda-case> src req opt rest kw inits gensyms body alt)
  1716. (inline-clause req opt rest kw inits gensyms body
  1717. (lambda () (lp alt)))))))
  1718. (($ <let> _ _ _ vals _)
  1719. ;; Attempt to inline `let' in the operator position.
  1720. ;;
  1721. ;; We have to re-visit the proc in value mode, since the
  1722. ;; `let' bindings might have been introduced or renamed,
  1723. ;; whereas the lambda (if any) in operator position has not
  1724. ;; been renamed.
  1725. (if (or (and-map constant-expression? vals)
  1726. (and-map constant-expression? orig-args))
  1727. ;; The arguments and the let-bound values commute.
  1728. (match (for-value orig-proc)
  1729. (($ <let> lsrc names syms vals body)
  1730. (log 'inline-let orig-proc)
  1731. (for-tail
  1732. (make-let lsrc names syms vals
  1733. (make-call src body orig-args))))
  1734. ;; It's possible for a `let' to go away after the
  1735. ;; visit due to the fact that visiting a procedure in
  1736. ;; value context will prune unused bindings, whereas
  1737. ;; visiting in operator mode can't because it doesn't
  1738. ;; traverse through lambdas. In that case re-visit
  1739. ;; the procedure.
  1740. (proc (revisit-proc proc)))
  1741. (residualize-call)))
  1742. (_ (residualize-call)))))
  1743. (($ <lambda> src meta body)
  1744. (case ctx
  1745. ((effect) (make-void #f))
  1746. ((test) (make-const #f #t))
  1747. ((operator) exp)
  1748. (else (record-source-expression!
  1749. exp
  1750. (make-lambda src meta (and body (for-values body)))))))
  1751. (($ <lambda-case> src req opt rest kw inits gensyms body alt)
  1752. (define (lift-applied-lambda body gensyms)
  1753. (and (null? opt) rest (not kw)
  1754. (match body
  1755. (($ <primcall> _ 'apply
  1756. (($ <lambda> _ _ (and lcase ($ <lambda-case> _ req1)))
  1757. ($ <lexical-ref> _ _ sym)
  1758. ...))
  1759. (and (equal? sym gensyms)
  1760. (not (lambda-case-alternate lcase))
  1761. (<= (length req) (length req1))
  1762. (every (lambda (s)
  1763. (= (lexical-refcount s) 1))
  1764. sym)
  1765. lcase))
  1766. (_ #f))))
  1767. (let* ((vars (map lookup-var gensyms))
  1768. (new (fresh-gensyms vars))
  1769. (env (fold extend-env env gensyms
  1770. (make-unbound-operands vars new)))
  1771. (new-sym (lambda (old)
  1772. (operand-sym (cdr (vhash-assq old env)))))
  1773. (body (loop body env counter ctx)))
  1774. (or
  1775. ;; (lambda args (apply (lambda ...) args)) => (lambda ...)
  1776. (lift-applied-lambda body new)
  1777. (make-lambda-case src req opt rest
  1778. (match kw
  1779. ((aok? (kw name old) ...)
  1780. (cons aok? (map list kw name (map new-sym old))))
  1781. (_ #f))
  1782. (map (cut loop <> env counter 'value) inits)
  1783. new
  1784. body
  1785. (and alt (for-tail alt))))))
  1786. (($ <seq> src head tail)
  1787. (let ((head (for-effect head))
  1788. (tail (for-tail tail)))
  1789. (if (void? head)
  1790. tail
  1791. (make-seq src
  1792. (if (and (seq? head)
  1793. (void? (seq-tail head)))
  1794. (seq-head head)
  1795. head)
  1796. tail))))
  1797. (($ <prompt> src escape-only? tag body handler)
  1798. (define (make-prompt-tag? x)
  1799. (match x
  1800. (($ <primcall> _ 'make-prompt-tag (or () ((? constant-expression?))))
  1801. #t)
  1802. (_ #f)))
  1803. (let ((tag (for-value tag))
  1804. (body (if escape-only? (for-tail body) (for-value body))))
  1805. (cond
  1806. ((find-definition tag 1)
  1807. (lambda (val op)
  1808. (make-prompt-tag? val))
  1809. => (lambda (val op)
  1810. ;; There is no way that an <abort> could know the tag
  1811. ;; for this <prompt>, so we can elide the <prompt>
  1812. ;; entirely.
  1813. (when op (unrecord-operand-uses op 1))
  1814. (for-tail (if escape-only? body (make-call src body '())))))
  1815. (else
  1816. (let ((handler (for-value handler)))
  1817. (define (escape-only-handler? handler)
  1818. (match handler
  1819. (($ <lambda> _ _
  1820. ($ <lambda-case> _ (_ . _) _ _ _ _ (k . _) body #f))
  1821. (not (tree-il-any
  1822. (match-lambda
  1823. (($ <lexical-ref> _ _ (? (cut eq? <> k))) #t)
  1824. (_ #f))
  1825. body)))
  1826. (else #f)))
  1827. (if (and (not escape-only?) (escape-only-handler? handler))
  1828. ;; Prompt transitioning to escape-only; transition body
  1829. ;; to be an expression.
  1830. (for-tail
  1831. (make-prompt src #t tag (make-call #f body '()) handler))
  1832. (make-prompt src escape-only? tag body handler)))))))
  1833. (($ <abort> src tag args tail)
  1834. (make-abort src (for-value tag) (map for-value args)
  1835. (for-value tail))))))