compile-cps.scm 93 KB

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