@@ -43,8 +43,8 @@ expression (that should evaluate to a function):
4343@verbatim|{
4444;; type Expr =
4545;; | ....
46- ;; | `(fun ,Variable )
47- ;; | `(call , Expr ,@ (Listof Expr))
46+ ;; | (Fun Id )
47+ ;; | (Call Expr (Listof Expr))
4848}|
4949
5050These new syntactic forms are temporary forms that don't correspond
@@ -73,18 +73,18 @@ value.
7373
7474@#reader scribble/comment-reader
7575(racketblock
76- ;; Variable -> Asm
76+ ;; Id -> Asm
7777(define (compile-fun f)
78- `( ; rax <- address of label f
79- (lea rax (offset ,( symbol->label f) 0 ))
80- ; write in to heap
81- (mov (offset rdi 0 ) rax)
82- ; rax <- pointer into heap
83- (mov rax rdi )
84- ; tag as procedure pointer
85- ( or rax , type-proc)
86- ; alloc
87- (add rdi 8 )))
78+ ; Load the address of the label into rax
79+ (seq (Lea rax (symbol->label f))
80+ ; Copy the value onto the heap
81+ (Mov (Offset rbx 0 ) rax)
82+ ; Copy the heap address into rax
83+ (Mov rax rbx )
84+ ; Tag the value as a proc
85+ (Or rax type-proc)
86+ ; Bump the heap pointer
87+ (Add rbx 8 )))
8888)
8989
9090A function call, @racket[(call _e0 _es ... )] will evaluate on the
@@ -93,45 +93,60 @@ function, i.e. tagged pointer. We can erase the tag to compute the
9393address in the heap. Dereferencing that location, gets us the label
9494address, which can then jump to.
9595
96+ Similar to `compile-app` from Iniquity, we have to be concerned about 16-byte
97+ alignment for `rsp`. However, the wrinkle is that we also have the function
98+ pointer on the stack, so we have to do the calculation with an `extended` env:
99+ `env`:
100+
96101@#reader scribble/comment-reader
97102(racketblock
98- ;; Expr (Listof Expr) CEnv -> Asm
99103(define (compile-fun-call e0 es c)
100- (let ((cs (compile-es es (cons #f c)))
101- (c0 (compile-e e0 c))
102- (i (- (add1 (length c))))
103- (stack-size (* 8 (length c))))
104- `(,@c0
105- ; save f in stack
106- (mov (offset rsp ,i) rax)
107- ,@cs
108- ; restore f
109- (mov rax (offset rsp ,i))
110- ,@assert-proc
111- (sub rsp ,stack-size)
112- (xor rax ,type-proc)
113- ; call f
114- (call (offset rax 0 ))
115- (add rsp ,stack-size))))
104+ (let ((d (length es))
105+ (env (cons #f c)))
106+ ; We have to computer the function pointer either way.
107+ (seq (compile-e e0 c)
108+ (assert-proc rax)
109+ (Push rax)
110+
111+ ; Then we worry about alignment
112+ (if (even? (+ d (length env)))
113+
114+ ; We will be 16-byte aligned
115+ (seq (compile-es es env)
116+ (Mov rax (Offset rsp (* 8 d)))
117+ (Xor rax type-proc)
118+ (Call (Offset rax 0 ))
119+ (Add rsp (* 8 (add1 d))))
120+
121+ ; We won't be 16-byte aligned, and need to adjust `rsp`
122+ (seq (Sub rsp 8 )
123+ (compile-es es env)
124+ (Mov rax (Offset rsp (* 8 (add1 d))))
125+ (Xor rax type-proc)
126+ (Call (Offset rax 0 ))
127+ ; pop arguments, padding, and function pointer
128+ (Add rsp (* 8 (+ 2 d))))))))
129+
116130)
117131
118132A tail call version of the above can be defined as:
119133
120134@#reader scribble/comment-reader
121135(racketblock
122- ;; Expr (Listof Expr) CEnv -> Asm
123- (define (compile-fun-tail-call e0 es c)
124- (let ((cs (compile-es es (cons #f c)))
125- (c0 (compile-e e0 c))
126- (i (- (add1 (length c)))))
127- `(,@c0
128- (mov (offset rsp ,i) rax)
129- ,@cs
130- (mov rax (offset rsp ,i))
131- ,@(move-args (length es) i)
132- ,@assert-proc
133- (xor rax ,type-proc)
134- (jmp (offset rax 0 )))))
136+ ;; Variable (Listof Expr) CEnv -> Asm
137+ ;; Compile a call in tail position
138+ (define (compile-tail-fun-call f es c)
139+ (let ((cnt (length es)))
140+ (seq (compile-e f c)
141+ (assert-proc rax)
142+ (Push rax)
143+ (compile-es es (cons #f c))
144+ (move-args cnt (+ cnt (add1 (in-frame c))))
145+ (Mov rax (Offset rsp (* 8 cnt)))
146+ (Xor rax type-proc)
147+ (Add rsp (* 8 (+ cnt (add1 (in-frame c)))))
148+ (Jmp (Offset rax 0 )))))
149+
135150)
136151
137152The complete compiler:
0 commit comments