12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609 |
- ;;; Continuation-passing style (CPS) intermediate language (IL)
- ;; Copyright (C) 2013-2015,2017-2021 Free Software Foundation, Inc.
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;;; Commentary:
- ;;;
- ;;; This pass converts Tree-IL to the continuation-passing style (CPS)
- ;;; language.
- ;;;
- ;;; CPS is a lower-level representation than Tree-IL. Converting to
- ;;; CPS, beyond adding names for all control points and all values,
- ;;; simplifies expressions in the following ways, among others:
- ;;;
- ;;; * Fixing the order of evaluation.
- ;;;
- ;;; * Converting assigned variables to boxed variables.
- ;;;
- ;;; * Requiring that Scheme's <letrec> has already been lowered to
- ;;; <fix>.
- ;;;
- ;;; * Inlining default-value initializers into lambda-case
- ;;; expressions.
- ;;;
- ;;; * Inlining prompt bodies.
- ;;;
- ;;; * Turning toplevel and module references into primcalls. This
- ;;; involves explicitly modelling the "scope" of toplevel lookups
- ;;; (indicating the module with respect to which toplevel bindings
- ;;; are resolved).
- ;;;
- ;;; The utility of CPS is that it gives a name to everything: every
- ;;; intermediate value, and every control point (continuation). As such
- ;;; it is more verbose than Tree-IL, but at the same time more simple as
- ;;; the number of concepts is reduced.
- ;;;
- ;;; Code:
- (define-module (language tree-il compile-cps)
- #:use-module (ice-9 match)
- #:use-module ((srfi srfi-1) #:select (fold filter-map))
- #:use-module (srfi srfi-26)
- #:use-module ((system foreign) #:select (make-pointer pointer->scm))
- #:use-module (system base target)
- #:use-module (system base types internal)
- #:use-module (language cps)
- #:use-module (language cps utils)
- #:use-module (language cps with-cps)
- #:use-module (language tree-il cps-primitives)
- #:use-module (language tree-il)
- #:use-module (language cps intmap)
- #:export (compile-cps))
- (define (convert-primcall/default cps k src op param . args)
- (with-cps cps
- (build-term
- ($continue k src ($primcall op param args)))))
- (define *primcall-converters* (make-hash-table))
- (define-syntax-rule (define-primcall-converter name proc)
- (hashq-set! *primcall-converters* 'name proc))
- (define (convert-primcall* cps k src op param args)
- (let ((proc (hashq-ref *primcall-converters* op convert-primcall/default)))
- (apply proc cps k src op param args)))
- (define (convert-primcall cps k src op param . args)
- (convert-primcall* cps k src op param args))
- (define (ensure-vector cps src op pred v have-length)
- (define msg
- (match pred
- ('vector?
- "Wrong type argument in position 1 (expecting vector): ~S")
- ('mutable-vector?
- "Wrong type argument in position 1 (expecting mutable vector): ~S")))
- (define not-vector (vector 'wrong-type-arg (symbol->string op) msg))
- (with-cps cps
- (letv w0 slen ulen rlen)
- (letk knot-vector
- ($kargs () () ($throw src 'throw/value+data not-vector (v))))
- (let$ body (have-length slen))
- (letk k ($kargs ('slen) (slen) ,body))
- (letk kcast
- ($kargs ('rlen) (rlen)
- ($continue k src ($primcall 'u64->s64 #f (rlen)))))
- (letk kassume
- ($kargs ('ulen) (ulen)
- ($continue kcast src
- ($primcall 'assume-u64 `(0 . ,(target-max-vector-length)) (ulen)))))
- (letk krsh
- ($kargs ('w0) (w0)
- ($continue kassume src ($primcall 'ursh/immediate 8 (w0)))))
- (letk kv
- ($kargs () ()
- ($continue krsh src
- ($primcall 'word-ref/immediate '(vector . 0) (v)))))
- (letk kheap-object
- ($kargs () ()
- ($branch knot-vector kv src pred #f (v))))
- (build-term
- ($branch knot-vector kheap-object src 'heap-object? #f (v)))))
- (define (untag-fixnum-index-in-range cps src op idx slen have-index-in-range)
- ;; Precondition: SLEN is a non-negative S64 that is representable as a
- ;; fixnum.
- (define not-fixnum
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 2 (expecting small integer): ~S"))
- (define out-of-range
- (vector 'out-of-range
- (symbol->string op)
- "Argument 2 out of range: ~S"))
- (with-cps cps
- (letv sidx)
- (letk knot-fixnum
- ($kargs () () ($throw src 'throw/value+data not-fixnum (idx))))
- (letk kout-of-range
- ($kargs () () ($throw src 'throw/value+data out-of-range (idx))))
- (let$ body (have-index-in-range sidx))
- (letk k ($kargs () () ,body))
- (letk kboundlen
- ($kargs () ()
- ($branch kout-of-range k src 's64-< #f (sidx slen))))
- (letk kbound0
- ($kargs ('sidx) (sidx)
- ($branch kboundlen kout-of-range src 's64-imm-< 0 (sidx))))
- (letk kuntag
- ($kargs () ()
- ($continue kbound0 src ($primcall 'untag-fixnum #f (idx)))))
- (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (idx)))))
- (define (untag-fixnum-in-imm-range cps src op size min max have-int-in-range)
- (define not-fixnum
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 2 (expecting small integer): ~S"))
- (define out-of-range
- (vector 'out-of-range
- (symbol->string op)
- "Argument 2 out of range: ~S"))
- (with-cps cps
- (letv ssize)
- (letk knot-fixnum
- ($kargs () () ($throw src 'throw/value+data not-fixnum (size))))
- (letk kout-of-range
- ($kargs () () ($throw src 'throw/value+data out-of-range (size))))
- (let$ body (have-int-in-range ssize))
- (letk k ($kargs () () ,body))
- (letk kboundlen
- ($kargs () ()
- ($branch k kout-of-range src 'imm-s64-< max (ssize))))
- (letk kbound0
- ($kargs ('ssize) (ssize)
- ($branch kboundlen kout-of-range src 's64-imm-< min (ssize))))
- (letk kuntag
- ($kargs () ()
- ($continue kbound0 src ($primcall 'untag-fixnum #f (size)))))
- (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (size)))))
- (define (compute-vector-access-pos cps src sidx have-pos)
- (with-cps cps
- (letv spos upos)
- (let$ body (have-pos upos))
- (letk kref ($kargs ('pos) (upos) ,body))
- (letk kcvt ($kargs ('pos) (spos)
- ($continue kref src ($primcall 's64->u64 #f (spos)))))
- (build-term
- ($continue kcvt src ($primcall 'sadd/immediate 1 (sidx))))))
- (define (prepare-vector-access cps src op pred v idx access)
- (ensure-vector
- cps src op pred v
- (lambda (cps slen)
- (untag-fixnum-index-in-range
- cps src op idx slen
- (lambda (cps sidx)
- (compute-vector-access-pos
- cps src sidx
- (lambda (cps pos)
- (access cps v pos))))))))
- (define (prepare-vector-access/immediate cps src op pred v idx access)
- (unless (and (exact-integer? idx) (<= 0 idx (1- (target-max-vector-length))))
- (error "precondition failed" idx))
- (ensure-vector
- cps src op pred v
- (lambda (cps slen)
- (define out-of-range
- (vector 'out-of-range
- (symbol->string op)
- "Argument 2 out of range: ~S"))
- (with-cps cps
- (letv tidx)
- (letk kthrow
- ($kargs ('tidx) (tidx)
- ($throw src 'throw/value+data out-of-range (tidx))))
- (letk kout-of-range
- ($kargs () ()
- ($continue kthrow src ($const idx))))
- (let$ body (access v (1+ idx)))
- (letk k ($kargs () () ,body))
- (build-term
- ($branch kout-of-range k src 'imm-s64-< idx (slen)))))))
- (define-primcall-converter vector-length
- (lambda (cps k src op param v)
- (ensure-vector
- cps src op 'vector? v
- (lambda (cps slen)
- (with-cps cps
- (build-term
- ($continue k src ($primcall 'tag-fixnum #f (slen)))))))))
- (define-primcall-converter vector-ref
- (lambda (cps k src op param v idx)
- (prepare-vector-access
- cps src op 'vector? v idx
- (lambda (cps v upos)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-ref 'vector (v upos)))))))))
- (define-primcall-converter vector-ref/immediate
- (lambda (cps k src op param v)
- (prepare-vector-access/immediate
- cps src 'vector-ref 'vector? v param
- (lambda (cps v pos)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-ref/immediate `(vector . ,pos) (v)))))))))
- (define-primcall-converter vector-set!
- (lambda (cps k src op param v idx val)
- (prepare-vector-access
- cps src op 'mutable-vector? v idx
- (lambda (cps v upos)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set! 'vector (v upos val)))))))))
- (define-primcall-converter vector-set!/immediate
- (lambda (cps k src op param v val)
- (prepare-vector-access/immediate
- cps src 'vector-set! 'mutable-vector? v param
- (lambda (cps v pos)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate `(vector . ,pos) (v val)))))))))
- (define-primcall-converter vector-init!
- (lambda (cps k src op param v val)
- (define pos (1+ param))
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate `(vector . ,pos) (v val)))))))
- (define (emit-initializations-as-loop cps k src obj annotation start nwords init)
- (with-cps cps
- (letv pos)
- (letk kloop ,#f) ;; Patched later.
- (letk kback
- ($kargs () ()
- ($continue kloop src
- ($primcall 'uadd/immediate 1 (pos)))))
- (letk kinit
- ($kargs () ()
- ($continue kback src
- ($primcall 'scm-set! annotation (obj pos init)))))
- (setk kloop
- ($kargs ('pos) (pos)
- ($branch k kinit src 'u64-< #f (pos nwords))))
- (build-term
- ($continue kloop src
- ($primcall 'load-u64 start ())))))
- (define-primcall-converter allocate-vector
- (lambda (cps k src op param)
- (define size param)
- (define nwords (1+ size))
- (unless (and (exact-integer? size) (<= 0 size (target-max-vector-length)))
- (error "precondition failed" size))
- (with-cps cps
- (letv v w0)
- (letk kdone
- ($kargs () ()
- ($continue k src ($values (v)))))
- (letk ktag1
- ($kargs ('w0) (w0)
- ($continue kdone src
- ($primcall 'word-set!/immediate '(vector . 0) (v w0)))))
- (letk ktag0
- ($kargs ('v) (v)
- ($continue ktag1 src
- ($primcall 'load-u64 (+ %tc7-vector (ash size 8)) ()))))
- (build-term
- ($continue ktag0 src
- ($primcall 'allocate-words/immediate `(vector . ,nwords) ()))))))
- (define-primcall-converter make-vector
- (lambda (cps k src op param size init)
- (untag-fixnum-in-imm-range
- cps src op size 0 (target-max-vector-length)
- (lambda (cps ssize)
- (with-cps cps
- (letv usize nwords v w0-high w0)
- (letk kdone
- ($kargs () ()
- ($continue k src ($values (v)))))
- (let$ init-loop
- (emit-initializations-as-loop kdone src v 'vector 1 nwords init))
- (letk kbody ($kargs () () ,init-loop))
- (letk ktag2
- ($kargs ('w0) (w0)
- ($continue kbody src
- ($primcall 'word-set!/immediate '(vector . 0) (v w0)))))
- (letk ktag1
- ($kargs ('w0-high) (w0-high)
- ($continue ktag2 src
- ($primcall 'uadd/immediate %tc7-vector (w0-high)))))
- (letk ktag0
- ($kargs ('v) (v)
- ($continue ktag1 src
- ($primcall 'ulsh/immediate 8 (usize)))))
- (letk kalloc
- ($kargs ('nwords) (nwords)
- ($continue ktag0 src
- ($primcall 'allocate-words 'vector (nwords)))))
- (letk kadd1
- ($kargs ('usize) (usize)
- ($continue kalloc src
- ;; Header word.
- ($primcall 'uadd/immediate 1 (usize)))))
- (build-term
- ($continue kadd1 src
- ;; Header word.
- ($primcall 's64->u64 #f (ssize)))))))))
- (define-primcall-converter make-vector/immediate
- (lambda (cps k src op param init)
- (define size param)
- (define nwords (1+ size))
- (define (init-fields cps v pos kdone)
- ;; Inline the initializations, up to vectors of size 32. Above
- ;; that it's a bit of a waste, so reify a loop instead.
- (cond
- ((<= 32 nwords)
- (with-cps cps
- (letv unwords)
- (let$ init-loop
- (emit-initializations-as-loop kdone src v 'vector
- pos unwords init))
- (letk kinit ($kargs ('unwords) (unwords) ,init-loop))
- (letk kusize ($kargs () ()
- ($continue kinit src
- ($primcall 'load-u64 nwords ()))))
- kusize))
- ((< pos nwords)
- (with-cps cps
- (let$ knext (init-fields v (1+ pos) kdone))
- (letk kinit
- ($kargs () ()
- ($continue knext src
- ($primcall 'scm-set!/immediate `(vector . ,pos)
- (v init)))))
- kinit))
- (else
- (with-cps cps
- kdone))))
- (unless (and (exact-integer? size) (<= 0 size (target-max-vector-length)))
- (error "precondition failed" size))
- (with-cps cps
- (letv v w0)
- (letk kdone
- ($kargs () ()
- ($continue k src ($values (v)))))
- (let$ kinit (init-fields v 1 kdone))
- (letk ktag1
- ($kargs ('w0) (w0)
- ($continue kinit src
- ($primcall 'word-set!/immediate '(vector . 0) (v w0)))))
- (letk ktag0
- ($kargs ('v) (v)
- ($continue ktag1 src
- ($primcall 'load-u64 (+ %tc7-vector (ash size 8)) ()))))
- (build-term
- ($continue ktag0 src
- ($primcall 'allocate-words/immediate `(vector . ,nwords) ()))))))
- (define (ensure-pair cps src op pred x is-pair)
- (define msg
- (match pred
- ('pair?
- "Wrong type argument in position 1 (expecting pair): ~S")
- ('mutable-pair?
- "Wrong type argument in position 1 (expecting mutable pair): ~S")))
- (define not-pair (vector 'wrong-type-arg (symbol->string op) msg))
- (with-cps cps
- (letk knot-pair ($kargs () () ($throw src 'throw/value+data not-pair (x))))
- (let$ body (is-pair))
- (letk k ($kargs () () ,body))
- (letk kheap-object ($kargs () () ($branch knot-pair k src pred #f (x))))
- (build-term ($branch knot-pair kheap-object src 'heap-object? #f (x)))))
- (define-primcall-converter cons
- (lambda (cps k src op param head tail)
- (with-cps cps
- (letv pair)
- (letk kdone
- ($kargs () ()
- ($continue k src ($values (pair)))))
- (letk ktail
- ($kargs () ()
- ($continue kdone src
- ($primcall 'scm-set!/immediate '(pair . 1) (pair tail)))))
- (letk khead
- ($kargs ('pair) (pair)
- ($continue ktail src
- ($primcall 'scm-set!/immediate '(pair . 0) (pair head)))))
- (build-term
- ($continue khead src
- ($primcall 'allocate-words/immediate '(pair . 2) ()))))))
- (define-primcall-converter car
- (lambda (cps k src op param pair)
- (ensure-pair
- cps src 'car 'pair? pair
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-ref/immediate '(pair . 0) (pair)))))))))
- (define-primcall-converter cdr
- (lambda (cps k src op param pair)
- (ensure-pair
- cps src 'cdr 'pair? pair
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-ref/immediate '(pair . 1) (pair)))))))))
- (define-primcall-converter set-car!
- (lambda (cps k src op param pair val)
- (ensure-pair
- ;; FIXME: Use mutable-pair? as predicate.
- cps src 'set-car! 'pair? pair
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate '(pair . 0) (pair val)))))))))
- (define-primcall-converter set-cdr!
- (lambda (cps k src op param pair val)
- (ensure-pair
- ;; FIXME: Use mutable-pair? as predicate.
- cps src 'set-cdr! 'pair? pair
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate '(pair . 1) (pair val)))))))))
- (define-primcall-converter box
- (lambda (cps k src op param val)
- (with-cps cps
- (letv obj tag)
- (letk kdone
- ($kargs () ()
- ($continue k src ($values (obj)))))
- (letk kval
- ($kargs () ()
- ($continue kdone src
- ($primcall 'scm-set!/immediate '(box . 1) (obj val)))))
- (letk ktag1
- ($kargs ('tag) (tag)
- ($continue kval src
- ($primcall 'word-set!/immediate '(box . 0) (obj tag)))))
- (letk ktag0
- ($kargs ('obj) (obj)
- ($continue ktag1 src
- ($primcall 'load-u64 %tc7-variable ()))))
- (build-term
- ($continue ktag0 src
- ($primcall 'allocate-words/immediate '(box . 2) ()))))))
- (define-primcall-converter %box-ref
- (lambda (cps k src op param box)
- (define unbound
- #(misc-error "variable-ref" "Unbound variable: ~S"))
- (with-cps cps
- (letv val)
- (letk kunbound ($kargs () () ($throw src 'throw/value unbound (box))))
- (letk kbound ($kargs () () ($continue k src ($values (val)))))
- (letk ktest
- ($kargs ('val) (val)
- ($branch kbound kunbound src 'undefined? #f (val))))
- (build-term
- ($continue ktest src
- ($primcall 'scm-ref/immediate '(box . 1) (box)))))))
- (define-primcall-converter %box-set!
- (lambda (cps k src op param box val)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate '(box . 1) (box val)))))))
- (define (ensure-box cps src op x is-box)
- (define not-box
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 1 (expecting box): ~S"))
- (with-cps cps
- (letk knot-box ($kargs () () ($throw src 'throw/value+data not-box (x))))
- (let$ body (is-box))
- (letk k ($kargs () () ,body))
- (letk kheap-object ($kargs () () ($branch knot-box k src 'variable? #f (x))))
- (build-term ($branch knot-box kheap-object src 'heap-object? #f (x)))))
- (define-primcall-converter box-ref
- (lambda (cps k src op param box)
- (ensure-box
- cps src 'variable-ref box
- (lambda (cps)
- (convert-primcall cps k src '%box-ref param box)))))
- (define-primcall-converter box-set!
- (lambda (cps k src op param box val)
- (ensure-box
- cps src 'variable-set! box
- (lambda (cps)
- (convert-primcall cps k src '%box-set! param box val)))))
- (define (ensure-struct cps src op x have-vtable)
- (define not-struct
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 1 (expecting struct): ~S"))
- (with-cps cps
- (letv vtable)
- (letk knot-struct
- ($kargs () () ($throw src 'throw/value+data not-struct (x))))
- (let$ body (have-vtable vtable))
- (letk k ($kargs ('vtable) (vtable) ,body))
- (letk kvtable ($kargs () ()
- ($continue k src ($primcall 'scm-ref/tag 'struct (x)))))
- (letk kheap-object
- ($kargs () () ($branch knot-struct kvtable src 'struct? #f (x))))
- (build-term ($branch knot-struct kheap-object src 'heap-object? #f (x)))))
- (define-primcall-converter struct-vtable
- (lambda (cps k src op param struct)
- (ensure-struct
- cps src 'struct-vtable struct
- (lambda (cps vtable)
- (with-cps cps
- (build-term
- ($continue k src ($values (vtable)))))))))
- (define (ensure-vtable cps src op vtable is-vtable)
- (ensure-struct
- cps src op vtable
- (lambda (cps vtable-vtable)
- (define not-vtable
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 1 (expecting vtable): ~S"))
- (define vtable-index-flags 1) ; FIXME: pull from struct.h
- (define vtable-offset-flags (1+ vtable-index-flags))
- (define vtable-validated-mask #b11)
- (define vtable-validated-value #b11)
- (with-cps cps
- (letv flags mask res)
- (letk knot-vtable
- ($kargs () () ($throw src 'throw/value+data not-vtable (vtable))))
- (let$ body (is-vtable))
- (letk k ($kargs () () ,body))
- (letk ktest
- ($kargs ('res) (res)
- ($branch knot-vtable k src
- 'u64-imm-= vtable-validated-value (res))))
- (letk kand
- ($kargs ('mask) (mask)
- ($continue ktest src
- ($primcall 'ulogand #f (flags mask)))))
- (letk kflags
- ($kargs ('flags) (flags)
- ($continue kand src
- ($primcall 'load-u64 vtable-validated-mask ()))))
- (build-term
- ($continue kflags src
- ($primcall 'word-ref/immediate
- `(struct . ,vtable-offset-flags) (vtable-vtable))))))))
- (define-primcall-converter allocate-struct
- (lambda (cps k src op nwords vtable)
- (ensure-vtable
- cps src 'allocate-struct vtable
- (lambda (cps)
- (define vtable-index-size 5) ; FIXME: pull from struct.h
- (define vtable-index-unboxed-fields 6) ; FIXME: pull from struct.h
- (define vtable-offset-size (1+ vtable-index-size))
- (define vtable-offset-unboxed-fields (1+ vtable-index-unboxed-fields))
- (define wrong-number
- (vector 'wrong-number-of-args
- (symbol->string op)
- "Wrong number of initializers when instantiating ~A"))
- (define has-unboxed
- (vector 'wrong-type-arg
- (symbol->string op)
- "Expected vtable with no unboxed fields: ~A"))
- (define (check-all-boxed cps kf kt vtable ptr word)
- (if (< (* word 32) nwords)
- (with-cps cps
- (letv idx bits)
- (let$ checkboxed (check-all-boxed kf kt vtable ptr (1+ word)))
- (letk kcheckboxed ($kargs () () ,checkboxed))
- (letk kcheck
- ($kargs ('bits) (bits)
- ($branch kf kcheckboxed src 'u64-imm-= 0 (bits))))
- (letk kword
- ($kargs ('idx) (idx)
- ($continue kcheck src
- ($primcall 'u32-ref 'bitmask (vtable ptr idx)))))
- (build-term
- ($continue kword src
- ($primcall 'load-u64 word ()))))
- (with-cps cps
- (build-term ($continue kt src ($values ()))))))
- (with-cps cps
- (letv rfields nfields ptr s)
- (letk kwna
- ($kargs () () ($throw src 'throw/value wrong-number (vtable))))
- (letk kunboxed
- ($kargs () () ($throw src 'throw/value+data has-unboxed (vtable))))
- (letk kdone
- ($kargs () () ($continue k src ($values (s)))))
- (letk ktag
- ($kargs ('s) (s)
- ($continue kdone src
- ($primcall 'scm-set!/tag 'struct (s vtable)))))
- (letk kalloc
- ($kargs () ()
- ($continue ktag src
- ($primcall 'allocate-words/immediate
- `(struct . ,(1+ nwords)) ()))))
- (let$ checkboxed (check-all-boxed kunboxed kalloc vtable ptr 0))
- (letk kcheckboxed ($kargs ('ptr) (ptr) ,checkboxed))
- (letk kaccess
- ($kargs () ()
- ($continue kcheckboxed src
- ($primcall 'pointer-ref/immediate
- `(struct . ,vtable-offset-unboxed-fields)
- (vtable)))))
- (letk knfields
- ($kargs ('nfields) (nfields)
- ($branch kwna kaccess src 'u64-imm-= nwords (nfields))))
- (letk kassume
- ($kargs ('rfields) (rfields)
- ($continue knfields src
- ($primcall 'assume-u64 `(0 . ,(target-max-size-t/scm))
- (rfields)))))
- (build-term
- ($continue kassume src
- ($primcall 'word-ref/immediate
- `(struct . ,vtable-offset-size) (vtable)))))))))
- (define (ensure-struct-index-in-range cps src op vtable idx boxed? in-range)
- (define vtable-index-size 5) ; FIXME: pull from struct.h
- (define vtable-index-unboxed-fields 6) ; FIXME: pull from struct.h
- (define vtable-offset-size (1+ vtable-index-size))
- (define vtable-offset-unboxed-fields (1+ vtable-index-unboxed-fields))
- (define bad-type
- (vector
- 'wrong-type-arg
- (symbol->string op)
- (if boxed?
- "Wrong type argument in position 2 (expecting boxed field): ~S"
- "Wrong type argument in position 2 (expecting unboxed field): ~S")))
- (define out-of-range
- (vector 'out-of-range
- (symbol->string op)
- "Argument 2 out of range: ~S"))
- (with-cps cps
- (letv rfields nfields ptr word bits mask res throwval1 throwval2)
- (letk kthrow1
- ($kargs (#f) (throwval1)
- ($throw src 'throw/value+data out-of-range (throwval1))))
- (letk kthrow2
- ($kargs (#f) (throwval2)
- ($throw src 'throw/value+data bad-type (throwval2))))
- (letk kbadidx ($kargs () () ($continue kthrow1 src ($const idx))))
- (letk kbadtype ($kargs () () ($continue kthrow2 src ($const idx))))
- (let$ body (in-range))
- (letk k ($kargs () () ,body))
- (letk ktest
- ($kargs ('res) (res)
- ($branch (if boxed? kbadtype k) (if boxed? k kbadtype) src
- 'u64-imm-= 0 (res))))
- (letk kand
- ($kargs ('mask) (mask)
- ($continue ktest src
- ($primcall 'ulogand #f (mask bits)))))
- (letk kbits
- ($kargs ('bits) (bits)
- ($continue kand src
- ($primcall 'load-u64 (ash 1 (logand idx 31)) ()))))
- (letk kword
- ($kargs ('word) (word)
- ($continue kbits src
- ($primcall 'u32-ref 'bitmask (vtable ptr word)))))
- (letk kptr
- ($kargs ('ptr) (ptr)
- ($continue kword src
- ($primcall 'load-u64 (ash idx -5) ()))))
- (letk kaccess
- ($kargs () ()
- ($continue kptr src
- ($primcall 'pointer-ref/immediate
- `(struct . ,vtable-offset-unboxed-fields)
- (vtable)))))
- (letk knfields
- ($kargs ('nfields) (nfields)
- ($branch kbadidx kaccess src 'imm-u64-< idx (nfields))))
- (letk kassume
- ($kargs ('rfields) (rfields)
- ($continue knfields src
- ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (rfields)))))
- (build-term
- ($continue kassume src
- ($primcall 'word-ref/immediate
- `(struct . ,vtable-offset-size) (vtable))))))
- (define (prepare-struct-scm-access cps src op struct idx boxed? have-pos)
- (define not-struct
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 1 (expecting struct): ~S"))
- (ensure-struct
- cps src op struct
- (lambda (cps vtable)
- (ensure-struct-index-in-range
- cps src op vtable idx boxed?
- (lambda (cps) (have-pos cps (1+ idx)))))))
- (define-primcall-converter struct-ref/immediate
- (lambda (cps k src op param struct)
- (prepare-struct-scm-access
- cps src op struct param #t
- (lambda (cps pos)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-ref/immediate `(struct . ,pos) (struct)))))))))
- (define-primcall-converter struct-set!/immediate
- (lambda (cps k src op param struct val)
- (prepare-struct-scm-access
- cps src op struct param #t
- (lambda (cps pos)
- (with-cps cps
- (letk k* ($kargs () () ($continue k src ($values (val)))))
- (build-term
- ($continue k* src
- ($primcall 'scm-set!/immediate `(struct . ,pos) (struct val)))))))))
- (define-primcall-converter struct-init!
- (lambda (cps k src op param s val)
- (define pos (1+ param))
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate `(struct . ,pos) (s val)))))))
- (define-primcall-converter struct-ref
- (lambda (cps k src op param struct idx)
- (with-cps cps
- (letv prim res)
- (letk krecv ($kreceive '(res) #f k))
- (letk kprim ($kargs ('prim) (prim)
- ($continue krecv src ($call prim (struct idx)))))
- (build-term
- ($continue kprim src ($prim 'struct-ref))))))
- (define-primcall-converter struct-set!
- (lambda (cps k src op param struct idx val)
- (with-cps cps
- (letv prim res)
- ;; struct-set! prim returns the value.
- (letk krecv ($kreceive '(res) #f k))
- (letk kprim ($kargs ('prim) (prim)
- ($continue krecv src ($call prim (struct idx val)))))
- (build-term
- ($continue kprim src ($prim 'struct-set!))))))
- (define (untag-bytevector-index cps src op idx ulen width have-uidx)
- (define not-fixnum
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 2 (expecting small integer): ~S"))
- (define out-of-range
- (vector 'out-of-range
- (symbol->string op)
- "Argument 2 out of range: ~S"))
- (with-cps cps
- (letv sidx uidx maxidx+1)
- (letk knot-fixnum
- ($kargs () () ($throw src 'throw/value+data not-fixnum (idx))))
- (letk kout-of-range
- ($kargs () () ($throw src 'throw/value+data out-of-range (idx))))
- (let$ body (have-uidx uidx))
- (letk k ($kargs () () ,body))
- (letk ktestidx
- ($kargs ('maxidx+1) (maxidx+1)
- ($branch kout-of-range k src 'u64-< #f (uidx maxidx+1))))
- (letk kdeclen
- ($kargs () ()
- ($continue ktestidx src
- ($primcall 'usub/immediate (1- width) (ulen)))))
- (letk ktestlen
- ($kargs ('uidx) (uidx)
- ($branch kout-of-range kdeclen src 'imm-u64-< (1- width) (ulen))))
- (letk kcvt
- ($kargs () ()
- ($continue ktestlen src ($primcall 's64->u64 #f (sidx)))))
- (letk kbound0
- ($kargs ('sidx) (sidx)
- ($branch kcvt kout-of-range src 's64-imm-< 0 (sidx))))
- (letk kuntag
- ($kargs () ()
- ($continue kbound0 src ($primcall 'untag-fixnum #f (idx)))))
- (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (idx)))))
- (define (ensure-bytevector cps k src op pred x)
- (define msg
- (match pred
- ('bytevector?
- "Wrong type argument in position 1 (expecting bytevector): ~S")
- ('mutable-bytevector?
- "Wrong type argument in position 1 (expecting mutable bytevector): ~S")))
- (define bad-type (vector 'wrong-type-arg (symbol->string op) msg))
- (with-cps cps
- (letk kf ($kargs () () ($throw src 'throw/value+data bad-type (x))))
- (letk kheap-object ($kargs () () ($branch kf k src pred #f (x))))
- (build-term ($branch kf kheap-object src 'heap-object? #f (x)))))
- (define (prepare-bytevector-access cps src op pred bv idx width
- have-ptr-and-uidx)
- (with-cps cps
- (letv ulen rlen)
- (let$ access
- (untag-bytevector-index
- src op idx rlen width
- (lambda (cps uidx)
- (with-cps cps
- (letv ptr)
- (let$ body (have-ptr-and-uidx ptr uidx))
- (letk k ($kargs ('ptr) (ptr) ,body))
- (build-term
- ($continue k src
- ($primcall 'pointer-ref/immediate '(bytevector . 2)
- (bv))))))))
- (letk k ($kargs ('rlen) (rlen) ,access))
- (letk kassume
- ($kargs ('ulen) (ulen)
- ($continue k src
- ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (ulen)))))
- (letk klen
- ($kargs () ()
- ($continue kassume src
- ($primcall 'word-ref/immediate '(bytevector . 1) (bv)))))
- ($ (ensure-bytevector klen src op pred bv))))
- (define (bytevector-ref-converter scheme-name ptr-op width kind)
- (define (tag cps k src val)
- (match kind
- ('unsigned
- (if (< (ash 1 (* width 8)) (target-most-positive-fixnum))
- (with-cps cps
- (letv s)
- (letk kcvt
- ($kargs ('s) (s)
- ($continue k src ($primcall 'tag-fixnum #f (s)))))
- (build-term
- ($continue kcvt src ($primcall 'u64->s64 #f (val)))))
- (with-cps cps
- (build-term
- ($continue k src ($primcall 'u64->scm #f (val)))))))
- ('signed
- (if (< (ash 1 (* width 8)) (target-most-positive-fixnum))
- (with-cps cps
- (build-term
- ($continue k src ($primcall 'tag-fixnum #f (val)))))
- (with-cps cps
- (build-term
- ($continue k src ($primcall 's64->scm #f (val)))))))
- ('float
- (with-cps cps
- (build-term
- ($continue k src ($primcall 'f64->scm #f (val))))))))
- (lambda (cps k src op param bv idx)
- (prepare-bytevector-access
- cps src scheme-name 'bytevector? bv idx width
- (lambda (cps ptr uidx)
- (with-cps cps
- (letv val)
- (let$ body (tag k src val))
- (letk ktag ($kargs ('val) (val) ,body))
- (build-term
- ($continue ktag src
- ($primcall ptr-op 'bytevector (bv ptr uidx)))))))))
- (define (bytevector-set-converter scheme-name ptr-op width kind)
- (define out-of-range
- (vector 'out-of-range
- (symbol->string scheme-name)
- "Argument 3 out of range: ~S"))
- (define (limit-urange cps src val uval hi in-range)
- (with-cps cps
- (letk kbad ($kargs () ()
- ($throw src 'throw/value+data out-of-range (val))))
- (let$ body (in-range uval))
- (letk k ($kargs () () ,body))
- (build-term
- ($branch k kbad src 'imm-u64-< hi (uval)))))
- (define (limit-srange cps src val sval lo hi in-range)
- (with-cps cps
- (letk kbad ($kargs () ()
- ($throw src 'throw/value+data out-of-range (val))))
- (let$ body (in-range sval))
- (letk k ($kargs () () ,body))
- (letk k' ($kargs () ()
- ($branch k kbad src 's64-imm-< lo (sval))))
- (build-term
- ($branch k' kbad src 'imm-s64-< hi (sval)))))
- (define (integer-unboxer lo hi)
- (lambda (cps src val have-val)
- (cond
- ((<= hi (target-most-positive-fixnum))
- (let ((have-val (if (zero? lo)
- (lambda (cps s)
- (with-cps cps
- (letv u)
- (let$ body (have-val u))
- (letk k ($kargs ('u) (u) ,body))
- (build-term
- ($continue k src
- ($primcall 's64->u64 #f (s))))))
- have-val)))
- (with-cps cps
- (letv sval)
- (letk kbad ($kargs () ()
- ($throw src 'throw/value+data out-of-range (val))))
- (let$ body (have-val sval))
- (letk k ($kargs () () ,body))
- (letk khi ($kargs () ()
- ($branch k kbad src 'imm-s64-< hi (sval))))
- (letk klo ($kargs ('sval) (sval)
- ($branch khi kbad src 's64-imm-< lo (sval))))
- (letk kuntag
- ($kargs () ()
- ($continue klo src ($primcall 'untag-fixnum #f (val)))))
- (build-term
- ($branch kbad kuntag src 'fixnum? #f (val))))))
- ((zero? lo)
- (with-cps cps
- (letv u)
- (let$ body (limit-urange src val u hi have-val))
- (letk khi ($kargs ('u) (u) ,body))
- (build-term
- ($continue khi src ($primcall 'scm->u64 #f (val))))))
- (else
- (with-cps cps
- (letv s)
- (let$ body (limit-srange src val s lo hi have-val))
- (letk khi ($kargs ('s) (s) ,body))
- (build-term
- ($continue khi src ($primcall 'scm->s64 #f (val)))))))))
- (define untag
- (match kind
- ('unsigned (integer-unboxer 0 (1- (ash 1 (* width 8)))))
- ('signed (integer-unboxer (ash -1 (1- (* width 8)))
- (1- (ash 1 (1- (* width 8))))))
- ('float
- (lambda (cps src val have-val)
- (with-cps cps
- (letv f)
- (let$ body (have-val f))
- (letk k ($kargs ('f) (f) ,body))
- (build-term
- ($continue k src ($primcall 'scm->f64 #f (val)))))))))
- (lambda (cps k src op param bv idx val)
- (prepare-bytevector-access
- cps src scheme-name 'bytevector? bv idx width
- (lambda (cps ptr uidx)
- (untag
- cps src val
- (lambda (cps uval)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall ptr-op 'bytevector (bv ptr uidx uval)))))))))))
- (define-syntax-rule (define-bytevector-ref-converter
- cps-name scheme-name op width kind)
- (define-primcall-converter cps-name
- (bytevector-ref-converter 'scheme-name 'op width 'kind)))
- (define-syntax-rule (define-bytevector-ref-converters (cvt ...) ...)
- (begin
- (define-bytevector-ref-converter cvt ...)
- ...))
- (define-syntax-rule (define-bytevector-set-converter
- cps-name scheme-name op width kind)
- (define-primcall-converter cps-name
- (bytevector-set-converter 'scheme-name 'op width 'kind)))
- (define-syntax-rule (define-bytevector-set-converters (cvt ...) ...)
- (begin
- (define-bytevector-set-converter cvt ...)
- ...))
- (define-primcall-converter bv-length
- (lambda (cps k src op param bv)
- (with-cps cps
- (letv ulen rlen)
- (letk ktag ($kargs ('rlen) (rlen)
- ($continue k src ($primcall 'u64->scm #f (rlen)))))
- (letk kassume
- ($kargs ('ulen) (ulen)
- ($continue ktag src
- ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (ulen)))))
- (letk klen
- ($kargs () ()
- ($continue kassume src
- ($primcall 'word-ref/immediate '(bytevector . 1) (bv)))))
- ($ (ensure-bytevector klen src op 'bytevector? bv)))))
- (define-bytevector-ref-converters
- (bv-u8-ref bytevector-u8-ref u8-ref 1 unsigned)
- (bv-u16-ref bytevector-u16-native-ref u16-ref 2 unsigned)
- (bv-u32-ref bytevector-u32-native-ref u32-ref 4 unsigned)
- (bv-u64-ref bytevector-u64-native-ref u64-ref 8 unsigned)
- (bv-s8-ref bytevector-s8-ref s8-ref 1 signed)
- (bv-s16-ref bytevector-s16-native-ref s16-ref 2 signed)
- (bv-s32-ref bytevector-s32-native-ref s32-ref 4 signed)
- (bv-s64-ref bytevector-s64-native-ref s64-ref 8 signed)
- (bv-f32-ref bytevector-ieee-single-native-ref f32-ref 4 float)
- (bv-f64-ref bytevector-ieee-double-native-ref f64-ref 8 float))
- (define-bytevector-set-converters
- (bv-u8-set! bytevector-u8-set! u8-set! 1 unsigned)
- (bv-u16-set! bytevector-u16-native-set! u16-set! 2 unsigned)
- (bv-u32-set! bytevector-u32-native-set! u32-set! 4 unsigned)
- (bv-u64-set! bytevector-u64-native-set! u64-set! 8 unsigned)
- (bv-s8-set! bytevector-s8-set! s8-set! 1 signed)
- (bv-s16-set! bytevector-s16-native-set! s16-set! 2 signed)
- (bv-s32-set! bytevector-s32-native-set! s32-set! 4 signed)
- (bv-s64-set! bytevector-s64-native-set! s64-set! 8 signed)
- (bv-f32-set! bytevector-ieee-single-native-set! f32-set! 4 float)
- (bv-f64-set! bytevector-ieee-double-native-set! f64-set! 8 float))
- (define (ensure-string cps src op x have-length)
- (define msg "Wrong type argument in position 1 (expecting string): ~S")
- (define not-string (vector 'wrong-type-arg (symbol->string op) msg))
- (with-cps cps
- (letv ulen rlen)
- (letk knot-string
- ($kargs () () ($throw src 'throw/value+data not-string (x))))
- (let$ body (have-length rlen))
- (letk k ($kargs ('rlen) (rlen) ,body))
- (letk kassume
- ($kargs ('ulen) (ulen)
- ($continue k src
- ($primcall 'assume-u64 `(0 . ,(target-max-size-t)) (ulen)))))
- (letk ks
- ($kargs () ()
- ($continue kassume src
- ($primcall 'word-ref/immediate '(string . 3) (x)))))
- (letk kheap-object
- ($kargs () ()
- ($branch knot-string ks src 'string? #f (x))))
- (build-term
- ($branch knot-string kheap-object src 'heap-object? #f (x)))))
- (define (ensure-char cps src op x have-char)
- (define msg "Wrong type argument (expecting char): ~S")
- (define not-char (vector 'wrong-type-arg (symbol->string op) msg))
- (with-cps cps
- (letv uchar)
- (letk knot-char
- ($kargs () () ($throw src 'throw/value+data not-char (x))))
- (let$ body (have-char uchar))
- (letk k ($kargs ('uchar) (uchar) ,body))
- (letk kchar
- ($kargs () () ($continue k src ($primcall 'untag-char #f (x)))))
- (build-term
- ($branch knot-char kchar src 'char? #f (x)))))
- (define-primcall-converter string-length
- (lambda (cps k src op param x)
- (ensure-string
- cps src op x
- (lambda (cps ulen)
- (with-cps cps
- (build-term
- ($continue k src ($primcall 'u64->scm #f (ulen)))))))))
- (define-primcall-converter string-ref
- (lambda (cps k src op param s idx)
- (define out-of-range
- #(out-of-range string-ref "Argument 2 out of range: ~S"))
- (define stringbuf-f-wide #x400)
- (ensure-string
- cps src op s
- (lambda (cps ulen)
- (with-cps cps
- (letv uidx start upos buf ptr tag mask bits uwpos u32 uchar)
- (letk kout-of-range
- ($kargs () ()
- ($throw src 'throw/value+data out-of-range (idx))))
- (letk kchar
- ($kargs ('uchar) (uchar)
- ($continue k src
- ($primcall 'tag-char #f (uchar)))))
- (letk kassume
- ($kargs ('u32) (u32)
- ($continue kchar src
- ($primcall 'assume-u64 '(0 . #xffffff) (u32)))))
- (letk kwideref
- ($kargs ('uwpos) (uwpos)
- ($continue kassume src
- ($primcall 'u32-ref 'stringbuf (buf ptr uwpos)))))
- (letk kwide
- ($kargs () ()
- ($continue kwideref src
- ($primcall 'ulsh/immediate 2 (upos)))))
- (letk knarrow
- ($kargs () ()
- ($continue kchar src
- ($primcall 'u8-ref 'stringbuf (buf ptr upos)))))
- (letk kcmp
- ($kargs ('bits) (bits)
- ($branch kwide knarrow src 'u64-imm-= 0 (bits))))
- (letk kmask
- ($kargs ('mask) (mask)
- ($continue kcmp src
- ($primcall 'ulogand #f (tag mask)))))
- (letk ktag
- ($kargs ('tag) (tag)
- ($continue kmask src
- ($primcall 'load-u64 stringbuf-f-wide ()))))
- (letk kptr
- ($kargs ('ptr) (ptr)
- ($continue ktag src
- ($primcall 'word-ref/immediate '(stringbuf . 0) (buf)))))
- (letk kwidth
- ($kargs ('buf) (buf)
- ($continue kptr src
- ($primcall 'tail-pointer-ref/immediate '(stringbuf . 2) (buf)))))
- (letk kbuf
- ($kargs ('upos) (upos)
- ($continue kwidth src
- ($primcall 'scm-ref/immediate '(string . 1) (s)))))
- (letk kadd
- ($kargs ('start) (start)
- ($continue kbuf src
- ($primcall 'uadd #f (start uidx)))))
- (letk kstart
- ($kargs () ()
- ($continue kadd src
- ($primcall 'word-ref/immediate '(string . 2) (s)))))
- (letk krange
- ($kargs ('uidx) (uidx)
- ($branch kout-of-range kstart src 'u64-< #f (uidx ulen))))
- (build-term
- ($continue krange src ($primcall 'scm->u64 #f (idx)))))))))
- (define-primcall-converter string-set!
- (lambda (cps k src op param s idx ch)
- (define out-of-range
- #(out-of-range string-ref "Argument 2 out of range: ~S"))
- (define stringbuf-f-wide #x400)
- (ensure-string
- cps src op s
- (lambda (cps ulen)
- (ensure-char
- cps src op ch
- (lambda (cps uchar)
- (with-cps cps
- (letv uidx)
- (letk kout-of-range
- ($kargs () ()
- ($throw src 'throw/value+data out-of-range (idx))))
- (letk kuidx
- ($kargs () ()
- ($continue k src
- ($primcall 'string-set! #f (s uidx uchar)))))
- (letk krange
- ($kargs ('uidx) (uidx)
- ($branch kout-of-range kuidx src 'u64-< #f (uidx ulen))))
- (build-term
- ($continue krange src ($primcall 'scm->u64 #f (idx)))))))))))
- (define-primcall-converter integer->char
- (lambda (cps k src op param i)
- (define not-fixnum
- #(wrong-type-arg
- "integer->char"
- "Wrong type argument in position 1 (expecting small integer): ~S"))
- (define out-of-range
- #(out-of-range
- "integer->char"
- "Argument 1 out of range: ~S"))
- (define codepoint-surrogate-start #xd800)
- (define codepoint-surrogate-end #xdfff)
- (define codepoint-max #x10ffff)
- (with-cps cps
- (letv si ui)
- (letk knot-fixnum
- ($kargs () () ($throw src 'throw/value+data not-fixnum (i))))
- (letk kf
- ($kargs () () ($throw src 'throw/value+data out-of-range (i))))
- (letk ktag ($kargs ('ui) (ui)
- ($continue k src ($primcall 'tag-char #f (ui)))))
- (letk kt ($kargs () ()
- ($continue ktag src ($primcall 's64->u64 #f (si)))))
- (letk kmax
- ($kargs () ()
- ($branch kt kf src 'imm-s64-< codepoint-max (si))))
- (letk khi
- ($kargs () ()
- ($branch kf kmax src 'imm-s64-< codepoint-surrogate-end (si))))
- (letk klo
- ($kargs () ()
- ($branch khi kt src 's64-imm-< codepoint-surrogate-start (si))))
- (letk kbound0
- ($kargs ('si) (si)
- ($branch klo kf src 's64-imm-< 0 (si))))
- (letk kuntag
- ($kargs () ()
- ($continue kbound0 src ($primcall 'untag-fixnum #f (i)))))
- (build-term ($branch knot-fixnum kuntag src 'fixnum? #f (i))))))
- (define-primcall-converter char->integer
- (lambda (cps k src op param ch)
- (define not-char
- #(wrong-type-arg
- "char->integer"
- "Wrong type argument in position 1 (expecting char): ~S"))
- (with-cps cps
- (letv ui si)
- (letk knot-char
- ($kargs () () ($throw src 'throw/value+data not-char (ch))))
- (letk ktag ($kargs ('si) (si)
- ($continue k src ($primcall 'tag-fixnum #f (si)))))
- (letk kcvt ($kargs ('ui) (ui)
- ($continue ktag src ($primcall 'u64->s64 #f (ui)))))
- (letk kuntag ($kargs () ()
- ($continue kcvt src ($primcall 'untag-char #f (ch)))))
- (build-term
- ($branch knot-char kuntag src 'char? #f (ch))))))
- (define (convert-shift cps k src op param obj idx)
- (with-cps cps
- (letv idx')
- (letk k' ($kargs ('idx) (idx')
- ($continue k src ($primcall op param (obj idx')))))
- (build-term ($continue k' src ($primcall 'scm->u64 #f (idx))))))
- (define-primcall-converter rsh convert-shift)
- (define-primcall-converter lsh convert-shift)
- (define-primcall-converter make-atomic-box
- (lambda (cps k src op param val)
- (with-cps cps
- (letv obj tag)
- (letk kdone
- ($kargs () ()
- ($continue k src ($values (obj)))))
- (letk kval
- ($kargs () ()
- ($continue kdone src
- ($primcall 'atomic-scm-set!/immediate '(atomic-box . 1) (obj val)))))
- (letk ktag1
- ($kargs ('tag) (tag)
- ($continue kval src
- ($primcall 'word-set!/immediate '(atomic-box . 0) (obj tag)))))
- (letk ktag0
- ($kargs ('obj) (obj)
- ($continue ktag1 src
- ($primcall 'load-u64 %tc7-atomic-box ()))))
- (build-term
- ($continue ktag0 src
- ($primcall 'allocate-words/immediate '(atomic-box . 2) ()))))))
- (define (ensure-atomic-box cps src op x is-atomic-box)
- (define bad-type
- (vector 'wrong-type-arg
- (symbol->string op)
- "Wrong type argument in position 1 (expecting atomic box): ~S"))
- (with-cps cps
- (letk kbad ($kargs () () ($throw src 'throw/value+data bad-type (x))))
- (let$ body (is-atomic-box))
- (letk k ($kargs () () ,body))
- (letk kheap-object ($kargs () () ($branch kbad k src 'atomic-box? #f (x))))
- (build-term ($branch kbad kheap-object src 'heap-object? #f (x)))))
- (define-primcall-converter atomic-box-ref
- (lambda (cps k src op param x)
- (ensure-atomic-box
- cps src 'atomic-box-ref x
- (lambda (cps)
- (with-cps cps
- (letv val)
- (build-term
- ($continue k src
- ($primcall 'atomic-scm-ref/immediate '(atomic-box . 1) (x)))))))))
- (define-primcall-converter atomic-box-set!
- (lambda (cps k src op param x val)
- (ensure-atomic-box
- cps src 'atomic-box-set! x
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'atomic-scm-set!/immediate '(atomic-box . 1)
- (x val)))))))))
- (define-primcall-converter atomic-box-swap!
- (lambda (cps k src op param x val)
- (ensure-atomic-box
- cps src 'atomic-box-swap! x
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'atomic-scm-swap!/immediate '(atomic-box . 1)
- (x val)))))))))
- (define-primcall-converter atomic-box-compare-and-swap!
- (lambda (cps k src op param x expected desired)
- (ensure-atomic-box
- cps src 'atomic-box-compare-and-swap! x
- (lambda (cps)
- (with-cps cps
- (build-term
- ($continue k src
- ($primcall 'atomic-scm-compare-and-swap!/immediate '(atomic-box . 1)
- (x expected desired)))))))))
- ;;; Guile's semantics are that a toplevel lambda captures a reference on
- ;;; the current module, and that all contained lambdas use that module
- ;;; to resolve toplevel variables. This parameter tracks whether or not
- ;;; we are in a toplevel lambda. If we are in a lambda, the parameter
- ;;; is bound to a fresh name identifying the module that was current
- ;;; when the toplevel lambda is defined.
- ;;;
- ;;; This is more complicated than it need be. Ideally we should resolve
- ;;; all toplevel bindings to bindings from specific modules, unless the
- ;;; binding is unbound. This is always valid if the compilation unit
- ;;; sets the module explicitly, as when compiling a module, but it
- ;;; doesn't work for files auto-compiled for use with `load'.
- ;;;
- (define current-topbox-scope (make-parameter #f))
- (define scope-counter (make-parameter #f))
- (define (fresh-scope-id)
- (let ((scope-id (scope-counter)))
- (scope-counter (1+ scope-id))
- scope-id))
- ;;; For calls to known imported values, we don't want to duplicate the
- ;;; "resolve the import" code at each call site. Instead we generate a
- ;;; stub per callee, and have callers call-label the callees.
- ;;;
- (define module-call-stubs (make-parameter #f))
- (define (module-call-label cps mod name public? nargs)
- "Return three values: the new CPS, the label to call, and the value to
- use as the proc slot."
- (define call-stub-key (list mod name public? nargs))
- (define var-cache-key (list mod name public?))
- (define var-cache
- (build-exp ($primcall 'cache-ref var-cache-key ())))
- (match (assoc-ref (module-call-stubs) call-stub-key)
- (#f
- (let* ((trampoline-name (string->symbol
- (format #f "~a~a~a"
- name (if public? "@" "@@")
- (string-join (map symbol->string mod)
- "/"))))
- (cached (fresh-var))
- (args (let lp ((n 0))
- (if (< n nargs)
- (cons (fresh-var) (lp (1+ n)))
- '())))
- (argv (cons cached args))
- (names (let lp ((n 0))
- (if (< n (1+ nargs))
- (cons (string->symbol
- (string-append "arg" (number->string n)))
- (lp (1+ n)))
- '()))))
- (with-cps cps
- (letv fresh-var var proc)
- (letk ktail ($ktail))
- (letk kcall
- ($kargs ('proc) (proc)
- ($continue ktail #f ($call proc args))))
- (letk kref
- ($kargs ('var) (var)
- ($continue kcall #f
- ($primcall 'scm-ref/immediate '(box . 1) (var)))))
- (letk kcache2
- ($kargs () ()
- ($continue kref #f ($values (fresh-var)))))
- (letk kcache
- ($kargs ('var) (fresh-var)
- ($continue kcache2 #f
- ($primcall 'cache-set! var-cache-key (fresh-var)))))
- (letk klookup
- ($kargs () ()
- ($continue kcache #f
- ($primcall (if public?
- 'lookup-bound-public
- 'lookup-bound-private)
- (list mod name) ()))))
- (letk kcached
- ($kargs () ()
- ($continue kref #f ($values (cached)))))
- (letk kentry
- ($kargs names argv
- ($branch klookup kcached #f 'heap-object? #f (cached))))
- (letk kfun ($kfun #f `((name . ,trampoline-name)) #f ktail kentry))
- ($ ((lambda (cps)
- (module-call-stubs
- (acons call-stub-key kfun (module-call-stubs)))
- (values cps kfun var-cache)))))))
- (kfun
- (values cps kfun var-cache))))
- (define (toplevel-box cps src name bound? have-var)
- (match (current-topbox-scope)
- (#f
- (with-cps cps
- (letv mod name-var box)
- (let$ body (have-var box))
- (letk kbox ($kargs ('box) (box) ,body))
- (letk kname ($kargs ('name) (name-var)
- ($continue kbox src
- ($primcall (if bound? 'lookup-bound 'lookup) #f
- (mod name-var)))))
- (letk kmod ($kargs ('mod) (mod)
- ($continue kname src ($const name))))
- (build-term
- ($continue kmod src ($primcall 'current-module #f ())))))
- (scope
- (with-cps cps
- (letv box)
- (let$ body (have-var box))
- (letk kbox ($kargs ('box) (box) ,body))
- ($ (convert-primcall kbox src 'cached-toplevel-box
- (list scope name bound?)))))))
- (define (module-box cps src module name public? bound? val-proc)
- (with-cps cps
- (letv box)
- (let$ body (val-proc box))
- (letk kbox ($kargs ('box) (box) ,body))
- ($ (convert-primcall kbox src 'cached-module-box
- (list module name public? bound?)))))
- (define (capture-toplevel-scope cps src scope-id k)
- (with-cps cps
- (letv module)
- (let$ body (convert-primcall k src 'cache-current-module!
- (list scope-id) module))
- (letk kmodule ($kargs ('module) (module) ,body))
- ($ (convert-primcall kmodule src 'current-module #f))))
- (define (fold-formals proc seed arity gensyms inits)
- (match arity
- (($ $arity req opt rest kw allow-other-keys?)
- (let ()
- (define (fold-req names gensyms seed)
- (match names
- (() (fold-opt opt gensyms inits seed))
- ((name . names)
- (proc name (car gensyms) #f
- (fold-req names (cdr gensyms) seed)))))
- (define (fold-opt names gensyms inits seed)
- (match names
- (() (fold-rest rest gensyms inits seed))
- ((name . names)
- (proc name (car gensyms) (car inits)
- (fold-opt names (cdr gensyms) (cdr inits) seed)))))
- (define (fold-rest rest gensyms inits seed)
- (match rest
- (#f (fold-kw kw gensyms inits seed))
- (name (proc name (car gensyms) #f
- (fold-kw kw (cdr gensyms) inits seed)))))
- (define (fold-kw kw gensyms inits seed)
- (match kw
- (()
- (unless (null? gensyms)
- (error "too many gensyms"))
- (unless (null? inits)
- (error "too many inits"))
- seed)
- (((key name var) . kw)
- ;; Could be that var is not a gensym any more.
- (when (symbol? var)
- (unless (eq? var (car gensyms))
- (error "unexpected keyword arg order")))
- (proc name (car gensyms) (car inits)
- (fold-kw kw (cdr gensyms) (cdr inits) seed)))))
- (fold-req req gensyms seed)))))
- (define (init-default-value cps name sym subst init body)
- (match (hashq-ref subst sym)
- ((orig-var subst-var box?)
- (let ((src (tree-il-src init)))
- (define (maybe-box cps k make-body)
- (if box?
- (with-cps cps
- (letv phi)
- (let$ body (convert-primcall k src 'box #f phi))
- (letk kbox ($kargs (name) (phi) ,body))
- ($ (make-body kbox)))
- (make-body cps k)))
- (with-cps cps
- (letk knext ($kargs (name) (subst-var) ,body))
- ($ (maybe-box
- knext
- (lambda (cps k)
- (with-cps cps
- (letk kbound ($kargs () () ($continue k src
- ($values (orig-var)))))
- (letv val rest)
- (letk krest ($kargs (name 'rest) (val rest)
- ($continue k src ($values (val)))))
- (letk kreceive ($kreceive (list name) 'rest krest))
- (let$ init (convert init kreceive subst))
- (letk kunbound ($kargs () () ,init))
- (build-term
- ($branch kbound kunbound src
- 'undefined? #f (orig-var))))))))))))
- (define (build-list cps k src vals)
- (match vals
- (()
- (with-cps cps
- (build-term ($continue k src ($const '())))))
- ((v . vals)
- (with-cps cps
- (letv tail)
- (let$ head (convert-primcall k src 'cons #f v tail))
- (letk ktail ($kargs ('tail) (tail) ,head))
- ($ (build-list ktail src vals))))))
- (define (sanitize-meta meta)
- (match meta
- (() '())
- (((k . v) . meta)
- (let ((meta (sanitize-meta meta)))
- (case k
- ((arg-representations noreturn return-type) meta)
- (else (acons k v meta)))))))
- ;;; The conversion from Tree-IL to CPS essentially wraps every
- ;;; expression in a $kreceive, which models the Tree-IL semantics that
- ;;; extra values are simply truncated. In CPS, this means that the
- ;;; $kreceive has a rest argument after the required arguments, if any,
- ;;; and that the rest argument is unused.
- ;;;
- ;;; All CPS expressions that can return a variable number of values
- ;;; (i.e., $call and $abort) must continue to $kreceive, which checks
- ;;; the return arity and on success passes the parsed values along to a
- ;;; $kargs. If the $call or $abort is in tail position they continue to
- ;;; $ktail instead, and then the values are parsed by the $kreceive of
- ;;; the non-tail caller.
- ;;;
- ;;; Other CPS terms like $values, $const, and the like all have a
- ;;; specific return arity, and must continue to $kargs instead of
- ;;; $kreceive or $ktail. This allows the compiler to reason precisely
- ;;; about their result values. To make sure that this is the case,
- ;;; whenever the CPS conversion would reify one of these terms it needs
- ;;; to ensure that the continuation actually accepts the return arity of
- ;;; the primcall.
- ;;;
- ;;; Some Tree-IL primcalls residualize CPS primcalls that return zero
- ;;; values, for example box-set!. In this case the Tree-IL semantics
- ;;; are that the result of the expression is the undefined value. That
- ;;; is to say, the result of this expression is #t:
- ;;;
- ;;; (let ((x 30)) (eq? (set! x 10) (if #f #f)))
- ;;;
- ;;; So in the case that the continuation expects a value but the
- ;;; primcall produces zero values, we insert the "unspecified" value.
- ;;;
- (define (adapt-arity cps k src nvals)
- (match nvals
- (0
- ;; As mentioned above, in the Tree-IL semantics the primcall
- ;; produces the unspecified value, but in CPS it produces no
- ;; values. Therefore we plug the unspecified value into the
- ;; continuation.
- (match (intmap-ref cps k)
- (($ $ktail)
- (with-cps cps
- (let$ body (with-cps-constants ((unspecified *unspecified*))
- (build-term
- ($continue k src ($values (unspecified))))))
- (letk kvoid ($kargs () () ,body))
- kvoid))
- (($ $kargs ()) (with-cps cps k))
- (($ $kreceive arity kargs)
- (match arity
- (($ $arity () () (not #f) () #f)
- (with-cps cps
- (letk kvoid ($kargs () () ($continue kargs src ($const '()))))
- kvoid))
- (($ $arity (_) () #f () #f)
- (with-cps cps
- (letk kvoid ($kargs () ()
- ($continue kargs src ($const *unspecified*))))
- kvoid))
- (($ $arity (_) () _ () #f)
- (with-cps cps
- (let$ void (with-cps-constants ((unspecified *unspecified*)
- (rest '()))
- (build-term
- ($continue kargs src
- ($values (unspecified rest))))))
- (letk kvoid ($kargs () () ,void))
- kvoid))
- (_
- ;; Arity mismatch. Serialize a values call.
- (with-cps cps
- (letv values)
- (let$ void (with-cps-constants ((unspecified *unspecified*))
- (build-term
- ($continue k src
- ($call values (unspecified))))))
- (letk kvoid ($kargs ('values) (values) ,void))
- (letk kvalues ($kargs () ()
- ($continue kvoid src ($prim 'values))))
- kvalues))))))
- (1
- (match (intmap-ref cps k)
- (($ $ktail)
- (with-cps cps
- (letv val)
- (letk kval ($kargs ('val) (val)
- ($continue k src ($values (val)))))
- kval))
- (($ $kargs (_)) (with-cps cps k))
- (($ $kreceive arity kargs)
- (match arity
- (($ $arity () () (not #f) () #f)
- (with-cps cps
- (letv val)
- (let$ body (with-cps-constants ((nil '()))
- ($ (convert-primcall kargs src 'cons #f
- val nil))))
- (letk kval ($kargs ('val) (val) ,body))
- kval))
- (($ $arity (_) () #f () #f)
- (with-cps cps
- kargs))
- (($ $arity (_) () _ () #f)
- (with-cps cps
- (letv val)
- (let$ body (with-cps-constants ((rest '()))
- (build-term
- ($continue kargs src ($values (val rest))))))
- (letk kval ($kargs ('val) (val) ,body))
- kval))
- (_
- ;; Arity mismatch. Serialize a values call.
- (with-cps cps
- (letv val values)
- (letk kvalues ($kargs ('values) (values)
- ($continue k src
- ($call values (val)))))
- (letk kval ($kargs ('val) (val)
- ($continue kvalues src ($prim 'values))))
- kval))))))))
- ;; cps exp k-name alist -> cps term
- (define (convert cps exp k subst)
- (define (zero-valued? exp)
- (match exp
- ((or ($ <module-set>) ($ <toplevel-set>) ($ <toplevel-define>)
- ($ <lexical-set>))
- #t)
- (($ <let> src names syms vals body) (zero-valued? body))
- ;; Can't use <fix> here as the hack that <fix> uses to convert its
- ;; functions relies on continuation being single-valued.
- ;; (($ <fix> src names syms vals body) (zero-valued? body))
- (($ <let-values> src exp body) (zero-valued? body))
- (($ <seq> src head tail) (zero-valued? tail))
- (($ <primcall> src 'values args) (= (length args) 0))
- (($ <primcall> src name args)
- (match (tree-il-primitive->cps-primitive+nargs+nvalues name)
- (#f #f)
- (#(cps-prim nargs nvalues)
- (and (eqv? nvalues 0)
- (eqv? nargs (length args))))))
- (_ #f)))
- (define (single-valued? exp)
- (match exp
- ((or ($ <void>) ($ <const>) ($ <primitive-ref>) ($ <module-ref>)
- ($ <toplevel-ref>) ($ <lambda>))
- #t)
- (($ <let> src names syms vals body) (single-valued? body))
- (($ <fix> src names syms vals body) (single-valued? body))
- (($ <let-values> src exp body) (single-valued? body))
- (($ <seq> src head tail) (single-valued? tail))
- (($ <primcall> src 'values args) (= (length args) 1))
- (($ <primcall> src name args)
- (match (tree-il-primitive->cps-primitive+nargs+nvalues name)
- (#f #f)
- (#(cps-prim nargs nvalues)
- (and (eqv? nvalues 1)
- (eqv? nargs (length args))))))
- (_ #f)))
- ;; exp (v-name -> term) -> term
- (define (convert-arg cps exp k)
- (match exp
- (($ <lexical-ref> src name sym)
- (match (hashq-ref subst sym)
- ((orig-var box #t)
- (with-cps cps
- (letv unboxed)
- (let$ body (k unboxed))
- (letk kunboxed ($kargs ('unboxed) (unboxed) ,body))
- (build-term ($continue kunboxed src
- ($primcall 'scm-ref/immediate '(box . 1) (box))))))
- ((orig-var subst-var #f) (k cps subst-var))
- (var (k cps var))))
- ((? single-valued?)
- (with-cps cps
- (letv arg)
- (let$ body (k arg))
- (letk karg ($kargs ('arg) (arg) ,body))
- ($ (convert exp karg subst))))
- (_
- (with-cps cps
- (letv arg rest)
- (let$ body (k arg))
- (letk karg ($kargs ('arg 'rest) (arg rest) ,body))
- (letk kreceive ($kreceive '(arg) 'rest karg))
- ($ (convert exp kreceive subst))))))
- ;; (exp ...) ((v-name ...) -> term) -> term
- (define (convert-args cps exps k)
- (match exps
- (() (k cps '()))
- ((exp . exps)
- (convert-arg cps exp
- (lambda (cps name)
- (convert-args cps exps
- (lambda (cps names)
- (k cps (cons name names)))))))))
- (define (box-bound-var cps name sym body)
- (match (hashq-ref subst sym)
- ((orig-var subst-var #t)
- (with-cps cps
- (letk k ($kargs (name) (subst-var) ,body))
- ($ (convert-primcall k #f 'box #f orig-var))))
- (else
- (with-cps cps body))))
- (define (box-bound-vars cps names syms body)
- (match (vector names syms)
- (#((name . names) (sym . syms))
- (with-cps cps
- (let$ body (box-bound-var name sym body))
- ($ (box-bound-vars names syms body))))
- (#(() ()) (with-cps cps body))))
- (define (bound-var sym)
- (match (hashq-ref subst sym)
- ((var . _) var)
- ((? exact-integer? var) var)))
- (match exp
- (($ <lexical-ref> src name sym)
- (with-cps cps
- (let$ k (adapt-arity k src 1))
- (rewrite-term (hashq-ref subst sym)
- ((orig-var box #t) ($continue k src
- ($primcall 'scm-ref/immediate '(box . 1) (box))))
- ((orig-var subst-var #f) ($continue k src ($values (subst-var))))
- (var ($continue k src ($values (var)))))))
- (($ <void> src)
- (with-cps cps
- (let$ k (adapt-arity k src 1))
- (build-term ($continue k src ($const *unspecified*)))))
- (($ <const> src exp)
- (with-cps cps
- (let$ k (adapt-arity k src 1))
- (build-term ($continue k src ($const exp)))))
- (($ <primitive-ref> src name)
- (with-cps cps
- (let$ k (adapt-arity k src 1))
- (build-term ($continue k src ($prim name)))))
- (($ <lambda> fun-src meta body)
- (let ()
- (define (convert-clauses cps body ktail)
- (match body
- (#f (values cps #f))
- (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
- (let* ((arity (make-$arity req (or opt '()) rest
- (map (match-lambda
- ((kw name sym)
- (list kw name (bound-var sym))))
- (if kw (cdr kw) '()))
- (and kw (car kw))))
- (names (fold-formals (lambda (name sym init names)
- (cons name names))
- '()
- arity gensyms inits)))
- (define (fold-formals* cps f seed arity gensyms inits)
- (match (fold-formals
- (lambda (name sym init cps+seed)
- (match cps+seed
- ((cps . seed)
- (call-with-values (lambda ()
- (f cps name sym init seed))
- (lambda (cps seed) (cons cps seed))))))
- (cons cps seed) arity gensyms inits)
- ((cps . seed) (values cps seed))))
- (with-cps cps
- (let$ kalt (convert-clauses alternate ktail))
- (let$ body (convert body ktail subst))
- (let$ body
- (fold-formals*
- (lambda (cps name sym init body)
- (if init
- (init-default-value cps name sym subst init body)
- (box-bound-var cps name sym body)))
- body arity gensyms inits))
- (letk kargs ($kargs names (map bound-var gensyms) ,body))
- (letk kclause ($kclause ,arity kargs kalt))
- kclause)))))
- (if (current-topbox-scope)
- (with-cps cps
- (letv self)
- (letk ktail ($ktail))
- (let$ kclause (convert-clauses body ktail))
- (letk kfun ($kfun fun-src (sanitize-meta meta) self ktail kclause))
- (let$ k (adapt-arity k fun-src 1))
- (build-term ($continue k fun-src ($fun kfun))))
- (let ((scope-id (fresh-scope-id)))
- (with-cps cps
- (let$ body ((lambda (cps)
- (parameterize ((current-topbox-scope scope-id))
- (convert cps exp k subst)))))
- (letk kscope ($kargs () () ,body))
- ($ (capture-toplevel-scope fun-src scope-id kscope)))))))
- (($ <module-ref> src mod name public?)
- (module-box
- cps src mod name public? #t
- (lambda (cps box)
- (with-cps cps
- (let$ k (adapt-arity k src 1))
- (build-term ($continue k src
- ($primcall 'scm-ref/immediate '(box . 1) (box))))))))
- (($ <module-set> src mod name public? exp)
- (convert-arg cps exp
- (lambda (cps val)
- (module-box
- cps src mod name public? #t
- (lambda (cps box)
- (with-cps cps
- (let$ k (adapt-arity k src 0))
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate '(box . 1) (box val))))))))))
- (($ <toplevel-ref> src mod name)
- (toplevel-box
- cps src name #t
- (lambda (cps box)
- (with-cps cps
- (let$ k (adapt-arity k src 1))
- (build-term
- ($continue k src
- ($primcall 'scm-ref/immediate '(box . 1) (box))))))))
- (($ <toplevel-set> src mod name exp)
- (convert-arg cps exp
- (lambda (cps val)
- (toplevel-box
- cps src name #f
- (lambda (cps box)
- (with-cps cps
- (let$ k (adapt-arity k src 0))
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate '(box . 1) (box val))))))))))
- (($ <toplevel-define> src modname name exp)
- (convert-arg cps exp
- (lambda (cps val)
- (with-cps cps
- (let$ k (adapt-arity k src 0))
- (letv box mod)
- (letk kset ($kargs ('box) (box)
- ($continue k src
- ($primcall 'scm-set!/immediate '(box . 1) (box val)))))
- ($ (with-cps-constants ((name name))
- (letk kmod
- ($kargs ('mod) (mod)
- ($continue kset src
- ($primcall 'define! #f (mod name)))))
- (build-term
- ($continue kmod src ($primcall 'current-module #f ())))))))))
- (($ <call> src ($ <module-ref> src2 mod name public?) args)
- (convert-args cps args
- (lambda (cps args)
- (call-with-values
- (lambda () (module-call-label cps mod name public? (length args)))
- (lambda (cps kfun proc-exp)
- (with-cps cps
- (letv cache)
- (letk kcall ($kargs ('cache) (cache)
- ($continue k src
- ($callk kfun #f ,(cons cache args)))))
- (build-term
- ($continue kcall src2 ,proc-exp))))))))
- (($ <call> src proc args)
- (convert-args cps (cons proc args)
- (match-lambda*
- ((cps (proc . args))
- (with-cps cps
- (build-term ($continue k src ($call proc args))))))))
- (($ <primcall> src name args)
- (cond
- ((eq? name 'throw)
- (let ()
- (define (fallback)
- (convert-args cps args
- (lambda (cps args)
- (match args
- ((key . args)
- (with-cps cps
- (letv arglist)
- (letk kargs ($kargs ('arglist) (arglist)
- ($throw src 'throw #f (key arglist))))
- ($ (build-list kargs src args))))))))
- (define (specialize op param . args)
- (convert-args cps args
- (lambda (cps args)
- (with-cps cps
- (build-term
- ($throw src op param args))))))
- (match args
- ((($ <const> _ key) ($ <const> _ subr) ($ <const> _ msg) args data)
- ;; Specialize `throw' invocations corresponding to common
- ;; "error" invocations.
- (let ()
- (match (vector args data)
- (#(($ <primcall> _ 'cons (x ($ <const> _ ())))
- ($ <primcall> _ 'cons (x ($ <const> _ ()))))
- (specialize 'throw/value+data `#(,key ,subr ,msg) x))
- (#(($ <primcall> _ 'cons (x ($ <const> _ ()))) ($ <const> _ #f))
- (specialize 'throw/value `#(,key ,subr ,msg) x))
- (_ (fallback)))))
- (_ (fallback)))))
- ((eq? name 'values)
- (convert-args cps args
- (lambda (cps args)
- (match (intmap-ref cps k)
- (($ $ktail)
- (with-cps cps
- (build-term
- ($continue k src ($values args)))))
- (($ $kargs names)
- ;; Can happen if continuation already saw we produced the
- ;; right number of values.
- (with-cps cps
- (build-term
- ($continue k src ($values args)))))
- (($ $kreceive ($ $arity req () rest () #f) kargs)
- (cond
- ((and (not rest) (= (length args) (length req)))
- (with-cps cps
- (build-term
- ($continue kargs src ($values args)))))
- ((and rest (>= (length args) (length req)))
- (with-cps cps
- (letv rest)
- (letk krest ($kargs ('rest) (rest)
- ($continue kargs src
- ($values ,(append (list-head args (length req))
- (list rest))))))
- ($ (build-list krest src (list-tail args (length req))))))
- (else
- ;; Number of values mismatch; reify a values call.
- (with-cps cps
- (letv val values)
- (letk kvalues ($kargs ('values) (values)
- ($continue k src ($call values args))))
- (build-term ($continue kvalues src ($prim 'values)))))))))))
- ((tree-il-primitive->cps-primitive+nargs+nvalues name)
- =>
- (match-lambda
- (#(cps-prim nargs nvalues)
- (define (cvt cps k src op args)
- (define (default)
- (convert-args cps args
- (lambda (cps args)
- (with-cps cps
- ($ (convert-primcall* k src op #f args))))))
- (define-syntax-rule (specialize-case (pat (op c (arg ...))) ...
- (_ def))
- (match (cons cps-prim args)
- (pat
- (convert-args cps (list arg ...)
- (lambda (cps args)
- (with-cps cps
- ($ (convert-primcall* k src 'op c args))))))
- ...
- (_ def)))
- (define (uint? val) (and (exact-integer? val) (<= 0 val)))
- (define (vector-index? val)
- (and (exact-integer? val)
- (<= 0 val (1- (target-max-vector-length)))))
- (define (vector-size? val)
- (and (exact-integer? val)
- (<= 0 val (target-max-vector-length))))
- (define (negint? val) (and (exact-integer? val) (< val 0)))
- ;; FIXME: Add case for mul
- (specialize-case
- (('allocate-vector ($ <const> _ n))
- (allocate-vector n ()))
- (('make-vector ($ <const> _ (? vector-size? n)) init)
- (make-vector/immediate n (init)))
- (('vector-ref v ($ <const> _ (? vector-index? n)))
- (vector-ref/immediate n (v)))
- (('vector-set! v ($ <const> _ (? vector-index? n)) x)
- (vector-set!/immediate n (v x)))
- (('vector-init! v ($ <const> _ n) x)
- (vector-init! n (v x)))
- (('allocate-struct v ($ <const> _ n))
- (allocate-struct n (v)))
- (('struct-ref s ($ <const> _ (? uint? n)))
- (struct-ref/immediate n (s)))
- (('struct-set! s ($ <const> _ (? uint? n)) x)
- (struct-set!/immediate n (s x)))
- (('struct-init! s ($ <const> _ n) x)
- (struct-init! n (s x)))
- (('add x ($ <const> _ (? number? y)))
- (add/immediate y (x)))
- (('add ($ <const> _ (? number? y)) x)
- (add/immediate y (x)))
- (('sub x ($ <const> _ (? number? y)))
- (sub/immediate y (x)))
- (('lsh x ($ <const> _ (? uint? y)))
- (lsh/immediate y (x)))
- (('rsh x ($ <const> _ (? uint? y)))
- (rsh/immediate y (x)))
- (_
- (default))))
- ;; Tree-IL primcalls are sloppy, in that it could be that
- ;; they are called with too many or too few arguments. In
- ;; CPS we are more strict and only residualize a $primcall
- ;; if the argument count matches.
- (if (= nargs (length args))
- (with-cps cps
- (let$ k (adapt-arity k src nvalues))
- ($ (cvt k src cps-prim args)))
- (convert-args cps args
- (lambda (cps args)
- (with-cps cps
- (letv prim)
- (letk kprim ($kargs ('prim) (prim)
- ($continue k src ($call prim args))))
- (build-term ($continue kprim src ($prim name))))))))))
- (else
- ;; We have something that's a primcall for Tree-IL but not for
- ;; CPS; compile as a call.
- (convert-args cps args
- (lambda (cps args)
- (with-cps cps
- (letv prim)
- (letk kprim ($kargs ('prim) (prim)
- ($continue k src ($call prim args))))
- (build-term ($continue kprim src ($prim name)))))))))
- ;; Prompts with inline handlers.
- (($ <prompt> src escape-only? tag body
- ($ <lambda> hsrc hmeta
- ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
- ;; Handler:
- ;; khargs: check args returned to handler, -> khbody
- ;; khbody: the handler, -> k
- ;;
- ;; Post-body:
- ;; krest: collect return vals from body to list, -> kpop
- ;; kpop: pop the prompt, -> kprim
- ;; kprim: load the values primitive, -> kret
- ;; kret: (apply values rvals), -> k
- ;;
- ;; Escape prompts evaluate the body with the continuation of krest.
- ;; Otherwise we do a no-inline call to body, continuing to krest.
- (convert-arg cps tag
- (lambda (cps tag)
- (let ((hnames (append hreq (if hrest (list hrest) '())))
- (bound-vars (map bound-var hsyms)))
- (define (convert-body cps khargs krest)
- (if escape-only?
- (with-cps cps
- (let$ body (convert body krest subst))
- (letk kbody ($kargs () () ,body))
- (build-term ($prompt kbody khargs src #t tag)))
- (convert-arg cps body
- (lambda (cps thunk)
- (with-cps cps
- (letk kbody ($kargs () ()
- ($continue krest (tree-il-src body)
- ($primcall 'call-thunk/no-inline #f
- (thunk)))))
- (build-term ($prompt kbody khargs (tree-il-src body)
- #f tag)))))))
- (with-cps cps
- (letv prim vals apply)
- (let$ hbody (convert hbody k subst))
- (let$ hbody (box-bound-vars hnames hsyms hbody))
- (letk khbody ($kargs hnames bound-vars ,hbody))
- (letk khargs ($kreceive hreq hrest khbody))
- (letk kapp ($kargs ('apply) (apply)
- ($continue k src ($call apply (prim vals)))))
- (letk kprim ($kargs ('prim) (prim)
- ($continue kapp src ($prim 'apply))))
- (letk kret ($kargs () ()
- ($continue kprim src ($prim 'values))))
- (letk kpop ($kargs ('rest) (vals)
- ($continue kret src ($primcall 'unwind #f ()))))
- ;; FIXME: Attach hsrc to $kreceive.
- (letk krest ($kreceive '() 'rest kpop))
- ($ (convert-body khargs krest)))))))
- (($ <abort> src tag args ($ <const> _ ()))
- (convert-args cps (cons tag args)
- (lambda (cps args*)
- (with-cps cps
- (letv abort)
- (letk kabort ($kargs ('abort) (abort)
- ($continue k src ($call abort args*))))
- (build-term
- ($continue kabort src ($prim 'abort-to-prompt)))))))
- (($ <abort> src tag args tail)
- (convert-args cps
- (append (list (make-primitive-ref #f 'apply)
- (make-primitive-ref #f 'abort-to-prompt)
- tag)
- args
- (list tail))
- (lambda (cps args*)
- (match args*
- ((apply . apply-args)
- (with-cps cps
- (build-term ($continue k src ($call apply apply-args)))))))))
- (($ <conditional> src test consequent alternate)
- (define (convert-test cps test kt kf)
- (match test
- (($ <primcall> src 'eq? (a ($ <const> _ b)))
- (convert-arg cps a
- (lambda (cps a)
- (with-cps cps
- (build-term ($branch kf kt src 'eq-constant? b (a)))))))
- (($ <primcall> src 'eq? (($ <const> _ a) b))
- (convert-arg cps b
- (lambda (cps b)
- (with-cps cps
- (build-term ($branch kf kt src 'eq-constant? a (b)))))))
- (($ <primcall> src (? branching-primitive? name) args)
- (convert-args cps args
- (lambda (cps args)
- (if (heap-type-predicate? name)
- (with-cps cps
- (letk kt* ($kargs () ()
- ($branch kf kt src name #f args)))
- (build-term
- ($branch kf kt* src 'heap-object? #f args)))
- (with-cps cps
- (build-term ($branch kf kt src name #f args)))))))
- (($ <conditional> src test consequent alternate)
- (with-cps cps
- (let$ t (convert-test consequent kt kf))
- (let$ f (convert-test alternate kt kf))
- (letk kt* ($kargs () () ,t))
- (letk kf* ($kargs () () ,f))
- ($ (convert-test test kt* kf*))))
- (($ <const> src c)
- (with-cps cps
- (build-term ($continue (if c kt kf) src ($values ())))))
- (_ (convert-arg cps test
- (lambda (cps test)
- (with-cps cps
- (build-term ($branch kt kf src 'false? #f (test)))))))))
- (with-cps cps
- (let$ t (convert consequent k subst))
- (let$ f (convert alternate k subst))
- (letk kt ($kargs () () ,t))
- (letk kf ($kargs () () ,f))
- ($ (convert-test test kt kf))))
- (($ <lexical-set> src name gensym exp)
- (convert-arg cps exp
- (lambda (cps exp)
- (match (hashq-ref subst gensym)
- ((orig-var box #t)
- (with-cps cps
- (let$ k (adapt-arity k src 0))
- (build-term
- ($continue k src
- ($primcall 'scm-set!/immediate '(box . 1) (box exp))))))))))
- (($ <seq> src head tail)
- (if (zero-valued? head)
- (with-cps cps
- (let$ tail (convert tail k subst))
- (letk kseq ($kargs () () ,tail))
- ($ (convert head kseq subst)))
- (with-cps cps
- (let$ tail (convert tail k subst))
- (letv vals)
- (letk kseq ($kargs ('vals) (vals) ,tail))
- (letk kreceive ($kreceive '() 'vals kseq))
- ($ (convert head kreceive subst)))))
- (($ <let> src names syms vals body)
- (let lp ((cps cps) (names names) (syms syms) (vals vals))
- (match (list names syms vals)
- ((() () ()) (convert cps body k subst))
- (((name . names) (sym . syms) (val . vals))
- (with-cps cps
- (let$ body (lp names syms vals))
- (let$ body (box-bound-var name sym body))
- ($ ((lambda (cps)
- (if (single-valued? val)
- (with-cps cps
- (letk klet ($kargs (name) ((bound-var sym)) ,body))
- ($ (convert val klet subst)))
- (with-cps cps
- (letv rest)
- (letk klet ($kargs (name 'rest) ((bound-var sym) rest) ,body))
- (letk kreceive ($kreceive (list name) 'rest klet))
- ($ (convert val kreceive subst))))))))))))
- (($ <fix> src names gensyms funs body)
- ;; Some letrecs can be contified; that happens later.
- (define (convert-funs cps funs)
- (match funs
- (()
- (with-cps cps '()))
- ((fun . funs)
- (with-cps cps
- (let$ fun (convert fun k subst))
- (let$ funs (convert-funs funs))
- (cons (match fun
- (($ $continue _ _ (and fun ($ $fun)))
- fun))
- funs)))))
- (if (current-topbox-scope)
- (let ((vars (map bound-var gensyms)))
- (with-cps cps
- (let$ body (convert body k subst))
- (letk krec ($kargs names vars ,body))
- (let$ funs (convert-funs funs))
- (build-term ($continue krec src ($rec names vars funs)))))
- (let ((scope-id (fresh-scope-id)))
- (with-cps cps
- (let$ body ((lambda (cps)
- (parameterize ((current-topbox-scope scope-id))
- (convert cps exp k subst)))))
- (letk kscope ($kargs () () ,body))
- ($ (capture-toplevel-scope src scope-id kscope))))))
- (($ <let-values> src exp
- ($ <lambda-case> lsrc req #f rest #f () syms body #f))
- (let ((names (append req (if rest (list rest) '())))
- (bound-vars (map bound-var syms)))
- (with-cps cps
- (let$ body (convert body k subst))
- (let$ body (box-bound-vars names syms body))
- (letk kargs ($kargs names bound-vars ,body))
- (letk kreceive ($kreceive req rest kargs))
- ($ (convert exp kreceive subst)))))))
- (define (build-subst exp)
- "Compute a mapping from lexical gensyms to CPS variable indexes. CPS
- uses small integers to identify variables, instead of gensyms.
- This subst table serves an additional purpose of mapping variables to
- replacements. The usual reason to replace one variable by another is
- assignment conversion. Default argument values is the other reason.
- The result is a hash table mapping symbols to substitutions (in the case
- that a variable is substituted) or to indexes. A substitution is a list
- of the form:
- (ORIG-INDEX SUBST-INDEX BOXED?)
- A true value for BOXED? indicates that the replacement variable is in a
- box. If a variable is not substituted, the mapped value is a small
- integer."
- (let ((table (make-hash-table)))
- (define (down exp)
- (match exp
- (($ <lexical-set> src name sym exp)
- (match (hashq-ref table sym)
- ((orig subst #t) #t)
- ((orig subst #f) (hashq-set! table sym (list orig subst #t)))
- ((? number? idx) (hashq-set! table sym (list idx (fresh-var) #t)))))
- (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
- (fold-formals (lambda (name sym init seed)
- (hashq-set! table sym
- (if init
- (list (fresh-var) (fresh-var) #f)
- (fresh-var))))
- #f
- (make-$arity req (or opt '()) rest
- (if kw (cdr kw) '()) (and kw (car kw)))
- gensyms
- inits))
- (($ <let> src names gensyms vals body)
- (for-each (lambda (sym)
- (hashq-set! table sym (fresh-var)))
- gensyms))
- (($ <fix> src names gensyms vals body)
- (for-each (lambda (sym)
- (hashq-set! table sym (fresh-var)))
- gensyms))
- (_ #t))
- (values))
- (define (up exp) (values))
- ((make-tree-il-folder) exp down up)
- table))
- (define (cps-convert/thunk exp)
- (parameterize ((label-counter 0)
- (var-counter 0)
- (scope-counter 0)
- (module-call-stubs '()))
- (with-cps empty-intmap
- (letv init)
- ;; Allocate kinit first so that we know that the entry point's
- ;; label is zero. This simplifies data flow in the compiler if we
- ;; can just pass around the program as a map of continuations and
- ;; know that the entry point is label 0.
- (letk kinit ,#f)
- (letk ktail ($ktail))
- (let$ body (convert exp ktail (build-subst exp)))
- (letk kbody ($kargs () () ,body))
- (letk kclause ($kclause ('() '() #f '() #f) kbody #f))
- ($ ((lambda (cps)
- (let ((init (build-cont
- ($kfun (tree-il-src exp) '() init ktail kclause))))
- (with-cps (persistent-intmap (intmap-replace! cps kinit init))
- kinit))))))))
- (define *comp-module* (make-fluid))
- (define (canonicalize exp)
- (define (reduce-conditional exp)
- (match exp
- (($ <conditional> src
- ($ <conditional> _ test ($ <const> _ t) ($ <const> _ f))
- consequent alternate)
- (cond
- ((and t (not f))
- (reduce-conditional (make-conditional src test consequent alternate)))
- ((and (not t) f)
- (reduce-conditional (make-conditional src test alternate consequent)))
- (else
- exp)))
- (_ exp)))
- (define (evaluate-args-eagerly-if-needed src inits k)
- ;; Some macros generate calls to "vector" or "list" with like 300
- ;; arguments. Since we eventually compile to lower-level operations
- ;; like make-vector and vector-set! or cons, it reduces live
- ;; variable pressure to sink initializers if we can, if we can prove
- ;; that the initializer can't capture the continuation. (More on
- ;; that caveat here:
- ;; http://wingolog.org/archives/2013/11/02/scheme-quiz-time).
- ;;
- ;; Normally we would do this transformation in the optimizer, but
- ;; it's quite tricky there and quite easy here, so we do it here.
- (match inits
- (() (k '()))
- ((init . inits)
- (match init
- ((or ($ <const>) ($ <void>) ($ <lambda>) ($ <lexical-ref>))
- (evaluate-args-eagerly-if-needed
- src inits (lambda (inits) (k (cons init inits)))))
- (_
- (with-lexicals src (init)
- (evaluate-args-eagerly-if-needed
- src inits (lambda (inits) (k (cons init inits))))))))))
- (post-order
- (lambda (exp)
- (match exp
- (($ <conditional>)
- (reduce-conditional exp))
- (($ <primcall> src 'exact-integer? (x))
- ;; Both fixnum? and bignum? are branching primitives.
- (with-lexicals src (x)
- (make-conditional
- src (make-primcall src 'fixnum? (list x))
- (make-const src #t)
- (make-conditional src (make-primcall src 'bignum? (list x))
- (make-const src #t)
- (make-const src #f)))))
- (($ <primcall> src '<= (a b))
- ;; No need to reduce as <= is a branching primitive.
- (make-conditional src (make-primcall src '<= (list a b))
- (make-const src #t)
- (make-const src #f)))
- (($ <primcall> src '>= (a b))
- ;; No need to reduce as < is a branching primitive.
- (make-conditional src (make-primcall src '<= (list b a))
- (make-const src #t)
- (make-const src #f)))
- (($ <primcall> src '> (a b))
- ;; No need to reduce as < is a branching primitive.
- (make-conditional src (make-primcall src '< (list b a))
- (make-const src #t)
- (make-const src #f)))
- (($ <primcall> src (? branching-primitive? name) args)
- ;; No need to reduce because test is not reducible: reifying
- ;; #t/#f is the right thing.
- (make-conditional src exp
- (make-const src #t)
- (make-const src #f)))
- (($ <primcall> src 'not (x))
- (reduce-conditional
- (make-conditional src x
- (make-const src #f)
- (make-const src #t))))
- (($ <primcall> src (or 'eqv? 'equal?) (a b))
- (let ()
- (define-syntax-rule (primcall name . args)
- (make-primcall src 'name (list . args)))
- (define-syntax primcall-chain
- (syntax-rules ()
- ((_ x) x)
- ((_ x . y)
- (make-conditional src (primcall . x) (primcall-chain . y)
- (make-const src #f)))))
- (define-syntax-rule (bool x)
- (make-conditional src x (make-const src #t) (make-const src #f)))
- (with-lexicals src (a b)
- (make-conditional
- src
- (primcall eq? a b)
- (make-const src #t)
- (match (primcall-name exp)
- ('eqv?
- ;; Completely inline.
- (primcall-chain (heap-number? a)
- (heap-number? b)
- (bool (primcall heap-numbers-equal? a b))))
- ('equal?
- ;; Partially inline.
- (primcall-chain (heap-object? a)
- (heap-object? b)
- (primcall equal? a b))))))))
- (($ <primcall> src 'vector args)
- ;; Expand to "allocate-vector" + "vector-init!".
- (evaluate-args-eagerly-if-needed
- src args
- (lambda (args)
- (define-syntax-rule (primcall name . args)
- (make-primcall src 'name (list . args)))
- (define-syntax-rule (const val)
- (make-const src val))
- (let ((v (primcall allocate-vector (const (length args)))))
- (with-lexicals src (v)
- (list->seq
- src
- (append (map (lambda (idx arg)
- (primcall vector-init! v (const idx) arg))
- (iota (length args))
- args)
- (list v))))))))
- (($ <primcall> src 'make-struct/simple (vtable . args))
- ;; Expand to "allocate-struct" + "struct-init!".
- (evaluate-args-eagerly-if-needed
- src args
- (lambda (args)
- (define-syntax-rule (primcall name . args)
- (make-primcall src 'name (list . args)))
- (define-syntax-rule (const val)
- (make-const src val))
- (let ((s (primcall allocate-struct vtable (const (length args)))))
- (with-lexicals src (s)
- (list->seq
- src
- (append (map (lambda (idx arg)
- (primcall struct-init! s (const idx) arg))
- (iota (length args))
- args)
- (list s))))))))
- (($ <primcall> src 'list args)
- ;; Expand to "cons".
- (evaluate-args-eagerly-if-needed
- src args
- (lambda (args)
- (define-syntax-rule (primcall name . args)
- (make-primcall src 'name (list . args)))
- (define-syntax-rule (const val)
- (make-const src val))
- (fold (lambda (arg tail) (primcall cons arg tail))
- (const '())
- (reverse args)))))
- ;; Lower (logand x (lognot y)) to (logsub x y). We do it here
- ;; instead of in CPS because it gets rid of the lognot entirely;
- ;; if type folding can't prove Y to be an exact integer, then DCE
- ;; would have to leave it in the program for its possible
- ;; effects.
- (($ <primcall> src 'logand (x ($ <primcall> _ 'lognot (y))))
- (make-primcall src 'logsub (list x y)))
- (($ <primcall> src 'logand (($ <primcall> _ 'lognot (y)) x))
- (make-primcall src 'logsub (list x y)))
- (($ <primcall> src 'throw ())
- (make-call src (make-primitive-ref src 'throw) '()))
- (($ <prompt> src escape-only? tag body
- ($ <lambda> hsrc hmeta
- ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
- exp)
- (($ <primcall> src 'ash (a b))
- (match b
- (($ <const> src2 (? exact-integer? n))
- (if (< n 0)
- (make-primcall src 'rsh (list a (make-const src2 (- n))))
- (make-primcall src 'lsh (list a b))))
- (_
- (with-lexicals src (a b)
- (make-conditional
- src
- (make-primcall src '< (list b (make-const src 0)))
- (let ((n (make-primcall src '- (list (make-const src 0) b))))
- (make-primcall src 'rsh (list a n)))
- (make-primcall src 'lsh (list a b)))))))
- (_ exp)))
- exp))
- (define (compile-cps exp env opts)
- (values (cps-convert/thunk (canonicalize exp)) env env))
- ;;; Local Variables:
- ;;; eval: (put 'convert-arg 'scheme-indent-function 2)
- ;;; eval: (put 'convert-args 'scheme-indent-function 2)
- ;;; End:
|