compile-cps.scm 100 KB

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