compile-bytecode.scm 54 KB

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