compile-cps.scm 99 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013-2015,2017-2019 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. ;;; Commentary:
  17. ;;;
  18. ;;; This pass converts Tree-IL to the continuation-passing style (CPS)
  19. ;;; language.
  20. ;;;
  21. ;;; CPS is a lower-level representation than Tree-IL. Converting to
  22. ;;; CPS, beyond adding names for all control points and all values,
  23. ;;; simplifies expressions in the following ways, among others:
  24. ;;;
  25. ;;; * Fixing the order of evaluation.
  26. ;;;
  27. ;;; * Converting assigned variables to boxed variables.
  28. ;;;
  29. ;;; * Requiring that Scheme's <letrec> has already been lowered to
  30. ;;; <fix>.
  31. ;;;
  32. ;;; * Inlining default-value initializers into lambda-case
  33. ;;; expressions.
  34. ;;;
  35. ;;; * Inlining prompt bodies.
  36. ;;;
  37. ;;; * Turning toplevel and module references into primcalls. This
  38. ;;; involves explicitly modelling the "scope" of toplevel lookups
  39. ;;; (indicating the module with respect to which toplevel bindings
  40. ;;; are resolved).
  41. ;;;
  42. ;;; The utility of CPS is that it gives a name to everything: every
  43. ;;; intermediate value, and every control point (continuation). As such
  44. ;;; it is more verbose than Tree-IL, but at the same time more simple as
  45. ;;; the number of concepts is reduced.
  46. ;;;
  47. ;;; Code:
  48. (define-module (language tree-il compile-cps)
  49. #:use-module (ice-9 match)
  50. #:use-module ((srfi srfi-1) #:select (fold filter-map))
  51. #:use-module (srfi srfi-26)
  52. #:use-module ((system foreign) #:select (make-pointer pointer->scm))
  53. #:use-module (system base target)
  54. #:use-module (system base types internal)
  55. #:use-module (language cps)
  56. #:use-module (language cps utils)
  57. #:use-module (language cps with-cps)
  58. #:use-module (language tree-il cps-primitives)
  59. #:use-module (language tree-il analyze)
  60. #:use-module (language tree-il optimize)
  61. #:use-module (language tree-il)
  62. #:use-module (language cps intmap)
  63. #:export (compile-cps))
  64. (define (convert-primcall/default cps k src op param . args)
  65. (with-cps cps
  66. (build-term
  67. ($continue k src ($primcall op param args)))))
  68. (define *primcall-converters* (make-hash-table))
  69. (define-syntax-rule (define-primcall-converter name proc)
  70. (hashq-set! *primcall-converters* 'name proc))
  71. (define (convert-primcall* cps k src op param args)
  72. (let ((proc (hashq-ref *primcall-converters* op convert-primcall/default)))
  73. (apply proc cps k src op param args)))
  74. (define (convert-primcall cps k src op param . args)
  75. (convert-primcall* cps k src op param args))
  76. (define (ensure-vector cps src op pred v have-length)
  77. (define msg
  78. (match pred
  79. ('vector?
  80. "Wrong type argument in position 1 (expecting vector): ~S")
  81. ('mutable-vector?
  82. "Wrong type argument in position 1 (expecting mutable vector): ~S")))
  83. (define not-vector (vector 'wrong-type-arg (symbol->string op) msg))
  84. (with-cps cps
  85. (letv w0 slen ulen rlen)
  86. (letk knot-vector
  87. ($kargs () () ($throw src 'throw/value+data not-vector (v))))
  88. (let$ body (have-length slen))
  89. (letk k ($kargs ('slen) (slen) ,body))
  90. (letk kcast
  91. ($kargs ('rlen) (rlen)
  92. ($continue k src ($primcall 'u64->s64 #f (rlen)))))
  93. (letk kassume
  94. ($kargs ('ulen) (ulen)
  95. ($continue kcast src
  96. ($primcall 'assume-u64 `(0 . ,(target-max-vector-length)) (ulen)))))
  97. (letk krsh
  98. ($kargs ('w0) (w0)
  99. ($continue kassume src ($primcall 'ursh/immediate 8 (w0)))))
  100. (letk kv
  101. ($kargs () ()
  102. ($continue krsh src
  103. ($primcall 'word-ref/immediate '(vector . 0) (v)))))
  104. (letk kheap-object
  105. ($kargs () ()
  106. ($branch knot-vector kv src pred #f (v))))
  107. (build-term
  108. ($branch knot-vector kheap-object src 'heap-object? #f (v)))))
  109. (define (untag-fixnum-index-in-range cps src op idx slen have-index-in-range)
  110. ;; Precondition: SLEN is a non-negative S64 that is representable as a
  111. ;; fixnum.
  112. (define not-fixnum
  113. (vector 'wrong-type-arg
  114. (symbol->string op)
  115. "Wrong type argument in position 2 (expecting small integer): ~S"))
  116. (define out-of-range
  117. (vector 'out-of-range
  118. (symbol->string op)
  119. "Argument 2 out of range: ~S"))
  120. (with-cps cps
  121. (letv sidx)
  122. (letk knot-fixnum
  123. ($kargs () () ($throw src 'throw/value+data not-fixnum (idx))))
  124. (letk kout-of-range
  125. ($kargs () () ($throw src 'throw/value+data out-of-range (idx))))
  126. (let$ body (have-index-in-range sidx))
  127. (letk k ($kargs () () ,body))
  128. (letk kboundlen
  129. ($kargs () ()
  130. ($branch kout-of-range k src 's64-< #f (sidx slen))))
  131. (letk kbound0
  132. ($kargs ('sidx) (sidx)
  133. ($branch kboundlen kout-of-range src 's64-imm-< 0 (sidx))))
  134. (letk kuntag
  135. ($kargs () ()
  136. ($continue kbound0 src ($primcall 'untag-fixnum #f (idx)))))
  137. (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (idx)))))
  138. (define (untag-fixnum-in-imm-range cps src op size min max have-int-in-range)
  139. (define not-fixnum
  140. (vector 'wrong-type-arg
  141. (symbol->string op)
  142. "Wrong type argument in position 2 (expecting small integer): ~S"))
  143. (define out-of-range
  144. (vector 'out-of-range
  145. (symbol->string op)
  146. "Argument 2 out of range: ~S"))
  147. (with-cps cps
  148. (letv ssize)
  149. (letk knot-fixnum
  150. ($kargs () () ($throw src 'throw/value+data not-fixnum (size))))
  151. (letk kout-of-range
  152. ($kargs () () ($throw src 'throw/value+data out-of-range (size))))
  153. (let$ body (have-int-in-range ssize))
  154. (letk k ($kargs () () ,body))
  155. (letk kboundlen
  156. ($kargs () ()
  157. ($branch k kout-of-range src 'imm-s64-< max (ssize))))
  158. (letk kbound0
  159. ($kargs ('ssize) (ssize)
  160. ($branch kboundlen kout-of-range src 's64-imm-< min (ssize))))
  161. (letk kuntag
  162. ($kargs () ()
  163. ($continue kbound0 src ($primcall 'untag-fixnum #f (size)))))
  164. (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (size)))))
  165. (define (compute-vector-access-pos cps src sidx have-pos)
  166. (with-cps cps
  167. (letv spos upos)
  168. (let$ body (have-pos upos))
  169. (letk kref ($kargs ('pos) (upos) ,body))
  170. (letk kcvt ($kargs ('pos) (spos)
  171. ($continue kref src ($primcall 's64->u64 #f (spos)))))
  172. (build-term
  173. ($continue kcvt src ($primcall 'sadd/immediate 1 (sidx))))))
  174. (define (prepare-vector-access cps src op pred v idx access)
  175. (ensure-vector
  176. cps src op pred v
  177. (lambda (cps slen)
  178. (untag-fixnum-index-in-range
  179. cps src op idx slen
  180. (lambda (cps sidx)
  181. (compute-vector-access-pos
  182. cps src sidx
  183. (lambda (cps pos)
  184. (access cps v pos))))))))
  185. (define (prepare-vector-access/immediate cps src op pred v idx access)
  186. (unless (and (exact-integer? idx) (<= 0 idx (1- (target-max-vector-length))))
  187. (error "precondition failed" idx))
  188. (ensure-vector
  189. cps src op pred v
  190. (lambda (cps slen)
  191. (define out-of-range
  192. (vector 'out-of-range
  193. (symbol->string op)
  194. "Argument 2 out of range: ~S"))
  195. (with-cps cps
  196. (letv tidx)
  197. (letk kthrow
  198. ($kargs ('tidx) (tidx)
  199. ($throw src 'throw/value+data out-of-range (tidx))))
  200. (letk kout-of-range
  201. ($kargs () ()
  202. ($continue kthrow src ($const idx))))
  203. (let$ body (access v (1+ idx)))
  204. (letk k ($kargs () () ,body))
  205. (build-term
  206. ($branch kout-of-range k src 'imm-s64-< idx (slen)))))))
  207. (define-primcall-converter vector-length
  208. (lambda (cps k src op param v)
  209. (ensure-vector
  210. cps src op 'vector? v
  211. (lambda (cps slen)
  212. (with-cps cps
  213. (build-term
  214. ($continue k src ($primcall 'tag-fixnum #f (slen)))))))))
  215. (define-primcall-converter vector-ref
  216. (lambda (cps k src op param v idx)
  217. (prepare-vector-access
  218. cps src op 'vector? v idx
  219. (lambda (cps v upos)
  220. (with-cps cps
  221. (build-term
  222. ($continue k src
  223. ($primcall 'scm-ref 'vector (v upos)))))))))
  224. (define-primcall-converter vector-ref/immediate
  225. (lambda (cps k src op param v)
  226. (prepare-vector-access/immediate
  227. cps src 'vector-ref 'vector? v param
  228. (lambda (cps v pos)
  229. (with-cps cps
  230. (build-term
  231. ($continue k src
  232. ($primcall 'scm-ref/immediate `(vector . ,pos) (v)))))))))
  233. (define-primcall-converter vector-set!
  234. (lambda (cps k src op param v idx val)
  235. (prepare-vector-access
  236. cps src op 'mutable-vector? v idx
  237. (lambda (cps v upos)
  238. (with-cps cps
  239. (build-term
  240. ($continue k src
  241. ($primcall 'scm-set! 'vector (v upos val)))))))))
  242. (define-primcall-converter vector-set!/immediate
  243. (lambda (cps k src op param v val)
  244. (prepare-vector-access/immediate
  245. cps src 'vector-set! 'mutable-vector? v param
  246. (lambda (cps v pos)
  247. (with-cps cps
  248. (build-term
  249. ($continue k src
  250. ($primcall 'scm-set!/immediate `(vector . ,pos) (v val)))))))))
  251. (define-primcall-converter vector-init!
  252. (lambda (cps k src op param v val)
  253. (define pos (1+ param))
  254. (with-cps cps
  255. (build-term
  256. ($continue k src
  257. ($primcall 'scm-set!/immediate `(vector . ,pos) (v val)))))))
  258. (define (emit-initializations-as-loop cps k src obj annotation start nwords init)
  259. (with-cps cps
  260. (letv pos)
  261. (letk kloop ,#f) ;; Patched later.
  262. (letk kback
  263. ($kargs () ()
  264. ($continue kloop src
  265. ($primcall 'uadd/immediate 1 (pos)))))
  266. (letk kinit
  267. ($kargs () ()
  268. ($continue kback src
  269. ($primcall 'scm-set! annotation (obj pos init)))))
  270. (setk kloop
  271. ($kargs ('pos) (pos)
  272. ($branch k kinit src 'u64-< #f (pos nwords))))
  273. (build-term
  274. ($continue kloop src
  275. ($primcall 'load-u64 start ())))))
  276. (define-primcall-converter allocate-vector
  277. (lambda (cps k src op param)
  278. (define size param)
  279. (define nwords (1+ size))
  280. (unless (and (exact-integer? size) (<= 0 size (target-max-vector-length)))
  281. (error "precondition failed" size))
  282. (with-cps cps
  283. (letv v w0)
  284. (letk kdone
  285. ($kargs () ()
  286. ($continue k src ($values (v)))))
  287. (letk ktag1
  288. ($kargs ('w0) (w0)
  289. ($continue kdone src
  290. ($primcall 'word-set!/immediate '(vector . 0) (v w0)))))
  291. (letk ktag0
  292. ($kargs ('v) (v)
  293. ($continue ktag1 src
  294. ($primcall 'load-u64 (+ %tc7-vector (ash size 8)) ()))))
  295. (build-term
  296. ($continue ktag0 src
  297. ($primcall 'allocate-words/immediate `(vector . ,nwords) ()))))))
  298. (define-primcall-converter make-vector
  299. (lambda (cps k src op param size init)
  300. (untag-fixnum-in-imm-range
  301. cps src op size 0 (target-max-vector-length)
  302. (lambda (cps ssize)
  303. (with-cps cps
  304. (letv usize nwords v w0-high w0)
  305. (letk kdone
  306. ($kargs () ()
  307. ($continue k src ($values (v)))))
  308. (let$ init-loop
  309. (emit-initializations-as-loop kdone src v 'vector 1 nwords init))
  310. (letk kbody ($kargs () () ,init-loop))
  311. (letk ktag2
  312. ($kargs ('w0) (w0)
  313. ($continue kbody src
  314. ($primcall 'word-set!/immediate '(vector . 0) (v w0)))))
  315. (letk ktag1
  316. ($kargs ('w0-high) (w0-high)
  317. ($continue ktag2 src
  318. ($primcall 'uadd/immediate %tc7-vector (w0-high)))))
  319. (letk ktag0
  320. ($kargs ('v) (v)
  321. ($continue ktag1 src
  322. ($primcall 'ulsh/immediate 8 (usize)))))
  323. (letk kalloc
  324. ($kargs ('nwords) (nwords)
  325. ($continue ktag0 src
  326. ($primcall 'allocate-words 'vector (nwords)))))
  327. (letk kadd1
  328. ($kargs ('usize) (usize)
  329. ($continue kalloc src
  330. ;; Header word.
  331. ($primcall 'uadd/immediate 1 (usize)))))
  332. (build-term
  333. ($continue kadd1 src
  334. ;; Header word.
  335. ($primcall 's64->u64 #f (ssize)))))))))
  336. (define-primcall-converter make-vector/immediate
  337. (lambda (cps k src op param init)
  338. (define size param)
  339. (define nwords (1+ size))
  340. (define (init-fields cps v pos kdone)
  341. ;; Inline the initializations, up to vectors of size 32. Above
  342. ;; that it's a bit of a waste, so reify a loop instead.
  343. (cond
  344. ((<= 32 nwords)
  345. (with-cps cps
  346. (letv unwords)
  347. (let$ init-loop
  348. (emit-initializations-as-loop kdone src v 'vector
  349. pos unwords init))
  350. (letk kinit ($kargs ('unwords) (unwords) ,init-loop))
  351. (letk kusize ($kargs () ()
  352. ($continue kinit src
  353. ($primcall 'load-u64 nwords ()))))
  354. kusize))
  355. ((< pos nwords)
  356. (with-cps cps
  357. (let$ knext (init-fields v (1+ pos) kdone))
  358. (letk kinit
  359. ($kargs () ()
  360. ($continue knext src
  361. ($primcall 'scm-set!/immediate `(vector . ,pos)
  362. (v init)))))
  363. kinit))
  364. (else
  365. (with-cps cps
  366. kdone))))
  367. (unless (and (exact-integer? size) (<= 0 size (target-max-vector-length)))
  368. (error "precondition failed" size))
  369. (with-cps cps
  370. (letv v w0)
  371. (letk kdone
  372. ($kargs () ()
  373. ($continue k src ($values (v)))))
  374. (let$ kinit (init-fields v 1 kdone))
  375. (letk ktag1
  376. ($kargs ('w0) (w0)
  377. ($continue kinit src
  378. ($primcall 'word-set!/immediate '(vector . 0) (v w0)))))
  379. (letk ktag0
  380. ($kargs ('v) (v)
  381. ($continue ktag1 src
  382. ($primcall 'load-u64 (+ %tc7-vector (ash size 8)) ()))))
  383. (build-term
  384. ($continue ktag0 src
  385. ($primcall 'allocate-words/immediate `(vector . ,nwords) ()))))))
  386. (define (ensure-pair cps src op pred x is-pair)
  387. (define msg
  388. (match pred
  389. ('pair?
  390. "Wrong type argument in position 1 (expecting pair): ~S")
  391. ('mutable-pair?
  392. "Wrong type argument in position 1 (expecting mutable pair): ~S")))
  393. (define not-pair (vector 'wrong-type-arg (symbol->string op) msg))
  394. (with-cps cps
  395. (letk knot-pair ($kargs () () ($throw src 'throw/value+data not-pair (x))))
  396. (let$ body (is-pair))
  397. (letk k ($kargs () () ,body))
  398. (letk kheap-object ($kargs () () ($branch knot-pair k src pred #f (x))))
  399. (build-term ($branch knot-pair kheap-object src 'heap-object? #f (x)))))
  400. (define-primcall-converter cons
  401. (lambda (cps k src op param head tail)
  402. (with-cps cps
  403. (letv pair)
  404. (letk kdone
  405. ($kargs () ()
  406. ($continue k src ($values (pair)))))
  407. (letk ktail
  408. ($kargs () ()
  409. ($continue kdone src
  410. ($primcall 'scm-set!/immediate '(pair . 1) (pair tail)))))
  411. (letk khead
  412. ($kargs ('pair) (pair)
  413. ($continue ktail src
  414. ($primcall 'scm-set!/immediate '(pair . 0) (pair head)))))
  415. (build-term
  416. ($continue khead src
  417. ($primcall 'allocate-words/immediate '(pair . 2) ()))))))
  418. (define-primcall-converter car
  419. (lambda (cps k src op param pair)
  420. (ensure-pair
  421. cps src 'car 'pair? pair
  422. (lambda (cps)
  423. (with-cps cps
  424. (build-term
  425. ($continue k src
  426. ($primcall 'scm-ref/immediate '(pair . 0) (pair)))))))))
  427. (define-primcall-converter cdr
  428. (lambda (cps k src op param pair)
  429. (ensure-pair
  430. cps src 'cdr 'pair? pair
  431. (lambda (cps)
  432. (with-cps cps
  433. (build-term
  434. ($continue k src
  435. ($primcall 'scm-ref/immediate '(pair . 1) (pair)))))))))
  436. (define-primcall-converter set-car!
  437. (lambda (cps k src op param pair val)
  438. (ensure-pair
  439. ;; FIXME: Use mutable-pair? as predicate.
  440. cps src 'set-car! 'pair? pair
  441. (lambda (cps)
  442. (with-cps cps
  443. (build-term
  444. ($continue k src
  445. ($primcall 'scm-set!/immediate '(pair . 0) (pair val)))))))))
  446. (define-primcall-converter set-cdr!
  447. (lambda (cps k src op param pair val)
  448. (ensure-pair
  449. ;; FIXME: Use mutable-pair? as predicate.
  450. cps src 'set-cdr! 'pair? pair
  451. (lambda (cps)
  452. (with-cps cps
  453. (build-term
  454. ($continue k src
  455. ($primcall 'scm-set!/immediate '(pair . 1) (pair val)))))))))
  456. (define-primcall-converter box
  457. (lambda (cps k src op param val)
  458. (with-cps cps
  459. (letv obj tag)
  460. (letk kdone
  461. ($kargs () ()
  462. ($continue k src ($values (obj)))))
  463. (letk kval
  464. ($kargs () ()
  465. ($continue kdone src
  466. ($primcall 'scm-set!/immediate '(box . 1) (obj val)))))
  467. (letk ktag1
  468. ($kargs ('tag) (tag)
  469. ($continue kval src
  470. ($primcall 'word-set!/immediate '(box . 0) (obj tag)))))
  471. (letk ktag0
  472. ($kargs ('obj) (obj)
  473. ($continue ktag1 src
  474. ($primcall 'load-u64 %tc7-variable ()))))
  475. (build-term
  476. ($continue ktag0 src
  477. ($primcall 'allocate-words/immediate '(box . 2) ()))))))
  478. (define-primcall-converter %box-ref
  479. (lambda (cps k src op param box)
  480. (define unbound
  481. #(misc-error "variable-ref" "Unbound variable: ~S"))
  482. (with-cps cps
  483. (letv val)
  484. (letk kunbound ($kargs () () ($throw src 'throw/value unbound (box))))
  485. (letk kbound ($kargs () () ($continue k src ($values (val)))))
  486. (letk ktest
  487. ($kargs ('val) (val)
  488. ($branch kbound kunbound src 'undefined? #f (val))))
  489. (build-term
  490. ($continue ktest src
  491. ($primcall 'scm-ref/immediate '(box . 1) (box)))))))
  492. (define-primcall-converter %box-set!
  493. (lambda (cps k src op param box val)
  494. (with-cps cps
  495. (build-term
  496. ($continue k src
  497. ($primcall 'scm-set!/immediate '(box . 1) (box val)))))))
  498. (define (ensure-box cps src op x is-box)
  499. (define not-box
  500. (vector 'wrong-type-arg
  501. (symbol->string op)
  502. "Wrong type argument in position 1 (expecting box): ~S"))
  503. (with-cps cps
  504. (letk knot-box ($kargs () () ($throw src 'throw/value+data not-box (x))))
  505. (let$ body (is-box))
  506. (letk k ($kargs () () ,body))
  507. (letk kheap-object ($kargs () () ($branch knot-box k src 'variable? #f (x))))
  508. (build-term ($branch knot-box kheap-object src 'heap-object? #f (x)))))
  509. (define-primcall-converter box-ref
  510. (lambda (cps k src op param box)
  511. (ensure-box
  512. cps src 'variable-ref box
  513. (lambda (cps)
  514. (convert-primcall cps k src '%box-ref param box)))))
  515. (define-primcall-converter box-set!
  516. (lambda (cps k src op param box val)
  517. (ensure-box
  518. cps src 'variable-set! box
  519. (lambda (cps)
  520. (convert-primcall cps k src '%box-set! param box val)))))
  521. (define (ensure-struct cps src op x have-vtable)
  522. (define not-struct
  523. (vector 'wrong-type-arg
  524. (symbol->string op)
  525. "Wrong type argument in position 1 (expecting struct): ~S"))
  526. (with-cps cps
  527. (letv vtable)
  528. (letk knot-struct
  529. ($kargs () () ($throw src 'throw/value+data not-struct (x))))
  530. (let$ body (have-vtable vtable))
  531. (letk k ($kargs ('vtable) (vtable) ,body))
  532. (letk kvtable ($kargs () ()
  533. ($continue k src ($primcall 'scm-ref/tag 'struct (x)))))
  534. (letk kheap-object
  535. ($kargs () () ($branch knot-struct kvtable src 'struct? #f (x))))
  536. (build-term ($branch knot-struct kheap-object src 'heap-object? #f (x)))))
  537. (define-primcall-converter struct-vtable
  538. (lambda (cps k src op param struct)
  539. (ensure-struct
  540. cps src 'struct-vtable struct
  541. (lambda (cps vtable)
  542. (with-cps cps
  543. (build-term
  544. ($continue k src ($values (vtable)))))))))
  545. (define (ensure-vtable cps src op vtable is-vtable)
  546. (ensure-struct
  547. cps src op vtable
  548. (lambda (cps vtable-vtable)
  549. (define not-vtable
  550. (vector 'wrong-type-arg
  551. (symbol->string op)
  552. "Wrong type argument in position 1 (expecting vtable): ~S"))
  553. (define vtable-index-flags 1) ; FIXME: pull from struct.h
  554. (define vtable-offset-flags (1+ vtable-index-flags))
  555. (define vtable-validated-mask #b11)
  556. (define vtable-validated-value #b11)
  557. (with-cps cps
  558. (letv flags mask res)
  559. (letk knot-vtable
  560. ($kargs () () ($throw src 'throw/value+data not-vtable (vtable))))
  561. (let$ body (is-vtable))
  562. (letk k ($kargs () () ,body))
  563. (letk ktest
  564. ($kargs ('res) (res)
  565. ($branch knot-vtable k src
  566. 'u64-imm-= vtable-validated-value (res))))
  567. (letk kand
  568. ($kargs ('mask) (mask)
  569. ($continue ktest src
  570. ($primcall 'ulogand #f (flags mask)))))
  571. (letk kflags
  572. ($kargs ('flags) (flags)
  573. ($continue kand src
  574. ($primcall 'load-u64 vtable-validated-mask ()))))
  575. (build-term
  576. ($continue kflags src
  577. ($primcall 'word-ref/immediate
  578. `(struct . ,vtable-offset-flags) (vtable-vtable))))))))
  579. (define-primcall-converter allocate-struct
  580. (lambda (cps k src op nwords vtable)
  581. (ensure-vtable
  582. cps src 'allocate-struct vtable
  583. (lambda (cps)
  584. (define vtable-index-size 5) ; FIXME: pull from struct.h
  585. (define vtable-index-unboxed-fields 6) ; FIXME: pull from struct.h
  586. (define vtable-offset-size (1+ vtable-index-size))
  587. (define vtable-offset-unboxed-fields (1+ vtable-index-unboxed-fields))
  588. (define wrong-number
  589. (vector 'wrong-number-of-args
  590. (symbol->string op)
  591. "Wrong number of initializers when instantiating ~A"))
  592. (define has-unboxed
  593. (vector 'wrong-type-arg
  594. (symbol->string op)
  595. "Expected vtable with no unboxed fields: ~A"))
  596. (define (check-all-boxed cps kf kt vtable ptr word)
  597. (if (< (* word 32) nwords)
  598. (with-cps cps
  599. (letv idx bits)
  600. (let$ checkboxed (check-all-boxed kf kt vtable ptr (1+ word)))
  601. (letk kcheckboxed ($kargs () () ,checkboxed))
  602. (letk kcheck
  603. ($kargs ('bits) (bits)
  604. ($branch kf kcheckboxed src 'u64-imm-= 0 (bits))))
  605. (letk kword
  606. ($kargs ('idx) (idx)
  607. ($continue kcheck src
  608. ($primcall 'u32-ref 'bitmask (vtable ptr idx)))))
  609. (build-term
  610. ($continue kword src
  611. ($primcall 'load-u64 word ()))))
  612. (with-cps cps
  613. (build-term ($continue kt src ($values ()))))))
  614. (with-cps cps
  615. (letv rfields nfields ptr s)
  616. (letk kwna
  617. ($kargs () () ($throw src 'throw/value wrong-number (vtable))))
  618. (letk kunboxed
  619. ($kargs () () ($throw src 'throw/value+data has-unboxed (vtable))))
  620. (letk kdone
  621. ($kargs () () ($continue k src ($values (s)))))
  622. (letk ktag
  623. ($kargs ('s) (s)
  624. ($continue kdone src
  625. ($primcall 'scm-set!/tag 'struct (s vtable)))))
  626. (letk kalloc
  627. ($kargs () ()
  628. ($continue ktag src
  629. ($primcall 'allocate-words/immediate
  630. `(struct . ,(1+ nwords)) ()))))
  631. (let$ checkboxed (check-all-boxed kunboxed kalloc vtable ptr 0))
  632. (letk kcheckboxed ($kargs ('ptr) (ptr) ,checkboxed))
  633. (letk kaccess
  634. ($kargs () ()
  635. ($continue kcheckboxed src
  636. ($primcall 'pointer-ref/immediate
  637. `(struct . ,vtable-offset-unboxed-fields)
  638. (vtable)))))
  639. (letk knfields
  640. ($kargs ('nfields) (nfields)
  641. ($branch kwna kaccess src 'u64-imm-= nwords (nfields))))
  642. (letk kassume
  643. ($kargs ('rfields) (rfields)
  644. ($continue knfields src
  645. ($primcall 'assume-u64 `(0 . ,(target-max-size-t/scm))
  646. (rfields)))))
  647. (build-term
  648. ($continue kassume src
  649. ($primcall 'word-ref/immediate
  650. `(struct . ,vtable-offset-size) (vtable)))))))))
  651. (define (ensure-struct-index-in-range cps src op vtable idx boxed? in-range)
  652. (define vtable-index-size 5) ; FIXME: pull from struct.h
  653. (define vtable-index-unboxed-fields 6) ; FIXME: pull from struct.h
  654. (define vtable-offset-size (1+ vtable-index-size))
  655. (define vtable-offset-unboxed-fields (1+ vtable-index-unboxed-fields))
  656. (define bad-type
  657. (vector
  658. 'wrong-type-arg
  659. (symbol->string op)
  660. (if boxed?
  661. "Wrong type argument in position 2 (expecting boxed field): ~S"
  662. "Wrong type argument in position 2 (expecting unboxed field): ~S")))
  663. (define out-of-range
  664. (vector 'out-of-range
  665. (symbol->string op)
  666. "Argument 2 out of range: ~S"))
  667. (with-cps cps
  668. (letv rfields nfields ptr word bits mask res throwval1 throwval2)
  669. (letk kthrow1
  670. ($kargs (#f) (throwval1)
  671. ($throw src 'throw/value+data out-of-range (throwval1))))
  672. (letk kthrow2
  673. ($kargs (#f) (throwval2)
  674. ($throw src 'throw/value+data bad-type (throwval2))))
  675. (letk kbadidx ($kargs () () ($continue kthrow1 src ($const idx))))
  676. (letk kbadtype ($kargs () () ($continue kthrow2 src ($const idx))))
  677. (let$ body (in-range))
  678. (letk k ($kargs () () ,body))
  679. (letk ktest
  680. ($kargs ('res) (res)
  681. ($branch (if boxed? kbadtype k) (if boxed? k kbadtype) src
  682. 'u64-imm-= 0 (res))))
  683. (letk kand
  684. ($kargs ('mask) (mask)
  685. ($continue ktest src
  686. ($primcall 'ulogand #f (mask bits)))))
  687. (letk kbits
  688. ($kargs ('bits) (bits)
  689. ($continue kand src
  690. ($primcall 'load-u64 (ash 1 (logand idx 31)) ()))))
  691. (letk kword
  692. ($kargs ('word) (word)
  693. ($continue kbits src
  694. ($primcall 'u32-ref 'bitmask (vtable ptr word)))))
  695. (letk kptr
  696. ($kargs ('ptr) (ptr)
  697. ($continue kword src
  698. ($primcall 'load-u64 (ash idx -5) ()))))
  699. (letk kaccess
  700. ($kargs () ()
  701. ($continue kptr src
  702. ($primcall 'pointer-ref/immediate
  703. `(struct . ,vtable-offset-unboxed-fields)
  704. (vtable)))))
  705. (letk knfields
  706. ($kargs ('nfields) (nfields)
  707. ($branch kbadidx kaccess src 'imm-u64-< idx (nfields))))
  708. (letk kassume
  709. ($kargs ('rfields) (rfields)
  710. ($continue knfields src
  711. ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (rfields)))))
  712. (build-term
  713. ($continue kassume src
  714. ($primcall 'word-ref/immediate
  715. `(struct . ,vtable-offset-size) (vtable))))))
  716. (define (prepare-struct-scm-access cps src op struct idx boxed? have-pos)
  717. (define not-struct
  718. (vector 'wrong-type-arg
  719. (symbol->string op)
  720. "Wrong type argument in position 1 (expecting struct): ~S"))
  721. (ensure-struct
  722. cps src op struct
  723. (lambda (cps vtable)
  724. (ensure-struct-index-in-range
  725. cps src op vtable idx boxed?
  726. (lambda (cps) (have-pos cps (1+ idx)))))))
  727. (define-primcall-converter struct-ref/immediate
  728. (lambda (cps k src op param struct)
  729. (prepare-struct-scm-access
  730. cps src op struct param #t
  731. (lambda (cps pos)
  732. (with-cps cps
  733. (build-term
  734. ($continue k src
  735. ($primcall 'scm-ref/immediate `(struct . ,pos) (struct)))))))))
  736. (define-primcall-converter struct-set!/immediate
  737. (lambda (cps k src op param struct val)
  738. (prepare-struct-scm-access
  739. cps src op struct param #t
  740. (lambda (cps pos)
  741. (with-cps cps
  742. (letk k* ($kargs () () ($continue k src ($values (val)))))
  743. (build-term
  744. ($continue k* src
  745. ($primcall 'scm-set!/immediate `(struct . ,pos) (struct val)))))))))
  746. (define-primcall-converter struct-init!
  747. (lambda (cps k src op param s val)
  748. (define pos (1+ param))
  749. (with-cps cps
  750. (build-term
  751. ($continue k src
  752. ($primcall 'scm-set!/immediate `(struct . ,pos) (s val)))))))
  753. (define-primcall-converter struct-ref
  754. (lambda (cps k src op param struct idx)
  755. (with-cps cps
  756. (letv prim res)
  757. (letk krecv ($kreceive '(res) #f k))
  758. (letk kprim ($kargs ('prim) (prim)
  759. ($continue krecv src ($call prim (struct idx)))))
  760. (build-term
  761. ($continue kprim src ($prim 'struct-ref))))))
  762. (define-primcall-converter struct-set!
  763. (lambda (cps k src op param struct idx val)
  764. (with-cps cps
  765. (letv prim res)
  766. ;; struct-set! prim returns the value.
  767. (letk krecv ($kreceive '(res) #f k))
  768. (letk kprim ($kargs ('prim) (prim)
  769. ($continue krecv src ($call prim (struct idx val)))))
  770. (build-term
  771. ($continue kprim src ($prim 'struct-set!))))))
  772. (define (untag-bytevector-index cps src op idx ulen width have-uidx)
  773. (define not-fixnum
  774. (vector 'wrong-type-arg
  775. (symbol->string op)
  776. "Wrong type argument in position 2 (expecting small integer): ~S"))
  777. (define out-of-range
  778. (vector 'out-of-range
  779. (symbol->string op)
  780. "Argument 2 out of range: ~S"))
  781. (with-cps cps
  782. (letv sidx uidx maxidx+1)
  783. (letk knot-fixnum
  784. ($kargs () () ($throw src 'throw/value+data not-fixnum (idx))))
  785. (letk kout-of-range
  786. ($kargs () () ($throw src 'throw/value+data out-of-range (idx))))
  787. (let$ body (have-uidx uidx))
  788. (letk k ($kargs () () ,body))
  789. (letk ktestidx
  790. ($kargs ('maxidx+1) (maxidx+1)
  791. ($branch kout-of-range k src 'u64-< #f (uidx maxidx+1))))
  792. (letk kdeclen
  793. ($kargs () ()
  794. ($continue ktestidx src
  795. ($primcall 'usub/immediate (1- width) (ulen)))))
  796. (letk ktestlen
  797. ($kargs ('uidx) (uidx)
  798. ($branch kout-of-range kdeclen src 'imm-u64-< (1- width) (ulen))))
  799. (letk kcvt
  800. ($kargs () ()
  801. ($continue ktestlen src ($primcall 's64->u64 #f (sidx)))))
  802. (letk kbound0
  803. ($kargs ('sidx) (sidx)
  804. ($branch kcvt kout-of-range src 's64-imm-< 0 (sidx))))
  805. (letk kuntag
  806. ($kargs () ()
  807. ($continue kbound0 src ($primcall 'untag-fixnum #f (idx)))))
  808. (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (idx)))))
  809. (define (ensure-bytevector cps k src op pred x)
  810. (define msg
  811. (match pred
  812. ('bytevector?
  813. "Wrong type argument in position 1 (expecting bytevector): ~S")
  814. ('mutable-bytevector?
  815. "Wrong type argument in position 1 (expecting mutable bytevector): ~S")))
  816. (define bad-type (vector 'wrong-type-arg (symbol->string op) msg))
  817. (with-cps cps
  818. (letk kf ($kargs () () ($throw src 'throw/value+data bad-type (x))))
  819. (letk kheap-object ($kargs () () ($branch kf k src pred #f (x))))
  820. (build-term ($branch kf kheap-object src 'heap-object? #f (x)))))
  821. (define (prepare-bytevector-access cps src op pred bv idx width
  822. have-ptr-and-uidx)
  823. (with-cps cps
  824. (letv ulen rlen)
  825. (let$ access
  826. (untag-bytevector-index
  827. src op idx rlen width
  828. (lambda (cps uidx)
  829. (with-cps cps
  830. (letv ptr)
  831. (let$ body (have-ptr-and-uidx ptr uidx))
  832. (letk k ($kargs ('ptr) (ptr) ,body))
  833. (build-term
  834. ($continue k src
  835. ($primcall 'pointer-ref/immediate '(bytevector . 2)
  836. (bv))))))))
  837. (letk k ($kargs ('rlen) (rlen) ,access))
  838. (letk kassume
  839. ($kargs ('ulen) (ulen)
  840. ($continue k src
  841. ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (ulen)))))
  842. (letk klen
  843. ($kargs () ()
  844. ($continue kassume src
  845. ($primcall 'word-ref/immediate '(bytevector . 1) (bv)))))
  846. ($ (ensure-bytevector klen src op pred bv))))
  847. (define (bytevector-ref-converter scheme-name ptr-op width kind)
  848. (define tag
  849. (match kind
  850. ('unsigned
  851. (if (< (ash 1 (* width 8)) (target-most-positive-fixnum))
  852. (lambda (cps k src val)
  853. (with-cps cps
  854. (letv s)
  855. (letk kcvt
  856. ($kargs ('s) (s)
  857. ($continue k src ($primcall 'tag-fixnum #f (s)))))
  858. (build-term
  859. ($continue kcvt src ($primcall 'u64->s64 #f (val))))))
  860. (lambda (cps k src val)
  861. (with-cps cps
  862. (build-term
  863. ($continue k src ($primcall 'u64->scm #f (val))))))))
  864. ('signed
  865. (if (< (ash 1 (* width 8)) (target-most-positive-fixnum))
  866. (lambda (cps k src val)
  867. (with-cps cps
  868. (build-term
  869. ($continue k src ($primcall 'tag-fixnum #f (val))))))
  870. (lambda (cps k src val)
  871. (with-cps cps
  872. (build-term
  873. ($continue k src ($primcall 's64->scm #f (val))))))))
  874. ('float
  875. (lambda (cps k src val)
  876. (with-cps cps
  877. (build-term
  878. ($continue k src ($primcall 'f64->scm #f (val)))))))))
  879. (lambda (cps k src op param bv idx)
  880. (prepare-bytevector-access
  881. cps src scheme-name 'bytevector? bv idx width
  882. (lambda (cps ptr uidx)
  883. (with-cps cps
  884. (letv val)
  885. (let$ body (tag k src val))
  886. (letk ktag ($kargs ('val) (val) ,body))
  887. (build-term
  888. ($continue ktag src
  889. ($primcall ptr-op 'bytevector (bv ptr uidx)))))))))
  890. (define (bytevector-set-converter scheme-name ptr-op width kind)
  891. (define out-of-range
  892. (vector 'out-of-range
  893. (symbol->string scheme-name)
  894. "Argument 3 out of range: ~S"))
  895. (define (limit-urange cps src val uval hi in-range)
  896. (with-cps cps
  897. (letk kbad ($kargs () ()
  898. ($throw src 'throw/value+data out-of-range (val))))
  899. (let$ body (in-range uval))
  900. (letk k ($kargs () () ,body))
  901. (build-term
  902. ($branch k kbad src 'imm-u64-< hi (uval)))))
  903. (define (limit-srange cps src val sval lo hi in-range)
  904. (with-cps cps
  905. (letk kbad ($kargs () ()
  906. ($throw src 'throw/value+data out-of-range (val))))
  907. (let$ body (in-range sval))
  908. (letk k ($kargs () () ,body))
  909. (letk k' ($kargs () ()
  910. ($branch k kbad src 's64-imm-< lo (sval))))
  911. (build-term
  912. ($branch k' kbad src 'imm-s64-< hi (sval)))))
  913. (define (integer-unboxer lo hi)
  914. (cond
  915. ((<= hi (target-most-positive-fixnum))
  916. (lambda (cps src val have-val)
  917. (let ((have-val (if (zero? lo)
  918. (lambda (cps s)
  919. (with-cps cps
  920. (letv u)
  921. (let$ body (have-val u))
  922. (letk k ($kargs ('u) (u) ,body))
  923. (build-term
  924. ($continue k src
  925. ($primcall 's64->u64 #f (s))))))
  926. have-val)))
  927. (with-cps cps
  928. (letv sval)
  929. (letk kbad ($kargs () ()
  930. ($throw src 'throw/value+data out-of-range (val))))
  931. (let$ body (have-val sval))
  932. (letk k ($kargs () () ,body))
  933. (letk khi ($kargs () ()
  934. ($branch k kbad src 'imm-s64-< hi (sval))))
  935. (letk klo ($kargs ('sval) (sval)
  936. ($branch khi kbad src 's64-imm-< lo (sval))))
  937. (letk kuntag
  938. ($kargs () ()
  939. ($continue klo src ($primcall 'untag-fixnum #f (val)))))
  940. (build-term
  941. ($branch kbad kuntag src 'fixnum? #f (val)))))))
  942. ((zero? lo)
  943. (lambda (cps src val have-val)
  944. (with-cps cps
  945. (letv u)
  946. (let$ body (limit-urange src val u hi have-val))
  947. (letk khi ($kargs ('u) (u) ,body))
  948. (build-term
  949. ($continue khi src ($primcall 'scm->u64 #f (val)))))))
  950. (else
  951. (lambda (cps src val have-val)
  952. (with-cps cps
  953. (letv s)
  954. (let$ body (limit-srange src val s lo hi have-val))
  955. (letk khi ($kargs ('s) (s) ,body))
  956. (build-term
  957. ($continue khi src ($primcall 'scm->s64 #f (val)))))))))
  958. (define untag
  959. (match kind
  960. ('unsigned (integer-unboxer 0 (1- (ash 1 (* width 8)))))
  961. ('signed (integer-unboxer (ash -1 (1- (* width 8)))
  962. (1- (ash 1 (1- (* width 8))))))
  963. ('float
  964. (lambda (cps src val have-val)
  965. (with-cps cps
  966. (letv f)
  967. (let$ body (have-val f))
  968. (letk k ($kargs ('f) (f) ,body))
  969. (build-term
  970. ($continue k src ($primcall 'scm->f64 #f (val)))))))))
  971. (lambda (cps k src op param bv idx val)
  972. (prepare-bytevector-access
  973. cps src scheme-name 'bytevector? bv idx width
  974. (lambda (cps ptr uidx)
  975. (untag
  976. cps src val
  977. (lambda (cps uval)
  978. (with-cps cps
  979. (build-term
  980. ($continue k src
  981. ($primcall ptr-op 'bytevector (bv ptr uidx uval)))))))))))
  982. (define-syntax-rule (define-bytevector-ref-converter
  983. cps-name scheme-name op width kind)
  984. (define-primcall-converter cps-name
  985. (bytevector-ref-converter 'scheme-name 'op width 'kind)))
  986. (define-syntax-rule (define-bytevector-ref-converters (cvt ...) ...)
  987. (begin
  988. (define-bytevector-ref-converter cvt ...)
  989. ...))
  990. (define-syntax-rule (define-bytevector-set-converter
  991. cps-name scheme-name op width kind)
  992. (define-primcall-converter cps-name
  993. (bytevector-set-converter 'scheme-name 'op width 'kind)))
  994. (define-syntax-rule (define-bytevector-set-converters (cvt ...) ...)
  995. (begin
  996. (define-bytevector-set-converter cvt ...)
  997. ...))
  998. (define-primcall-converter bv-length
  999. (lambda (cps k src op param bv)
  1000. (with-cps cps
  1001. (letv ulen rlen)
  1002. (letk ktag ($kargs ('rlen) (rlen)
  1003. ($continue k src ($primcall 'u64->scm #f (rlen)))))
  1004. (letk kassume
  1005. ($kargs ('ulen) (ulen)
  1006. ($continue ktag src
  1007. ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (ulen)))))
  1008. (letk klen
  1009. ($kargs () ()
  1010. ($continue kassume src
  1011. ($primcall 'word-ref/immediate '(bytevector . 1) (bv)))))
  1012. ($ (ensure-bytevector klen src op 'bytevector? bv)))))
  1013. (define-bytevector-ref-converters
  1014. (bv-u8-ref bytevector-u8-ref u8-ref 1 unsigned)
  1015. (bv-u16-ref bytevector-u16-native-ref u16-ref 2 unsigned)
  1016. (bv-u32-ref bytevector-u32-native-ref u32-ref 4 unsigned)
  1017. (bv-u64-ref bytevector-u64-native-ref u64-ref 8 unsigned)
  1018. (bv-s8-ref bytevector-s8-ref s8-ref 1 signed)
  1019. (bv-s16-ref bytevector-s16-native-ref s16-ref 2 signed)
  1020. (bv-s32-ref bytevector-s32-native-ref s32-ref 4 signed)
  1021. (bv-s64-ref bytevector-s64-native-ref s64-ref 8 signed)
  1022. (bv-f32-ref bytevector-ieee-single-native-ref f32-ref 4 float)
  1023. (bv-f64-ref bytevector-ieee-double-native-ref f64-ref 8 float))
  1024. (define-bytevector-set-converters
  1025. (bv-u8-set! bytevector-u8-set! u8-set! 1 unsigned)
  1026. (bv-u16-set! bytevector-u16-native-set! u16-set! 2 unsigned)
  1027. (bv-u32-set! bytevector-u32-native-set! u32-set! 4 unsigned)
  1028. (bv-u64-set! bytevector-u64-native-set! u64-set! 8 unsigned)
  1029. (bv-s8-set! bytevector-s8-set! s8-set! 1 signed)
  1030. (bv-s16-set! bytevector-s16-native-set! s16-set! 2 signed)
  1031. (bv-s32-set! bytevector-s32-native-set! s32-set! 4 signed)
  1032. (bv-s64-set! bytevector-s64-native-set! s64-set! 8 signed)
  1033. (bv-f32-set! bytevector-ieee-single-native-set! f32-set! 4 float)
  1034. (bv-f64-set! bytevector-ieee-double-native-set! f64-set! 8 float))
  1035. (define (ensure-string cps src op x have-length)
  1036. (define msg "Wrong type argument in position 1 (expecting string): ~S")
  1037. (define not-string (vector 'wrong-type-arg (symbol->string op) msg))
  1038. (with-cps cps
  1039. (letv ulen rlen)
  1040. (letk knot-string
  1041. ($kargs () () ($throw src 'throw/value+data not-string (x))))
  1042. (let$ body (have-length rlen))
  1043. (letk k ($kargs ('rlen) (rlen) ,body))
  1044. (letk kassume
  1045. ($kargs ('ulen) (ulen)
  1046. ($continue k src
  1047. ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (ulen)))))
  1048. (letk ks
  1049. ($kargs () ()
  1050. ($continue kassume src
  1051. ($primcall 'word-ref/immediate '(string . 3) (x)))))
  1052. (letk kheap-object
  1053. ($kargs () ()
  1054. ($branch knot-string ks src 'string? #f (x))))
  1055. (build-term
  1056. ($branch knot-string kheap-object src 'heap-object? #f (x)))))
  1057. (define (ensure-char cps src op x have-char)
  1058. (define msg "Wrong type argument (expecting char): ~S")
  1059. (define not-char (vector 'wrong-type-arg (symbol->string op) msg))
  1060. (with-cps cps
  1061. (letv uchar)
  1062. (letk knot-char
  1063. ($kargs () () ($throw src 'throw/value+data not-char (x))))
  1064. (let$ body (have-char uchar))
  1065. (letk k ($kargs ('uchar) (uchar) ,body))
  1066. (letk kchar
  1067. ($kargs () () ($continue k src ($primcall 'untag-char #f (x)))))
  1068. (build-term
  1069. ($branch knot-char kchar src 'char? #f (x)))))
  1070. (define-primcall-converter string-length
  1071. (lambda (cps k src op param x)
  1072. (ensure-string
  1073. cps src op x
  1074. (lambda (cps ulen)
  1075. (with-cps cps
  1076. (build-term
  1077. ($continue k src ($primcall 'u64->scm #f (ulen)))))))))
  1078. (define-primcall-converter string-ref
  1079. (lambda (cps k src op param s idx)
  1080. (define out-of-range
  1081. #(out-of-range string-ref "Argument 2 out of range: ~S"))
  1082. (define stringbuf-f-wide #x400)
  1083. (ensure-string
  1084. cps src op s
  1085. (lambda (cps ulen)
  1086. (with-cps cps
  1087. (letv uidx start upos buf ptr tag mask bits uwpos u32 uchar)
  1088. (letk kout-of-range
  1089. ($kargs () ()
  1090. ($throw src 'throw/value+data out-of-range (idx))))
  1091. (letk kchar
  1092. ($kargs ('uchar) (uchar)
  1093. ($continue k src
  1094. ($primcall 'tag-char #f (uchar)))))
  1095. (letk kassume
  1096. ($kargs ('u32) (u32)
  1097. ($continue kchar src
  1098. ($primcall 'assume-u64 '(0 . #xffffff) (u32)))))
  1099. (letk kwideref
  1100. ($kargs ('uwpos) (uwpos)
  1101. ($continue kassume src
  1102. ($primcall 'u32-ref 'stringbuf (buf ptr uwpos)))))
  1103. (letk kwide
  1104. ($kargs () ()
  1105. ($continue kwideref src
  1106. ($primcall 'ulsh/immediate 2 (upos)))))
  1107. (letk knarrow
  1108. ($kargs () ()
  1109. ($continue kchar src
  1110. ($primcall 'u8-ref 'stringbuf (buf ptr upos)))))
  1111. (letk kcmp
  1112. ($kargs ('bits) (bits)
  1113. ($branch kwide knarrow src 'u64-imm-= 0 (bits))))
  1114. (letk kmask
  1115. ($kargs ('mask) (mask)
  1116. ($continue kcmp src
  1117. ($primcall 'ulogand #f (tag mask)))))
  1118. (letk ktag
  1119. ($kargs ('tag) (tag)
  1120. ($continue kmask src
  1121. ($primcall 'load-u64 stringbuf-f-wide ()))))
  1122. (letk kptr
  1123. ($kargs ('ptr) (ptr)
  1124. ($continue ktag src
  1125. ($primcall 'word-ref/immediate '(stringbuf . 0) (buf)))))
  1126. (letk kwidth
  1127. ($kargs ('buf) (buf)
  1128. ($continue kptr src
  1129. ($primcall 'tail-pointer-ref/immediate '(stringbuf . 2) (buf)))))
  1130. (letk kbuf
  1131. ($kargs ('upos) (upos)
  1132. ($continue kwidth src
  1133. ($primcall 'scm-ref/immediate '(string . 1) (s)))))
  1134. (letk kadd
  1135. ($kargs ('start) (start)
  1136. ($continue kbuf src
  1137. ($primcall 'uadd #f (start uidx)))))
  1138. (letk kstart
  1139. ($kargs () ()
  1140. ($continue kadd src
  1141. ($primcall 'word-ref/immediate '(string . 2) (s)))))
  1142. (letk krange
  1143. ($kargs ('uidx) (uidx)
  1144. ($branch kout-of-range kstart src 'u64-< #f (uidx ulen))))
  1145. (build-term
  1146. ($continue krange src ($primcall 'scm->u64 #f (idx)))))))))
  1147. (define-primcall-converter string-set!
  1148. (lambda (cps k src op param s idx ch)
  1149. (define out-of-range
  1150. #(out-of-range string-ref "Argument 2 out of range: ~S"))
  1151. (define stringbuf-f-wide #x400)
  1152. (ensure-string
  1153. cps src op s
  1154. (lambda (cps ulen)
  1155. (ensure-char
  1156. cps src op ch
  1157. (lambda (cps uchar)
  1158. (with-cps cps
  1159. (letv uidx)
  1160. (letk kout-of-range
  1161. ($kargs () ()
  1162. ($throw src 'throw/value+data out-of-range (idx))))
  1163. (letk kuidx
  1164. ($kargs () ()
  1165. ($continue k src
  1166. ($primcall 'string-set! #f (s uidx uchar)))))
  1167. (letk krange
  1168. ($kargs ('uidx) (uidx)
  1169. ($branch kout-of-range kuidx src 'u64-< #f (uidx ulen))))
  1170. (build-term
  1171. ($continue krange src ($primcall 'scm->u64 #f (idx)))))))))))
  1172. (define-primcall-converter integer->char
  1173. (lambda (cps k src op param i)
  1174. (define not-fixnum
  1175. #(wrong-type-arg
  1176. "integer->char"
  1177. "Wrong type argument in position 1 (expecting small integer): ~S"))
  1178. (define out-of-range
  1179. #(out-of-range
  1180. "integer->char"
  1181. "Argument 1 out of range: ~S"))
  1182. (define codepoint-surrogate-start #xd800)
  1183. (define codepoint-surrogate-end #xdfff)
  1184. (define codepoint-max #x10ffff)
  1185. (with-cps cps
  1186. (letv si ui)
  1187. (letk knot-fixnum
  1188. ($kargs () () ($throw src 'throw/value+data not-fixnum (i))))
  1189. (letk kf
  1190. ($kargs () () ($throw src 'throw/value+data out-of-range (i))))
  1191. (letk ktag ($kargs ('ui) (ui)
  1192. ($continue k src ($primcall 'tag-char #f (ui)))))
  1193. (letk kt ($kargs () ()
  1194. ($continue ktag src ($primcall 's64->u64 #f (si)))))
  1195. (letk kmax
  1196. ($kargs () ()
  1197. ($branch kt kf src 'imm-s64-< codepoint-max (si))))
  1198. (letk khi
  1199. ($kargs () ()
  1200. ($branch kf kmax src 'imm-s64-< codepoint-surrogate-end (si))))
  1201. (letk klo
  1202. ($kargs () ()
  1203. ($branch khi kt src 's64-imm-< codepoint-surrogate-start (si))))
  1204. (letk kbound0
  1205. ($kargs ('si) (si)
  1206. ($branch klo kf src 's64-imm-< 0 (si))))
  1207. (letk kuntag
  1208. ($kargs () ()
  1209. ($continue kbound0 src ($primcall 'untag-fixnum #f (i)))))
  1210. (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (i))))))
  1211. (define-primcall-converter char->integer
  1212. (lambda (cps k src op param ch)
  1213. (define not-char
  1214. #(wrong-type-arg
  1215. "char->integer"
  1216. "Wrong type argument in position 1 (expecting char): ~S"))
  1217. (with-cps cps
  1218. (letv ui si)
  1219. (letk knot-char
  1220. ($kargs () () ($throw src 'throw/value+data not-char (ch))))
  1221. (letk ktag ($kargs ('si) (si)
  1222. ($continue k src ($primcall 'tag-fixnum #f (si)))))
  1223. (letk kcvt ($kargs ('ui) (ui)
  1224. ($continue ktag src ($primcall 'u64->s64 #f (ui)))))
  1225. (letk kuntag ($kargs () ()
  1226. ($continue kcvt src ($primcall 'untag-char #f (ch)))))
  1227. (build-term
  1228. ($branch knot-char kuntag src 'char? #f (ch))))))
  1229. (define (convert-shift cps k src op param obj idx)
  1230. (with-cps cps
  1231. (letv idx')
  1232. (letk k' ($kargs ('idx) (idx')
  1233. ($continue k src ($primcall op param (obj idx')))))
  1234. (build-term ($continue k' src ($primcall 'scm->u64 #f (idx))))))
  1235. (define-primcall-converter rsh convert-shift)
  1236. (define-primcall-converter lsh convert-shift)
  1237. (define-primcall-converter make-atomic-box
  1238. (lambda (cps k src op param val)
  1239. (with-cps cps
  1240. (letv obj tag)
  1241. (letk kdone
  1242. ($kargs () ()
  1243. ($continue k src ($values (obj)))))
  1244. (letk kval
  1245. ($kargs () ()
  1246. ($continue kdone src
  1247. ($primcall 'atomic-scm-set!/immediate '(atomic-box . 1) (obj val)))))
  1248. (letk ktag1
  1249. ($kargs ('tag) (tag)
  1250. ($continue kval src
  1251. ($primcall 'word-set!/immediate '(atomic-box . 0) (obj tag)))))
  1252. (letk ktag0
  1253. ($kargs ('obj) (obj)
  1254. ($continue ktag1 src
  1255. ($primcall 'load-u64 %tc7-atomic-box ()))))
  1256. (build-term
  1257. ($continue ktag0 src
  1258. ($primcall 'allocate-words/immediate '(atomic-box . 2) ()))))))
  1259. (define (ensure-atomic-box cps src op x is-atomic-box)
  1260. (define bad-type
  1261. (vector 'wrong-type-arg
  1262. (symbol->string op)
  1263. "Wrong type argument in position 1 (expecting atomic box): ~S"))
  1264. (with-cps cps
  1265. (letk kbad ($kargs () () ($throw src 'throw/value+data bad-type (x))))
  1266. (let$ body (is-atomic-box))
  1267. (letk k ($kargs () () ,body))
  1268. (letk kheap-object ($kargs () () ($branch kbad k src 'atomic-box? #f (x))))
  1269. (build-term ($branch kbad kheap-object src 'heap-object? #f (x)))))
  1270. (define-primcall-converter atomic-box-ref
  1271. (lambda (cps k src op param x)
  1272. (ensure-atomic-box
  1273. cps src 'atomic-box-ref x
  1274. (lambda (cps)
  1275. (with-cps cps
  1276. (letv val)
  1277. (build-term
  1278. ($continue k src
  1279. ($primcall 'atomic-scm-ref/immediate '(atomic-box . 1) (x)))))))))
  1280. (define-primcall-converter atomic-box-set!
  1281. (lambda (cps k src op param x val)
  1282. (ensure-atomic-box
  1283. cps src 'atomic-box-set! x
  1284. (lambda (cps)
  1285. (with-cps cps
  1286. (build-term
  1287. ($continue k src
  1288. ($primcall 'atomic-scm-set!/immediate '(atomic-box . 1)
  1289. (x val)))))))))
  1290. (define-primcall-converter atomic-box-swap!
  1291. (lambda (cps k src op param x val)
  1292. (ensure-atomic-box
  1293. cps src 'atomic-box-swap! x
  1294. (lambda (cps)
  1295. (with-cps cps
  1296. (build-term
  1297. ($continue k src
  1298. ($primcall 'atomic-scm-swap!/immediate '(atomic-box . 1)
  1299. (x val)))))))))
  1300. (define-primcall-converter atomic-box-compare-and-swap!
  1301. (lambda (cps k src op param x expected desired)
  1302. (ensure-atomic-box
  1303. cps src 'atomic-box-compare-and-swap! x
  1304. (lambda (cps)
  1305. (with-cps cps
  1306. (build-term
  1307. ($continue k src
  1308. ($primcall 'atomic-scm-compare-and-swap!/immediate '(atomic-box . 1)
  1309. (x expected desired)))))))))
  1310. ;;; Guile's semantics are that a toplevel lambda captures a reference on
  1311. ;;; the current module, and that all contained lambdas use that module
  1312. ;;; to resolve toplevel variables. This parameter tracks whether or not
  1313. ;;; we are in a toplevel lambda. If we are in a lambda, the parameter
  1314. ;;; is bound to a fresh name identifying the module that was current
  1315. ;;; when the toplevel lambda is defined.
  1316. ;;;
  1317. ;;; This is more complicated than it need be. Ideally we should resolve
  1318. ;;; all toplevel bindings to bindings from specific modules, unless the
  1319. ;;; binding is unbound. This is always valid if the compilation unit
  1320. ;;; sets the module explicitly, as when compiling a module, but it
  1321. ;;; doesn't work for files auto-compiled for use with `load'.
  1322. ;;;
  1323. (define current-topbox-scope (make-parameter #f))
  1324. (define scope-counter (make-parameter #f))
  1325. (define (fresh-scope-id)
  1326. (let ((scope-id (scope-counter)))
  1327. (scope-counter (1+ scope-id))
  1328. scope-id))
  1329. (define (toplevel-box cps src name bound? have-var)
  1330. (define %unbound
  1331. #(unbound-variable #f "Unbound variable: ~S"))
  1332. (match (current-topbox-scope)
  1333. (#f
  1334. (with-cps cps
  1335. (letv mod name-var box)
  1336. (letk kbad ($kargs () () ($throw src 'throw/value %unbound (name-var))))
  1337. (let$ body
  1338. ((if bound?
  1339. (lambda (cps)
  1340. (with-cps cps
  1341. (letv val)
  1342. (let$ body (have-var box))
  1343. (letk kdef ($kargs () () ,body))
  1344. (letk ktest ($kargs ('val) (val)
  1345. ($branch kdef kbad src
  1346. 'undefined? #f (val))))
  1347. (build-term
  1348. ($continue ktest src
  1349. ($primcall 'scm-ref/immediate
  1350. '(box . 1) (box))))))
  1351. (lambda (cps)
  1352. (with-cps cps
  1353. ($ (have-var box)))))))
  1354. (letk ktest ($kargs () () ,body))
  1355. (letk kbox ($kargs ('box) (box)
  1356. ($branch kbad ktest src 'heap-object? #f (box))))
  1357. (letk kname ($kargs ('name) (name-var)
  1358. ($continue kbox src
  1359. ($primcall 'lookup #f (mod name-var)))))
  1360. (letk kmod ($kargs ('mod) (mod)
  1361. ($continue kname src ($const name))))
  1362. (build-term
  1363. ($continue kmod src ($primcall 'current-module #f ())))))
  1364. (scope
  1365. (with-cps cps
  1366. (letv box)
  1367. (let$ body (have-var box))
  1368. (letk kbox ($kargs ('box) (box) ,body))
  1369. ($ (convert-primcall kbox src 'cached-toplevel-box
  1370. (list scope name bound?)))))))
  1371. (define (module-box cps src module name public? bound? val-proc)
  1372. (with-cps cps
  1373. (letv box)
  1374. (let$ body (val-proc box))
  1375. (letk kbox ($kargs ('box) (box) ,body))
  1376. ($ (convert-primcall kbox src 'cached-module-box
  1377. (list module name public? bound?)))))
  1378. (define (capture-toplevel-scope cps src scope-id k)
  1379. (with-cps cps
  1380. (letv module)
  1381. (let$ body (convert-primcall k src 'cache-current-module!
  1382. (list scope-id) module))
  1383. (letk kmodule ($kargs ('module) (module) ,body))
  1384. ($ (convert-primcall kmodule src 'current-module #f))))
  1385. (define (fold-formals proc seed arity gensyms inits)
  1386. (match arity
  1387. (($ $arity req opt rest kw allow-other-keys?)
  1388. (let ()
  1389. (define (fold-req names gensyms seed)
  1390. (match names
  1391. (() (fold-opt opt gensyms inits seed))
  1392. ((name . names)
  1393. (proc name (car gensyms) #f
  1394. (fold-req names (cdr gensyms) seed)))))
  1395. (define (fold-opt names gensyms inits seed)
  1396. (match names
  1397. (() (fold-rest rest gensyms inits seed))
  1398. ((name . names)
  1399. (proc name (car gensyms) (car inits)
  1400. (fold-opt names (cdr gensyms) (cdr inits) seed)))))
  1401. (define (fold-rest rest gensyms inits seed)
  1402. (match rest
  1403. (#f (fold-kw kw gensyms inits seed))
  1404. (name (proc name (car gensyms) #f
  1405. (fold-kw kw (cdr gensyms) inits seed)))))
  1406. (define (fold-kw kw gensyms inits seed)
  1407. (match kw
  1408. (()
  1409. (unless (null? gensyms)
  1410. (error "too many gensyms"))
  1411. (unless (null? inits)
  1412. (error "too many inits"))
  1413. seed)
  1414. (((key name var) . kw)
  1415. ;; Could be that var is not a gensym any more.
  1416. (when (symbol? var)
  1417. (unless (eq? var (car gensyms))
  1418. (error "unexpected keyword arg order")))
  1419. (proc name (car gensyms) (car inits)
  1420. (fold-kw kw (cdr gensyms) (cdr inits) seed)))))
  1421. (fold-req req gensyms seed)))))
  1422. (define (init-default-value cps name sym subst init body)
  1423. (match (hashq-ref subst sym)
  1424. ((orig-var subst-var box?)
  1425. (let ((src (tree-il-src init)))
  1426. (define (maybe-box cps k make-body)
  1427. (if box?
  1428. (with-cps cps
  1429. (letv phi)
  1430. (let$ body (convert-primcall k src 'box #f phi))
  1431. (letk kbox ($kargs (name) (phi) ,body))
  1432. ($ (make-body kbox)))
  1433. (make-body cps k)))
  1434. (with-cps cps
  1435. (letk knext ($kargs (name) (subst-var) ,body))
  1436. ($ (maybe-box
  1437. knext
  1438. (lambda (cps k)
  1439. (with-cps cps
  1440. (letk kbound ($kargs () () ($continue k src
  1441. ($values (orig-var)))))
  1442. (letv val rest)
  1443. (letk krest ($kargs (name 'rest) (val rest)
  1444. ($continue k src ($values (val)))))
  1445. (letk kreceive ($kreceive (list name) 'rest krest))
  1446. (let$ init (convert init kreceive subst))
  1447. (letk kunbound ($kargs () () ,init))
  1448. (build-term
  1449. ($branch kbound kunbound src
  1450. 'undefined? #f (orig-var))))))))))))
  1451. (define (build-list cps k src vals)
  1452. (match vals
  1453. (()
  1454. (with-cps cps
  1455. (build-term ($continue k src ($const '())))))
  1456. ((v . vals)
  1457. (with-cps cps
  1458. (letv tail)
  1459. (let$ head (convert-primcall k src 'cons #f v tail))
  1460. (letk ktail ($kargs ('tail) (tail) ,head))
  1461. ($ (build-list ktail src vals))))))
  1462. ;;; The conversion from Tree-IL to CPS essentially wraps every
  1463. ;;; expression in a $kreceive, which models the Tree-IL semantics that
  1464. ;;; extra values are simply truncated. In CPS, this means that the
  1465. ;;; $kreceive has a rest argument after the required arguments, if any,
  1466. ;;; and that the rest argument is unused.
  1467. ;;;
  1468. ;;; All CPS expressions that can return a variable number of values
  1469. ;;; (i.e., $call and $abort) must continue to $kreceive, which checks
  1470. ;;; the return arity and on success passes the parsed values along to a
  1471. ;;; $kargs. If the $call or $abort is in tail position they continue to
  1472. ;;; $ktail instead, and then the values are parsed by the $kreceive of
  1473. ;;; the non-tail caller.
  1474. ;;;
  1475. ;;; Other CPS terms like $values, $const, and the like all have a
  1476. ;;; specific return arity, and must continue to $kargs instead of
  1477. ;;; $kreceive or $ktail. This allows the compiler to reason precisely
  1478. ;;; about their result values. To make sure that this is the case,
  1479. ;;; whenever the CPS conversion would reify one of these terms it needs
  1480. ;;; to ensure that the continuation actually accepts the return arity of
  1481. ;;; the primcall.
  1482. ;;;
  1483. ;;; Some Tree-IL primcalls residualize CPS primcalls that return zero
  1484. ;;; values, for example box-set!. In this case the Tree-IL semantics
  1485. ;;; are that the result of the expression is the undefined value. That
  1486. ;;; is to say, the result of this expression is #t:
  1487. ;;;
  1488. ;;; (let ((x 30)) (eq? (set! x 10) (if #f #f)))
  1489. ;;;
  1490. ;;; So in the case that the continuation expects a value but the
  1491. ;;; primcall produces zero values, we insert the "unspecified" value.
  1492. ;;;
  1493. (define (adapt-arity cps k src nvals)
  1494. (match nvals
  1495. (0
  1496. ;; As mentioned above, in the Tree-IL semantics the primcall
  1497. ;; produces the unspecified value, but in CPS it produces no
  1498. ;; values. Therefore we plug the unspecified value into the
  1499. ;; continuation.
  1500. (match (intmap-ref cps k)
  1501. (($ $ktail)
  1502. (with-cps cps
  1503. (let$ body (with-cps-constants ((unspecified *unspecified*))
  1504. (build-term
  1505. ($continue k src ($values (unspecified))))))
  1506. (letk kvoid ($kargs () () ,body))
  1507. kvoid))
  1508. (($ $kargs ()) (with-cps cps k))
  1509. (($ $kreceive arity kargs)
  1510. (match arity
  1511. (($ $arity () () (not #f) () #f)
  1512. (with-cps cps
  1513. (letk kvoid ($kargs () () ($continue kargs src ($const '()))))
  1514. kvoid))
  1515. (($ $arity (_) () #f () #f)
  1516. (with-cps cps
  1517. (letk kvoid ($kargs () ()
  1518. ($continue kargs src ($const *unspecified*))))
  1519. kvoid))
  1520. (($ $arity (_) () _ () #f)
  1521. (with-cps cps
  1522. (let$ void (with-cps-constants ((unspecified *unspecified*)
  1523. (rest '()))
  1524. (build-term
  1525. ($continue kargs src
  1526. ($values (unspecified rest))))))
  1527. (letk kvoid ($kargs () () ,void))
  1528. kvoid))
  1529. (_
  1530. ;; Arity mismatch. Serialize a values call.
  1531. (with-cps cps
  1532. (letv values)
  1533. (let$ void (with-cps-constants ((unspecified *unspecified*))
  1534. (build-term
  1535. ($continue k src
  1536. ($call values (unspecified))))))
  1537. (letk kvoid ($kargs ('values) (values) ,void))
  1538. (letk kvalues ($kargs () ()
  1539. ($continue kvoid src ($prim 'values))))
  1540. kvalues))))))
  1541. (1
  1542. (match (intmap-ref cps k)
  1543. (($ $ktail)
  1544. (with-cps cps
  1545. (letv val)
  1546. (letk kval ($kargs ('val) (val)
  1547. ($continue k src ($values (val)))))
  1548. kval))
  1549. (($ $kargs (_)) (with-cps cps k))
  1550. (($ $kreceive arity kargs)
  1551. (match arity
  1552. (($ $arity () () (not #f) () #f)
  1553. (with-cps cps
  1554. (letv val)
  1555. (let$ body (with-cps-constants ((nil '()))
  1556. ($ (convert-primcall kargs src 'cons #f
  1557. val nil))))
  1558. (letk kval ($kargs ('val) (val) ,body))
  1559. kval))
  1560. (($ $arity (_) () #f () #f)
  1561. (with-cps cps
  1562. kargs))
  1563. (($ $arity (_) () _ () #f)
  1564. (with-cps cps
  1565. (letv val)
  1566. (let$ body (with-cps-constants ((rest '()))
  1567. (build-term
  1568. ($continue kargs src ($values (val rest))))))
  1569. (letk kval ($kargs ('val) (val) ,body))
  1570. kval))
  1571. (_
  1572. ;; Arity mismatch. Serialize a values call.
  1573. (with-cps cps
  1574. (letv val values)
  1575. (letk kvalues ($kargs ('values) (values)
  1576. ($continue k src
  1577. ($call values (val)))))
  1578. (letk kval ($kargs ('val) (val)
  1579. ($continue kvalues src ($prim 'values))))
  1580. kval))))))))
  1581. ;; cps exp k-name alist -> cps term
  1582. (define (convert cps exp k subst)
  1583. (define (zero-valued? exp)
  1584. (match exp
  1585. ((or ($ <module-set>) ($ <toplevel-set>) ($ <toplevel-define>)
  1586. ($ <lexical-set>))
  1587. #t)
  1588. (($ <let> src names syms vals body) (zero-valued? body))
  1589. ;; Can't use <fix> here as the hack that <fix> uses to convert its
  1590. ;; functions relies on continuation being single-valued.
  1591. ;; (($ <fix> src names syms vals body) (zero-valued? body))
  1592. (($ <let-values> src exp body) (zero-valued? body))
  1593. (($ <seq> src head tail) (zero-valued? tail))
  1594. (($ <primcall> src 'values args) (= (length args) 0))
  1595. (($ <primcall> src name args)
  1596. (match (tree-il-primitive->cps-primitive+nargs+nvalues name)
  1597. (#f #f)
  1598. (#(cps-prim nargs nvalues)
  1599. (and (eqv? nvalues 0)
  1600. (eqv? nargs (length args))))))
  1601. (_ #f)))
  1602. (define (single-valued? exp)
  1603. (match exp
  1604. ((or ($ <void>) ($ <const>) ($ <primitive-ref>) ($ <module-ref>)
  1605. ($ <toplevel-ref>) ($ <lambda>))
  1606. #t)
  1607. (($ <let> src names syms vals body) (single-valued? body))
  1608. (($ <fix> src names syms vals body) (single-valued? body))
  1609. (($ <let-values> src exp body) (single-valued? body))
  1610. (($ <seq> src head tail) (single-valued? tail))
  1611. (($ <primcall> src 'values args) (= (length args) 1))
  1612. (($ <primcall> src name args)
  1613. (match (tree-il-primitive->cps-primitive+nargs+nvalues name)
  1614. (#f #f)
  1615. (#(cps-prim nargs nvalues)
  1616. (and (eqv? nvalues 1)
  1617. (eqv? nargs (length args))))))
  1618. (_ #f)))
  1619. ;; exp (v-name -> term) -> term
  1620. (define (convert-arg cps exp k)
  1621. (match exp
  1622. (($ <lexical-ref> src name sym)
  1623. (match (hashq-ref subst sym)
  1624. ((orig-var box #t)
  1625. (with-cps cps
  1626. (letv unboxed)
  1627. (let$ body (k unboxed))
  1628. (letk kunboxed ($kargs ('unboxed) (unboxed) ,body))
  1629. (build-term ($continue kunboxed src
  1630. ($primcall 'scm-ref/immediate '(box . 1) (box))))))
  1631. ((orig-var subst-var #f) (k cps subst-var))
  1632. (var (k cps var))))
  1633. ((? single-valued?)
  1634. (with-cps cps
  1635. (letv arg)
  1636. (let$ body (k arg))
  1637. (letk karg ($kargs ('arg) (arg) ,body))
  1638. ($ (convert exp karg subst))))
  1639. (_
  1640. (with-cps cps
  1641. (letv arg rest)
  1642. (let$ body (k arg))
  1643. (letk karg ($kargs ('arg 'rest) (arg rest) ,body))
  1644. (letk kreceive ($kreceive '(arg) 'rest karg))
  1645. ($ (convert exp kreceive subst))))))
  1646. ;; (exp ...) ((v-name ...) -> term) -> term
  1647. (define (convert-args cps exps k)
  1648. (match exps
  1649. (() (k cps '()))
  1650. ((exp . exps)
  1651. (convert-arg cps exp
  1652. (lambda (cps name)
  1653. (convert-args cps exps
  1654. (lambda (cps names)
  1655. (k cps (cons name names)))))))))
  1656. (define (box-bound-var cps name sym body)
  1657. (match (hashq-ref subst sym)
  1658. ((orig-var subst-var #t)
  1659. (with-cps cps
  1660. (letk k ($kargs (name) (subst-var) ,body))
  1661. ($ (convert-primcall k #f 'box #f orig-var))))
  1662. (else
  1663. (with-cps cps body))))
  1664. (define (box-bound-vars cps names syms body)
  1665. (match (vector names syms)
  1666. (#((name . names) (sym . syms))
  1667. (with-cps cps
  1668. (let$ body (box-bound-var name sym body))
  1669. ($ (box-bound-vars names syms body))))
  1670. (#(() ()) (with-cps cps body))))
  1671. (define (bound-var sym)
  1672. (match (hashq-ref subst sym)
  1673. ((var . _) var)
  1674. ((? exact-integer? var) var)))
  1675. (match exp
  1676. (($ <lexical-ref> src name sym)
  1677. (with-cps cps
  1678. (let$ k (adapt-arity k src 1))
  1679. (rewrite-term (hashq-ref subst sym)
  1680. ((orig-var box #t) ($continue k src
  1681. ($primcall 'scm-ref/immediate '(box . 1) (box))))
  1682. ((orig-var subst-var #f) ($continue k src ($values (subst-var))))
  1683. (var ($continue k src ($values (var)))))))
  1684. (($ <void> src)
  1685. (with-cps cps
  1686. (let$ k (adapt-arity k src 1))
  1687. (build-term ($continue k src ($const *unspecified*)))))
  1688. (($ <const> src exp)
  1689. (with-cps cps
  1690. (let$ k (adapt-arity k src 1))
  1691. (build-term ($continue k src ($const exp)))))
  1692. (($ <primitive-ref> src name)
  1693. (with-cps cps
  1694. (let$ k (adapt-arity k src 1))
  1695. (build-term ($continue k src ($prim name)))))
  1696. (($ <lambda> fun-src meta body)
  1697. (let ()
  1698. (define (convert-clauses cps body ktail)
  1699. (match body
  1700. (#f (values cps #f))
  1701. (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
  1702. (let* ((arity (make-$arity req (or opt '()) rest
  1703. (map (match-lambda
  1704. ((kw name sym)
  1705. (list kw name (bound-var sym))))
  1706. (if kw (cdr kw) '()))
  1707. (and kw (car kw))))
  1708. (names (fold-formals (lambda (name sym init names)
  1709. (cons name names))
  1710. '()
  1711. arity gensyms inits)))
  1712. (define (fold-formals* cps f seed arity gensyms inits)
  1713. (match (fold-formals
  1714. (lambda (name sym init cps+seed)
  1715. (match cps+seed
  1716. ((cps . seed)
  1717. (call-with-values (lambda ()
  1718. (f cps name sym init seed))
  1719. (lambda (cps seed) (cons cps seed))))))
  1720. (cons cps seed) arity gensyms inits)
  1721. ((cps . seed) (values cps seed))))
  1722. (with-cps cps
  1723. (let$ kalt (convert-clauses alternate ktail))
  1724. (let$ body (convert body ktail subst))
  1725. (let$ body
  1726. (fold-formals*
  1727. (lambda (cps name sym init body)
  1728. (if init
  1729. (init-default-value cps name sym subst init body)
  1730. (box-bound-var cps name sym body)))
  1731. body arity gensyms inits))
  1732. (letk kargs ($kargs names (map bound-var gensyms) ,body))
  1733. (letk kclause ($kclause ,arity kargs kalt))
  1734. kclause)))))
  1735. (if (current-topbox-scope)
  1736. (with-cps cps
  1737. (letv self)
  1738. (letk ktail ($ktail))
  1739. (let$ kclause (convert-clauses body ktail))
  1740. (letk kfun ($kfun fun-src meta self ktail kclause))
  1741. (let$ k (adapt-arity k fun-src 1))
  1742. (build-term ($continue k fun-src ($fun kfun))))
  1743. (let ((scope-id (fresh-scope-id)))
  1744. (with-cps cps
  1745. (let$ body ((lambda (cps)
  1746. (parameterize ((current-topbox-scope scope-id))
  1747. (convert cps exp k subst)))))
  1748. (letk kscope ($kargs () () ,body))
  1749. ($ (capture-toplevel-scope fun-src scope-id kscope)))))))
  1750. (($ <module-ref> src mod name public?)
  1751. (module-box
  1752. cps src mod name public? #t
  1753. (lambda (cps box)
  1754. (with-cps cps
  1755. (let$ k (adapt-arity k src 1))
  1756. (build-term ($continue k src
  1757. ($primcall 'scm-ref/immediate '(box . 1) (box))))))))
  1758. (($ <module-set> src mod name public? exp)
  1759. (convert-arg cps exp
  1760. (lambda (cps val)
  1761. (module-box
  1762. cps src mod name public? #t
  1763. (lambda (cps box)
  1764. (with-cps cps
  1765. (let$ k (adapt-arity k src 0))
  1766. (build-term
  1767. ($continue k src
  1768. ($primcall 'scm-set!/immediate '(box . 1) (box val))))))))))
  1769. (($ <toplevel-ref> src mod name)
  1770. (toplevel-box
  1771. cps src name #t
  1772. (lambda (cps box)
  1773. (with-cps cps
  1774. (let$ k (adapt-arity k src 1))
  1775. (build-term
  1776. ($continue k src
  1777. ($primcall 'scm-ref/immediate '(box . 1) (box))))))))
  1778. (($ <toplevel-set> src mod name exp)
  1779. (convert-arg cps exp
  1780. (lambda (cps val)
  1781. (toplevel-box
  1782. cps src name #f
  1783. (lambda (cps box)
  1784. (with-cps cps
  1785. (let$ k (adapt-arity k src 0))
  1786. (build-term
  1787. ($continue k src
  1788. ($primcall 'scm-set!/immediate '(box . 1) (box val))))))))))
  1789. (($ <toplevel-define> src modname name exp)
  1790. (convert-arg cps exp
  1791. (lambda (cps val)
  1792. (with-cps cps
  1793. (let$ k (adapt-arity k src 0))
  1794. (letv box mod)
  1795. (letk kset ($kargs ('box) (box)
  1796. ($continue k src
  1797. ($primcall 'scm-set!/immediate '(box . 1) (box val)))))
  1798. ($ (with-cps-constants ((name name))
  1799. (letk kmod
  1800. ($kargs ('mod) (mod)
  1801. ($continue kset src
  1802. ($primcall 'define! #f (mod name)))))
  1803. (build-term
  1804. ($continue kmod src ($primcall 'current-module #f ())))))))))
  1805. (($ <call> src proc args)
  1806. (convert-args cps (cons proc args)
  1807. (match-lambda*
  1808. ((cps (proc . args))
  1809. (with-cps cps
  1810. (build-term ($continue k src ($call proc args))))))))
  1811. (($ <primcall> src name args)
  1812. (cond
  1813. ((eq? name 'throw)
  1814. (let ()
  1815. (define (fallback)
  1816. (convert-args cps args
  1817. (lambda (cps args)
  1818. (match args
  1819. ((key . args)
  1820. (with-cps cps
  1821. (letv arglist)
  1822. (letk kargs ($kargs ('arglist) (arglist)
  1823. ($throw src 'throw #f (key arglist))))
  1824. ($ (build-list kargs src args))))))))
  1825. (define (specialize op param . args)
  1826. (convert-args cps args
  1827. (lambda (cps args)
  1828. (with-cps cps
  1829. (build-term
  1830. ($throw src op param args))))))
  1831. (match args
  1832. ((($ <const> _ key) ($ <const> _ subr) ($ <const> _ msg) args data)
  1833. ;; Specialize `throw' invocations corresponding to common
  1834. ;; "error" invocations.
  1835. (let ()
  1836. (match (vector args data)
  1837. (#(($ <primcall> _ 'cons (x ($ <const> _ ())))
  1838. ($ <primcall> _ 'cons (x ($ <const> _ ()))))
  1839. (specialize 'throw/value+data `#(,key ,subr ,msg) x))
  1840. (#(($ <primcall> _ 'cons (x ($ <const> _ ()))) ($ <const> _ #f))
  1841. (specialize 'throw/value `#(,key ,subr ,msg) x))
  1842. (_ (fallback)))))
  1843. (_ (fallback)))))
  1844. ((eq? name 'values)
  1845. (convert-args cps args
  1846. (lambda (cps args)
  1847. (match (intmap-ref cps k)
  1848. (($ $ktail)
  1849. (with-cps cps
  1850. (build-term
  1851. ($continue k src ($values args)))))
  1852. (($ $kargs names)
  1853. ;; Can happen if continuation already saw we produced the
  1854. ;; right number of values.
  1855. (with-cps cps
  1856. (build-term
  1857. ($continue k src ($values args)))))
  1858. (($ $kreceive ($ $arity req () rest () #f) kargs)
  1859. (cond
  1860. ((and (not rest) (= (length args) (length req)))
  1861. (with-cps cps
  1862. (build-term
  1863. ($continue kargs src ($values args)))))
  1864. ((and rest (>= (length args) (length req)))
  1865. (with-cps cps
  1866. (letv rest)
  1867. (letk krest ($kargs ('rest) (rest)
  1868. ($continue kargs src
  1869. ($values ,(append (list-head args (length req))
  1870. (list rest))))))
  1871. ($ (build-list krest src (list-tail args (length req))))))
  1872. (else
  1873. ;; Number of values mismatch; reify a values call.
  1874. (with-cps cps
  1875. (letv val values)
  1876. (letk kvalues ($kargs ('values) (values)
  1877. ($continue k src ($call values args))))
  1878. (build-term ($continue kvalues src ($prim 'values)))))))))))
  1879. ((tree-il-primitive->cps-primitive+nargs+nvalues name)
  1880. =>
  1881. (match-lambda
  1882. (#(cps-prim nargs nvalues)
  1883. (define (cvt cps k src op args)
  1884. (define (default)
  1885. (convert-args cps args
  1886. (lambda (cps args)
  1887. (with-cps cps
  1888. ($ (convert-primcall* k src op #f args))))))
  1889. (define-syntax-rule (specialize-case (pat (op c (arg ...))) ...
  1890. (_ def))
  1891. (match (cons cps-prim args)
  1892. (pat
  1893. (convert-args cps (list arg ...)
  1894. (lambda (cps args)
  1895. (with-cps cps
  1896. ($ (convert-primcall* k src 'op c args))))))
  1897. ...
  1898. (_ def)))
  1899. (define (uint? val) (and (exact-integer? val) (<= 0 val)))
  1900. (define (vector-index? val)
  1901. (and (exact-integer? val)
  1902. (<= 0 val (1- (target-max-vector-length)))))
  1903. (define (vector-size? val)
  1904. (and (exact-integer? val)
  1905. (<= 0 val (target-max-vector-length))))
  1906. (define (negint? val) (and (exact-integer? val) (< val 0)))
  1907. ;; FIXME: Add case for mul
  1908. (specialize-case
  1909. (('allocate-vector ($ <const> _ n))
  1910. (allocate-vector n ()))
  1911. (('make-vector ($ <const> _ (? vector-size? n)) init)
  1912. (make-vector/immediate n (init)))
  1913. (('vector-ref v ($ <const> _ (? vector-index? n)))
  1914. (vector-ref/immediate n (v)))
  1915. (('vector-set! v ($ <const> _ (? vector-index? n)) x)
  1916. (vector-set!/immediate n (v x)))
  1917. (('vector-init! v ($ <const> _ n) x)
  1918. (vector-init! n (v x)))
  1919. (('allocate-struct v ($ <const> _ n))
  1920. (allocate-struct n (v)))
  1921. (('struct-ref s ($ <const> _ (? uint? n)))
  1922. (struct-ref/immediate n (s)))
  1923. (('struct-set! s ($ <const> _ (? uint? n)) x)
  1924. (struct-set!/immediate n (s x)))
  1925. (('struct-init! s ($ <const> _ n) x)
  1926. (struct-init! n (s x)))
  1927. (('add x ($ <const> _ (? number? y)))
  1928. (add/immediate y (x)))
  1929. (('add ($ <const> _ (? number? y)) x)
  1930. (add/immediate y (x)))
  1931. (('sub x ($ <const> _ (? number? y)))
  1932. (sub/immediate y (x)))
  1933. (('lsh x ($ <const> _ (? uint? y)))
  1934. (lsh/immediate y (x)))
  1935. (('rsh x ($ <const> _ (? uint? y)))
  1936. (rsh/immediate y (x)))
  1937. (_
  1938. (default))))
  1939. ;; Tree-IL primcalls are sloppy, in that it could be that
  1940. ;; they are called with too many or too few arguments. In
  1941. ;; CPS we are more strict and only residualize a $primcall
  1942. ;; if the argument count matches.
  1943. (if (= nargs (length args))
  1944. (with-cps cps
  1945. (let$ k (adapt-arity k src nvalues))
  1946. ($ (cvt k src cps-prim args)))
  1947. (convert-args cps args
  1948. (lambda (cps args)
  1949. (with-cps cps
  1950. (letv prim)
  1951. (letk kprim ($kargs ('prim) (prim)
  1952. ($continue k src ($call prim args))))
  1953. (build-term ($continue kprim src ($prim name))))))))))
  1954. (else
  1955. ;; We have something that's a primcall for Tree-IL but not for
  1956. ;; CPS; compile as a call.
  1957. (convert-args cps args
  1958. (lambda (cps args)
  1959. (with-cps cps
  1960. (letv prim)
  1961. (letk kprim ($kargs ('prim) (prim)
  1962. ($continue k src ($call prim args))))
  1963. (build-term ($continue kprim src ($prim name)))))))))
  1964. ;; Prompts with inline handlers.
  1965. (($ <prompt> src escape-only? tag body
  1966. ($ <lambda> hsrc hmeta
  1967. ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
  1968. ;; Handler:
  1969. ;; khargs: check args returned to handler, -> khbody
  1970. ;; khbody: the handler, -> k
  1971. ;;
  1972. ;; Post-body:
  1973. ;; krest: collect return vals from body to list, -> kpop
  1974. ;; kpop: pop the prompt, -> kprim
  1975. ;; kprim: load the values primitive, -> kret
  1976. ;; kret: (apply values rvals), -> k
  1977. ;;
  1978. ;; Escape prompts evaluate the body with the continuation of krest.
  1979. ;; Otherwise we do a no-inline call to body, continuing to krest.
  1980. (convert-arg cps tag
  1981. (lambda (cps tag)
  1982. (let ((hnames (append hreq (if hrest (list hrest) '())))
  1983. (bound-vars (map bound-var hsyms)))
  1984. (define (convert-body cps khargs krest)
  1985. (if escape-only?
  1986. (with-cps cps
  1987. (let$ body (convert body krest subst))
  1988. (letk kbody ($kargs () () ,body))
  1989. (build-term ($prompt kbody khargs src #t tag)))
  1990. (convert-arg cps body
  1991. (lambda (cps thunk)
  1992. (with-cps cps
  1993. (letk kbody ($kargs () ()
  1994. ($continue krest (tree-il-src body)
  1995. ($primcall 'call-thunk/no-inline #f
  1996. (thunk)))))
  1997. (build-term ($prompt kbody khargs (tree-il-src body)
  1998. #f tag)))))))
  1999. (with-cps cps
  2000. (letv prim vals apply)
  2001. (let$ hbody (convert hbody k subst))
  2002. (let$ hbody (box-bound-vars hnames hsyms hbody))
  2003. (letk khbody ($kargs hnames bound-vars ,hbody))
  2004. (letk khargs ($kreceive hreq hrest khbody))
  2005. (letk kapp ($kargs ('apply) (apply)
  2006. ($continue k src ($call apply (prim vals)))))
  2007. (letk kprim ($kargs ('prim) (prim)
  2008. ($continue kapp src ($prim 'apply))))
  2009. (letk kret ($kargs () ()
  2010. ($continue kprim src ($prim 'values))))
  2011. (letk kpop ($kargs ('rest) (vals)
  2012. ($continue kret src ($primcall 'unwind #f ()))))
  2013. ;; FIXME: Attach hsrc to $kreceive.
  2014. (letk krest ($kreceive '() 'rest kpop))
  2015. ($ (convert-body khargs krest)))))))
  2016. (($ <abort> src tag args ($ <const> _ ()))
  2017. (convert-args cps (cons tag args)
  2018. (lambda (cps args*)
  2019. (with-cps cps
  2020. (letv abort)
  2021. (letk kabort ($kargs ('abort) (abort)
  2022. ($continue k src ($call abort args*))))
  2023. (build-term
  2024. ($continue kabort src ($prim 'abort-to-prompt)))))))
  2025. (($ <abort> src tag args tail)
  2026. (convert-args cps
  2027. (append (list (make-primitive-ref #f 'apply)
  2028. (make-primitive-ref #f 'abort-to-prompt)
  2029. tag)
  2030. args
  2031. (list tail))
  2032. (lambda (cps args*)
  2033. (match args*
  2034. ((apply . apply-args)
  2035. (with-cps cps
  2036. (build-term ($continue k src ($call apply apply-args)))))))))
  2037. (($ <conditional> src test consequent alternate)
  2038. (define (convert-test cps test kt kf)
  2039. (match test
  2040. (($ <primcall> src (? branching-primitive? name) args)
  2041. (convert-args cps args
  2042. (lambda (cps args)
  2043. (if (heap-type-predicate? name)
  2044. (with-cps cps
  2045. (letk kt* ($kargs () ()
  2046. ($branch kf kt src name #f args)))
  2047. (build-term
  2048. ($branch kf kt* src 'heap-object? #f args)))
  2049. (with-cps cps
  2050. (build-term ($branch kf kt src name #f args)))))))
  2051. (($ <conditional> src test consequent alternate)
  2052. (with-cps cps
  2053. (let$ t (convert-test consequent kt kf))
  2054. (let$ f (convert-test alternate kt kf))
  2055. (letk kt* ($kargs () () ,t))
  2056. (letk kf* ($kargs () () ,f))
  2057. ($ (convert-test test kt* kf*))))
  2058. (($ <const> src c)
  2059. (with-cps cps
  2060. (build-term ($continue (if c kt kf) src ($values ())))))
  2061. (_ (convert-arg cps test
  2062. (lambda (cps test)
  2063. (with-cps cps
  2064. (build-term ($branch kt kf src 'false? #f (test)))))))))
  2065. (with-cps cps
  2066. (let$ t (convert consequent k subst))
  2067. (let$ f (convert alternate k subst))
  2068. (letk kt ($kargs () () ,t))
  2069. (letk kf ($kargs () () ,f))
  2070. ($ (convert-test test kt kf))))
  2071. (($ <lexical-set> src name gensym exp)
  2072. (convert-arg cps exp
  2073. (lambda (cps exp)
  2074. (match (hashq-ref subst gensym)
  2075. ((orig-var box #t)
  2076. (with-cps cps
  2077. (let$ k (adapt-arity k src 0))
  2078. (build-term
  2079. ($continue k src
  2080. ($primcall 'scm-set!/immediate '(box . 1) (box exp))))))))))
  2081. (($ <seq> src head tail)
  2082. (if (zero-valued? head)
  2083. (with-cps cps
  2084. (let$ tail (convert tail k subst))
  2085. (letk kseq ($kargs () () ,tail))
  2086. ($ (convert head kseq subst)))
  2087. (with-cps cps
  2088. (let$ tail (convert tail k subst))
  2089. (letv vals)
  2090. (letk kseq ($kargs ('vals) (vals) ,tail))
  2091. (letk kreceive ($kreceive '() 'vals kseq))
  2092. ($ (convert head kreceive subst)))))
  2093. (($ <let> src names syms vals body)
  2094. (let lp ((cps cps) (names names) (syms syms) (vals vals))
  2095. (match (list names syms vals)
  2096. ((() () ()) (convert cps body k subst))
  2097. (((name . names) (sym . syms) (val . vals))
  2098. (with-cps cps
  2099. (let$ body (lp names syms vals))
  2100. (let$ body (box-bound-var name sym body))
  2101. ($ ((lambda (cps)
  2102. (if (single-valued? val)
  2103. (with-cps cps
  2104. (letk klet ($kargs (name) ((bound-var sym)) ,body))
  2105. ($ (convert val klet subst)))
  2106. (with-cps cps
  2107. (letv rest)
  2108. (letk klet ($kargs (name 'rest) ((bound-var sym) rest) ,body))
  2109. (letk kreceive ($kreceive (list name) 'rest klet))
  2110. ($ (convert val kreceive subst))))))))))))
  2111. (($ <fix> src names gensyms funs body)
  2112. ;; Some letrecs can be contified; that happens later.
  2113. (define (convert-funs cps funs)
  2114. (match funs
  2115. (()
  2116. (with-cps cps '()))
  2117. ((fun . funs)
  2118. (with-cps cps
  2119. (let$ fun (convert fun k subst))
  2120. (let$ funs (convert-funs funs))
  2121. (cons (match fun
  2122. (($ $continue _ _ (and fun ($ $fun)))
  2123. fun))
  2124. funs)))))
  2125. (if (current-topbox-scope)
  2126. (let ((vars (map bound-var gensyms)))
  2127. (with-cps cps
  2128. (let$ body (convert body k subst))
  2129. (letk krec ($kargs names vars ,body))
  2130. (let$ funs (convert-funs funs))
  2131. (build-term ($continue krec src ($rec names vars funs)))))
  2132. (let ((scope-id (fresh-scope-id)))
  2133. (with-cps cps
  2134. (let$ body ((lambda (cps)
  2135. (parameterize ((current-topbox-scope scope-id))
  2136. (convert cps exp k subst)))))
  2137. (letk kscope ($kargs () () ,body))
  2138. ($ (capture-toplevel-scope src scope-id kscope))))))
  2139. (($ <let-values> src exp
  2140. ($ <lambda-case> lsrc req #f rest #f () syms body #f))
  2141. (let ((names (append req (if rest (list rest) '())))
  2142. (bound-vars (map bound-var syms)))
  2143. (with-cps cps
  2144. (let$ body (convert body k subst))
  2145. (let$ body (box-bound-vars names syms body))
  2146. (letk kargs ($kargs names bound-vars ,body))
  2147. (letk kreceive ($kreceive req rest kargs))
  2148. ($ (convert exp kreceive subst)))))))
  2149. (define (build-subst exp)
  2150. "Compute a mapping from lexical gensyms to CPS variable indexes. CPS
  2151. uses small integers to identify variables, instead of gensyms.
  2152. This subst table serves an additional purpose of mapping variables to
  2153. replacements. The usual reason to replace one variable by another is
  2154. assignment conversion. Default argument values is the other reason.
  2155. The result is a hash table mapping symbols to substitutions (in the case
  2156. that a variable is substituted) or to indexes. A substitution is a list
  2157. of the form:
  2158. (ORIG-INDEX SUBST-INDEX BOXED?)
  2159. A true value for BOXED? indicates that the replacement variable is in a
  2160. box. If a variable is not substituted, the mapped value is a small
  2161. integer."
  2162. (let ((table (make-hash-table)))
  2163. (define (down exp)
  2164. (match exp
  2165. (($ <lexical-set> src name sym exp)
  2166. (match (hashq-ref table sym)
  2167. ((orig subst #t) #t)
  2168. ((orig subst #f) (hashq-set! table sym (list orig subst #t)))
  2169. ((? number? idx) (hashq-set! table sym (list idx (fresh-var) #t)))))
  2170. (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
  2171. (fold-formals (lambda (name sym init seed)
  2172. (hashq-set! table sym
  2173. (if init
  2174. (list (fresh-var) (fresh-var) #f)
  2175. (fresh-var))))
  2176. #f
  2177. (make-$arity req (or opt '()) rest
  2178. (if kw (cdr kw) '()) (and kw (car kw)))
  2179. gensyms
  2180. inits))
  2181. (($ <let> src names gensyms vals body)
  2182. (for-each (lambda (sym)
  2183. (hashq-set! table sym (fresh-var)))
  2184. gensyms))
  2185. (($ <fix> src names gensyms vals body)
  2186. (for-each (lambda (sym)
  2187. (hashq-set! table sym (fresh-var)))
  2188. gensyms))
  2189. (_ #t))
  2190. (values))
  2191. (define (up exp) (values))
  2192. ((make-tree-il-folder) exp down up)
  2193. table))
  2194. (define (cps-convert/thunk exp)
  2195. (parameterize ((label-counter 0)
  2196. (var-counter 0)
  2197. (scope-counter 0))
  2198. (with-cps empty-intmap
  2199. (letv init)
  2200. ;; Allocate kinit first so that we know that the entry point's
  2201. ;; label is zero. This simplifies data flow in the compiler if we
  2202. ;; can just pass around the program as a map of continuations and
  2203. ;; know that the entry point is label 0.
  2204. (letk kinit ,#f)
  2205. (letk ktail ($ktail))
  2206. (let$ body (convert exp ktail (build-subst exp)))
  2207. (letk kbody ($kargs () () ,body))
  2208. (letk kclause ($kclause ('() '() #f '() #f) kbody #f))
  2209. ($ ((lambda (cps)
  2210. (let ((init (build-cont
  2211. ($kfun (tree-il-src exp) '() init ktail kclause))))
  2212. (with-cps (persistent-intmap (intmap-replace! cps kinit init))
  2213. kinit))))))))
  2214. (define *comp-module* (make-fluid))
  2215. (define %warning-passes
  2216. `((unused-variable . ,unused-variable-analysis)
  2217. (unused-toplevel . ,unused-toplevel-analysis)
  2218. (shadowed-toplevel . ,shadowed-toplevel-analysis)
  2219. (unbound-variable . ,unbound-variable-analysis)
  2220. (macro-use-before-definition . ,macro-use-before-definition-analysis)
  2221. (arity-mismatch . ,arity-analysis)
  2222. (format . ,format-analysis)))
  2223. (define (optimize-tree-il x e opts)
  2224. (define warnings
  2225. (or (and=> (memq #:warnings opts) cadr)
  2226. '()))
  2227. ;; Go through the warning passes.
  2228. (let ((analyses (filter-map (lambda (kind)
  2229. (assoc-ref %warning-passes kind))
  2230. warnings)))
  2231. (analyze-tree analyses x e))
  2232. (optimize x e opts))
  2233. (define (canonicalize exp)
  2234. (define-syntax-rule (with-lexical src id . body)
  2235. (let ((k (lambda (id) . body)))
  2236. (match id
  2237. (($ <lexical-ref>) (k id))
  2238. (_
  2239. (let ((v (gensym "v ")))
  2240. (make-let src (list 'v) (list v) (list id)
  2241. (k (make-lexical-ref src 'v v))))))))
  2242. (define-syntax with-lexicals
  2243. (syntax-rules ()
  2244. ((with-lexicals src () . body) (let () . body))
  2245. ((with-lexicals src (id . ids) . body)
  2246. (with-lexical src id (with-lexicals src ids . body)))))
  2247. (define (reduce-conditional exp)
  2248. (match exp
  2249. (($ <conditional> src
  2250. ($ <conditional> _ test ($ <const> _ t) ($ <const> _ f))
  2251. consequent alternate)
  2252. (cond
  2253. ((and t (not f))
  2254. (reduce-conditional (make-conditional src test consequent alternate)))
  2255. ((and (not t) f)
  2256. (reduce-conditional (make-conditional src test alternate consequent)))
  2257. (else
  2258. exp)))
  2259. (_ exp)))
  2260. (define (evaluate-args-eagerly-if-needed src inits k)
  2261. ;; Some macros generate calls to "vector" or "list" with like 300
  2262. ;; arguments. Since we eventually compile to lower-level operations
  2263. ;; like make-vector and vector-set! or cons, it reduces live
  2264. ;; variable pressure to sink initializers if we can, if we can prove
  2265. ;; that the initializer can't capture the continuation. (More on
  2266. ;; that caveat here:
  2267. ;; http://wingolog.org/archives/2013/11/02/scheme-quiz-time).
  2268. ;;
  2269. ;; Normally we would do this transformation in the optimizer, but
  2270. ;; it's quite tricky there and quite easy here, so we do it here.
  2271. (match inits
  2272. (() (k '()))
  2273. ((init . inits)
  2274. (match init
  2275. ((or ($ <const>) ($ <void>) ($ <lambda>) ($ <lexical-ref>))
  2276. (evaluate-args-eagerly-if-needed
  2277. src inits (lambda (inits) (k (cons init inits)))))
  2278. (_
  2279. (with-lexical
  2280. src init
  2281. (evaluate-args-eagerly-if-needed
  2282. src inits (lambda (inits) (k (cons init inits))))))))))
  2283. (post-order
  2284. (lambda (exp)
  2285. (match exp
  2286. (($ <conditional>)
  2287. (reduce-conditional exp))
  2288. (($ <primcall> src 'exact-integer? (x))
  2289. ;; Both fixnum? and bignum? are branching primitives.
  2290. (with-lexicals src (x)
  2291. (make-conditional
  2292. src (make-primcall src 'fixnum? (list x))
  2293. (make-const src #t)
  2294. (make-conditional src (make-primcall src 'bignum? (list x))
  2295. (make-const src #t)
  2296. (make-const src #f)))))
  2297. (($ <primcall> src '<= (a b))
  2298. ;; No need to reduce as <= is a branching primitive.
  2299. (make-conditional src (make-primcall src '<= (list a b))
  2300. (make-const src #t)
  2301. (make-const src #f)))
  2302. (($ <primcall> src '>= (a b))
  2303. ;; No need to reduce as < is a branching primitive.
  2304. (make-conditional src (make-primcall src '<= (list b a))
  2305. (make-const src #t)
  2306. (make-const src #f)))
  2307. (($ <primcall> src '> (a b))
  2308. ;; No need to reduce as < is a branching primitive.
  2309. (make-conditional src (make-primcall src '< (list b a))
  2310. (make-const src #t)
  2311. (make-const src #f)))
  2312. (($ <primcall> src (? branching-primitive? name) args)
  2313. ;; No need to reduce because test is not reducible: reifying
  2314. ;; #t/#f is the right thing.
  2315. (make-conditional src exp
  2316. (make-const src #t)
  2317. (make-const src #f)))
  2318. (($ <primcall> src 'not (x))
  2319. (reduce-conditional
  2320. (make-conditional src x
  2321. (make-const src #f)
  2322. (make-const src #t))))
  2323. (($ <primcall> src (or 'eqv? 'equal?) (a b))
  2324. (let ()
  2325. (define-syntax-rule (primcall name . args)
  2326. (make-primcall src 'name (list . args)))
  2327. (define-syntax primcall-chain
  2328. (syntax-rules ()
  2329. ((_ x) x)
  2330. ((_ x . y)
  2331. (make-conditional src (primcall . x) (primcall-chain . y)
  2332. (make-const src #f)))))
  2333. (define-syntax-rule (bool x)
  2334. (make-conditional src x (make-const src #t) (make-const src #f)))
  2335. (with-lexicals src (a b)
  2336. (make-conditional
  2337. src
  2338. (primcall eq? a b)
  2339. (make-const src #t)
  2340. (match (primcall-name exp)
  2341. ('eqv?
  2342. ;; Completely inline.
  2343. (primcall-chain (heap-number? a)
  2344. (heap-number? b)
  2345. (bool (primcall heap-numbers-equal? a b))))
  2346. ('equal?
  2347. ;; Partially inline.
  2348. (primcall-chain (heap-object? a)
  2349. (heap-object? b)
  2350. (primcall equal? a b))))))))
  2351. (($ <primcall> src 'vector args)
  2352. ;; Expand to "allocate-vector" + "vector-init!".
  2353. (evaluate-args-eagerly-if-needed
  2354. src args
  2355. (lambda (args)
  2356. (define-syntax-rule (primcall name . args)
  2357. (make-primcall src 'name (list . args)))
  2358. (define-syntax-rule (const val)
  2359. (make-const src val))
  2360. (let ((v (primcall allocate-vector (const (length args)))))
  2361. (with-lexicals src (v)
  2362. (list->seq
  2363. src
  2364. (append (map (lambda (idx arg)
  2365. (primcall vector-init! v (const idx) arg))
  2366. (iota (length args))
  2367. args)
  2368. (list v))))))))
  2369. (($ <primcall> src 'make-struct/simple (vtable . args))
  2370. ;; Expand to "allocate-struct" + "struct-init!".
  2371. (evaluate-args-eagerly-if-needed
  2372. src args
  2373. (lambda (args)
  2374. (define-syntax-rule (primcall name . args)
  2375. (make-primcall src 'name (list . args)))
  2376. (define-syntax-rule (const val)
  2377. (make-const src val))
  2378. (let ((s (primcall allocate-struct vtable (const (length args)))))
  2379. (with-lexicals src (s)
  2380. (list->seq
  2381. src
  2382. (append (map (lambda (idx arg)
  2383. (primcall struct-init! s (const idx) arg))
  2384. (iota (length args))
  2385. args)
  2386. (list s))))))))
  2387. (($ <primcall> src 'list args)
  2388. ;; Expand to "cons".
  2389. (evaluate-args-eagerly-if-needed
  2390. src args
  2391. (lambda (args)
  2392. (define-syntax-rule (primcall name . args)
  2393. (make-primcall src 'name (list . args)))
  2394. (define-syntax-rule (const val)
  2395. (make-const src val))
  2396. (fold (lambda (arg tail) (primcall cons arg tail))
  2397. (const '())
  2398. (reverse args)))))
  2399. ;; Lower (logand x (lognot y)) to (logsub x y). We do it here
  2400. ;; instead of in CPS because it gets rid of the lognot entirely;
  2401. ;; if type folding can't prove Y to be an exact integer, then DCE
  2402. ;; would have to leave it in the program for its possible
  2403. ;; effects.
  2404. (($ <primcall> src 'logand (x ($ <primcall> _ 'lognot (y))))
  2405. (make-primcall src 'logsub (list x y)))
  2406. (($ <primcall> src 'logand (($ <primcall> _ 'lognot (y)) x))
  2407. (make-primcall src 'logsub (list x y)))
  2408. (($ <primcall> src 'throw ())
  2409. (make-call src (make-primitive-ref src 'throw) '()))
  2410. (($ <prompt> src escape-only? tag body
  2411. ($ <lambda> hsrc hmeta
  2412. ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
  2413. exp)
  2414. (($ <primcall> src 'ash (a b))
  2415. (match b
  2416. (($ <const> src2 (? exact-integer? n))
  2417. (if (< n 0)
  2418. (make-primcall src 'rsh (list a (make-const src2 (- n))))
  2419. (make-primcall src 'lsh (list a b))))
  2420. (_
  2421. (with-lexicals src (a b)
  2422. (make-conditional
  2423. src
  2424. (make-primcall src '< (list b (make-const src 0)))
  2425. (let ((n (make-primcall src '- (list (make-const src 0) b))))
  2426. (make-primcall src 'rsh (list a n)))
  2427. (make-primcall src 'lsh (list a b)))))))
  2428. ;; Eta-convert prompts without inline handlers.
  2429. (($ <prompt> src escape-only? tag body handler)
  2430. (let ((h (gensym "h "))
  2431. (args (gensym "args ")))
  2432. (define-syntax-rule (primcall name . args)
  2433. (make-primcall src 'name (list . args)))
  2434. (define-syntax-rule (const val)
  2435. (make-const src val))
  2436. (with-lexicals src (handler)
  2437. (make-conditional
  2438. src
  2439. (primcall procedure? handler)
  2440. (make-prompt
  2441. src escape-only? tag body
  2442. (make-lambda
  2443. src '()
  2444. (make-lambda-case
  2445. src '() #f 'args #f '() (list args)
  2446. (primcall apply handler (make-lexical-ref #f 'args args))
  2447. #f)))
  2448. (primcall throw
  2449. (const 'wrong-type-arg)
  2450. (const "call-with-prompt")
  2451. (const "Wrong type (expecting procedure): ~S")
  2452. (primcall cons handler (const '()))
  2453. (primcall cons handler (const '())))))))
  2454. (_ exp)))
  2455. exp))
  2456. (define (compile-cps exp env opts)
  2457. (values (cps-convert/thunk
  2458. (canonicalize (optimize-tree-il exp env opts)))
  2459. env
  2460. env))
  2461. ;;; Local Variables:
  2462. ;;; eval: (put 'convert-arg 'scheme-indent-function 2)
  2463. ;;; eval: (put 'convert-args 'scheme-indent-function 2)
  2464. ;;; eval: (put 'with-lexicals 'scheme-indent-function 2)
  2465. ;;; End: