compile-bytecode.scm 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415
  1. ;;; Lightweight compiler directly from Tree-IL to bytecode
  2. ;; Copyright (C) 2020-2021,2023 Free Software Foundation, Inc.
  3. ;;; This library is free software; you can redistribute it and/or modify it
  4. ;;; under the terms of the GNU Lesser General Public License as published by
  5. ;;; the Free Software Foundation; either version 3 of the License, or (at
  6. ;;; your option) any later version.
  7. ;;;
  8. ;;; This library is distributed in the hope that it will be useful, but
  9. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
  11. ;;; General Public License for more details.
  12. ;;;
  13. ;;; You should have received a copy of the GNU Lesser General Public License
  14. ;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; This pass converts Tree-IL directly to bytecode. Whereas first
  18. ;;; compiling to CPS will yield better-quality bytecode if the optimizer
  19. ;;; is on, this approach is much faster and less memory-hungry. It's
  20. ;;; useful if it's more important to reduce time spent in the compiler
  21. ;;; than to have a fast program.
  22. ;;;
  23. ;;; Code:
  24. (define-module (language tree-il compile-bytecode)
  25. #:use-module (ice-9 match)
  26. #:use-module (language bytecode)
  27. #:use-module (language tree-il)
  28. #:use-module ((srfi srfi-1) #:select (filter-map
  29. fold
  30. lset-adjoin lset-union lset-difference))
  31. #:use-module (srfi srfi-9)
  32. #:use-module (system base types internal)
  33. #:use-module (system vm assembler)
  34. #:export (compile-bytecode))
  35. (define (u6? x) (and (exact-integer? x) (<= 0 x #x3f)))
  36. (define (u8? x) (and (exact-integer? x) (<= 0 x #xff)))
  37. (define (u12? x) (and (exact-integer? x) (<= 0 x #xfff)))
  38. (define (emit-box asm dst src)
  39. (cond
  40. ((= src dst)
  41. (emit-mov asm 1 src)
  42. (emit-box asm dst 1))
  43. (else
  44. (let ((tmp 0))
  45. (emit-allocate-words/immediate asm dst 2)
  46. (emit-load-u64 asm tmp %tc7-variable)
  47. (emit-word-set!/immediate asm dst 0 tmp)
  48. (emit-word-set!/immediate asm dst 1 src)))))
  49. (define (emit-box-set! asm loc val)
  50. (emit-scm-set!/immediate asm loc 1 val))
  51. (define (emit-box-ref asm dst loc)
  52. (emit-scm-ref/immediate asm dst loc 1))
  53. (define (emit-cons asm dst car cdr)
  54. (cond
  55. ((= car dst)
  56. (emit-mov asm 1 car)
  57. (emit-cons asm dst 1 (if (= cdr dst) 1 cdr)))
  58. ((= cdr dst)
  59. (emit-mov asm 1 cdr)
  60. (emit-cons asm dst car 1))
  61. (else
  62. (emit-allocate-words/immediate asm dst 2)
  63. (emit-scm-set!/immediate asm dst 0 car)
  64. (emit-scm-set!/immediate asm dst 1 cdr))))
  65. (define (emit-cached-module-box asm dst mod name public? bound? tmp)
  66. (define key (cons mod name))
  67. (define cached (gensym "cached"))
  68. (emit-cache-ref asm dst key)
  69. (emit-heap-object? asm dst)
  70. (emit-je asm cached)
  71. (cond
  72. (bound?
  73. (let ((name (symbol->string name)))
  74. (if public?
  75. (emit-lookup-bound-public asm dst mod name)
  76. (emit-lookup-bound-private asm dst mod name))))
  77. (else
  78. (emit-load-constant asm dst mod)
  79. (emit-resolve-module asm dst dst public?)
  80. (emit-load-constant asm tmp name)
  81. (emit-lookup asm dst dst tmp)))
  82. (emit-cache-set! asm key dst)
  83. (emit-label asm cached))
  84. (define (emit-cached-toplevel-box asm dst scope name bound? tmp)
  85. (define key (cons scope name))
  86. (define cached (gensym "cached"))
  87. (emit-cache-ref asm dst key)
  88. (emit-heap-object? asm dst)
  89. (emit-je asm cached)
  90. (emit-cache-ref asm dst scope)
  91. (emit-load-constant asm tmp name)
  92. (if bound?
  93. (emit-lookup-bound asm dst dst tmp)
  94. (emit-lookup asm dst dst tmp))
  95. (emit-cache-set! asm key dst)
  96. (emit-label asm cached))
  97. (define (emit-toplevel-box asm dst name bound? tmp)
  98. (emit-current-module asm dst)
  99. (emit-load-constant asm tmp name)
  100. (if bound?
  101. (emit-lookup-bound asm dst dst tmp)
  102. (emit-lookup asm dst dst tmp)))
  103. (define closure-header-words 2)
  104. (define (emit-allocate-closure asm dst nfree label tmp)
  105. (let ((nwords (+ nfree closure-header-words)))
  106. (cond
  107. ((u12? nwords)
  108. (emit-allocate-words/immediate asm dst nwords))
  109. (else
  110. (emit-load-u64 asm tmp nwords)
  111. (emit-allocate-words asm dst tmp)))
  112. (emit-load-u64 asm tmp (+ %tc7-program (ash nfree 16)))
  113. (emit-word-set!/immediate asm dst 0 tmp)
  114. (emit-load-label asm tmp label)
  115. (emit-word-set!/immediate asm dst 1 tmp)))
  116. (define (emit-maybe-allocate-closure asm dst nfree label tmp)
  117. (if (zero? nfree)
  118. (emit-load-static-procedure asm dst label)
  119. (emit-allocate-closure asm dst nfree label tmp)))
  120. (define (emit-load-free-variable asm dst src idx tmp)
  121. (let ((idx (+ idx closure-header-words)))
  122. (cond
  123. ((u8? idx)
  124. (emit-scm-ref/immediate asm dst src idx))
  125. (else
  126. (emit-load-u64 asm tmp idx)
  127. (emit-scm-ref asm dst src tmp)))))
  128. (define (emit-init-free-variable asm closure idx val tmp)
  129. (let ((idx (+ idx closure-header-words)))
  130. (cond
  131. ((u8? idx)
  132. (emit-scm-set!/immediate asm closure idx val))
  133. (else
  134. (emit-load-u64 asm tmp idx)
  135. (emit-scm-set! asm closure tmp val)))))
  136. (define vector-header-words 1)
  137. (define (emit-allocate-vector asm dst len tmp)
  138. (let ((nwords (+ len vector-header-words)))
  139. (cond
  140. ((u12? nwords)
  141. (emit-allocate-words/immediate asm dst nwords))
  142. (else
  143. (emit-load-u64 asm tmp nwords)
  144. (emit-allocate-words asm dst tmp)))
  145. (emit-load-u64 asm tmp (+ %tc7-vector (ash len 8)))
  146. (emit-word-set!/immediate asm dst 0 tmp)))
  147. (define (emit-vector-init! asm v idx val tmp)
  148. (let ((idx (+ idx vector-header-words)))
  149. (cond
  150. ((u8? idx)
  151. (emit-scm-set!/immediate asm v idx val))
  152. (else
  153. (emit-load-u64 asm tmp idx)
  154. (emit-scm-set! asm v tmp val)))))
  155. (define struct-header-words 1)
  156. (define (emit-struct-init! asm s idx val tmp)
  157. (let ((idx (+ idx struct-header-words)))
  158. (cond
  159. ((u8? idx)
  160. (emit-scm-set!/immediate asm s idx val))
  161. (else
  162. (emit-load-u64 asm tmp idx)
  163. (emit-scm-set! asm s tmp val)))))
  164. (define-syntax-rule (define-record-type/keywords rtd
  165. make-rtd pred (field getter init) ...)
  166. (begin
  167. (define-record-type rtd (%make-rtd field ...) pred (field getter) ...)
  168. (define* (make-rtd #:key (field init) ...)
  169. (%make-rtd field ...))))
  170. (define-record-type/keywords <primitive>
  171. make-primitive
  172. primitive?
  173. (name primitive-name (error "name required"))
  174. (nargs primitive-nargs (error "nargs required"))
  175. (has-result? primitive-has-result? #f)
  176. (predicate? primitive-predicate? #f)
  177. (emit primitive-emitter (error "emitter required"))
  178. (immediate-in-range? primitive-immediate-in-range-predicate #f)
  179. (emit/immediate primitive-emitter/immediate #f))
  180. (define *primitives* (make-hash-table))
  181. (define (lookup-primitive name) (hashq-ref *primitives* name))
  182. (define-syntax-rule (define-primitive primitive kw ...)
  183. (hashq-set! *primitives* 'primitive
  184. (make-primitive #:name 'primitive kw ...)))
  185. (define-syntax-rule (define-primitives (primitive kw ...) ...)
  186. (begin (define-primitive primitive kw ...) ...))
  187. (define-primitives
  188. (+ #:nargs 2 #:has-result? #t #:emit emit-add
  189. #:immediate-in-range? u8?
  190. #:emit/immediate emit-add/immediate)
  191. (- #:nargs 2 #:has-result? #t #:emit emit-sub
  192. #:immediate-in-range? u8?
  193. #:emit/immediate emit-sub/immediate)
  194. (* #:nargs 2 #:has-result? #t #:emit emit-mul)
  195. (/ #:nargs 2 #:has-result? #t #:emit emit-div)
  196. (quotient #:nargs 2 #:has-result? #t #:emit emit-quo)
  197. (remainder #:nargs 2 #:has-result? #t #:emit emit-rem)
  198. (modulo #:nargs 2 #:has-result? #t #:emit emit-mod)
  199. (exact->inexact #:nargs 1 #:has-result? #t #:emit emit-inexact)
  200. (sqrt #:nargs 1 #:has-result? #t #:emit emit-sqrt)
  201. (abs #:nargs 1 #:has-result? #t #:emit emit-abs)
  202. (floor #:nargs 1 #:has-result? #t #:emit emit-floor)
  203. (ceiling #:nargs 1 #:has-result? #t #:emit emit-ceiling)
  204. (sin #:nargs 1 #:has-result? #t #:emit emit-sin)
  205. (cos #:nargs 1 #:has-result? #t #:emit emit-cos)
  206. (tan #:nargs 1 #:has-result? #t #:emit emit-tan)
  207. (asin #:nargs 1 #:has-result? #t #:emit emit-asin)
  208. (acos #:nargs 1 #:has-result? #t #:emit emit-acos)
  209. (atan #:nargs 1 #:has-result? #t #:emit emit-atan)
  210. (atan2 #:nargs 2 #:has-result? #t #:emit emit-atan2)
  211. (logand #:nargs 2 #:has-result? #t #:emit emit-logand)
  212. (logior #:nargs 2 #:has-result? #t #:emit emit-logior)
  213. (logxor #:nargs 2 #:has-result? #t #:emit emit-logxor)
  214. (logsub #:nargs 2 #:has-result? #t #:emit emit-logsub)
  215. (lsh #:nargs 2 #:has-result? #t #:emit emit-lsh
  216. #:immediate-in-range? u6?
  217. #:emit/immediate emit-lsh/immediate)
  218. (rsh #:nargs 2 #:has-result? #t #:emit emit-rsh
  219. #:immediate-in-range? u6?
  220. #:emit/immediate emit-rsh/immediate)
  221. (throw #:nargs 2 #:emit emit-throw)
  222. (throw/value #:nargs 2 #:emit #f
  223. #:immediate-in-range? (lambda (_) #t)
  224. #:emit/immediate emit-throw/value)
  225. (throw/value+data #:nargs 2 #:emit #f
  226. #:immediate-in-range? (lambda (_) #t)
  227. #:emit/immediate emit-throw/value+data)
  228. (current-thread #:nargs 2 #:has-result? #t #:emit emit-current-thread)
  229. (current-module #:nargs 0 #:has-result? #t #:emit emit-current-module)
  230. (module-ensure-local-variable! #:nargs 2 #:has-result? #t #:emit emit-define!)
  231. (builtin-ref #:nargs 1 #:has-result? #t #:emit #f
  232. #:immediate-in-range? (lambda (_) #t)
  233. #:emit/immediate emit-builtin-ref)
  234. (wind #:nargs 2 #:emit emit-wind)
  235. (unwind #:nargs 0 #:emit emit-unwind)
  236. (push-dynamic-state #:nargs 1 #:emit emit-push-dynamic-state)
  237. (pop-dynamic-state #:nargs 0 #:emit emit-pop-dynamic-state)
  238. (push-fluid #:nargs 2 #:emit emit-push-fluid)
  239. (pop-fluid #:nargs 0 #:emit emit-pop-fluid)
  240. (pop-fluid-state #:nargs 0 #:emit emit-pop-dynamic-state)
  241. (fluid-ref #:nargs 1 #:has-result? #t #:emit emit-fluid-ref)
  242. (fluid-set! #:nargs 2 #:emit emit-fluid-set!)
  243. (string->number #:nargs 1 #:has-result? #t #:emit emit-string->number)
  244. (string->symbol #:nargs 1 #:has-result? #t #:emit emit-string->symbol)
  245. (symbol->keyword #:nargs 1 #:has-result? #t #:emit emit-symbol->keyword)
  246. (class-of #:nargs 1 #:has-result? #t #:emit emit-class-of)
  247. (cons #:nargs 2 #:has-result? #t #:emit emit-cons)
  248. (car #:nargs 1 #:has-result? #t #:emit emit-$car)
  249. (cdr #:nargs 1 #:has-result? #t #:emit emit-$cdr)
  250. (set-car! #:nargs 2 #:emit emit-$set-car!)
  251. (set-cdr! #:nargs 2 #:emit emit-$set-cdr!)
  252. (box #:nargs 1 #:has-result? #t #:emit emit-box)
  253. (variable-ref #:nargs 1 #:has-result? #t #:emit emit-$variable-ref)
  254. (variable-set! #:nargs 2 #:emit emit-$variable-set!)
  255. (%variable-ref #:nargs 1 #:has-result? #t #:emit emit-$variable-ref)
  256. (%variable-set! #:nargs 2 #:emit emit-box-set!)
  257. (vector-length #:nargs 1 #:has-result? #t #:emit emit-$vector-length)
  258. (vector-ref #:nargs 2 #:has-result? #t #:emit emit-$vector-ref
  259. #:immediate-in-range? u8?
  260. #:emit/immediate emit-$vector-ref/immediate)
  261. (vector-set! #:nargs 3 #:emit emit-$vector-set!
  262. #:immediate-in-range? u8?
  263. #:emit/immediate emit-$vector-set!/immediate)
  264. (struct-vtable #:nargs 1 #:has-result? #t #:emit emit-$struct-vtable)
  265. (struct-ref #:nargs 2 #:has-result? #t #:emit emit-$struct-ref
  266. #:immediate-in-range? u8?
  267. #:emit/immediate emit-$struct-ref/immediate)
  268. (struct-set! #:nargs 3 #:emit emit-$struct-set!
  269. #:immediate-in-range? u8?
  270. #:emit/immediate emit-$struct-set!/immediate)
  271. (eq? #:nargs 2 #:predicate? #t #:emit (lambda (asm a b kf)
  272. (emit-eq? asm a b)
  273. (emit-jne asm kf))
  274. #:immediate-in-range? (lambda (x)
  275. (and=>
  276. (scm->immediate-bits x)
  277. (lambda (bits)
  278. (truncate-bits bits 16 #t))))
  279. #:emit/immediate (lambda (asm a b kf)
  280. (emit-eq-immediate? asm a b)
  281. (emit-jne asm kf)))
  282. (< #:nargs 2 #:predicate? #t #:emit (lambda (asm a b kf)
  283. (emit-<? asm a b)
  284. (emit-jnl asm kf)))
  285. (<= #:nargs 2 #:predicate? #t #:emit (lambda (asm a b kf)
  286. (emit-<? asm b a)
  287. (emit-jnge asm kf)))
  288. (= #:nargs 2 #:predicate? #t #:emit (lambda (asm a b kf)
  289. (emit-=? asm a b)
  290. (emit-jne asm kf))))
  291. (define (variadic-constructor? name)
  292. (memq name '(vector list make-struct/simple)))
  293. (define-syntax predicate-emitter
  294. (lambda (stx)
  295. (define (id-prepend pre id)
  296. (datum->syntax id (symbol-append pre (syntax->datum id))))
  297. (syntax-case stx ()
  298. ((_ pred)
  299. #`(lambda (asm a kf)
  300. (#,(id-prepend 'emit- #'pred) asm a)
  301. (emit-jne asm kf))))))
  302. (define-syntax define-immediate-type-predicate
  303. (syntax-rules ()
  304. ((_ name #f mask tag) #f)
  305. ((_ name pred mask tag)
  306. (define-primitive pred #:nargs 1 #:predicate? #t
  307. #:emit (predicate-emitter pred)))))
  308. (define-syntax-rule (define-heap-type-predicate name pred mask tag)
  309. (define-primitive pred #:nargs 1 #:predicate? #t
  310. #:emit (lambda (asm a kf)
  311. (emit-heap-object? asm a)
  312. (emit-jne asm kf)
  313. ((predicate-emitter pred) asm a kf))))
  314. (visit-immediate-tags define-immediate-type-predicate)
  315. (visit-heap-tags define-heap-type-predicate)
  316. (define (primitive-module name)
  317. (case name
  318. ((bytevector?
  319. bytevector-length
  320. bytevector-u8-ref bytevector-u8-set!
  321. bytevector-s8-ref bytevector-s8-set!
  322. bytevector-u16-ref bytevector-u16-set!
  323. bytevector-u16-native-ref bytevector-u16-native-set!
  324. bytevector-s16-ref bytevector-s16-set!
  325. bytevector-s16-native-ref bytevector-s16-native-set!
  326. bytevector-u32-ref bytevector-u32-set!
  327. bytevector-u32-native-ref bytevector-u32-native-set!
  328. bytevector-s32-ref bytevector-s32-set!
  329. bytevector-s32-native-ref bytevector-s32-native-set!
  330. bytevector-u64-ref bytevector-u64-set!
  331. bytevector-u64-native-ref bytevector-u64-native-set!
  332. bytevector-s64-ref bytevector-s64-set!
  333. bytevector-s64-native-ref bytevector-s64-native-set!
  334. bytevector-ieee-single-ref bytevector-ieee-single-set!
  335. bytevector-ieee-single-native-ref bytevector-ieee-single-native-set!
  336. bytevector-ieee-double-ref bytevector-ieee-double-set!
  337. bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!)
  338. '(rnrs bytevectors))
  339. ((atomic-box?
  340. make-atomic-box atomic-box-ref atomic-box-set!
  341. atomic-box-swap! atomic-box-compare-and-swap!)
  342. '(ice-9 atomic))
  343. ((current-thread) '(ice-9 threads))
  344. ((class-of) '(oop goops))
  345. ((u8vector-ref
  346. u8vector-set! s8vector-ref s8vector-set!
  347. u16vector-ref u16vector-set! s16vector-ref s16vector-set!
  348. u32vector-ref u32vector-set! s32vector-ref s32vector-set!
  349. u64vector-ref u64vector-set! s64vector-ref s64vector-set!
  350. f32vector-ref f32vector-set! f64vector-ref f64vector-set!)
  351. '(srfi srfi-4))
  352. (else '(guile))))
  353. (define (canonicalize exp)
  354. (define (reify-primref src name)
  355. ;; some are builtin-ref
  356. (cond
  357. ((builtin-name->index name)
  358. => (lambda (idx)
  359. (make-primcall src 'builtin-ref (list (make-const #f idx)))))
  360. (else
  361. (make-module-ref src (primitive-module name) name #t))))
  362. (define (reify-primcall src name args)
  363. (make-call src (reify-primref src name) args))
  364. (define (reify-branch src name args)
  365. (make-conditional src
  366. (make-primcall src name args)
  367. (make-const src #t)
  368. (make-const src #f)))
  369. (define (finish-conditional exp)
  370. (define (true? x) (match x (($ <const> _ val) val) (_ #f)))
  371. (define (false? x) (match x (($ <const> _ val) (not val)) (_ #f)))
  372. (define (predicate? name)
  373. (and=> (lookup-primitive name) primitive-predicate?))
  374. (match exp
  375. (($ <conditional> src ($ <conditional> _ test (? true?) (? false?))
  376. consequent alternate)
  377. (finish-conditional (make-conditional src test consequent alternate)))
  378. (($ <conditional> src ($ <conditional> _ test (? false?) (? true?))
  379. consequent alternate)
  380. (finish-conditional (make-conditional src test alternate consequent)))
  381. (($ <conditional> src ($ <primcall> _ (? predicate?)))
  382. exp)
  383. (($ <conditional> src test consequent alternate)
  384. (make-conditional src (make-primcall src 'false? (list test))
  385. alternate consequent))))
  386. (post-order
  387. (lambda (exp)
  388. (match exp
  389. ;; Turn <void> into *unspecified*.
  390. (($ <void> src) (make-const src *unspecified*))
  391. ;; Ensure the test of a conditional is a branching primcall.
  392. (($ <conditional>) (finish-conditional exp))
  393. ;; Reify primitives.
  394. (($ <primitive-ref> src name) (reify-primref src name))
  395. ;; Invert >= and >.
  396. (($ <primcall> src '>= (a b)) (reify-branch src '<= (list b a)))
  397. (($ <primcall> src '> (a b)) (reify-branch src '< (list b a)))
  398. ;; For eq? on constants, make the second arg the constant.
  399. (($ <primcall> src 'eq? ((and a ($ <const>))
  400. (and b (not ($ <const>)))))
  401. (reify-branch src 'eq? (list b a)))
  402. ;; Simplify "not".
  403. (($ <primcall> src 'not (x))
  404. (finish-conditional
  405. (make-conditional src x (make-const src #f) (make-const src #t))))
  406. ;; Special cases for variadic list, vector, make-struct/simple.
  407. (($ <primcall> src (? variadic-constructor?)) exp)
  408. ;; struct-set! needs to return its value.
  409. (($ <primcall> src 'struct-set! (x idx v))
  410. (with-lexicals src (v)
  411. (make-seq src
  412. (make-primcall src 'struct-set! (list x idx v))
  413. v)))
  414. ;; Transform "ash" to lsh / rsh.
  415. (($ <primcall> src 'ash (x ($ <const> src* (? exact-integer? y))))
  416. (if (negative? y)
  417. (make-primcall src 'rsh (list x (make-const src* (- y))))
  418. (make-primcall src 'lsh (list x (make-const src* y)))))
  419. ;; (throw key subr msg (list x) (list x))
  420. (($ <primcall> src 'throw
  421. (($ <const> _ key) ($ <const> _ subr) ($ <const> _ msg)
  422. ($ <primcall> _ 'list (x))
  423. ($ <primcall> _ 'list (x))))
  424. (make-primcall src 'throw/value+data
  425. (list x (make-const #f `#(,key ,subr ,msg)))))
  426. ;; (throw key subr msg (list x) #f)
  427. (($ <primcall> src 'throw
  428. (($ <const> _ key) ($ <const> _ subr) ($ <const> _ msg)
  429. ($ <primcall> _ 'list (x))
  430. ($ <const> _ #f)))
  431. (make-primcall src 'throw/value
  432. (list x (make-const #f `#(,key ,subr ,msg)))))
  433. ;; (throw key arg ...)
  434. (($ <primcall> src 'throw (key . args))
  435. (make-primcall src 'throw
  436. (list key (make-primcall #f 'list args))))
  437. ;; Now that we handled special cases, ensure remaining primcalls
  438. ;; are understood by the code generator, and if not, reify them
  439. ;; as calls.
  440. (($ <primcall> src name args)
  441. (or (and=> (lookup-primitive name)
  442. (lambda (prim)
  443. (and (= (primitive-nargs prim) (length args))
  444. (if (primitive-predicate? prim)
  445. (reify-branch src name args)
  446. exp))))
  447. (reify-primcall src name args)))
  448. ;; Add a clause to clauseless lambdas.
  449. (($ <lambda> src meta #f)
  450. (make-lambda src meta
  451. (make-lambda-case
  452. src '() #f #f #f '() '()
  453. (make-primcall
  454. src 'throw
  455. (list (make-const src 'wrong-number-of-args)
  456. (make-const src #f)
  457. (make-const src "Wrong number of arguments")
  458. (make-const src '())
  459. (make-const src #f)))
  460. #f)))
  461. ;; Turn <abort> into abort-to-prompt.
  462. (($ <abort> src tag args ($ <const> _ ()))
  463. (reify-primcall src 'abort-to-prompt (cons tag args)))
  464. (($ <abort> src tag args tail)
  465. (reify-primcall src 'apply
  466. (cons* (reify-primref src 'abort-to-prompt)
  467. tag
  468. (append args (list tail)))))
  469. ;; Change non-escape-only prompt bodies from being thunks to
  470. ;; expressions. (Escape-only prompt bodies are already
  471. ;; expressions.)
  472. (($ <prompt> src #f tag body handler)
  473. (make-prompt src #f tag (make-call src body '()) handler))
  474. (_ exp)))
  475. exp))
  476. (define-record-type <closure>
  477. (make-closure label code module-scope free-vars)
  478. closure?
  479. (label closure-label)
  480. (code closure-code)
  481. (module-scope closure-module-scope)
  482. (free-vars closure-free-vars))
  483. ;; Identify closures and assigned variables within X.
  484. (define (split-closures exp)
  485. (define closures '())
  486. (define assigned (make-hash-table))
  487. ;; Guile's current semantics are that a toplevel lambda captures a
  488. ;; reference on the current module, and that all contained lambdas use
  489. ;; that module to resolve toplevel variables. The `module-scope'
  490. ;; parameter of `visit-closure' tracks whether or not we are in a
  491. ;; toplevel lambda. Visiting a top-level lambda allocates a new
  492. ;; module-scope by incrementing this counter. Visiting a nested
  493. ;; lambda re-uses the same module-scope. The code generator will
  494. ;; associate these ID's with the module that was current at the point
  495. ;; the top-level lambda is created.
  496. (define scope-counter 0)
  497. ;; Compute free variables in X, adding entries to `free-vars' as
  498. ;; lambdas are seen, and adding set! vars to `assigned'.
  499. (define (visit-closure exp module-scope)
  500. (define (visit exp)
  501. (define (adjoin sym f) (lset-adjoin eq? f sym))
  502. (define (union f1 f2) (lset-union eq? f1 f2))
  503. (define (union3 f1 f2 f3) (union f1 (union f2 f3)))
  504. (define (difference f1 f2) (lset-difference eq? f1 f2))
  505. (define (visit* xs) (fold (lambda (x free) (union (visit x) free))
  506. '() xs))
  507. (match exp
  508. (($ <lexical-ref> src name sym)
  509. (list sym))
  510. ((or ($ <const>) ($ <module-ref>) ($ <toplevel-ref>))
  511. '())
  512. (($ <lambda> src meta body)
  513. (let* ((module-scope (or module-scope
  514. (let ((scope scope-counter))
  515. (set! scope-counter (1+ scope-counter))
  516. scope)))
  517. (free (visit-closure body module-scope))
  518. (label (gensym "closure")))
  519. (set! closures
  520. (cons (make-closure label exp module-scope free)
  521. closures))
  522. free))
  523. (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
  524. (union (difference (union (visit* inits) (visit body))
  525. gensyms)
  526. (if alternate
  527. (visit alternate)
  528. '())))
  529. (($ <module-set> src mod name public? exp)
  530. (visit exp))
  531. (($ <toplevel-set> src mod name exp)
  532. (visit exp))
  533. (($ <toplevel-define> src modname name exp)
  534. (visit exp))
  535. (($ <call> src proc args)
  536. (union (visit proc) (visit* args)))
  537. (($ <primcall> src name args)
  538. (visit* args))
  539. (($ <prompt> src escape-only? tag body
  540. ($ <lambda> hsrc hmeta hclause))
  541. (union3 (visit tag) (visit body) (visit hclause)))
  542. (($ <conditional> src test consequent alternate)
  543. (union3 (visit test) (visit consequent) (visit alternate)))
  544. (($ <lexical-set> src name gensym exp)
  545. (hashq-set! assigned gensym #t)
  546. (adjoin gensym (visit exp)))
  547. (($ <seq> src head tail)
  548. (union (visit head) (visit tail)))
  549. (($ <let> src names syms vals body)
  550. (union (visit* vals)
  551. (difference (visit body) syms)))
  552. (($ <fix> src names gensyms funs body)
  553. (difference (union (visit* funs) (visit body))
  554. gensyms))
  555. (($ <let-values> src exp body)
  556. (union (visit exp) (visit body)))))
  557. (visit exp))
  558. (match (visit-closure exp #f)
  559. (()
  560. (let ()
  561. (define x-thunk
  562. (let ((src (tree-il-srcv exp)))
  563. (make-lambda src '()
  564. (make-lambda-case src '() #f #f #f '() '() exp #f))))
  565. (values (cons (make-closure 'init x-thunk #f '())
  566. (reverse closures))
  567. assigned)))
  568. (vars
  569. (error "unexpected free vars" vars))))
  570. (define call-frame-size 3)
  571. (define (compute-frame-size clause)
  572. "Compute a conservative count of how many stack slots will be needed
  573. in the frame with for the lambda-case clause @var{clause}."
  574. (define (visit* xs)
  575. (fold (lambda (x size) (max (visit x) size)) 0 xs))
  576. (define (visit-args xs)
  577. (let lp ((i 0) (xs xs))
  578. (match xs
  579. (() i)
  580. ((x . xs)
  581. (max (+ i (visit x))
  582. (lp (+ i 1) xs))))))
  583. ;; Computing a value may require temporaries. For example, for
  584. ;; module-ref, we may need a temporary for the module and a temporary
  585. ;; for the symbol. Instead of trying to be extraordinarily precise
  586. ;; about temporary usage in all the different cases, let's just
  587. ;; reserve 3 temporaries.
  588. (define temporary-count 3)
  589. (define (visit exp)
  590. (match exp
  591. ((or ($ <const>) ($ <lexical-ref>) ($ <module-ref>) ($ <toplevel-ref>)
  592. ($ <lambda>))
  593. 1)
  594. (($ <module-set> src mod name public? exp)
  595. (+ 1 (visit exp)))
  596. (($ <toplevel-set> src mod name exp)
  597. (+ 1 (visit exp)))
  598. (($ <toplevel-define> src modname name exp)
  599. (+ 1 (visit exp)))
  600. (($ <call> src proc args)
  601. (+ call-frame-size (visit-args (cons proc args))))
  602. (($ <primcall> src name args)
  603. (visit-args args))
  604. (($ <prompt> src escape-only? tag body
  605. ($ <lambda> hsrc hmeta
  606. ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
  607. (max (visit tag)
  608. (visit body)
  609. (+ (length hsyms) (visit hbody))))
  610. (($ <conditional> src test consequent alternate)
  611. (max (visit test) (visit consequent) (visit alternate)))
  612. (($ <lexical-set> src name gensym exp)
  613. (+ 1 (visit exp)))
  614. (($ <seq> src head tail)
  615. (max (visit head) (visit tail)))
  616. (($ <let> src names syms vals body)
  617. (max (visit-args vals)
  618. (+ (length vals) (visit body))))
  619. (($ <fix> src names gensyms funs body)
  620. (+ (length funs) (visit body)))
  621. (($ <let-values> src exp
  622. ($ <lambda-case> lsrc req #f rest #f () syms body #f))
  623. (max (visit exp)
  624. (+ (length syms) (visit body))))))
  625. (match clause
  626. (($ <lambda-case> src req opt rest kw inits syms body alt)
  627. (+ 1 ; One slot for the closure.
  628. (length syms) ; One slot for each arg.
  629. (max (visit* inits) ; Prologue.
  630. (visit body)) ; Body.
  631. temporary-count)))) ; Temporaries.
  632. (define (sanitize-meta meta)
  633. (match meta
  634. (() '())
  635. (((k . v) . meta)
  636. (let ((meta (sanitize-meta meta)))
  637. (case k
  638. ((maybe-unused) meta)
  639. (else (acons k v meta)))))))
  640. (define (compile-closure asm closure assigned? lookup-closure)
  641. (define-record-type <env>
  642. (make-env prev name id idx closure? boxed? next-local)
  643. env?
  644. ;; Outer <env>, or #f.
  645. (prev env-prev)
  646. ;; Pretty name of the binding, or #f.
  647. (name env-name)
  648. ;; For a lexical (local or closure), its sym. For temporaries, #f.
  649. (id env-id)
  650. ;; For temporary or local, index from SP at which this value can be
  651. ;; loaded. Otherwise index from closure.
  652. (idx env-idx)
  653. ;; True for closure vars, false otherwise.
  654. (closure? env-closure?)
  655. ;; True for boxed vars, false otherwise. Only lexicals can be boxed.
  656. (boxed? env-boxed?)
  657. ;; If another local is pushed on inside this lexical environment,
  658. ;; where it should be written. Usually the same as (1- idx) except
  659. ;; in the case of lexical aliases. Invariant: no binding in the
  660. ;; <env> chain has an idx of next-local or lower. For closure
  661. ;; bindings, #f.
  662. (next-local env-next-local))
  663. (define (lookup-lexical sym env)
  664. (match env
  665. (($ <env> prev _ id)
  666. (if (eq? id sym)
  667. env
  668. (lookup-lexical sym prev)))
  669. (_ (error "sym not found!" sym))))
  670. (define (compile-body clause module-scope free-vars frame-size)
  671. (define (push-free-var sym idx env)
  672. (make-env env sym sym idx #t (assigned? sym) (env-next-local env)))
  673. (define (push-local name sym env)
  674. (let ((idx (env-next-local env)))
  675. (emit-definition asm name (- frame-size idx 1) 'scm)
  676. (make-env env name sym idx #f (assigned? sym) (1- idx))))
  677. (define (push-closure env)
  678. (push-local 'closure #f env))
  679. (define (push-local-alias name sym idx env)
  680. (make-env env name sym idx #f #f (env-next-local env)))
  681. (define (push-temp env)
  682. (let ((idx (env-next-local env)))
  683. (make-env env #f #f idx #f #f (1- idx))))
  684. (define (push-frame env)
  685. (let lp ((i 0) (env env))
  686. (if (< i call-frame-size)
  687. (lp (1+ i) (push-temp env))
  688. env)))
  689. (define (create-initial-env names syms free-syms)
  690. (define (push-free-vars env)
  691. (let lp ((idx 0) (free free-syms) (env env))
  692. (match free
  693. (() env)
  694. ((sym . free)
  695. (lp (1+ idx) free
  696. (push-free-var sym idx env))))))
  697. (define frame-base
  698. (make-env #f 'frame-base #f #f #f #f (- frame-size 1)))
  699. (fold push-local (push-closure (push-free-vars frame-base)) names syms))
  700. (define (stack-height-under-local idx)
  701. (- frame-size idx 1))
  702. (define (stack-height env)
  703. (stack-height-under-local (env-next-local env)))
  704. (define (maybe-cache-module! scope tmp)
  705. (unless module-scope
  706. (emit-current-module asm 0)
  707. (emit-cache-set! asm scope 0)))
  708. (define (maybe-emit-source source)
  709. (when source (emit-source asm source)))
  710. (define (init-free-vars dst free-vars env tmp0 tmp1)
  711. (let lp ((free-idx 0) (free-vars free-vars))
  712. (unless (null? free-vars)
  713. (let* ((loc (lookup-lexical (car free-vars) env))
  714. (idx (env-idx loc)))
  715. (cond
  716. ((env-closure? loc)
  717. (emit-load-free-variable asm tmp0 (1- frame-size) idx tmp1)
  718. (emit-init-free-variable asm dst free-idx tmp0 tmp1))
  719. (else
  720. (emit-init-free-variable asm dst free-idx idx tmp0))))
  721. (lp (1+ free-idx) (cdr free-vars)))))
  722. ;; Visit let-values or prompt handler.
  723. (define (visit-values-handler src req rest syms body env ctx)
  724. (define (push-bindings names syms env)
  725. (fold (lambda (name sym env)
  726. (let ((env (push-local name sym env)))
  727. (when (env-boxed? env)
  728. (emit-box asm (env-idx env) (env-idx env)))
  729. env))
  730. env names syms))
  731. (let ((proc-slot (stack-height env))
  732. (nreq (length req)))
  733. (maybe-emit-source src)
  734. (unless (and rest (zero? nreq))
  735. (emit-receive-values asm proc-slot (->bool rest) nreq))
  736. (when rest
  737. (emit-bind-rest asm (+ proc-slot nreq)))
  738. (emit-reset-frame asm frame-size)
  739. (let ((names (append req (if rest (list rest) '()))))
  740. (for-context body (push-bindings names syms env) ctx))))
  741. (define (visit-prompt exp env ctx)
  742. (match exp
  743. (($ <prompt> src escape-only? tag body
  744. ($ <lambda> hsrc hmeta
  745. ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
  746. (maybe-emit-source src)
  747. (let ((tag (env-idx (for-value tag env)))
  748. (proc-slot (stack-height env))
  749. (khandler (gensym "handler"))
  750. (done (gensym "done")))
  751. (emit-prompt asm tag escape-only? proc-slot khandler)
  752. (match ctx
  753. ('tail
  754. ;; Would be nice if we could invoke the body in true tail
  755. ;; context, but that's not how it currently is.
  756. (for-values-at body env 0)
  757. (emit-unwind asm)
  758. (emit-handle-interrupts asm)
  759. (emit-return-values asm))
  760. (_
  761. (for-context body env ctx)
  762. (emit-unwind asm)
  763. (emit-j asm done)))
  764. (emit-label asm khandler)
  765. (visit-values-handler hsrc hreq hrest hsyms hbody env ctx)
  766. (emit-label asm done)))))
  767. (define (visit-conditional exp env ctx)
  768. (match exp
  769. (($ <conditional> src ($ <primcall> tsrc name args)
  770. consequent alternate)
  771. (maybe-emit-source tsrc)
  772. (let ((prim (lookup-primitive name))
  773. (kf (gensym "false"))
  774. (kdone (gensym "done")))
  775. (define (emit/immediate? val)
  776. (and=> (primitive-immediate-in-range-predicate prim)
  777. (lambda (pred) (pred val))))
  778. (match args
  779. ((a ($ <const> _ (? emit/immediate? b)))
  780. (let ((emit (primitive-emitter/immediate prim)))
  781. (match (for-args (list a) env)
  782. ((a)
  783. (maybe-emit-source src)
  784. (emit asm a b kf)))))
  785. (_
  786. (let ((emit (primitive-emitter prim))
  787. (args (for-args args env)))
  788. (maybe-emit-source src)
  789. (match args
  790. ((a) (emit asm a kf))
  791. ((a b) (emit asm a b kf))))))
  792. (for-context consequent env ctx)
  793. (unless (eq? ctx 'tail)
  794. (emit-j asm kdone))
  795. (emit-label asm kf)
  796. (for-context alternate env ctx)
  797. (emit-label asm kdone)))))
  798. (define (visit-seq exp env ctx)
  799. (match exp
  800. (($ <seq> src head tail)
  801. (maybe-emit-source src)
  802. (for-effect head env)
  803. (for-context tail env ctx))))
  804. (define (visit-let exp env ctx)
  805. (define (push-bindings names syms vals env)
  806. (fold (lambda (name sym val env)
  807. (for-push val env)
  808. (let ((env (push-local name sym env)))
  809. (when (env-boxed? env)
  810. (emit-box asm (env-idx env) (env-idx env)))
  811. env))
  812. env names syms vals))
  813. (match exp
  814. (($ <let> src names syms vals body)
  815. (maybe-emit-source src)
  816. (for-context body (push-bindings names syms vals env) ctx))))
  817. (define (visit-fix exp env ctx)
  818. (define (push-bindings names syms vals env)
  819. (let* ((closures (map lookup-closure vals))
  820. (env (fold
  821. (lambda (name sym closure env)
  822. (let ((env (push-local name sym env)))
  823. (match closure
  824. (($ <closure> label code scope free-vars)
  825. ;; FIXME: Allocate one scope per fix.
  826. (maybe-cache-module! scope 0)
  827. (emit-maybe-allocate-closure
  828. asm (env-idx env) (length free-vars) label 0)
  829. env))))
  830. env names syms closures)))
  831. (for-each
  832. (lambda (sym closure)
  833. (let ((idx (env-idx (lookup-lexical sym env))))
  834. (match closure
  835. (($ <closure> label code scope free-vars)
  836. (init-free-vars idx free-vars env 0 1)))))
  837. syms closures)
  838. env))
  839. (match exp
  840. (($ <fix> src names syms vals body)
  841. (maybe-emit-source src)
  842. (for-context body (push-bindings names syms vals env) ctx))))
  843. (define (visit-let-values exp env ctx)
  844. (match exp
  845. (($ <let-values> src exp
  846. ($ <lambda-case> lsrc req #f rest #f () syms body #f))
  847. (maybe-emit-source src)
  848. (for-values exp env)
  849. (visit-values-handler lsrc req rest syms body env ctx))))
  850. (define (for-context exp env ctx)
  851. (match ctx
  852. ('effect (for-effect exp env))
  853. ('value (for-value exp env))
  854. ('tail (for-tail exp env))
  855. (('value-at . dst) (for-value-at exp env dst))
  856. (('values-at . height) (for-values-at exp env height))))
  857. (define (for-args exps env)
  858. (match exps
  859. (() '())
  860. ((exp . exps)
  861. (let ((env (for-value exp env)))
  862. (cons (env-idx env) (for-args exps env))))))
  863. (define (for-effect exp env)
  864. (match exp
  865. ((or ($ <lexical-ref>) ($ <const>) ($ <lambda>))
  866. ;; Nothing to do.
  867. (values))
  868. ((or ($ <module-ref>) ($ <toplevel-ref>)
  869. ($ <primcall> _ (? variadic-constructor?)))
  870. ;; Cause side effects but ignore value.
  871. (for-value exp env))
  872. (($ <lexical-set> src name sym exp)
  873. (let ((env (for-value exp env)))
  874. (maybe-emit-source src)
  875. (match (lookup-lexical sym env)
  876. (($ <env> _ _ _ idx #t #t) ;; Boxed closure.
  877. (emit-load-free-variable asm 0 (1- frame-size) idx 0)
  878. (emit-box-set! asm 0 (env-idx env)))
  879. (($ <env> _ _ _ idx #f #t) ;; Boxed local.
  880. (emit-box-set! asm idx (env-idx env))))))
  881. (($ <module-set> src mod name public? exp)
  882. (let ((env (for-value exp env)))
  883. (maybe-emit-source src)
  884. (emit-cached-module-box asm 0 mod name public? #f 1)
  885. (emit-box-set! asm 0 (env-idx env))))
  886. (($ <toplevel-set> src mod name exp)
  887. (let ((env (for-value exp env)))
  888. (maybe-emit-source src)
  889. (if module-scope
  890. (emit-cached-toplevel-box asm 0 module-scope name #f 1)
  891. (emit-toplevel-box asm 0 name #f 1))
  892. (emit-box-set! asm 0 (env-idx env))))
  893. (($ <toplevel-define> src mod name exp)
  894. (let ((env (for-value exp env)))
  895. (maybe-emit-source src)
  896. (emit-current-module asm 0)
  897. (emit-load-constant asm 1 name)
  898. (emit-define! asm 0 0 1)
  899. (emit-box-set! asm 0 (env-idx env))))
  900. (($ <call> src proc args)
  901. (let ((proc-slot (let ((env (push-frame env)))
  902. (fold for-push (for-push proc env) args)
  903. (stack-height env))))
  904. (maybe-emit-source src)
  905. (emit-handle-interrupts asm)
  906. (emit-call asm proc-slot (1+ (length args)))
  907. (emit-reset-frame asm frame-size)))
  908. (($ <primcall> src name args)
  909. (let ((prim (lookup-primitive name)))
  910. (define (emit/immediate? val)
  911. (and=> (primitive-immediate-in-range-predicate prim)
  912. (lambda (pred) (pred val))))
  913. (cond
  914. ((primitive-has-result? prim)
  915. (for-value exp env))
  916. (else
  917. (match args
  918. ((a ($ <const> _ (? emit/immediate? b)))
  919. (let ((emit (primitive-emitter/immediate prim)))
  920. (match (for-args (list a) env)
  921. ((a)
  922. (maybe-emit-source src)
  923. (emit asm a b)))))
  924. ((a ($ <const> _ (? emit/immediate? b)) c)
  925. (let ((emit (primitive-emitter/immediate prim)))
  926. (match (for-args (list a c) env)
  927. ((a c)
  928. (maybe-emit-source src)
  929. (emit asm a b c)))))
  930. (_
  931. (let ((emit (primitive-emitter prim))
  932. (args (for-args args env)))
  933. (maybe-emit-source src)
  934. (apply emit asm args))))))))
  935. (($ <prompt>) (visit-prompt exp env 'effect))
  936. (($ <conditional>) (visit-conditional exp env 'effect))
  937. (($ <seq>) (visit-seq exp env 'effect))
  938. (($ <let>) (visit-let exp env 'effect))
  939. (($ <fix>) (visit-fix exp env 'effect))
  940. (($ <let-values>) (visit-let-values exp env 'effect))))
  941. (define (for-value-at exp env dst)
  942. ;; The baseline compiler follows a stack discipline: compiling
  943. ;; temporaries pushes entries on an abstract compile-time stack
  944. ;; (the "env"), which are then popped as they are used. Generally
  945. ;; speaking the "env" is compiled as stack slots: compiling an
  946. ;; operand pushes on an "env" entry, which increments the current
  947. ;; stack height, allocating a new slot that is in use by no live
  948. ;; value. However since we're targetting a register VM though,
  949. ;; there are some important optimizations we should make.
  950. ;;
  951. ;; 1. In the case of (lambda (x) (+ x x)), we don't want to cause
  952. ;; the references to "x" to allocate new stack slots. We want
  953. ;; to emit:
  954. ;;
  955. ;; (add 0 0 0)
  956. ;; (return-values)
  957. ;;
  958. ;; and not:
  959. ;;
  960. ;; (mov 1 0)
  961. ;; (mov 2 0)
  962. ;; (add 0 1 2)
  963. ;; (return-values)
  964. ;;
  965. ;; (These examples use FP-relative indexes.)
  966. ;;
  967. ;; This optimization is handled by for-value, which can push
  968. ;; on a special "env" that aliases a lexical binding.
  969. ;;
  970. ;; 2. Again for (lambda (x) (+ x x)), we want to write the result
  971. ;; directly to its destination, which may alias an operand.
  972. ;; So we want to avoid this:
  973. ;;
  974. ;; (add 1 0 0)
  975. ;; (mov 0 1)
  976. ;; (return-values)
  977. ;;
  978. ;; That optimization is implemented by for-value-at and
  979. ;; for-values-at. It works as long as long as the destination
  980. ;; is clobbered only after operands are used, so each part of
  981. ;; this function has to be careful not to do some kind of
  982. ;; multi-part computation that first clobbers "dst" and then
  983. ;; reads the operands.
  984. (match exp
  985. (($ <lexical-ref> src name sym)
  986. (maybe-emit-source src)
  987. (match (lookup-lexical sym env)
  988. (($ <env> _ _ _ idx #t #t)
  989. (emit-load-free-variable asm dst (1- frame-size) idx 0)
  990. (emit-box-ref asm dst dst))
  991. (($ <env> _ _ _ idx #t #f)
  992. (emit-load-free-variable asm dst (1- frame-size) idx 0))
  993. (($ <env> _ _ _ idx #f #t)
  994. (emit-box-ref asm dst idx))
  995. (($ <env> _ _ _ idx #f #f)
  996. (emit-mov asm dst idx))))
  997. (($ <const> src val)
  998. (maybe-emit-source src)
  999. (emit-load-constant asm dst val))
  1000. (($ <module-ref> src mod name public?)
  1001. (maybe-emit-source src)
  1002. (emit-cached-module-box asm 0 mod name public? #t 1)
  1003. (emit-box-ref asm dst 0))
  1004. (($ <toplevel-ref> src mod name)
  1005. (maybe-emit-source src)
  1006. (if module-scope
  1007. (emit-cached-toplevel-box asm 0 module-scope name #t 1)
  1008. (emit-toplevel-box asm 0 name #t 1))
  1009. (emit-box-ref asm dst 0))
  1010. (($ <lambda> src)
  1011. (maybe-emit-source src)
  1012. (match (lookup-closure exp)
  1013. (($ <closure> label code scope free-vars)
  1014. (maybe-cache-module! scope 0)
  1015. (match (length free-vars)
  1016. (0
  1017. (emit-load-static-procedure asm dst label))
  1018. (nfree
  1019. ;; Stage closure in 0 to avoid stompling captured free
  1020. ;; vars.
  1021. (emit-allocate-closure asm 0 nfree label 1)
  1022. (init-free-vars 0 free-vars env 1 2)
  1023. (emit-mov asm dst 0))))))
  1024. ((or ($ <lexical-set>)
  1025. ($ <module-set>)
  1026. ($ <toplevel-set>)
  1027. ($ <toplevel-define>))
  1028. (for-effect exp env)
  1029. (emit-load-constant asm dst *unspecified*))
  1030. (($ <call> src proc args)
  1031. (let ((proc-slot (let ((env (push-frame env)))
  1032. (fold for-push (for-push proc env) args)
  1033. (stack-height env))))
  1034. (maybe-emit-source src)
  1035. (emit-handle-interrupts asm)
  1036. (emit-call asm proc-slot (1+ (length args)))
  1037. (emit-receive asm (stack-height-under-local dst) proc-slot
  1038. frame-size)))
  1039. (($ <primcall> src (? variadic-constructor? name) args)
  1040. ;; Stage result in 0 to avoid stompling args.
  1041. (let ((args (for-args args env)))
  1042. (maybe-emit-source src)
  1043. (match name
  1044. ('list
  1045. (emit-load-constant asm 0 '())
  1046. (for-each (lambda (arg)
  1047. (emit-cons asm 0 arg 0))
  1048. (reverse args)))
  1049. ('vector
  1050. (let ((len (length args)))
  1051. (emit-allocate-vector asm 0 len 1)
  1052. (let lp ((i 0) (args args))
  1053. (when (< i len)
  1054. (emit-vector-init! asm 0 i (car args) 1)
  1055. (lp (1+ i) (cdr args))))))
  1056. ('make-struct/simple
  1057. (match args
  1058. ((vtable . args)
  1059. (emit-load-constant asm 0 (length args))
  1060. (emit-$allocate-struct asm 0 vtable 0)
  1061. (let lp ((i 0) (args args))
  1062. (match args
  1063. (() #t)
  1064. ((arg . args)
  1065. (emit-struct-init! asm 0 i arg 1)
  1066. (lp (1+ i) args))))))))
  1067. (emit-mov asm dst 0)))
  1068. (($ <primcall> src name args)
  1069. (let ((prim (lookup-primitive name)))
  1070. (define (emit/immediate? val)
  1071. (and=> (primitive-immediate-in-range-predicate prim)
  1072. (lambda (pred) (pred val))))
  1073. (cond
  1074. ((not (primitive-has-result? prim))
  1075. (for-effect exp env)
  1076. (emit-load-constant asm dst *unspecified*))
  1077. (else
  1078. (match args
  1079. ((($ <const> _ (? emit/immediate? a)))
  1080. (let* ((emit (primitive-emitter/immediate prim)))
  1081. (maybe-emit-source src)
  1082. (emit asm dst a)))
  1083. ((a ($ <const> _ (? emit/immediate? b)))
  1084. (let* ((emit (primitive-emitter/immediate prim))
  1085. (a (for-value a env)))
  1086. (maybe-emit-source src)
  1087. (emit asm dst (env-idx a) b)))
  1088. (_
  1089. (let ((emit (primitive-emitter prim))
  1090. (args (for-args args env)))
  1091. (maybe-emit-source src)
  1092. (apply emit asm dst args))))))))
  1093. (($ <prompt>) (visit-prompt exp env `(value-at . ,dst)))
  1094. (($ <conditional>) (visit-conditional exp env `(value-at . ,dst)))
  1095. (($ <seq>) (visit-seq exp env `(value-at . ,dst)))
  1096. (($ <let>) (visit-let exp env `(value-at . ,dst)))
  1097. (($ <fix>) (visit-fix exp env `(value-at . ,dst)))
  1098. (($ <let-values>) (visit-let-values exp env `(value-at . ,dst)))))
  1099. (define (for-value exp env)
  1100. (match (and (lexical-ref? exp)
  1101. (lookup-lexical (lexical-ref-gensym exp) env))
  1102. (($ <env> _ name sym idx #f #f)
  1103. (push-local-alias name sym idx env))
  1104. (_
  1105. (for-push exp env))))
  1106. (define (for-push exp env)
  1107. (for-value-at exp env (env-next-local env))
  1108. (push-temp env))
  1109. (define (for-init sym init env)
  1110. (match (lookup-lexical sym env)
  1111. (($ <env> prev name sym idx #f boxed? next-local)
  1112. (when init
  1113. (let ((done (gensym "post-init")))
  1114. (emit-undefined? asm idx)
  1115. (emit-jne asm done)
  1116. (for-value-at init env idx)
  1117. (emit-label asm done)))
  1118. (when boxed?
  1119. (emit-box asm idx idx)))))
  1120. (define (for-values-at exp env height)
  1121. (match exp
  1122. ((or ($ <const>)
  1123. ($ <lexical-ref>)
  1124. ($ <lexical-set>)
  1125. ($ <toplevel-ref>)
  1126. ($ <toplevel-set>)
  1127. ($ <toplevel-define>)
  1128. ($ <module-ref>)
  1129. ($ <module-set>)
  1130. ($ <lambda>)
  1131. ($ <primcall>))
  1132. (for-value-at exp env (- frame-size height 1))
  1133. (emit-reset-frame asm (1+ height)))
  1134. (($ <call> src proc args)
  1135. (let* ((env (push-frame env))
  1136. (from (stack-height env)))
  1137. (fold for-push (for-push proc env) args)
  1138. (maybe-emit-source src)
  1139. (emit-handle-interrupts asm)
  1140. (emit-call asm from (1+ (length args)))
  1141. (unless (= from height)
  1142. (emit-shuffle-down asm from height))))
  1143. (($ <prompt>) (visit-prompt exp env `(values-at . ,height)))
  1144. (($ <conditional>) (visit-conditional exp env `(values-at . ,height)))
  1145. (($ <seq>) (visit-seq exp env `(values-at . ,height)))
  1146. (($ <let>) (visit-let exp env `(values-at . ,height)))
  1147. (($ <fix>) (visit-fix exp env `(values-at . ,height)))
  1148. (($ <let-values>) (visit-let-values exp env `(values-at . ,height)))))
  1149. (define (for-values exp env)
  1150. (for-values-at exp env (stack-height env)))
  1151. (define (for-tail exp env)
  1152. (match exp
  1153. ((or ($ <const>)
  1154. ($ <lexical-ref>)
  1155. ($ <lexical-set>)
  1156. ($ <toplevel-ref>)
  1157. ($ <toplevel-set>)
  1158. ($ <toplevel-define>)
  1159. ($ <module-ref>)
  1160. ($ <module-set>)
  1161. ($ <lambda>)
  1162. ($ <primcall>))
  1163. (for-values-at exp env 0)
  1164. (emit-handle-interrupts asm)
  1165. (emit-return-values asm))
  1166. (($ <call> src proc args)
  1167. (let* ((base (stack-height env))
  1168. (env (fold for-push (for-push proc env) args)))
  1169. (maybe-emit-source src)
  1170. (let lp ((i (length args)) (env env))
  1171. (when (<= 0 i)
  1172. (lp (1- i) (env-prev env))
  1173. (emit-mov asm (+ (env-idx env) base) (env-idx env))))
  1174. (emit-reset-frame asm (+ 1 (length args)))
  1175. (emit-handle-interrupts asm)
  1176. (emit-tail-call asm)))
  1177. (($ <prompt>) (visit-prompt exp env 'tail))
  1178. (($ <conditional>) (visit-conditional exp env 'tail))
  1179. (($ <seq>) (visit-seq exp env 'tail))
  1180. (($ <let>) (visit-let exp env 'tail))
  1181. (($ <fix>) (visit-fix exp env 'tail))
  1182. (($ <let-values>) (visit-let-values exp env 'tail))))
  1183. (match clause
  1184. (($ <lambda-case> src req opt rest kw inits syms body alt)
  1185. (let ((names (append req
  1186. (or opt '())
  1187. (if rest (list rest) '())
  1188. (match kw
  1189. ((aok? (key name sym) ...) name)
  1190. (#f '()))))
  1191. (inits (append (make-list (length req) #f)
  1192. (list-head inits (if opt (length opt) 0))
  1193. (if rest '(#f) '())
  1194. (list-tail inits (if opt (length opt) 0)))))
  1195. (unless (= (length names) (length syms) (length inits))
  1196. (error "unexpected args" names syms inits))
  1197. (maybe-emit-source src)
  1198. (let ((env (create-initial-env names syms free-vars)))
  1199. (for-each (lambda (sym init) (for-init sym init env)) syms inits)
  1200. (for-tail body env))))))
  1201. (define (emit-clause label clause module-scope free)
  1202. (let ((frame-size (compute-frame-size clause)))
  1203. (match clause
  1204. (($ <lambda-case> src req opt rest kw inits syms body alt)
  1205. (let ((alt-label (and alt (gensym "clause"))))
  1206. (call-with-values
  1207. (lambda ()
  1208. (match kw
  1209. (#f (values #f '()))
  1210. ((aok? . kw)
  1211. (values aok?
  1212. (map (match-lambda
  1213. ((key name sym)
  1214. (cons key (1+ (list-index syms sym)))))
  1215. kw)))))
  1216. (lambda (allow-other-keys? kw-indices)
  1217. (when label (emit-label asm label))
  1218. (let ((has-closure? #t) (opt (or opt '())))
  1219. (emit-begin-kw-arity asm has-closure? req opt rest kw-indices
  1220. allow-other-keys? frame-size alt-label))
  1221. (compile-body clause module-scope free frame-size)
  1222. (emit-end-arity asm)
  1223. (when alt
  1224. (emit-clause alt-label alt module-scope free)))))))))
  1225. (match closure
  1226. (($ <closure> label ($ <lambda> src meta body) module-scope free)
  1227. (when src (emit-source asm src))
  1228. (emit-begin-program asm label (sanitize-meta meta))
  1229. (emit-clause #f body module-scope free)
  1230. (emit-end-program asm))))
  1231. (define (kw-arg-ref args kw default)
  1232. (match (memq kw args)
  1233. ((_ val . _) val)
  1234. (_ default)))
  1235. (define (compile-bytecode exp env opts)
  1236. (let* ((exp (canonicalize exp))
  1237. (asm (make-assembler)))
  1238. (call-with-values (lambda () (split-closures exp))
  1239. (lambda (closures assigned)
  1240. (let ((by-code (make-hash-table)))
  1241. (for-each (lambda (closure)
  1242. (hashq-set! by-code (closure-code closure) closure))
  1243. closures)
  1244. (define (assigned? sym)
  1245. (hashq-ref assigned sym))
  1246. (define (lookup-closure x)
  1247. (or (hashq-ref by-code x) (error "missing <closure>" x)))
  1248. (for-each (lambda (closure)
  1249. (compile-closure asm closure assigned? lookup-closure))
  1250. closures))))
  1251. (values (link-assembly asm #:page-aligned? (kw-arg-ref opts #:to-file? #f))
  1252. env
  1253. env)))