-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathx86_asm.rkt
154 lines (115 loc) · 3.64 KB
/
x86_asm.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#lang racket/base
(require racket/match)
(provide (all-defined-out))
(module+ test
(require rackunit))
;; constants
(define fixnum-shift 2)
(define fixnum-tag 0)
(define fixnum-mask 3)
(define empty-list 47)
(define bool-shift 7)
(define bool-tag 31)
(define true-rep 159)
(define false-rep 31)
(define wordsize 8) ;Assuming 64-bit architecture
;; These by and large just format the assembly
(define (move-func-rax func-name)
(format "leaq _~a(%rip), %rax" func-name))
(define (leaq addr dest-reg)
(format "leaq ~a, ~a" addr dest-reg))
(define (movq val dest)
;; TODO: I'd like to generalize this so that it can handle memory locations
(format "movq ~a, ~a" val dest))
(define (addq reg-a reg-b)
(format "addq ~a, ~a" reg-a reg-b))
(define (subq reg-a reg-b)
(format "subq ~a, ~a" reg-a reg-b))
(define (mulq reg-a reg-b)
;; This emits two instructions: first the multiply instruction, then
;; a shift instruction to correct
(format "imulq ~a, ~a\n\tshr $~a, ~a" reg-a reg-b fixnum-shift reg-b))
(define (num-equals reg-a reg-b)
(format "cmpq ~a, ~a\n\tsete ~a\n\tmovzbq ~a, ~a\n\tshl $~a, ~a\n\txorq $~a, ~a"
reg-a reg-b ; cmpq args
(reg 'ret-val-small) ; sete
(reg 'ret-val-small) (reg 'ret-val) ; movzbq
bool-shift (reg 'ret-val) ; shl
bool-tag (reg 'ret-val) ; xorq
))
(define (prim-bin-op name)
(match name
['+ addq]
['- subq]
['* mulq]
['= num-equals]))
(define (cmpq a b)
(format "cmpq ~a, ~a" a b))
(define (sete short-reg)
(format "sete ~a" short-reg))
(define (salq a b)
(format "salq ~a, ~a" a b))
(define (je loc)
(format "je _~a" loc))
(define (jmp loc)
(format "jmp _~a" loc))
(define (orq reg1 reg2)
(format "orq ~a, ~a" reg1 reg2))
(define (xorq reg1 reg2)
(format "xorq ~a, ~a" reg1 reg2))
;; convert val to its immediate representation
(define (immediate val)
(match val
[(? integer?)
(format "$~a" (arithmetic-shift val fixnum-shift))]
[(? boolean?)
(format "$~a" (if val true-rep false-rep))]))
;; Like `immeidate`, but doesn't do any converting
(define (raw-immediate val)
(format "$~a" val))
;; Tag the current heap pointer with its type
(define (tag-heap kind)
(match kind
['pair (orq (raw-immediate 1) (reg 'heap))]))
(define (label sym)
(format "_~a:" sym))
(define (function-label name)
(gensym (string-append "func_" (symbol->string name))))
(define (ret) "ret")
(define (call label)
(format "call _~a" label))
(define (call-indirect reg)
(format "callq *(~a)" reg))
(define (push place)
(format "push ~a" place))
(define (pop place)
(format "pop ~a" place))
(define (fresh-label)
(gensym (string-append "l_")))
(define (mem #:offset [imm #f] #:reg-b [rb #f] #:reg-i [ri #f] #:s [s #f])
(string-append
(if imm (format "~a" imm) "")
(if (or rb ri s)
(format "(~a)"
(string-append
(if rb (format "~a" rb) "")
(if ri (format ",~a" ri) "")
(if s (format ",~a" s) "")))
"")))
(define (stack [offset (- wordsize)])
(mem #:offset offset #:reg-b (reg 'stack)))
(define (heap [offset (- wordsize)])
(mem #:offset offset #:reg-b (reg 'heap)))
(define (reg reg-name)
(match reg-name
['ret-val "%rax"]
['ret-val-small "%al"]
['stack "%rsp"]
['heap "%r15"]
['closure "%rdi"]
['swap-1 "%r13"]))
[module+ test
(check-equal? (mem #:offset 42) "42")
(check-equal? (mem #:offset 42 #:reg-i (reg 'param-1) #:s 4) "42(,%rdi,4)")
(check-equal? (mem #:reg-b (reg 'param-1)) "(%rdi)")
]