codegen for binop

This commit is contained in:
janis 2025-11-02 01:07:37 +01:00
parent b9712dacfb
commit 6ebc6afb2b
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 419 additions and 5 deletions

View file

@ -1,6 +1,7 @@
default rel
%include "src/ast.inc"
%include "src/tokeniser.inc"
extern panic
extern vec_extend
@ -10,6 +11,7 @@ extern vec_insert_sorted
extern vec_insert_many
extern vec_init_with
extern int_to_str2
extern strlen
global codegen_function
global get_register_name
@ -961,10 +963,10 @@ codegen_expr:
push r15
push r14
; scratch [16..48]
; scratch [16..80]
; function_ctx: [8..16]
; ctx [0..8]
sub rsp, 48
sub rsp, 80
mov [rsp], rdi ; ctx
mov [rsp + 8], rsi ; &function_ctx
@ -1090,9 +1092,201 @@ codegen_expr:
mov rdx, qword [rsp + 24]
jmp .done
.binary_op:
mov rax, [rax + 8] ; AstNode.data
mov [rsp + 16], rax ; scratch = *AstBinaryOp
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
mov rdx, [rax + 0] ; left operand index
call codegen_expr
mov [rsp + 32], rax ; left operand
mov [rsp + 40], rdx
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
mov rdx, [rsp + 16] ; *AstBinaryOp
mov rdx, [rdx + 16] ; right operand index
call codegen_expr
mov [rsp + 48], rax ; right operand
mov [rsp + 56], rdx
mov rax, [rsp + 16] ; *AstBinaryOp
mov al, byte [rax + 8] ; operator
mov rbx, -1
cmp al, TOKEN_PLUS
cmove rbx, [rel ADD_]
cmp al, TOKEN_MINUS
cmove rbx, [rel SUB_]
cmp rbx, -1
jne .gen_op
cmp al, TOKEN_STAR
cmove rbx, [rel MUL_]
cmp al, TOKEN_SLASH
cmove rbx, [rel DIV_]
cmp al, TOKEN_PERCENT
cmove rbx, [rel DIV_]
cmp rbx, -1
je .panic ; unknown operator
.mul_div:
; mul/div need to clobber rax:rdx
; TODO only check for div
mov rax, [rsp + 8] ; &function_ctx
mov ax, word [rax + 48] ; register_bitset
bt ax, 3 ; is rdx used?
jnc .after_spill_rdx
; allocate scratch value for rdx
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, 8 ; width
call codegen_allocate_place
mov [rsp + 64], rax
mov [rsp + 72], rdx
; mov scratch, rdx
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 64] ; scratch value
lea rdx, [rel OPERAND_RDX] ; rax
call codegen_move_dst_src
; check if rhs is rdx
mov rax, [rsp + 48] ; right operand
and rax, 0xFFF
mov rdx, [rel OPERAND_RDX]
and rdx, 0xFFF
cmp rax, rdx
jne .after_spill_rdx
; free rhs
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 48] ; right operand
call codegen_free_operand
mov rdx, [rsp + 48] ; right operand
and rdx, 0xF000 ; Operand.width
mov rax, [rsp + 64] ; scratch value
or rax, rdx ; preserve width
mov rdx, [rsp + 72]
mov [rsp + 48], rax ; right operand
mov [rsp + 56], rdx
.after_spill_rdx:
mov rax, [rsp + 16] ; *AstBinaryOp
mov al, byte [rax + 8] ; operator
cmp al, TOKEN_STAR
je .after_clear_rdx
; clear rdx for div
; xor rdx, rdx
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel XOR_RDX_RDX] ; rdx
mov rdx, XOR_RDX_RDX_LEN
call vec_extend
.after_clear_rdx:
; mov rax, lhs
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel OPERAND_RAX] ; rax
lea rdx, [rsp + 32] ; left operand
call codegen_move_dst_src
; op rhs
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
push rbx
lea rsi, [rsp] ; op
mov rdx, 4
call vec_extend
pop rbx
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 48] ; left operand
call codegen_write_operand
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
mov rsi, 10
push rsi
lea rsi, [rsp] ; newline
call vec_push
pop rsi
mov rax, [rsp + 16] ; *AstBinaryOp
mov al, byte [rax + 8] ; operator
cmp al, TOKEN_PERCENT
jne .after_rem
; mov rax, rdx // only for rem
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel OPERAND_RAX] ; rax
lea rdx, [rel OPERAND_RDX] ; rdx
call codegen_move_dst_src
.after_rem:
mov rax, [rsp + 8] ; &function_ctx
mov ax, word [rax + 48] ; register_bitset
bt ax, 3 ; is rdx used?
jnc .after_unspill_rdx
; mov rdx, scratch
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel OPERAND_RDX] ; rdx
lea rdx, [rsp + 64] ; scratch value
call codegen_move_dst_src
.after_unspill_rdx:
; free [scratch, rhs, lhs]
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 64] ; scratch value
call codegen_free_operand
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 48] ; right operand
call codegen_free_operand
mov rdi, [rsp + 8] ; &function_ctx
lea rsi, [rsp + 32] ; left operand
call codegen_free_operand
; alloca dst
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, 8 ; width
call codegen_allocate_value
mov [rsp + 32], rax
mov [rsp + 40], rdx
; mov dst, rax
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 32] ; dst
lea rdx, [rel OPERAND_RAX] ; rax
call codegen_move_dst_src
; return dst
mov rax, [rsp + 32]
mov rdx, [rsp + 40]
jmp .done
.gen_op:
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, [rsp] ; ctx
lea rsi, [rsi + 8] ; &ctx.text
lea rdx, [rsp + 32] ; left operand
lea rcx, [rsp + 48] ; right operand
mov r8, rbx ; operation
call codegen_binary_op_rm64_rm64
jmp .done
.var_decl:
.var_ref:
.binary_op:
.assignment:
.place_to_value:
.value_to_place:
@ -1101,7 +1295,7 @@ codegen_expr:
; TODO
.done:
add rsp, 48
add rsp, 80
pop r14
pop r15
pop rbx
@ -1362,6 +1556,218 @@ codegen_move_rbp_slot_src:
pop rbp
ret
;; rdi: *function_ctx
;; rsi: *text
;; rdx: lhs: *Operand
;; rcx: rhs: *Operand
;; r8: op: [u8; 8]
;; Generates: {op} {lhs}, {rhs} for a binary operation that has the encodings rN, rmN and rmN, rN
codegen_binary_op_rm64_rm64:
push rbp
mov rbp, rsp
push rbx
; dst [32..48]
sub rsp, 48
mov [rsp], rdi ; *function_ctx
mov [rsp + 8], rsi ; *text
mov [rsp + 16], rdx ; lhs
mov [rsp + 24], rcx ; rhs
mov [rsp + 32], r8 ; op
; if lhs.kind == REGISTER || lhs.kind < ADDRESS && rhs.kind == REGISTER {
cmp byte [rdx + 0], OPERAND_REGISTER
je .simple
cmp byte [rdx + 0], OPERAND_ADDRESS
setb al
cmp byte [rcx + 0], OPERAND_REGISTER
sete bl
test al, bl
jne .simple
jmp .complex
.simple:
; op lhs, rhs
lea rdi, [rsp + 32] ; op
call strlen
mov rdi, [rsp + 8] ; *text
lea rsi, [rsp + 32] ; op
mov rdx, rax ; op length
call vec_extend
mov rdi, [rsp + 8] ; *text
mov rsi, [rsp + 16] ; lhs
call codegen_write_operand
mov rdi, [rsp + 8] ; *text
lea rsi, [rel COMMA_RAX]
mov rdx, 2
call vec_extend
mov rdi, [rsp + 8] ; *text
mov rsi, [rsp + 24] ; rhs
call codegen_write_operand
mov byte [rsp + 32], 10 ; newline
mov rdi, [rsp + 8] ; *text
lea rsi, [rsp + 32]
call vec_push
; free rhs
mov rdi, [rsp] ; *function_ctx
mov rsi, [rsp + 24] ; rhs
call codegen_free_operand
; ret lhs
mov rbx, [rsp + 16] ; lhs
mov rax, [rbx]
mov rdx, [rbx + 8]
jmp .epilogue
; } else {
.complex:
; if lhs.kind < ADDRESS {
cmp byte [rdx + 0], OPERAND_ADDRESS
jae .check_rhs
; mov rax, rhs
mov rdi, [rsp + 8] ; *text
lea rsi, [rel OPERAND_RAX]
mov rdx, [rsp + 24] ; rhs
call codegen_move_dst_src
; op lhs, rax
mov rdi, [rsp + 8] ; *text
mov rsi, [rsp + 16] ; lhs
lea rdx, [rel OPERAND_RAX] ; rax
mov rcx, [rsp + 32] ; op
call codegen_binary_op_unchecked
; free rhs
mov rdi, [rsp] ; *function_ctx
mov rsi, [rsp + 24] ; rhs
call codegen_free_operand
; ret lhs
mov rbx, [rsp + 16] ; lhs
mov rax, [rbx]
mov rdx, [rbx + 8]
jmp .epilogue
.check_rhs:
; } else if rhs.kind < ADDRESS {
cmp byte [rcx + 0], OPERAND_ADDRESS
jae .allocate_dst
; mov rax, lhs
mov rdi, [rsp + 8] ; *text
lea rsi, [rel OPERAND_RAX]
mov rdx, [rsp + 16] ; lhs
call codegen_move_dst_src
; op rax, rhs
mov rdi, [rsp + 8] ; *text
lea rsi, [rel OPERAND_RAX] ; rax
mov rdx, [rsp + 24] ; rhs
mov rcx, [rsp + 32] ; op
call codegen_binary_op_unchecked
; mov rhs, rax
mov rdi, [rsp + 8] ; *text
mov rsi, [rsp + 24] ; rhs
lea rdx, [rel OPERAND_RAX]
call codegen_move_dst_src
; free lhs
mov rdi, [rsp] ; *function_ctx
mov rsi, [rsp + 16] ; rhs
call codegen_free_operand
; ret rhs
mov rbx, [rsp + 24] ; rhs
mov rax, [rbx]
mov rdx, [rbx + 8]
jmp .epilogue
; } else {
.allocate_dst:
; dst = allocate_value
mov rdi, [rsp] ; *function_ctx
mov rsi, 8 ; width = 8
call codegen_allocate_value
mov [rsp + 32], rax ; dst
mov [rsp + 40], rdx
; mov dst, lhs
mov rdi, [rsp + 8] ; *text
lea rsi, [rsp + 32] ; dst
mov rdx, [rsp + 16] ; lhs
call codegen_move_dst_src
; mov rax, rhs
mov rdi, [rsp + 8] ; *text
lea rsi, [rel OPERAND_RAX] ; rax
mov rdx, [rsp + 24] ; rhs
call codegen_move_dst_src
; op dst, rax
mov rdi, [rsp + 8] ; *text
lea rsi, [rsp + 32] ; dst
lea rdx, [rel OPERAND_RAX] ; rax
mov rcx, [rsp + 32] ; op
call codegen_binary_op_unchecked
; ret dst
mov rax, [rsp + 32] ; dst
mov rdx, [rsp + 40]
; }
.epilogue:
add rsp, 48
pop rbx
pop rbp
ret
;; rdi: *text
;; rsi: lhs: *Operand
;; rdx: rhs: *Operand
;; rcx: op: [u8; 8]
codegen_binary_op_unchecked:
push rbp
mov rbp, rsp
sub rsp, 32
mov [rsp], rdi ; *text
mov [rsp + 8], rsi ; lhs
mov [rsp + 16], rdx ; rhs
mov [rsp + 24], rcx ; op
; op lhs, rax
lea rdi, [rsp + 24] ; op
call strlen
mov rdi, [rsp] ; *text
lea rsi, [rsp + 24] ; op
mov rdx, rax ; op length
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; lhs
call codegen_write_operand
mov rdi, [rsp] ; *text
lea rsi, [rel COMMA_RAX]
mov rdx, 2
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 16] ; rhs
call codegen_write_operand
mov byte [rsp + 31], 10 ; newline
mov rdi, [rsp + 8] ; *text
lea rsi, [rsp + 31]
call vec_push
add rsp, 32
pop rbp
ret
;; rdi: *text
;; rsi: dst: *Operand
;; rdx: src: *Operand
@ -1458,7 +1864,15 @@ section .rdata
MOV_RAX_COMMA_LEN equ $ - MOV_RAX_COMMA
COMMA_RAX db ", rax"
COMMA_RAX_LEN equ $ - COMMA_RAX
XOR_RDX_RDX db "xor rdx, rdx", 10
XOR_RDX_RDX_LEN equ $ - XOR_RDX_RDX
ADD_ dq "add "
SUB_ dq "sub "
MUL_ dq "mul "
DIV_ dq "div "
; Operand { kind: REGISTER, register: 0, width: 8, len: 0, padding: 0, value: 0 }
align 8
OPERAND_RAX dq 0x0000_8001, 0
OPERAND_RDX dq 0x0000_8301, 0

View file

@ -93,7 +93,7 @@ fn main() {
print_ast(
b"fn main(a: u32) -> void {
return 4;
return 2 * 3 + 4 * 5;
}",
|ast| unsafe { parse_func(ast) },
);