|
1 | 1 | #lang racket |
2 | 2 | (provide (all-defined-out)) |
3 | 3 |
|
4 | | -(define int-tag #b0000) ; 0, 2, 4... integer |
5 | | -(define box-tag #b0001) ; 1 box |
6 | | -(define pair-tag #b0011) ; 3 pairs |
7 | | -(define vect-tag #b0101) ; 5 vectors |
8 | | -(define str-tag #b0111) ; 7 strings |
9 | | -(define true-tag #b1001) ; 9 |
10 | | -(define false-tag #b1011) ; 11 |
11 | | -(define empty-tag #b1101) ; 13 |
12 | | -(define char-tag #b1111) ; 15 |
| 4 | +;; An immediate is anything ending in #b0000 |
| 5 | +;; All other tags in mask #b111 are pointers |
| 6 | + |
| 7 | +(define result-shift 3) |
| 8 | +(define result-type-mask (sub1 (arithmetic-shift 1 result-shift))) |
| 9 | +(define type-imm #b000) |
| 10 | +(define type-box #b001) |
| 11 | +(define type-pair #b010) |
| 12 | + |
| 13 | +(define imm-shift (+ 3 result-shift)) |
| 14 | +(define imm-type-mask (sub1 (arithmetic-shift 1 imm-shift))) |
| 15 | +(define imm-type-int (arithmetic-shift #b000 result-shift)) |
| 16 | +(define imm-type-true (arithmetic-shift #b001 result-shift)) |
| 17 | +(define imm-type-false (arithmetic-shift #b010 result-shift)) |
| 18 | +(define imm-type-empty (arithmetic-shift #b011 result-shift)) |
| 19 | +(define imm-type-char (arithmetic-shift #b100 result-shift)) |
13 | 20 |
|
14 | 21 | ;; Allocate in 64-bit (8-byte) increments, so pointers |
15 | | -;; end in #b000 and we tag with #b001 for pairs, etc. |
| 22 | +;; end in #b000 and we tag with #b001 for boxes, etc. |
16 | 23 |
|
17 | 24 | ;; type CEnv = (Listof (Maybe Variable)) |
18 | 25 |
|
19 | 26 | ;; Expr -> Asm |
20 | 27 | (define (compile e) |
21 | 28 | `(entry |
| 29 | + (sar rdi 4) ;; align on quad boundary |
| 30 | + (sal rdi 4) |
22 | 31 | (add rdi 16) |
23 | 32 | ,@(compile-e e '()) |
24 | 33 | ret |
|
30 | 39 | ;; Expr CEnv -> Asm |
31 | 40 | (define (compile-e e c) |
32 | 41 | (match e |
33 | | - [''() `((mov rax ,empty-tag))] |
| 42 | + [''() `((mov rax ,imm-type-empty))] |
34 | 43 | [`(box ,e0) |
35 | 44 | (let ((c0 (compile-e e0 c))) |
36 | 45 | `(,@c0 |
37 | 46 | (mov (offset rdi 0) rax) |
38 | 47 | (mov rax rdi) |
39 | | - (or rax ,box-tag) |
40 | | - (add rdi 8) ; bump by 8 bytes |
41 | | - ))] |
| 48 | + (or rax ,type-box) |
| 49 | + (add rdi 8)))] ; allocate 8 bytes |
42 | 50 | [`(unbox ,e0) |
43 | 51 | (let ((c0 (compile-e e0 c))) |
44 | 52 | `(,@c0 |
45 | 53 | ;; assert box |
46 | | - (xor rax ,box-tag) |
| 54 | + (xor rax ,type-box) |
47 | 55 | (mov rax (offset rax 0))))] |
48 | 56 | [`(cons ,e0 ,e1) |
49 | 57 | (let ((c0 (compile-e e0 c)) |
|
55 | 63 | (mov rax (offset rsp ,(- (add1 (length c))))) |
56 | 64 | (mov (offset rdi 1) rax) |
57 | 65 | (mov rax rdi) |
58 | | - (or rax ,pair-tag) |
| 66 | + (or rax ,type-pair) |
59 | 67 | (add rdi 16)))] |
60 | 68 | [`(car ,e0) |
61 | 69 | (let ((c0 (compile-e e0 c))) |
62 | 70 | `(,@c0 |
63 | 71 | ;; assert pair |
64 | | - (xor rax ,pair-tag) |
| 72 | + (xor rax ,type-pair) |
65 | 73 | (mov rax (offset rax 1))))] |
66 | 74 | [`(cdr ,e0) |
67 | 75 | (let ((c0 (compile-e e0 c))) |
68 | 76 | `(,@c0 |
69 | 77 | ;; assert pair |
70 | | - (xor rax ,pair-tag) |
| 78 | + (xor rax ,type-pair) |
71 | 79 | (mov rax (offset rax 0))))] |
72 | 80 | [(? integer? i) |
73 | | - `((mov rax ,(* i 2)))] |
| 81 | + `((mov rax ,(arithmetic-shift i imm-shift)))] |
74 | 82 | [(? boolean? b) |
75 | | - `((mov rax ,(if b true-tag false-tag)))] |
| 83 | + `((mov rax ,(if b imm-type-true imm-type-false)))] |
76 | 84 | [`(add1 ,e0) |
77 | 85 | (let ((c0 (compile-e e0 c))) |
78 | 86 | `(,@c0 |
79 | 87 | ,@assert-integer |
80 | | - (add rax 2)))] |
| 88 | + (add rax ,(arithmetic-shift 1 imm-shift))))] |
81 | 89 | [`(sub1 ,e0) |
82 | 90 | (let ((c0 (compile-e e0 c))) |
83 | 91 | `(,@c0 |
84 | 92 | ,@assert-integer |
85 | | - (sub rax 2)))] |
| 93 | + (sub rax ,(arithmetic-shift 1 imm-shift))))] |
86 | 94 | [`(zero? ,e0) |
87 | 95 | (let ((c0 (compile-e e0 c)) |
88 | 96 | (l0 (gensym)) |
89 | 97 | (l1 (gensym))) |
90 | 98 | `(,@c0 |
91 | 99 | ,@assert-integer |
92 | 100 | (cmp rax 0) |
93 | | - (mov rax ,false-tag) ; #f |
| 101 | + (mov rax ,imm-type-false) |
94 | 102 | (jne ,l0) |
95 | | - (mov rax ,true-tag) ; #t |
| 103 | + (mov rax ,imm-type-true) |
96 | 104 | ,l0))] |
97 | 105 | [`(if ,e0 ,e1 ,e2) |
98 | 106 | (let ((c0 (compile-e e0 c)) |
|
101 | 109 | (l0 (gensym)) |
102 | 110 | (l1 (gensym))) |
103 | 111 | `(,@c0 |
104 | | - (cmp rax ,false-tag) ; compare to #f |
105 | | - (je ,l0) ; jump to c2 if #f |
| 112 | + (cmp rax ,imm-type-false) |
| 113 | + (je ,l0) |
106 | 114 | ,@c1 |
107 | | - (jmp ,l1) ; jump past c2 |
| 115 | + (jmp ,l1) |
108 | 116 | ,l0 |
109 | 117 | ,@c2 |
110 | 118 | ,l1))] |
|
138 | 146 | ,@assert-integer |
139 | 147 | (sub rax (offset rsp ,(- (add1 (length c)))))))])) |
140 | 148 |
|
| 149 | +;; code for "abc" |
| 150 | +'((mov (offset rdi 0) |
| 151 | + (integer->bits 3)) |
| 152 | + (mov (offset rdi 1) |
| 153 | + (compile-char #\a)) |
| 154 | + (mov (offset rdi 1) |
| 155 | + (char->bits #\b)) |
| 156 | + (mov (offset-rdi 2) |
| 157 | + (char->bits #\c)) |
| 158 | + (mov rdi rax) |
| 159 | + (or rax ,str-tag)) |
| 160 | + |
| 161 | + |
| 162 | + |
141 | 163 |
|
142 | 164 | ;; Variable CEnv -> Natural |
143 | 165 | (define (lookup x cenv) |
|
150 | 172 |
|
151 | 173 | (define assert-integer |
152 | 174 | `((mov rbx rax) |
153 | | - (and rbx 1) |
| 175 | + (and rbx ,imm-type-mask) |
154 | 176 | (cmp rbx 0) |
155 | 177 | (jne err))) |
0 commit comments