compile-bytecode.scm 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013, 2014, 2015 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 primitives)
  27. #:use-module (language cps slot-allocation)
  28. #:use-module (language cps utils)
  29. #:use-module (language cps closure-conversion)
  30. #:use-module (language cps handle-interrupts)
  31. #:use-module (language cps optimize)
  32. #:use-module (language cps reify-primitives)
  33. #:use-module (language cps renumber)
  34. #:use-module (language cps split-rec)
  35. #:use-module (language cps intmap)
  36. #:use-module (language cps intset)
  37. #:use-module (system vm assembler)
  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)
  76. (let* ((allocation (allocate-slots cps))
  77. (forwarding-labels (compute-forwarding-labels cps allocation))
  78. (frame-size #f))
  79. (define (forward-label k)
  80. (intmap-ref forwarding-labels k (lambda (k) k)))
  81. (define (elide-cont? label)
  82. (match (intmap-ref forwarding-labels label (lambda (_) #f))
  83. (#f #f)
  84. (target (not (eqv? label target)))))
  85. (define (maybe-slot sym)
  86. (lookup-maybe-slot sym allocation))
  87. (define (slot sym)
  88. (lookup-slot sym allocation))
  89. (define (constant sym)
  90. (lookup-constant-value sym allocation))
  91. (define (from-sp var)
  92. (- frame-size 1 var))
  93. (define (maybe-mov dst src)
  94. (unless (= dst src)
  95. (emit-mov asm (from-sp dst) (from-sp src))))
  96. (define (compile-tail label exp)
  97. ;; There are only three kinds of expressions in tail position:
  98. ;; tail calls, multiple-value returns, and single-value returns.
  99. (match exp
  100. (($ $call proc args)
  101. (for-each (match-lambda
  102. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  103. (lookup-parallel-moves label allocation))
  104. (emit-tail-call asm (1+ (length args))))
  105. (($ $callk k proc args)
  106. (for-each (match-lambda
  107. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  108. (lookup-parallel-moves label allocation))
  109. (emit-tail-call-label asm (1+ (length args)) k))
  110. (($ $values args)
  111. (for-each (match-lambda
  112. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  113. (lookup-parallel-moves label allocation))
  114. (emit-return-values asm (1+ (length args))))))
  115. (define (compile-value label exp dst)
  116. (match exp
  117. (($ $values (arg))
  118. (maybe-mov dst (slot arg)))
  119. (($ $const exp)
  120. (emit-load-constant asm (from-sp dst) exp))
  121. (($ $closure k 0)
  122. (emit-load-static-procedure asm (from-sp dst) k))
  123. (($ $closure k nfree)
  124. (emit-make-closure asm (from-sp dst) k nfree))
  125. (($ $primcall 'current-module)
  126. (emit-current-module asm (from-sp dst)))
  127. (($ $primcall 'current-thread)
  128. (emit-current-thread asm (from-sp dst)))
  129. (($ $primcall 'cached-toplevel-box (scope name bound?))
  130. (emit-cached-toplevel-box asm (from-sp dst)
  131. (constant scope) (constant name)
  132. (constant bound?)))
  133. (($ $primcall 'cached-module-box (mod name public? bound?))
  134. (emit-cached-module-box asm (from-sp dst)
  135. (constant mod) (constant name)
  136. (constant public?) (constant bound?)))
  137. (($ $primcall 'define! (sym))
  138. (emit-define! asm (from-sp dst) (from-sp (slot sym))))
  139. (($ $primcall 'resolve (name bound?))
  140. (emit-resolve asm (from-sp dst) (constant bound?)
  141. (from-sp (slot name))))
  142. (($ $primcall 'free-ref (closure idx))
  143. (emit-free-ref asm (from-sp dst) (from-sp (slot closure))
  144. (constant idx)))
  145. (($ $primcall 'vector-ref (vector index))
  146. (emit-vector-ref asm (from-sp dst) (from-sp (slot vector))
  147. (from-sp (slot index))))
  148. (($ $primcall 'make-vector (length init))
  149. (emit-make-vector asm (from-sp dst) (from-sp (slot length))
  150. (from-sp (slot init))))
  151. (($ $primcall 'make-vector/immediate (length init))
  152. (emit-make-vector/immediate asm (from-sp dst) (constant length)
  153. (from-sp (slot init))))
  154. (($ $primcall 'vector-ref/immediate (vector index))
  155. (emit-vector-ref/immediate asm (from-sp dst) (from-sp (slot vector))
  156. (constant index)))
  157. (($ $primcall 'allocate-struct (vtable nfields))
  158. (emit-allocate-struct asm (from-sp dst) (from-sp (slot vtable))
  159. (from-sp (slot nfields))))
  160. (($ $primcall 'allocate-struct/immediate (vtable nfields))
  161. (emit-allocate-struct/immediate asm (from-sp dst)
  162. (from-sp (slot vtable))
  163. (constant nfields)))
  164. (($ $primcall 'struct-ref (struct n))
  165. (emit-struct-ref asm (from-sp dst) (from-sp (slot struct))
  166. (from-sp (slot n))))
  167. (($ $primcall 'struct-ref/immediate (struct n))
  168. (emit-struct-ref/immediate asm (from-sp dst) (from-sp (slot struct))
  169. (constant n)))
  170. (($ $primcall 'char->integer (src))
  171. (emit-char->integer asm (from-sp dst) (from-sp (slot src))))
  172. (($ $primcall 'integer->char (src))
  173. (emit-integer->char asm (from-sp dst) (from-sp (slot src))))
  174. (($ $primcall 'add/immediate (x y))
  175. (emit-add/immediate asm (from-sp dst) (from-sp (slot x)) (constant y)))
  176. (($ $primcall 'sub/immediate (x y))
  177. (emit-sub/immediate asm (from-sp dst) (from-sp (slot x)) (constant y)))
  178. (($ $primcall 'uadd/immediate (x y))
  179. (emit-uadd/immediate asm (from-sp dst) (from-sp (slot x))
  180. (constant y)))
  181. (($ $primcall 'usub/immediate (x y))
  182. (emit-usub/immediate asm (from-sp dst) (from-sp (slot x))
  183. (constant y)))
  184. (($ $primcall 'umul/immediate (x y))
  185. (emit-umul/immediate asm (from-sp dst) (from-sp (slot x))
  186. (constant y)))
  187. (($ $primcall 'ursh/immediate (x y))
  188. (emit-ursh/immediate asm (from-sp dst) (from-sp (slot x))
  189. (constant y)))
  190. (($ $primcall 'ulsh/immediate (x y))
  191. (emit-ulsh/immediate asm (from-sp dst) (from-sp (slot x))
  192. (constant y)))
  193. (($ $primcall 'builtin-ref (name))
  194. (emit-builtin-ref asm (from-sp dst) (constant name)))
  195. (($ $primcall 'scm->f64 (src))
  196. (emit-scm->f64 asm (from-sp dst) (from-sp (slot src))))
  197. (($ $primcall 'load-f64 (src))
  198. (emit-load-f64 asm (from-sp dst) (constant src)))
  199. (($ $primcall 'f64->scm (src))
  200. (emit-f64->scm asm (from-sp dst) (from-sp (slot src))))
  201. (($ $primcall 'scm->u64 (src))
  202. (emit-scm->u64 asm (from-sp dst) (from-sp (slot src))))
  203. (($ $primcall 'scm->u64/truncate (src))
  204. (emit-scm->u64/truncate asm (from-sp dst) (from-sp (slot src))))
  205. (($ $primcall 'load-u64 (src))
  206. (emit-load-u64 asm (from-sp dst) (constant src)))
  207. (($ $primcall 'u64->scm (src))
  208. (emit-u64->scm asm (from-sp dst) (from-sp (slot src))))
  209. (($ $primcall 'scm->s64 (src))
  210. (emit-scm->s64 asm (from-sp dst) (from-sp (slot src))))
  211. (($ $primcall 'load-s64 (src))
  212. (emit-load-s64 asm (from-sp dst) (constant src)))
  213. (($ $primcall 's64->scm (src))
  214. (emit-s64->scm asm (from-sp dst) (from-sp (slot src))))
  215. (($ $primcall 'bv-length (bv))
  216. (emit-bv-length asm (from-sp dst) (from-sp (slot bv))))
  217. (($ $primcall 'bv-u8-ref (bv idx))
  218. (emit-bv-u8-ref asm (from-sp dst) (from-sp (slot bv))
  219. (from-sp (slot idx))))
  220. (($ $primcall 'bv-s8-ref (bv idx))
  221. (emit-bv-s8-ref asm (from-sp dst) (from-sp (slot bv))
  222. (from-sp (slot idx))))
  223. (($ $primcall 'bv-u16-ref (bv idx))
  224. (emit-bv-u16-ref asm (from-sp dst) (from-sp (slot bv))
  225. (from-sp (slot idx))))
  226. (($ $primcall 'bv-s16-ref (bv idx))
  227. (emit-bv-s16-ref asm (from-sp dst) (from-sp (slot bv))
  228. (from-sp (slot idx))))
  229. (($ $primcall 'bv-u32-ref (bv idx val))
  230. (emit-bv-u32-ref asm (from-sp dst) (from-sp (slot bv))
  231. (from-sp (slot idx))))
  232. (($ $primcall 'bv-s32-ref (bv idx val))
  233. (emit-bv-s32-ref asm (from-sp dst) (from-sp (slot bv))
  234. (from-sp (slot idx))))
  235. (($ $primcall 'bv-u64-ref (bv idx val))
  236. (emit-bv-u64-ref asm (from-sp dst) (from-sp (slot bv))
  237. (from-sp (slot idx))))
  238. (($ $primcall 'bv-s64-ref (bv idx val))
  239. (emit-bv-s64-ref asm (from-sp dst) (from-sp (slot bv))
  240. (from-sp (slot idx))))
  241. (($ $primcall 'bv-f32-ref (bv idx val))
  242. (emit-bv-f32-ref asm (from-sp dst) (from-sp (slot bv))
  243. (from-sp (slot idx))))
  244. (($ $primcall 'bv-f64-ref (bv idx val))
  245. (emit-bv-f64-ref asm (from-sp dst) (from-sp (slot bv))
  246. (from-sp (slot idx))))
  247. (($ $primcall 'make-atomic-box (init))
  248. (emit-make-atomic-box asm (from-sp dst) (from-sp (slot init))))
  249. (($ $primcall 'atomic-box-ref (box))
  250. (emit-atomic-box-ref asm (from-sp dst) (from-sp (slot box))))
  251. (($ $primcall 'atomic-box-swap! (box val))
  252. (emit-atomic-box-swap! asm (from-sp dst) (from-sp (slot box))
  253. (from-sp (slot val))))
  254. (($ $primcall 'atomic-box-compare-and-swap! (box expected desired))
  255. (emit-atomic-box-compare-and-swap!
  256. asm (from-sp dst) (from-sp (slot box))
  257. (from-sp (slot expected)) (from-sp (slot desired))))
  258. (($ $primcall name args)
  259. ;; FIXME: Inline all the cases.
  260. (let ((inst (prim-instruction name)))
  261. (emit-text asm `((,inst ,(from-sp dst)
  262. ,@(map (compose from-sp slot) args))))))))
  263. (define (compile-effect label exp k)
  264. (match exp
  265. (($ $values ()) #f)
  266. (($ $prompt escape? tag handler)
  267. (match (intmap-ref cps handler)
  268. (($ $kreceive ($ $arity req () rest () #f) khandler-body)
  269. (let ((receive-args (gensym "handler"))
  270. (nreq (length req))
  271. (proc-slot (lookup-call-proc-slot label allocation)))
  272. (emit-prompt asm (from-sp (slot tag)) escape? proc-slot
  273. receive-args)
  274. (emit-br asm k)
  275. (emit-label asm receive-args)
  276. (unless (and rest (zero? nreq))
  277. (emit-receive-values asm proc-slot (->bool rest) nreq))
  278. (when (and rest
  279. (match (intmap-ref cps khandler-body)
  280. (($ $kargs names (_ ... rest))
  281. (maybe-slot rest))))
  282. (emit-bind-rest asm (+ proc-slot 1 nreq)))
  283. (for-each (match-lambda
  284. ((src . dst) (emit-fmov asm dst src)))
  285. (lookup-parallel-moves handler allocation))
  286. (emit-reset-frame asm frame-size)
  287. (emit-br asm (forward-label khandler-body))))))
  288. (($ $primcall 'cache-current-module! (sym scope))
  289. (emit-cache-current-module! asm (from-sp (slot sym)) (constant scope)))
  290. (($ $primcall 'free-set! (closure idx value))
  291. (emit-free-set! asm (from-sp (slot closure)) (from-sp (slot value))
  292. (constant idx)))
  293. (($ $primcall 'box-set! (box value))
  294. (emit-box-set! asm (from-sp (slot box)) (from-sp (slot value))))
  295. (($ $primcall 'struct-set! (struct index value))
  296. (emit-struct-set! asm (from-sp (slot struct)) (from-sp (slot index))
  297. (from-sp (slot value))))
  298. (($ $primcall 'struct-set!/immediate (struct index value))
  299. (emit-struct-set!/immediate asm (from-sp (slot struct))
  300. (constant index) (from-sp (slot value))))
  301. (($ $primcall 'vector-set! (vector index value))
  302. (emit-vector-set! asm (from-sp (slot vector)) (from-sp (slot index))
  303. (from-sp (slot value))))
  304. (($ $primcall 'vector-set!/immediate (vector index value))
  305. (emit-vector-set!/immediate asm (from-sp (slot vector))
  306. (constant index) (from-sp (slot value))))
  307. (($ $primcall 'set-car! (pair value))
  308. (emit-set-car! asm (from-sp (slot pair)) (from-sp (slot value))))
  309. (($ $primcall 'set-cdr! (pair value))
  310. (emit-set-cdr! asm (from-sp (slot pair)) (from-sp (slot value))))
  311. (($ $primcall 'push-fluid (fluid val))
  312. (emit-push-fluid asm (from-sp (slot fluid)) (from-sp (slot val))))
  313. (($ $primcall 'pop-fluid ())
  314. (emit-pop-fluid asm))
  315. (($ $primcall 'wind (winder unwinder))
  316. (emit-wind asm (from-sp (slot winder)) (from-sp (slot unwinder))))
  317. (($ $primcall 'bv-u8-set! (bv idx val))
  318. (emit-bv-u8-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  319. (from-sp (slot val))))
  320. (($ $primcall 'bv-s8-set! (bv idx val))
  321. (emit-bv-s8-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  322. (from-sp (slot val))))
  323. (($ $primcall 'bv-u16-set! (bv idx val))
  324. (emit-bv-u16-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  325. (from-sp (slot val))))
  326. (($ $primcall 'bv-s16-set! (bv idx val))
  327. (emit-bv-s16-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  328. (from-sp (slot val))))
  329. (($ $primcall 'bv-u32-set! (bv idx val))
  330. (emit-bv-u32-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  331. (from-sp (slot val))))
  332. (($ $primcall 'bv-s32-set! (bv idx val))
  333. (emit-bv-s32-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  334. (from-sp (slot val))))
  335. (($ $primcall 'bv-u64-set! (bv idx val))
  336. (emit-bv-u64-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  337. (from-sp (slot val))))
  338. (($ $primcall 'bv-s64-set! (bv idx val))
  339. (emit-bv-s64-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  340. (from-sp (slot val))))
  341. (($ $primcall 'bv-f32-set! (bv idx val))
  342. (emit-bv-f32-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  343. (from-sp (slot val))))
  344. (($ $primcall 'bv-f64-set! (bv idx val))
  345. (emit-bv-f64-set! asm (from-sp (slot bv)) (from-sp (slot idx))
  346. (from-sp (slot val))))
  347. (($ $primcall 'unwind ())
  348. (emit-unwind asm))
  349. (($ $primcall 'atomic-box-set! (box val))
  350. (emit-atomic-box-set! asm (from-sp (slot box)) (from-sp (slot val))))
  351. (($ $primcall 'handle-interrupts ())
  352. (emit-handle-interrupts asm))))
  353. (define (compile-values label exp syms)
  354. (match exp
  355. (($ $values args)
  356. (for-each (match-lambda
  357. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  358. (lookup-parallel-moves label allocation)))))
  359. (define (compile-test label exp kt kf next-label)
  360. (define (prefer-true?)
  361. (if (< (max kt kf) label)
  362. ;; Two backwards branches. Prefer
  363. ;; the nearest.
  364. (> kt kf)
  365. ;; Otherwise prefer a backwards
  366. ;; branch or a near jump.
  367. (< kt kf)))
  368. (define (unary op sym)
  369. (cond
  370. ((eq? kt next-label)
  371. (op asm (from-sp (slot sym)) #t kf))
  372. ((eq? kf next-label)
  373. (op asm (from-sp (slot sym)) #f kt))
  374. (else
  375. (let ((invert? (not (prefer-true?))))
  376. (op asm (from-sp (slot sym)) invert? (if invert? kf kt))
  377. (emit-br asm (if invert? kt kf))))))
  378. (define (binary op a b)
  379. (cond
  380. ((eq? kt next-label)
  381. (op asm (from-sp (slot a)) (from-sp (slot b)) #t kf))
  382. ((eq? kf next-label)
  383. (op asm (from-sp (slot a)) (from-sp (slot b)) #f kt))
  384. (else
  385. (let ((invert? (not (prefer-true?))))
  386. (op asm (from-sp (slot a)) (from-sp (slot b)) invert?
  387. (if invert? kf kt))
  388. (emit-br asm (if invert? kt kf))))))
  389. (match exp
  390. (($ $values (sym)) (unary emit-br-if-true sym))
  391. (($ $primcall 'null? (a)) (unary emit-br-if-null a))
  392. (($ $primcall 'nil? (a)) (unary emit-br-if-nil a))
  393. (($ $primcall 'pair? (a)) (unary emit-br-if-pair a))
  394. (($ $primcall 'struct? (a)) (unary emit-br-if-struct a))
  395. (($ $primcall 'char? (a)) (unary emit-br-if-char a))
  396. (($ $primcall 'symbol? (a)) (unary emit-br-if-symbol a))
  397. (($ $primcall 'variable? (a)) (unary emit-br-if-variable a))
  398. (($ $primcall 'vector? (a)) (unary emit-br-if-vector a))
  399. (($ $primcall 'string? (a)) (unary emit-br-if-string a))
  400. (($ $primcall 'bytevector? (a)) (unary emit-br-if-bytevector a))
  401. (($ $primcall 'bitvector? (a)) (unary emit-br-if-bitvector a))
  402. (($ $primcall 'keyword? (a)) (unary emit-br-if-keyword a))
  403. ;; Add more TC7 tests here. Keep in sync with
  404. ;; *branching-primcall-arities* in (language cps primitives) and
  405. ;; the set of macro-instructions in assembly.scm.
  406. (($ $primcall 'eq? (a b)) (binary emit-br-if-eq a b))
  407. (($ $primcall 'eqv? (a b)) (binary emit-br-if-eqv a b))
  408. (($ $primcall '< (a b)) (binary emit-br-if-< a b))
  409. (($ $primcall '<= (a b)) (binary emit-br-if-<= a b))
  410. (($ $primcall '= (a b)) (binary emit-br-if-= a b))
  411. (($ $primcall '>= (a b)) (binary emit-br-if-<= b a))
  412. (($ $primcall '> (a b)) (binary emit-br-if-< b a))
  413. (($ $primcall 'u64-< (a b)) (binary emit-br-if-u64-< a b))
  414. (($ $primcall 'u64-<= (a b)) (binary emit-br-if-u64-<= a b))
  415. (($ $primcall 'u64-= (a b)) (binary emit-br-if-u64-= a b))
  416. (($ $primcall 'u64->= (a b)) (binary emit-br-if-u64-<= b a))
  417. (($ $primcall 'u64-> (a b)) (binary emit-br-if-u64-< b a))
  418. (($ $primcall 'u64-<-scm (a b)) (binary emit-br-if-u64-<-scm a b))
  419. (($ $primcall 'u64-<=-scm (a b)) (binary emit-br-if-u64-<=-scm a b))
  420. (($ $primcall 'u64-=-scm (a b)) (binary emit-br-if-u64-=-scm a b))
  421. (($ $primcall 'u64->=-scm (a b)) (binary emit-br-if-u64->=-scm a b))
  422. (($ $primcall 'u64->-scm (a b)) (binary emit-br-if-u64->-scm a b))
  423. (($ $primcall 'logtest (a b)) (binary emit-br-if-logtest a b))))
  424. (define (compile-trunc label k exp nreq rest-var)
  425. (define (do-call proc args emit-call)
  426. (let* ((proc-slot (lookup-call-proc-slot label allocation))
  427. (nargs (1+ (length args)))
  428. (arg-slots (map (lambda (x) (+ x proc-slot)) (iota nargs))))
  429. (for-each (match-lambda
  430. ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
  431. (lookup-parallel-moves label allocation))
  432. (emit-call asm proc-slot nargs)
  433. (emit-slot-map asm proc-slot (lookup-slot-map label allocation))
  434. (cond
  435. ((and (= 1 nreq) (and rest-var) (not (maybe-slot rest-var))
  436. (match (lookup-parallel-moves k allocation)
  437. ((((? (lambda (src) (= src (1+ proc-slot))) src)
  438. . dst)) dst)
  439. (_ #f)))
  440. ;; The usual case: one required live return value, ignoring
  441. ;; any additional values.
  442. => (lambda (dst)
  443. (emit-receive asm dst proc-slot frame-size)))
  444. (else
  445. (unless (and (zero? nreq) rest-var)
  446. (emit-receive-values asm proc-slot (->bool rest-var) nreq))
  447. (when (and rest-var (maybe-slot rest-var))
  448. (emit-bind-rest asm (+ proc-slot 1 nreq)))
  449. (for-each (match-lambda
  450. ((src . dst) (emit-fmov asm dst src)))
  451. (lookup-parallel-moves k allocation))
  452. (emit-reset-frame asm frame-size)))))
  453. (match exp
  454. (($ $call proc args)
  455. (do-call proc args
  456. (lambda (asm proc-slot nargs)
  457. (emit-call asm proc-slot nargs))))
  458. (($ $callk k proc args)
  459. (do-call proc args
  460. (lambda (asm proc-slot nargs)
  461. (emit-call-label asm proc-slot nargs k))))))
  462. (define (skip-elided-conts label)
  463. (if (elide-cont? label)
  464. (skip-elided-conts (1+ label))
  465. label))
  466. (define (compile-expression label k exp)
  467. (let* ((forwarded-k (forward-label k))
  468. (fallthrough? (= forwarded-k (skip-elided-conts (1+ label)))))
  469. (define (maybe-emit-jump)
  470. (unless fallthrough?
  471. (emit-br asm forwarded-k)))
  472. (match (intmap-ref cps k)
  473. (($ $ktail)
  474. (compile-tail label exp))
  475. (($ $kargs (name) (sym))
  476. (let ((dst (maybe-slot sym)))
  477. (when dst
  478. (compile-value label exp dst)))
  479. (maybe-emit-jump))
  480. (($ $kargs () ())
  481. (match exp
  482. (($ $branch kt exp)
  483. (compile-test label exp (forward-label kt) forwarded-k
  484. (skip-elided-conts (1+ label))))
  485. (_
  486. (compile-effect label exp k)
  487. (maybe-emit-jump))))
  488. (($ $kargs names syms)
  489. (compile-values label exp syms)
  490. (maybe-emit-jump))
  491. (($ $kreceive ($ $arity req () rest () #f) kargs)
  492. (compile-trunc label k exp (length req)
  493. (and rest
  494. (match (intmap-ref cps kargs)
  495. (($ $kargs names (_ ... rest)) rest))))
  496. (let* ((kargs (forward-label kargs))
  497. (fallthrough? (and fallthrough?
  498. (= kargs (skip-elided-conts (1+ k))))))
  499. (unless fallthrough?
  500. (emit-br asm kargs)))))))
  501. (define (compile-cont label cont)
  502. (match cont
  503. (($ $kfun src meta self tail clause)
  504. (when src
  505. (emit-source asm src))
  506. (emit-begin-program asm label meta))
  507. (($ $kclause ($ $arity req opt rest kw allow-other-keys?) body alt)
  508. (let ((first? (match (intmap-ref cps (1- label))
  509. (($ $kfun) #t)
  510. (_ #f)))
  511. (kw-indices (map (match-lambda
  512. ((key name sym)
  513. (cons key (lookup-slot sym allocation))))
  514. kw)))
  515. (unless first?
  516. (emit-end-arity asm))
  517. (emit-label asm label)
  518. (set! frame-size (lookup-nlocals label allocation))
  519. (emit-begin-kw-arity asm req opt rest kw-indices allow-other-keys?
  520. frame-size alt)
  521. ;; All arities define a closure binding in slot 0.
  522. (emit-definition asm 'closure 0 'scm)))
  523. (($ $kargs names vars ($ $continue k src exp))
  524. (emit-label asm label)
  525. (for-each (lambda (name var)
  526. (let ((slot (maybe-slot var)))
  527. (when slot
  528. (let ((repr (lookup-representation var allocation)))
  529. (emit-definition asm name slot repr)))))
  530. names vars)
  531. (when src
  532. (emit-source asm src))
  533. (unless (elide-cont? label)
  534. (compile-expression label k exp)))
  535. (($ $kreceive arity kargs)
  536. (emit-label asm label))
  537. (($ $ktail)
  538. (emit-end-arity asm)
  539. (emit-end-program asm))))
  540. (intmap-for-each compile-cont cps)))
  541. (define (emit-bytecode exp env opts)
  542. (let ((asm (make-assembler)))
  543. (intmap-for-each (lambda (kfun body)
  544. (compile-function (intmap-select exp body) asm))
  545. (compute-reachable-functions exp 0))
  546. (values (link-assembly asm #:page-aligned? (kw-arg-ref opts #:to-file? #f))
  547. env
  548. env)))
  549. (define (lower-cps exp opts)
  550. ;; FIXME: For now the closure conversion pass relies on $rec instances
  551. ;; being separated into SCCs. We should fix this to not be the case,
  552. ;; and instead move the split-rec pass back to
  553. ;; optimize-higher-order-cps.
  554. (set! exp (split-rec exp))
  555. (set! exp (optimize-higher-order-cps exp opts))
  556. (set! exp (convert-closures exp))
  557. (set! exp (optimize-first-order-cps exp opts))
  558. (set! exp (reify-primitives exp))
  559. (set! exp (add-handle-interrupts exp))
  560. (renumber exp))
  561. (define (compile-bytecode exp env opts)
  562. (set! exp (lower-cps exp opts))
  563. (emit-bytecode exp env opts))