|
1 | 1 | #lang racket |
2 | | -(require "syntax.rkt") |
| 2 | +(require "syntax.rkt" "ast.rkt") |
3 | 3 | (provide (all-defined-out)) |
4 | 4 |
|
5 | 5 | ;; An immediate is anything ending in #b000 |
|
11 | 11 | (define type-box #b001) |
12 | 12 | (define type-pair #b010) |
13 | 13 | (define type-string #b011) |
14 | | -(define type-proc #b100) ;; <-- NEW: procedure value: points to function label in memory |
| 14 | +(define type-proc #b100) |
15 | 15 |
|
16 | 16 | (define imm-shift (+ 2 result-shift)) |
17 | 17 | (define imm-type-mask (sub1 (arithmetic-shift 1 imm-shift))) |
|
35 | 35 |
|
36 | 36 | ;; type Label = (quote Symbol) |
37 | 37 |
|
| 38 | +;; Prog -> Asm |
| 39 | +(define (compile p) |
| 40 | + ; Remove all of the explicit function definitions |
| 41 | + (match (desugar-prog p) |
| 42 | + [(prog _ e) |
| 43 | + (compile-entry (label-λ e))])) |
| 44 | + |
| 45 | + |
38 | 46 | ;; Expr -> Asm |
39 | | -(define (compile e) |
40 | | - (let ((le (label-λ (desugar e)))) |
41 | | - `(entry |
42 | | - ,@(compile-tail-e le '()) |
| 47 | +(define (compile-entry e) |
| 48 | + `(,@(make-externs (ffi-calls e)) |
| 49 | + (section text) |
| 50 | + entry |
| 51 | + ,@(compile-tail-e e '()) |
43 | 52 | ret |
44 | | - ,@(compile-λ-definitions (λs le)) |
| 53 | + ,@(compile-λ-definitions (λs e)) |
45 | 54 | err |
46 | 55 | (push rbp) |
47 | 56 | (call error) |
48 | | - ret))) |
| 57 | + ret)) |
| 58 | + |
| 59 | +;; (Listof Symbol) -> Asm |
| 60 | +(define (make-externs fs) |
| 61 | + (map (lambda (s) `(extern ,s)) fs)) |
49 | 62 |
|
50 | 63 | ;; (Listof Lambda) -> Asm |
51 | 64 | (define (compile-λ-definitions ls) |
|
54 | 67 | ;; Lambda -> Asm |
55 | 68 | (define (compile-λ-definition l) |
56 | 69 | (match l |
57 | | - [`(λ ,xs ',f ,e0) |
| 70 | + [(lam-t f xs e0) |
58 | 71 | (let ((c0 (compile-tail-e e0 (reverse (append xs (fvs l)))))) |
59 | 72 | `(,f |
60 | 73 | ,@c0 |
61 | | - ret))])) |
| 74 | + ret))] |
| 75 | + [(lam-e _ _) (error "Lambdas need to be labeled before compiling")])) |
62 | 76 |
|
63 | 77 | ;; LExpr CEnv -> Asm |
64 | 78 | ;; Compile an expression in tail position |
65 | 79 | (define (compile-tail-e e c) |
66 | 80 | (match e |
67 | | - [(? symbol? x) (compile-variable x c)] |
68 | | - [(? imm? i) (compile-imm i)] |
69 | | - [`(box ,e0) (compile-box e0 c)] |
70 | | - [`(unbox ,e0) (compile-unbox e0 c)] |
71 | | - [`(cons ,e0 ,e1) (compile-cons e0 e1 c)] |
72 | | - [`(car ,e0) (compile-car e0 c)] |
73 | | - [`(cdr ,e0) (compile-cdr e0 c)] |
74 | | - [`(add1 ,e0) (compile-add1 e0 c)] |
75 | | - [`(sub1 ,e0) (compile-sub1 e0 c)] |
76 | | - [`(zero? ,e0) (compile-zero? e0 c)] |
77 | | - [`(empty? ,e0) (compile-empty? e0 c)] |
78 | | - [`(if ,e0 ,e1 ,e2) (compile-tail-if e0 e1 e2 c)] |
79 | | - [`(+ ,e0 ,e1) (compile-+ e0 e1 c)] |
80 | | - [`(let ((,x ,e0)) ,e1) (compile-tail-let x e0 e1 c)] |
81 | | - [`(letrec ,bs ,e0) (compile-tail-letrec (map first bs) (map second bs) e0 c)] |
82 | | - [`(λ ,xs ',l ,e0) (compile-λ xs l (fvs e) c)] |
83 | | - [`(ccall ,f . ,es) (compile-ccall f es c)] |
84 | | - [`(,e . ,es) (compile-tail-call e es c)])) |
| 81 | + [(var-e v) (compile-variable v c)] |
| 82 | + [(? imm? i) (compile-imm i)] |
| 83 | + [(prim-e (? prim? p) es) (compile-prim p es c)] |
| 84 | + [(if-e p t f) (compile-tail-if p t f c)] |
| 85 | + [(let-e (list b) body) (compile-tail-let b body c)] |
| 86 | + [(letr-e bs body) (compile-tail-letrec (get-vars bs) (get-defs bs) body c)] |
| 87 | + [(app-e f es) (compile-tail-call f es c)] |
| 88 | + [(lam-t l xs e0) (compile-λ xs l (fvs e) c)])) |
| 89 | + |
| 90 | + |
85 | 91 |
|
86 | 92 | ;; LExpr CEnv -> Asm |
87 | 93 | ;; Compile an expression in non-tail position |
88 | 94 | (define (compile-e e c) |
89 | 95 | (match e |
90 | | - [(? symbol? x) (compile-variable x c)] |
91 | | - [(? imm? i) (compile-imm i)] |
| 96 | + [(var-e v) (compile-variable v c)] |
| 97 | + [(? imm? i) (compile-imm i)] |
| 98 | + [(prim-e (? prim? p) es) (compile-prim p es c)] |
| 99 | + [(if-e p t f) (compile-if p t f c)] |
| 100 | + [(let-e (list b) body) (compile-let b body c)] |
| 101 | + [(letr-e bs body) (compile-letrec (get-vars bs) (get-defs bs) body c)] |
| 102 | + [(ccall-e f es) (compile-ccall f es c)] |
| 103 | + [(app-e f es) (compile-call f es c)] |
| 104 | + [(lam-t l xs e0) (compile-λ xs l (fvs e) c)])) |
| 105 | + |
| 106 | +;; Our current set of primitive operations require no function calls, |
| 107 | +;; so there's no difference between tail and non-tail call positions |
| 108 | +(define (compile-prim p es c) |
| 109 | + (match (cons p es) |
92 | 110 | [`(box ,e0) (compile-box e0 c)] |
93 | 111 | [`(unbox ,e0) (compile-unbox e0 c)] |
94 | 112 | [`(cons ,e0 ,e1) (compile-cons e0 e1 c)] |
|
98 | 116 | [`(sub1 ,e0) (compile-sub1 e0 c)] |
99 | 117 | [`(zero? ,e0) (compile-zero? e0 c)] |
100 | 118 | [`(empty? ,e0) (compile-empty? e0 c)] |
101 | | - [`(if ,e0 ,e1 ,e2) (compile-if e0 e1 e2 c)] |
102 | 119 | [`(+ ,e0 ,e1) (compile-+ e0 e1 c)] |
103 | | - [`(let ((,x ,e0)) ,e1) (compile-let x e0 e1 c)] |
104 | | - [`(λ ,xs ',l ,e0) (compile-λ xs l (fvs e) c)] |
105 | | - [`(letrec ,bs ,e0) (compile-letrec (map first bs) (map second bs) e0 c)] |
106 | | - [`(ccall ,f . ,es) (compile-ccall f es c)] |
107 | | - [`(,e . ,es) (compile-call e es c)])) |
| 120 | + [_ (error |
| 121 | + (format "prim applied to wrong number of args: ~a ~a" p es))])) |
108 | 122 |
|
109 | 123 | ;; Label (listof Expr) -> Asm |
110 | 124 | (define (compile-ccall f es c) |
|
128 | 142 | )] |
129 | 143 | [_ `()]))) |
130 | 144 |
|
131 | | -;; (Listof Variable) Label (Listof Varialbe) CEnv -> Asm |
| 145 | +;; (Listof Variable) Label (Listof Variable) CEnv -> Asm |
132 | 146 | (define (compile-λ xs f ys c) |
133 | | - `(;; Save label address |
134 | | - (lea rax (offset ,f 0)) |
| 147 | + ; Save label address |
| 148 | + `((lea rax (offset ,f 0)) |
135 | 149 | (mov (offset rdi 0) rax) |
136 | 150 |
|
137 | | - ;; Save the environment |
| 151 | + ; Save the environment |
138 | 152 | (mov r8 ,(length ys)) |
139 | 153 | (mov (offset rdi 1) r8) |
140 | 154 | (mov r9 rdi) |
141 | 155 | (add r9 16) |
142 | 156 | ,@(copy-env-to-heap ys c 0) |
143 | 157 |
|
144 | | - ;; Return a pointer to the closure |
| 158 | + ; Return a pointer to the closure |
145 | 159 | (mov rax rdi) |
146 | 160 | (or rax ,type-proc) |
147 | 161 | (add rdi ,(* 8 (+ 2 (length ys)))))) |
|
206 | 220 | ;,@(copy-closure-env-to-stack (length es)) |
207 | 221 | (jmp (offset rax 0))))) |
208 | 222 |
|
| 223 | + |
209 | 224 | ;; -> Asm |
210 | 225 | ;; Copy closure's (in rax) env to stack in rcx |
211 | 226 | (define (copy-closure-env-to-stack) |
|
218 | 233 | (cmp r8 0) |
219 | 234 | (je ,copy-done) |
220 | 235 | (mov rbx (offset r9 0)) |
221 | | - (mov (offset rcx 0) rbx) |
| 236 | + (mov (offset rcx 0) rbx) ; Move val onto stack |
222 | 237 | (sub r8 1) |
223 | 238 | (add r9 8) |
224 | 239 | (sub rcx 8) |
|
249 | 264 | (match ls |
250 | 265 | ['() '()] |
251 | 266 | [(cons l ls) |
252 | | - (let ((cs (compile-letrec-λs ls (cons #f c))) |
253 | | - (ys (fvs l))) |
254 | | - `((lea rax (offset ,(second (third l)) 0)) |
255 | | - (mov (offset rdi 0) rax) |
256 | | - (mov rax ,(length ys)) |
257 | | - (mov (offset rdi 1) rax) |
258 | | - (mov rax rdi) |
259 | | - (or rax ,type-proc) |
260 | | - (add rdi ,(* 8 (+ 2 (length ys)))) |
261 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
262 | | - ,@cs))])) |
| 267 | + (match l |
| 268 | + [(lam-t lab as body) |
| 269 | + (let ((cs (compile-letrec-λs ls (cons #f c))) |
| 270 | + (ys (fvs l))) |
| 271 | + `((lea rax (offset ,lab 0)) |
| 272 | + (mov (offset rdi 0) rax) |
| 273 | + (mov rax ,(length ys)) |
| 274 | + (mov (offset rdi 1) rax) |
| 275 | + (mov rax rdi) |
| 276 | + (or rax ,type-proc) |
| 277 | + (add rdi ,(* 8 (+ 2 (length ys)))) |
| 278 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 279 | + ,@cs))])])) |
263 | 280 |
|
264 | 281 | ;; (Listof Variable) (Listof Lambda) CEnv -> Asm |
265 | 282 | (define (compile-letrec-init fs ls c) |
|
292 | 309 | ;; Imm -> Integer |
293 | 310 | (define (imm->bits i) |
294 | 311 | (match i |
295 | | - [(? integer? i) (arithmetic-shift i imm-shift)] |
296 | | - [(? char? c) (+ (arithmetic-shift (char->integer c) imm-shift) imm-type-char)] |
297 | | - [(? boolean? b) (if b imm-val-true imm-val-false)] |
298 | | - [''() imm-type-empty])) |
| 312 | + [(int-e i) (arithmetic-shift i imm-shift)] |
| 313 | + [(char-e c) (+ (arithmetic-shift (char->integer c) imm-shift) imm-type-char)] |
| 314 | + [(bool-e b) (if b imm-val-true imm-val-false)] |
| 315 | + [(nil-e) imm-type-empty])) |
| 316 | + |
299 | 317 |
|
300 | 318 | ;; Variable CEnv -> Asm |
301 | 319 | (define (compile-variable x c) |
|
421 | 439 | ,l1))) |
422 | 440 |
|
423 | 441 | ;; Variable LExpr LExpr CEnv -> Asm |
424 | | -(define (compile-tail-let x e0 e1 c) |
425 | | - (let ((c0 (compile-e e0 c)) |
426 | | - (c1 (compile-tail-e e1 (cons x c)))) |
427 | | - `(,@c0 |
428 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
429 | | - ,@c1))) |
| 442 | +(define (compile-tail-let b body c) |
| 443 | + (match b |
| 444 | + [(binding x def) |
| 445 | + (let ((c0 (compile-e def c)) |
| 446 | + (c1 (compile-tail-e body (cons x c)))) |
| 447 | + `(,@c0 |
| 448 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 449 | + ,@c1))])) |
430 | 450 |
|
431 | 451 | ;; Variable LExpr LExpr CEnv -> Asm |
432 | | -(define (compile-let x e0 e1 c) |
433 | | - (let ((c0 (compile-e e0 c)) |
434 | | - (c1 (compile-e e1 (cons x c)))) |
435 | | - `(,@c0 |
436 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
437 | | - ,@c1))) |
| 452 | +(define (compile-let b body c) |
| 453 | + (match b |
| 454 | + [(binding x def) |
| 455 | + (let ((c0 (compile-e def c)) |
| 456 | + (c1 (compile-e body (cons x c)))) |
| 457 | + `(,@c0 |
| 458 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 459 | + ,@c1))])) |
438 | 460 |
|
439 | 461 | ;; LExpr LExpr CEnv -> Asm |
440 | 462 | (define (compile-+ e0 e1 c) |
|
0 commit comments