compile-bytecode.scm 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013, 2014, 2015, 2017, 2018 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Commentary:
  17. ;;;
  18. ;;; Compiling CPS to bytecode. The result is in the bytecode language,
  19. ;;; which happens to be an ELF image as a bytecode.
  20. ;;;
  21. ;;; Code:
  22. (define-module (language cps compile-bytecode)
  23. #:use-module (ice-9 match)
  24. #:use-module (srfi srfi-1)
  25. #:use-module (language cps)
  26. #:use-module (language cps slot-allocation)
  27. #:use-module (language cps utils)
  28. #:use-module (language cps closure-conversion)
  29. #:use-module (language cps loop-instrumentation)
  30. #:use-module (language cps optimize)
  31. #:use-module (language cps reify-primitives)
  32. #:use-module (language cps renumber)
  33. #:use-module (language cps split-rec)
  34. #:use-module (language cps intmap)
  35. #:use-module (language cps intset)
  36. #:use-module (system vm assembler)
  37. #:use-module (system base types internal)
  38. #:export (compile-bytecode))
  39. (define (kw-arg-ref args kw default)
  40. (match (memq kw args)
  41. ((_ val . _) val)
  42. (_ default)))
  43. (define (intmap-for-each f map)
  44. (intmap-fold (lambda (k v seed) (f k v) seed) map *unspecified*))
  45. (define (intmap-select map set)
  46. (persistent-intmap
  47. (intset-fold
  48. (lambda (k out)
  49. (intmap-add! out k (intmap-ref map k)))
  50. set
  51. empty-intmap)))
  52. ;; Any $values expression that continues to a $kargs and causes no
  53. ;; shuffles is a forwarding label.
  54. (define (compute-forwarding-labels cps allocation)
  55. (fixpoint
  56. (lambda (forwarding-map)
  57. (intmap-fold (lambda (label target forwarding-map)
  58. (let ((new-target (intmap-ref forwarding-map target
  59. (lambda (target) target))))
  60. (if (eqv? target new-target)
  61. forwarding-map
  62. (intmap-replace forwarding-map label new-target))))
  63. forwarding-map forwarding-map))
  64. (intmap-fold (lambda (label cont forwarding-labels)
  65. (match cont
  66. (($ $kargs _ _ ($ $continue k _ ($ $values)))
  67. (match (lookup-parallel-moves label allocation)
  68. (()
  69. (match (intmap-ref cps k)
  70. (($ $ktail) forwarding-labels)
  71. (_ (intmap-add forwarding-labels label k))))
  72. (_ forwarding-labels)))
  73. (_ forwarding-labels)))
  74. cps empty-intmap)))
  75. (define (compile-function cps asm opts)
  76. (let* ((allocation (allocate-slots cps #:precolor-calls?
  77. (kw-arg-ref opts #:precolor-calls? #t)))
  78. (forwarding-labels (compute-forwarding-labels cps allocation))
  79. (frame-size (lookup-nlocals allocation)))
  80. (define (forward-label k)
  81. (intmap-ref forwarding-labels k (lambda (k) k)))
  82. (define (elide-cont? label)
  83. (match (intmap-ref forwarding-labels label (lambda (_) #f))
  84. (#f #f)
  85. (target (not (eqv? label target)))))
  86. (define (maybe-slot sym)
  87. (lookup-maybe-slot sym allocation))
  88. (define (slot sym)
  89. (lookup-slot sym allocation))
  90. (define (from-sp var)
  91. (- frame-size 1 var))
  92. (define (maybe-mov dst src)
  93. (unless (= dst src)
  94. (emit-mov asm (from-sp dst) (from-sp src))))
  95. (define (compile-tail label exp)
  96. ;; There are only three kinds of expressions in tail position:
  97. ;; tail calls, multiple-value returns, and single-value returns.
  98. (define (maybe-reset-frame nlocals)
  99. (unless (= frame-size nlocals)
  100. (emit-reset-frame asm nlocals)))
  101. (match exp
  102. (($ $call proc args)
  103. (for-each (match-lambda
  104. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  105. (lookup-parallel-moves label allocation))
  106. (maybe-reset-frame (1+ (length args)))
  107. (emit-handle-interrupts asm)
  108. (emit-tail-call asm))
  109. (($ $callk k proc args)
  110. (for-each (match-lambda
  111. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  112. (lookup-parallel-moves label allocation))
  113. (maybe-reset-frame (1+ (length args)))
  114. (emit-handle-interrupts asm)
  115. (emit-tail-call-label asm k))
  116. (($ $values args)
  117. (for-each (match-lambda
  118. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  119. (lookup-parallel-moves label allocation))
  120. (maybe-reset-frame (length args))
  121. (emit-handle-interrupts asm)
  122. (emit-return-values asm))))
  123. (define (compile-value label exp dst)
  124. (match exp
  125. (($ $values (arg))
  126. (maybe-mov dst (slot arg)))
  127. (($ $primcall (or 's64->u64 'u64->s64) #f (arg))
  128. (maybe-mov dst (slot arg)))
  129. (($ $const exp)
  130. (emit-load-constant asm (from-sp dst) exp))
  131. (($ $const-fun k)
  132. (emit-load-static-procedure asm (from-sp dst) k))
  133. (($ $code k)
  134. (emit-load-label asm (from-sp dst) k))
  135. (($ $primcall 'current-module)
  136. (emit-current-module asm (from-sp dst)))
  137. (($ $primcall 'current-thread)
  138. (emit-current-thread asm (from-sp dst)))
  139. (($ $primcall 'define! #f (mod sym))
  140. (emit-define! asm (from-sp dst)
  141. (from-sp (slot mod)) (from-sp (slot sym))))
  142. (($ $primcall 'resolve (bound?) (name))
  143. (emit-resolve asm (from-sp dst) bound? (from-sp (slot name))))
  144. (($ $primcall 'allocate-words annotation (nfields))
  145. (emit-allocate-words asm (from-sp dst) (from-sp (slot nfields))))
  146. (($ $primcall 'allocate-words/immediate (annotation . nfields))
  147. (emit-allocate-words/immediate asm (from-sp dst) nfields))
  148. (($ $primcall 'scm-ref annotation (obj idx))
  149. (emit-scm-ref asm (from-sp dst) (from-sp (slot obj))
  150. (from-sp (slot idx))))
  151. (($ $primcall 'scm-ref/tag annotation (obj))
  152. (let ((tag (match annotation
  153. ('pair 0)
  154. ('struct %tc5-struct))))
  155. (emit-scm-ref/tag asm (from-sp dst) (from-sp (slot obj)) tag)))
  156. (($ $primcall 'scm-ref/immediate (annotation . idx) (obj))
  157. (emit-scm-ref/immediate asm (from-sp dst) (from-sp (slot obj)) idx))
  158. (($ $primcall 'word-ref annotation (obj idx))
  159. (emit-word-ref asm (from-sp dst) (from-sp (slot obj))
  160. (from-sp (slot idx))))
  161. (($ $primcall 'word-ref/immediate (annotation . idx) (obj))
  162. (emit-word-ref/immediate asm (from-sp dst) (from-sp (slot obj)) idx))
  163. (($ $primcall 'pointer-ref/immediate (annotation . idx) (obj))
  164. (emit-pointer-ref/immediate asm (from-sp dst) (from-sp (slot obj)) idx))
  165. (($ $primcall 'tail-pointer-ref/immediate (annotation . idx) (obj))
  166. (emit-tail-pointer-ref/immediate asm (from-sp dst) (from-sp (slot obj))
  167. idx))
  168. (($ $primcall 'cache-ref key ())
  169. (emit-cache-ref asm (from-sp dst) key))
  170. (($ $primcall 'resolve-module public? (name))
  171. (emit-resolve-module asm (from-sp dst) (from-sp (slot name)) public?))
  172. (($ $primcall 'lookup #f (mod name))
  173. (emit-lookup asm (from-sp dst) (from-sp (slot mod)) (from-sp (slot name))))
  174. (($ $primcall 'add/immediate y (x))
  175. (emit-add/immediate asm (from-sp dst) (from-sp (slot x)) y))
  176. (($ $primcall 'sub/immediate y (x))
  177. (emit-sub/immediate asm (from-sp dst) (from-sp (slot x)) y))
  178. (($ $primcall 'uadd/immediate y (x))
  179. (emit-uadd/immediate asm (from-sp dst) (from-sp (slot x)) y))
  180. (($ $primcall 'usub/immediate y (x))
  181. (emit-usub/immediate asm (from-sp dst) (from-sp (slot x)) y))
  182. (($ $primcall 'umul/immediate y (x))
  183. (emit-umul/immediate asm (from-sp dst) (from-sp (slot x)) y))
  184. (($ $primcall 'rsh (x y))
  185. (emit-rsh asm (from-sp dst) (from-sp (slot x)) (from-sp (slot y))))
  186. (($ $primcall 'lsh (x y))
  187. (emit-lsh asm (from-sp dst) (from-sp (slot x)) (from-sp (slot y))))
  188. (($ $primcall 'rsh/immediate y (x))
  189. (emit-rsh/immediate asm (from-sp dst) (from-sp (slot x)) y))
  190. (($ $primcall 'lsh/immediate y (x))
  191. (emit-lsh/immediate asm (from-sp dst) (from-sp (slot x)) y))
  192. (($ $primcall 'ursh/immediate y (x))
  193. (emit-ursh/immediate asm (from-sp dst) (from-sp (slot x)) y))
  194. (($ $primcall 'srsh/immediate y (x))
  195. (emit-srsh/immediate asm (from-sp dst) (from-sp (slot x)) y))
  196. (($ $primcall 'ulsh/immediate y (x))
  197. (emit-ulsh/immediate asm (from-sp dst) (from-sp (slot x)) y))
  198. (($ $primcall 'builtin-ref idx ())
  199. (emit-builtin-ref asm (from-sp dst) idx))
  200. (($ $primcall 'scm->f64 #f (src))
  201. (emit-scm->f64 asm (from-sp dst) (from-sp (slot src))))
  202. (($ $primcall 'load-f64 val ())
  203. (emit-load-f64 asm (from-sp dst) val))
  204. (($ $primcall 'f64->scm #f (src))
  205. (emit-f64->scm asm (from-sp dst) (from-sp (slot src))))
  206. (($ $primcall 'scm->u64 #f (src))
  207. (emit-scm->u64 asm (from-sp dst) (from-sp (slot src))))
  208. (($ $primcall 'scm->u64/truncate #f (src))
  209. (emit-scm->u64/truncate asm (from-sp dst) (from-sp (slot src))))
  210. (($ $primcall 'load-u64 val ())
  211. (emit-load-u64 asm (from-sp dst) val))
  212. (($ $primcall 'u64->scm #f (src))
  213. (emit-u64->scm asm (from-sp dst) (from-sp (slot src))))
  214. (($ $primcall 'scm->s64 #f (src))
  215. (emit-scm->s64 asm (from-sp dst) (from-sp (slot src))))
  216. (($ $primcall 'load-s64 val ())
  217. (emit-load-s64 asm (from-sp dst) val))
  218. (($ $primcall 's64->scm #f (src))
  219. (emit-s64->scm asm (from-sp dst) (from-sp (slot src))))
  220. (($ $primcall 'u8-ref ann (obj ptr idx))
  221. (emit-u8-ref asm (from-sp dst) (from-sp (slot ptr))
  222. (from-sp (slot idx))))
  223. (($ $primcall 's8-ref ann (obj ptr idx))
  224. (emit-s8-ref asm (from-sp dst) (from-sp (slot ptr))
  225. (from-sp (slot idx))))
  226. (($ $primcall 'u16-ref ann (obj ptr idx))
  227. (emit-u16-ref asm (from-sp dst) (from-sp (slot ptr))
  228. (from-sp (slot idx))))
  229. (($ $primcall 's16-ref ann (obj ptr idx))
  230. (emit-s16-ref asm (from-sp dst) (from-sp (slot ptr))
  231. (from-sp (slot idx))))
  232. (($ $primcall 'u32-ref ann (obj ptr idx))
  233. (emit-u32-ref asm (from-sp dst) (from-sp (slot ptr))
  234. (from-sp (slot idx))))
  235. (($ $primcall 's32-ref ann (obj ptr idx))
  236. (emit-s32-ref asm (from-sp dst) (from-sp (slot ptr))
  237. (from-sp (slot idx))))
  238. (($ $primcall 'u64-ref ann (obj ptr idx))
  239. (emit-u64-ref asm (from-sp dst) (from-sp (slot ptr))
  240. (from-sp (slot idx))))
  241. (($ $primcall 's64-ref ann (obj ptr idx))
  242. (emit-s64-ref asm (from-sp dst) (from-sp (slot ptr))
  243. (from-sp (slot idx))))
  244. (($ $primcall 'f32-ref ann (obj ptr idx))
  245. (emit-f32-ref asm (from-sp dst) (from-sp (slot ptr))
  246. (from-sp (slot idx))))
  247. (($ $primcall 'f64-ref ann (obj ptr idx))
  248. (emit-f64-ref asm (from-sp dst) (from-sp (slot ptr))
  249. (from-sp (slot idx))))
  250. (($ $primcall 'atomic-scm-ref/immediate (annotation . idx) (obj))
  251. (emit-atomic-scm-ref/immediate asm (from-sp dst) (from-sp (slot obj))
  252. idx))
  253. (($ $primcall 'atomic-scm-swap!/immediate (annotation . idx) (obj val))
  254. (emit-atomic-scm-swap!/immediate asm (from-sp dst) (from-sp (slot obj))
  255. idx (from-sp (slot val))))
  256. (($ $primcall 'atomic-scm-compare-and-swap!/immediate (annotation . idx)
  257. (obj expected desired))
  258. (emit-atomic-scm-compare-and-swap!/immediate
  259. asm (from-sp dst) (from-sp (slot obj)) idx (from-sp (slot expected))
  260. (from-sp (slot desired))))
  261. (($ $primcall 'untag-fixnum #f (src))
  262. (emit-untag-fixnum asm (from-sp dst) (from-sp (slot src))))
  263. (($ $primcall 'tag-fixnum #f (src))
  264. (emit-tag-fixnum asm (from-sp dst) (from-sp (slot src))))
  265. (($ $primcall 'untag-char #f (src))
  266. (emit-untag-char asm (from-sp dst) (from-sp (slot src))))
  267. (($ $primcall 'tag-char #f (src))
  268. (emit-tag-char asm (from-sp dst) (from-sp (slot src))))
  269. (($ $primcall name #f args)
  270. ;; FIXME: Inline all the cases.
  271. (emit-text asm `((,name ,(from-sp dst)
  272. ,@(map (compose from-sp slot) args)))))))
  273. (define (compile-effect label exp k)
  274. (match exp
  275. (($ $values ()) #f)
  276. (($ $primcall 'cache-set! key (val))
  277. (emit-cache-set! asm key (from-sp (slot val))))
  278. (($ $primcall 'scm-set! annotation (obj idx val))
  279. (emit-scm-set! asm (from-sp (slot obj)) (from-sp (slot idx))
  280. (from-sp (slot val))))
  281. (($ $primcall 'scm-set!/tag annotation (obj val))
  282. (let ((tag (match annotation
  283. ('pair 0)
  284. ('struct %tc5-struct))))
  285. (emit-scm-set!/tag asm (from-sp (slot obj)) tag
  286. (from-sp (slot val)))))
  287. (($ $primcall 'scm-set!/immediate (annotation . idx) (obj val))
  288. (emit-scm-set!/immediate asm (from-sp (slot obj)) idx
  289. (from-sp (slot val))))
  290. (($ $primcall 'word-set! annotation (obj idx val))
  291. (emit-word-set! asm (from-sp (slot obj)) (from-sp (slot idx))
  292. (from-sp (slot val))))
  293. (($ $primcall 'word-set!/immediate (annotation . idx) (obj val))
  294. (emit-word-set!/immediate asm (from-sp (slot obj)) idx
  295. (from-sp (slot val))))
  296. (($ $primcall 'pointer-set!/immediate (annotation . idx) (obj val))
  297. (emit-pointer-set!/immediate asm (from-sp (slot obj)) idx
  298. (from-sp (slot val))))
  299. (($ $primcall 'string-set! #f (string index char))
  300. (emit-string-set! asm (from-sp (slot string)) (from-sp (slot index))
  301. (from-sp (slot char))))
  302. (($ $primcall 'push-fluid #f (fluid val))
  303. (emit-push-fluid asm (from-sp (slot fluid)) (from-sp (slot val))))
  304. (($ $primcall 'pop-fluid #f ())
  305. (emit-pop-fluid asm))
  306. (($ $primcall 'push-dynamic-state #f (state))
  307. (emit-push-dynamic-state asm (from-sp (slot state))))
  308. (($ $primcall 'pop-dynamic-state #f ())
  309. (emit-pop-dynamic-state asm))
  310. (($ $primcall 'wind #f (winder unwinder))
  311. (emit-wind asm (from-sp (slot winder)) (from-sp (slot unwinder))))
  312. (($ $primcall 'u8-set! ann (obj ptr idx val))
  313. (emit-u8-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  314. (from-sp (slot val))))
  315. (($ $primcall 's8-set! ann (obj ptr idx val))
  316. (emit-s8-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  317. (from-sp (slot val))))
  318. (($ $primcall 'u16-set! ann (obj ptr idx val))
  319. (emit-u16-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  320. (from-sp (slot val))))
  321. (($ $primcall 's16-set! ann (obj ptr idx val))
  322. (emit-s16-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  323. (from-sp (slot val))))
  324. (($ $primcall 'u32-set! ann (obj ptr idx val))
  325. (emit-u32-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  326. (from-sp (slot val))))
  327. (($ $primcall 's32-set! ann (obj ptr idx val))
  328. (emit-s32-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  329. (from-sp (slot val))))
  330. (($ $primcall 'u64-set! ann (obj ptr idx val))
  331. (emit-u64-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  332. (from-sp (slot val))))
  333. (($ $primcall 's64-set! ann (obj ptr idx val))
  334. (emit-s64-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  335. (from-sp (slot val))))
  336. (($ $primcall 'f32-set! ann (obj ptr idx val))
  337. (emit-f32-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  338. (from-sp (slot val))))
  339. (($ $primcall 'f64-set! ann (obj ptr idx val))
  340. (emit-f64-set! asm (from-sp (slot ptr)) (from-sp (slot idx))
  341. (from-sp (slot val))))
  342. (($ $primcall 'unwind #f ())
  343. (emit-unwind asm))
  344. (($ $primcall 'fluid-set! #f (fluid value))
  345. (emit-fluid-set! asm (from-sp (slot fluid)) (from-sp (slot value))))
  346. (($ $primcall 'atomic-scm-set!/immediate (annotation . idx) (obj val))
  347. (emit-atomic-scm-set!/immediate asm (from-sp (slot obj)) idx
  348. (from-sp (slot val))))
  349. (($ $primcall 'instrument-loop #f ())
  350. (emit-instrument-loop asm)
  351. (emit-handle-interrupts asm))))
  352. (define (compile-throw op param args)
  353. (match (vector op param args)
  354. (#('throw #f (key args))
  355. (emit-throw asm (from-sp (slot key)) (from-sp (slot args))))
  356. (#('throw/value param (val))
  357. (emit-throw/value asm (from-sp (slot val)) param))
  358. (#('throw/value+data param (val))
  359. (emit-throw/value+data asm (from-sp (slot val)) param))))
  360. (define (compile-prompt label k kh escape? tag)
  361. (match (intmap-ref cps kh)
  362. (($ $kreceive ($ $arity req () rest () #f) khandler-body)
  363. (let ((receive-args (gensym "handler"))
  364. (nreq (length req))
  365. (proc-slot (lookup-call-proc-slot label allocation)))
  366. (emit-prompt asm (from-sp (slot tag)) escape? proc-slot
  367. receive-args)
  368. (emit-j asm k)
  369. (emit-label asm receive-args)
  370. (unless (and rest (zero? nreq))
  371. (emit-receive-values asm proc-slot (->bool rest) nreq))
  372. (when (and rest
  373. (match (intmap-ref cps khandler-body)
  374. (($ $kargs names (_ ... rest))
  375. (maybe-slot rest))))
  376. (emit-bind-rest asm (+ proc-slot nreq)))
  377. (for-each (match-lambda
  378. ((src . dst) (emit-fmov asm dst src)))
  379. (lookup-parallel-moves kh allocation))
  380. (emit-reset-frame asm frame-size)
  381. (emit-j asm (forward-label khandler-body))))))
  382. (define (compile-values label exp syms)
  383. (match exp
  384. (($ $values args)
  385. (for-each (match-lambda
  386. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  387. (lookup-parallel-moves label allocation)))))
  388. (define (compile-test label next-label kf kt op param args)
  389. (define (prefer-true?)
  390. (if (< (max kt kf) label)
  391. ;; Two backwards branches. Prefer
  392. ;; the nearest.
  393. (> kt kf)
  394. ;; Otherwise prefer a backwards
  395. ;; branch or a near jump.
  396. (< kt kf)))
  397. (define (emit-branch emit-jt emit-jf)
  398. (cond
  399. ((eq? kt next-label)
  400. (emit-jf asm kf))
  401. ((eq? kf next-label)
  402. (emit-jt asm kt))
  403. ((prefer-true?)
  404. (emit-jt asm kt)
  405. (emit-j asm kf))
  406. (else
  407. (emit-jf asm kf)
  408. (emit-j asm kt))))
  409. (define (unary op a)
  410. (op asm (from-sp (slot a)))
  411. (emit-branch emit-je emit-jne))
  412. (define (binary op emit-jt emit-jf a b)
  413. (op asm (from-sp (slot a)) (from-sp (slot b)))
  414. (emit-branch emit-jt emit-jf))
  415. (define (binary-test op a b)
  416. (binary op emit-je emit-jne a b))
  417. (define (binary-< emit-<? a b)
  418. (binary emit-<? emit-jl emit-jnl a b))
  419. (define (binary-<= emit-<? a b)
  420. (binary emit-<? emit-jge emit-jnge b a))
  421. (define (binary-test/imm op a b)
  422. (op asm (from-sp (slot a)) b)
  423. (emit-branch emit-je emit-jne))
  424. (define (binary-</imm op a b)
  425. (op asm (from-sp (slot a)) b)
  426. (emit-branch emit-jl emit-jnl))
  427. (match (vector op param args)
  428. ;; Immediate type tag predicates.
  429. (#('fixnum? #f (a)) (unary emit-fixnum? a))
  430. (#('heap-object? #f (a)) (unary emit-heap-object? a))
  431. (#('char? #f (a)) (unary emit-char? a))
  432. (#('eq-false? #f (a)) (unary emit-eq-false? a))
  433. (#('eq-nil? #f (a)) (unary emit-eq-nil? a))
  434. (#('eq-null? #f (a)) (unary emit-eq-null? a))
  435. (#('eq-true? #f (a)) (unary emit-eq-true? a))
  436. (#('unspecified? #f (a)) (unary emit-unspecified? a))
  437. (#('undefined? #f (a)) (unary emit-undefined? a))
  438. (#('eof-object? #f (a)) (unary emit-eof-object? a))
  439. (#('null? #f (a)) (unary emit-null? a))
  440. (#('false? #f (a)) (unary emit-false? a))
  441. (#('nil? #f (a)) (unary emit-nil? a))
  442. ;; Heap type tag predicates.
  443. (#('non-pair-heap-object? #f (a)) (unary emit-non-pair-heap-object? a))
  444. (#('struct? #f (a)) (unary emit-struct? a))
  445. (#('symbol? #f (a)) (unary emit-symbol? a))
  446. (#('variable? #f (a)) (unary emit-variable? a))
  447. (#('vector? #f (a)) (unary emit-vector? a))
  448. (#('mutable-vector? #f (a)) (unary emit-mutable-vector? a))
  449. (#('immutable-vector? #f (a)) (unary emit-immutable-vector? a))
  450. (#('string? #f (a)) (unary emit-string? a))
  451. (#('heap-number? #f (a)) (unary emit-heap-number? a))
  452. (#('hash-table? #f (a)) (unary emit-hash-table? a))
  453. (#('pointer? #f (a)) (unary emit-pointer? a))
  454. (#('fluid? #f (a)) (unary emit-fluid? a))
  455. (#('stringbuf? #f (a)) (unary emit-stringbuf? a))
  456. (#('dynamic-state? #f (a)) (unary emit-dynamic-state? a))
  457. (#('frame? #f (a)) (unary emit-frame? a))
  458. (#('keyword? #f (a)) (unary emit-keyword? a))
  459. (#('atomic-box? #f (a)) (unary emit-atomic-box? a))
  460. (#('syntax? #f (a)) (unary emit-syntax? a))
  461. (#('program? #f (a)) (unary emit-program? a))
  462. (#('vm-continuation? #f (a)) (unary emit-vm-continuation? a))
  463. (#('bytevector? #f (a)) (unary emit-bytevector? a))
  464. (#('weak-set? #f (a)) (unary emit-weak-set? a))
  465. (#('weak-table? #f (a)) (unary emit-weak-table? a))
  466. (#('array? #f (a)) (unary emit-array? a))
  467. (#('bitvector? #f (a)) (unary emit-bitvector? a))
  468. (#('smob? #f (a)) (unary emit-smob? a))
  469. (#('port? #f (a)) (unary emit-port? a))
  470. (#('bignum? #f (a)) (unary emit-bignum? a))
  471. (#('flonum? #f (a)) (unary emit-flonum? a))
  472. (#('compnum? #f (a)) (unary emit-compnum? a))
  473. (#('fracnum? #f (a)) (unary emit-fracnum? a))
  474. ;; Binary predicates.
  475. (#('eq? #f (a b)) (binary-test emit-eq? a b))
  476. (#('heap-numbers-equal? #f (a b))
  477. (binary-test emit-heap-numbers-equal? a b))
  478. (#('< #f (a b)) (binary-< emit-<? a b))
  479. (#('<= #f (a b)) (binary-<= emit-<? a b))
  480. (#('= #f (a b)) (binary-test emit-=? a b))
  481. (#('u64-< #f (a b)) (binary-< emit-u64<? a b))
  482. (#('u64-imm-< b (a)) (binary-</imm emit-u64-imm<? a b))
  483. (#('imm-u64-< b (a)) (binary-</imm emit-imm-u64<? a b))
  484. (#('u64-= #f (a b)) (binary-test emit-u64=? a b))
  485. (#('u64-imm-= b (a)) (binary-test/imm emit-s64-imm=? a b))
  486. (#('s64-= #f (a b)) (binary-test emit-u64=? a b))
  487. (#('s64-imm-= b (a)) (binary-test/imm emit-s64-imm=? a b))
  488. (#('s64-< #f (a b)) (binary-< emit-s64<? a b))
  489. (#('s64-imm-< b (a)) (binary-</imm emit-s64-imm<? a b))
  490. (#('imm-s64-< b (a)) (binary-</imm emit-imm-s64<? a b))
  491. (#('f64-< #f (a b)) (binary-< emit-f64<? a b))
  492. (#('f64-<= #f (a b)) (binary-<= emit-f64<? a b))
  493. (#('f64-= #f (a b)) (binary-test emit-f64=? a b))))
  494. (define (compile-trunc label k exp nreq rest-var)
  495. (define (do-call proc args emit-call)
  496. (let* ((proc-slot (lookup-call-proc-slot label allocation))
  497. (nargs (1+ (length args)))
  498. (arg-slots (map (lambda (x) (+ x proc-slot)) (iota nargs))))
  499. (for-each (match-lambda
  500. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  501. (lookup-parallel-moves label allocation))
  502. (emit-handle-interrupts asm)
  503. (emit-call asm proc-slot nargs)
  504. (emit-slot-map asm proc-slot (lookup-slot-map label allocation))
  505. (cond
  506. ((and (= 1 nreq) (and rest-var) (not (maybe-slot rest-var))
  507. (match (lookup-parallel-moves k allocation)
  508. ((((? (lambda (src) (= src proc-slot)) src)
  509. . dst)) dst)
  510. (_ #f)))
  511. ;; The usual case: one required live return value, ignoring
  512. ;; any additional values.
  513. => (lambda (dst)
  514. (emit-receive asm dst proc-slot frame-size)))
  515. (else
  516. (unless (and (zero? nreq) rest-var)
  517. (emit-receive-values asm proc-slot (->bool rest-var) nreq))
  518. (when (and rest-var (maybe-slot rest-var))
  519. (emit-bind-rest asm (+ proc-slot nreq)))
  520. (for-each (match-lambda
  521. ((src . dst) (emit-fmov asm dst src)))
  522. (lookup-parallel-moves k allocation))
  523. (emit-reset-frame asm frame-size)))))
  524. (match exp
  525. (($ $call proc args)
  526. (do-call proc args
  527. (lambda (asm proc-slot nargs)
  528. (emit-call asm proc-slot nargs))))
  529. (($ $callk k proc args)
  530. (do-call proc args
  531. (lambda (asm proc-slot nargs)
  532. (emit-call-label asm proc-slot nargs k))))))
  533. (define (skip-elided-conts label)
  534. (if (elide-cont? label)
  535. (skip-elided-conts (1+ label))
  536. label))
  537. (define (compile-expression label k exp)
  538. (let* ((forwarded-k (forward-label k))
  539. (fallthrough? (= forwarded-k (skip-elided-conts (1+ label)))))
  540. (define (maybe-emit-jump)
  541. (unless fallthrough?
  542. (emit-j asm forwarded-k)))
  543. (match (intmap-ref cps k)
  544. (($ $ktail)
  545. (compile-tail label exp))
  546. (($ $kargs (name) (sym))
  547. (let ((dst (maybe-slot sym)))
  548. (when dst
  549. (compile-value label exp dst)))
  550. (maybe-emit-jump))
  551. (($ $kargs () ())
  552. (compile-effect label exp k)
  553. (maybe-emit-jump))
  554. (($ $kargs names syms)
  555. (compile-values label exp syms)
  556. (maybe-emit-jump))
  557. (($ $kreceive ($ $arity req () rest () #f) kargs)
  558. (compile-trunc label k exp (length req)
  559. (and rest
  560. (match (intmap-ref cps kargs)
  561. (($ $kargs names (_ ... rest)) rest))))
  562. (let* ((kargs (forward-label kargs))
  563. (fallthrough? (and fallthrough?
  564. (= kargs (skip-elided-conts (1+ k))))))
  565. (unless fallthrough?
  566. (emit-j asm kargs)))))))
  567. (define (compile-term label term)
  568. (match term
  569. (($ $continue k src exp)
  570. (when src
  571. (emit-source asm src))
  572. (unless (elide-cont? label)
  573. (compile-expression label k exp)))
  574. (($ $branch kf kt src op param args)
  575. (when src
  576. (emit-source asm src))
  577. (compile-test label (skip-elided-conts (1+ label))
  578. (forward-label kf) (forward-label kt)
  579. op param args))
  580. (($ $prompt k kh src escape? tag)
  581. (when src
  582. (emit-source asm src))
  583. (compile-prompt label (skip-elided-conts k) kh escape? tag))
  584. (($ $throw src op param args)
  585. (when src
  586. (emit-source asm src))
  587. (compile-throw op param args))))
  588. (define (compile-cont label cont)
  589. (match cont
  590. (($ $kfun src meta self tail clause)
  591. (when src
  592. (emit-source asm src))
  593. (emit-begin-program asm label meta))
  594. (($ $kclause ($ $arity req opt rest kw allow-other-keys?) body alt)
  595. (let ((first? (match (intmap-ref cps (1- label))
  596. (($ $kfun) #t)
  597. (_ #f)))
  598. (kw-indices (map (match-lambda
  599. ((key name sym)
  600. (cons key (lookup-slot sym allocation))))
  601. kw)))
  602. (unless first?
  603. (emit-end-arity asm))
  604. (emit-label asm label)
  605. (emit-begin-kw-arity asm req opt rest kw-indices allow-other-keys?
  606. frame-size alt)
  607. ;; All arities define a closure binding in slot 0.
  608. (emit-definition asm 'closure 0 'scm)
  609. ;; Usually we just fall through, but it could be the body is
  610. ;; contified into another clause.
  611. (let ((body (forward-label body)))
  612. (unless (= body (skip-elided-conts (1+ label)))
  613. (emit-j asm body)))))
  614. (($ $kargs names vars term)
  615. (emit-label asm label)
  616. (for-each (lambda (name var)
  617. (let ((slot (maybe-slot var)))
  618. (when slot
  619. (let ((repr (lookup-representation var allocation)))
  620. (emit-definition asm name slot repr)))))
  621. names vars)
  622. (compile-term label term))
  623. (($ $kreceive arity kargs)
  624. (emit-label asm label))
  625. (($ $ktail)
  626. (emit-end-arity asm)
  627. (emit-end-program asm))))
  628. (intmap-for-each compile-cont cps)))
  629. (define (emit-bytecode exp env opts)
  630. (let ((asm (make-assembler)))
  631. (intmap-for-each (lambda (kfun body)
  632. (compile-function (intmap-select exp body) asm opts))
  633. (compute-reachable-functions exp 0))
  634. (values (link-assembly asm #:page-aligned? (kw-arg-ref opts #:to-file? #f))
  635. env
  636. env)))
  637. (define (lower-cps exp opts)
  638. ;; FIXME: For now the closure conversion pass relies on $rec instances
  639. ;; being separated into SCCs. We should fix this to not be the case,
  640. ;; and instead move the split-rec pass back to
  641. ;; optimize-higher-order-cps.
  642. (set! exp (split-rec exp))
  643. (set! exp (optimize-higher-order-cps exp opts))
  644. (set! exp (convert-closures exp))
  645. (set! exp (optimize-first-order-cps exp opts))
  646. (set! exp (reify-primitives exp))
  647. (set! exp (add-loop-instrumentation exp))
  648. (renumber exp))
  649. (define (compile-bytecode exp env opts)
  650. (set! exp (lower-cps exp opts))
  651. (emit-bytecode exp env opts))