many small fixes

This commit is contained in:
janis 2025-11-01 01:41:13 +01:00
parent e43424b780
commit a25dcdabbb
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 520 additions and 53 deletions

View file

@ -7,7 +7,9 @@ extern vec_extend
extern vec_get
extern vec_push
extern vec_insert_sorted
extern vec_insert_many
extern vec_init_with
extern int_to_str2
global codegen_function
global get_register_name
@ -29,9 +31,27 @@ section .rdata
MOV_RAX_LEN equ $ - MOV_RAX
JMP_EPILOGUE db 10, "jmp .epilogue", 10
JMP_EPILOGUE_LEN equ $ - JMP_EPILOGUE
DOT_ARGS db ".args:", 10
DOT_ARGS_LEN equ $ - DOT_ARGS
DOT_BODY db ".body:", 10
DOT_BODY_LEN equ $ - DOT_BODY
DOT_PROLOGUE db ".prologue:", 10
DOT_PROLOGUE_LEN equ $ - DOT_PROLOGUE
DOT_EPILOGUE db ".epilogue:", 10
DOT_EPILOGUE_LEN equ $ - DOT_EPILOGUE
JMP_ARGS db 10, "jmp .args", 10
JMP_ARGS_LEN equ $ - JMP_ARGS
JMP_BODY db 10, "jmp .body", 10
JMP_BODY_LEN equ $ - JMP_BODY
JMP_PROLOGUE db 10, "jmp .prologue", 10
JMP_PROLOGUE_LEN equ $ - JMP_PROLOGUE
SUB_RSP db "sub rsp, "
SUB_RSP_LEN equ $ - SUB_RSP
ADD_RSP db "add rsp, "
ADD_RSP_LEN equ $ - ADD_RSP
REGISTER_NAMES db "abcdsidibpspr8r9r10r11r12r13r14r15"
WIDTHS db "erxliwdbp"
section .text
@ -153,6 +173,73 @@ write_register_name:
ret
;; rdi: arg index
;; Returns the `Operand` for the given argument index
codegen_arg_to_operand:
push rbp
mov rbp, rsp
cmp rdi, 6
jge .stack_arg
; register args in sysV make this strange movement through the canonical register indices:
; 3 2 1 0 4 5
; [a,b,c,d,si,di,bp,sp,8,9,10,11,12,13,14,15]
; at least there's 6 register args and not 4 line on win64..
cmp rdi, 2
jge .rdx
mov rax, 5
sub rax, rdi
jmp .reg_arg
.rdx:
cmp rdi, 4
jge .r8
mov rax, 5
sub rax, rdi
jmp .reg_arg
.r8:
add rdi, 4 ; offset to r8
mov rax, rdi
.reg_arg:
mov rdi, rax
xor rax, rax
mov eax, 0 ; Operand.len = 0
shl eax, 16
or eax, 8 ; Operand.width = 8
shl eax, 4
or eax, edi ; Operand.register
shl eax, 8
or eax, OPERAND_REGISTER ; Operand.kind
mov rdx, 0 ; Operand.value = 0
jmp .epilogue
.stack_arg:
sub rdi, 6
mov rax, 8
mul rdi
add rax, 16 ; return address + old rbp
; construct Operand
mov rdx, rax ; Operand.value = offset
xor rax, rax
mov eax, 0 ; Operand.len = 0
shl eax, 16
or eax, 8 ; Operand.width = 8
shl eax, 4
; or eax, 0 ; Operand.register = undef
shl eax, 8
or eax, OPERAND_RBP_OFFSET ; Operand.kind
.epilogue:
pop rbp
ret
;; rdi: ctx
;; rsi: a: *const (index, offset)
;; rdx: b: *const (index, offset)
@ -259,6 +346,7 @@ codegen_function:
push rbx
push r15
push r14
push r13
; scratch [104..120]
; dirtied-register-bitset [88..104] [a,b,c,d,si,di,bp,sp,8,9,10,11,12,13,14,15]
@ -340,6 +428,21 @@ codegen_function:
; allocate args on stack
; rbx = *AstFunction
; "jmp .prologue\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel JMP_PROLOGUE]
mov rdx, JMP_PROLOGUE_LEN
call vec_extend
; ".args:\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel DOT_ARGS]
mov rdx, DOT_ARGS_LEN
call vec_extend
mov r15, [rbx + 24] ; AstFunction.args_len
xor r14, r14 ; arg index
.arg_loop:
@ -359,28 +462,126 @@ codegen_function:
mov rdx, stackvar_cmp
mov rcx, 0
call vec_insert_sorted
; spill arg from register to newly allocated stack slot
; get source Operand
mov r13, [rsp + 112] ; current_stack_size before increment
mov rdi, [rsp + 104] ; arg index
call codegen_arg_to_operand
mov [rsp + 104], rax
mov [rsp + 112], rdx
mov rdx, r13 ; offset
neg rdx
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 104] ; src
call codegen_move_rbp_slot_src
inc r14
jmp .arg_loop
.arg_loop_done:
; "jmp .body\n"
; ".body:\n"
mov rdi, [rsp] ; ctx
lea rsi, [rsp + 24] ; &function_ctx
mov rdx, [rbx + 48] ; AstFunction.body
call codegen_block
call codegen_expr
; TODO: generate function body
; push "ret\n"
; ".epilogue:\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel DOT_EPILOGUE]
mov rdx, DOT_EPILOGUE_LEN
call vec_extend
; "pop {dirtied registers}\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
mov rsi, [rsp + 24] ; &function_ctx
mov rdx, 0 ; push = false
call codegen_push_pop_dirtied_registers
; "add rsp, {current_stack_size}\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel ADD_RSP]
mov rdx, ADD_RSP_LEN
call vec_extend
mov rdi, [rsp + 24] ; &function_ctx
mov rdi, [rdi + 0] ; current_stack_size
lea rsi, [rsp + 104] ; scratch
mov rdx, 16 ; buffer length
mov rcx, 10 ; radix
call int_to_str2
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rax + rdx]
mov byte [rsi], 10 ; add newline
mov rsi, rax
mov rdx, rdx ; length from int_to_str2
call vec_extend
; "ret\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel RET_NL]
mov rdx, RET_NL_LEN
call vec_extend
; ".prologue:\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel DOT_PROLOGUE]
mov rdx, DOT_PROLOGUE_LEN
call vec_extend
; "sub rsp, {current_stack_size}\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel SUB_RSP]
mov rdx, SUB_RSP_LEN
call vec_extend
mov rdi, [rsp + 24] ; &function_ctx
mov rdi, [rdi + 0] ; current_stack_size
lea rsi, [rsp + 104] ; scratch
mov rdx, 16 ; buffer length
mov rcx, 10 ; radix
call int_to_str2
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rax + rdx]
mov byte [rsi], 10 ; add newline
mov rsi, rax
mov rdx, rdx ; length from int_to_str2
call vec_extend
; "push{dirtied registers}\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
mov rsi, [rsp + 24] ; &function_ctx
mov rdx, 1 ; push = false
call codegen_push_pop_dirtied_registers
; "jmp .args\n"
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel JMP_ARGS]
mov rdx, JMP_ARGS_LEN
call vec_extend
add rsp, 120
pop r15
pop r14
push r13
push r14
push r15
pop rbx
pop rbp
ret
@ -388,6 +589,116 @@ codegen_function:
.panic:
call panic
;; rdi: *text
;; rsi: &function_ctx
;; rdx: push: bool
codegen_push_pop_dirtied_registers:
push rbp
mov rbp, rsp
push rbx
push r15
push r14
sub rsp, 32
mov [rsp], rdi
mov [rsp + 8], rsi
mov byte [rsp + 29 + 3], 10 ; newline
mov qword [rsp + 16], -1
mov rax, ' hsup'
mov qword [rsp + 24], rax
test rdx, rdx
jz .skip_setup_pop
mov rax, ' pop'
mov qword [rsp + 24], rax
mov rdi, [rsp] ; text
mov rax, [rdi + 8] ; text.len()
mov [rsp + 16], rax
.skip_setup_pop:
; low: 0b01000000 high: 0b00001111
; preserved registers:
mov rax, [rsi + 48 + 16] ; dirtied_register_bitset low
mov rbx, 0b01000000
and rax, rbx
test rax, rax
jz .skip_rbp
mov rdi, 2
mov rsi, 8
lea rdx, [rsp + 29]
call get_register_name
mov rax, -1
cmp [rsp + 16], rax
jne .rbx_pop
mov rdi, [rsp] ; text
lea rsi, [rsp + 24]
mov rdx, 9
call vec_extend
jmp .skip_rbp
.rbx_pop:
mov rdi, [rsp] ; text
lea rsi, [rsp + 24]
mov rdx, 9
mov rcx, [rsp + 16] ; text.len()
call vec_insert_many
.skip_rbp:
mov rax, [rsi + 48 + 16 + 8] ; dirtied_register_bitset high
mov rbx, 0b00001111
and rax, rbx
test rax, rax
jz .done
mov r15, 8
xor r14, r14
.reg_loop:
cmp r14, r15
jge .done
bt rax, r14
jnc .next_reg
mov rdi, 8
add rdi, r14
mov rsi, 8
lea rdx, [rsp + 29]
call get_register_name
mov rax, -1
cmp [rsp + 16], rax
jne .reg_pop
mov rdi, [rsp] ; text
lea rsi, [rsp + 24]
mov rdx, 9
call vec_extend
jmp .next_reg
.reg_pop:
mov rdi, [rsp] ; text
lea rsi, [rsp + 24]
mov rdx, 9
mov rcx, [rsp + 16] ; text.len()
call vec_insert_many
.next_reg:
inc r14
jmp .reg_loop
.done:
add rsp, 32
pop r14
pop r15
pop rbx
pop rbp
ret
;; rdi: ctx
;; rsi: &function_ctx
;; rdx: block index
@ -405,17 +716,17 @@ codegen_block:
mov rdi, [rdi] ; ast
mov rsi, rdx ; block index
call vec_get
mov 15, [rax + 8] ; AstNode.extra
mov rbx, [rax + 0] ; AstNode.data
mov r15, [rax + 8] ; AstNode.extra
mov rbx, [rax + 0] ; AstNode.data
xor r14, r14 ; statement index
.stmt_loop:
cmp r14, r15
jge .stmt_loop_done
mov rdi, [rsp] ; ctx
lea mov, [rsp + 8] ; &function_ctx
lea rbx, [rsp + 8] ; &function_ctx
mov rdx, [rbx + r14 * 8] ; statements[i]
call codegen_statement
call codegen_expr
inc r14
jmp .stmt_loop
@ -436,11 +747,13 @@ codegen_expr:
push rbp
mov rbp, rsp
push rbx
push r15
push r14
; scratch [16..32]
; scratch [16..48]
; function_ctx: [8..16]
; ctx [0..8]
sub rsp, 32
sub rsp, 48
mov [rsp], rdi ; ctx
mov [rsp + 8], rsi ; &function_ctx
@ -475,52 +788,112 @@ codegen_expr:
je .address_of
jmp .panic
.block:
mov rbx, [rax + 8] ; AstNode.data
mov r15, [rax + 16] ; AstNode.extra
xor r14, r14 ; statement index
.stmt_loop:
cmp r14, r15
jge .stmt_loop_done
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
mov rdx, [rbx + r14 * 8] ; statements[i]
call codegen_expr
inc r14
jmp .stmt_loop
.stmt_loop_done:
xor rax, rax
xor rdx, rdx
jmp .done
.return:
; codegen inner expr
mov rdi, [rsp] ; ctx
mov rsi, [rsp + 8] ; &function_ctx
mov rdx, [rax + 8] ; AstNode.data
call codegen_expr
mov rbx, rax
; mov rax, {inner expr result}
mov [rsp + 16], rax
mov [rsp + 24], rdx
mov rax, qword [rel OPERAND_RAX]
mov rdx, qword [rel OPERAND_RAX + 8]
mov [rsp + 32], rax
mov [rsp + 40], rdx
mov rdi, [rsp] ; ctx
mov rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel MOV_RAX]
mov rdx, MOV_RAX_LEN
call vec_extend
mov rdi, rbx
mov rsi, 8
lea rdx, [rsp + 16] ; scratch
call get_register_name
mov rdi, [rsp] ; ctx
mov rdi, [rdi + 8] ; &ctx.text
mov rsi, rax
call vec_extend
lea rsi, [rsp + 32] ; dst
lea rdx, [rsp + 16] ; src
call codegen_move_dst_src
; push "jmp .epilogue\n"
mov rdi, [rsp] ; ctx
mov rdi, [rdi + 8] ; &ctx.text
lea rsi, [rel JMP_EPILOGUE]
mov rdx, JMP_EPILOGUE_LEN
call vec_extend
mov rax, 0
; construct return operand
; Operand { kind: REGISTER, register_and_width: (register | (width << 4)), len: 0, value: 0 }
mov eax, 0 ; len = 0
shl eax, 16
or eax, 8 ; width = 8
shl eax, 4
or eax, 0 ; register = rax
shl eax, 8
or eax, OPERAND_REGISTER ; kind
mov rdx, 0 ; value = 0
jmp .done
.number:
; rax = *AstNode
mov [rsp + 16], rax ; scratch = *AstNode
mov rbx, [rax + 8] ; AstNode.data = value
mov [rsp + 40], rbx ; Operand.value
mov rdi, [rsp + 8] ; &function_ctx
call codegen_allocate_register
xor rbx, rbx
or rbx, 8 ; width = 8
shl rbx, 4
or rbx, rax ; register
shl rbx, 8
or rbx, OPERAND_REGISTER ; kind
mov [rsp + 16], rbx ;
mov qword [rsp + 24], 0 ; value = 0
mov byte [rsp + 32], OPERAND_IMMEDIATE ; Operand.kind
mov bl, 8 ; width = 8
shl bl, 4 ; register = undef
mov byte [rsp + 33], bl ; Operand.register_and_width
mov word [rsp + 34], 0 ; Operand.len = 0
mov rdi, [rsp] ; ctx
mov rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 16] ; dst
lea rdx, [rsp + 16] ; src
call codegen_move_dst_src
mov rax, qword [rsp + 16]
mov rdx, qword [rsp + 24]
jmp .done
.var_decl:
.var_ref:
.binary_op:
.assignment:
.place_to_value:
.value_to_place:
.deref:
.address_of:
; TODO
.done:
add rsp, 32
add rsp, 48
pop r14
pop r15
pop rbx
pop rbp
ret
@ -539,19 +912,21 @@ codegen_expr:
;; or: register: u4, width: u4
section .rdata
;; start-consts
OPERAND_REGISTER db 1 ; e.g. rax, rbx
OPERAND_RBP_OFFSET db 2 ; e.g. [rbp - 8]
OPERAND_RSP_OFFSET db 3 ; e.g. [rsp + 16]
OPERAND_ADDRESS db 4 ; e.g. [rel OPERAND_ADDRESS]
OPERAND_IMMEDIATE db 5 ; e.g. 0x10
OPERAND_CONSTANT db 6 ; e.g. OPERAND_CONSTANT
OPERAND_LABEL db 7 ; e.g. label_1234
OPERAND_REGISTER equ 1 ; e.g. rax, rbx
OPERAND_RBP_OFFSET equ 2 ; e.g. [rbp - 8]
OPERAND_RSP_OFFSET equ 3 ; e.g. [rsp + 16]
OPERAND_ADDRESS equ 4 ; e.g. [rel OPERAND_ADDRESS]
OPERAND_IMMEDIATE equ 5 ; e.g. 0x10
OPERAND_CONSTANT equ 6 ; e.g. OPERAND_CONSTANT
OPERAND_LABEL equ 7 ; e.g. label_1234
;; end-consts
WIDTH_BYTE db 'byte '
WIDTH_WORD db 'word '
WIDTH_DWORD db 'dword '
WIDTH_QWORD db 'qword '
section .text
;; rdi: *text
;; rsi: op: *Operand
codegen_write_operand:
@ -587,7 +962,7 @@ codegen_write_operand:
mov rbx, rsi
mov rdi, [rbx + 1] ; register_and_width
mov rsi, rdi
mov dil, dil ; low 4 bits = register
and dil, 0x0F ; low 4 bits = register
shr rsi, 4 ; high 4 bits = width
lea rdx, [rsp + 16] ; buffer
call get_register_name
@ -601,7 +976,7 @@ codegen_write_operand:
.rsp_offset:
; {width} [rbp {+/-} offset]
mov rsi, [rsp + 8] ; op
mov sil, byte [rsi + 1] ; register_and_width
mov sil, byte [rsi + 1] ; Operand.register_and_width
shr sil, 4 ; width
mov rdi, [rsp] ; *text
call codegen_write_width
@ -614,10 +989,10 @@ codegen_write_operand:
; if op.kind == OPERAND_RBP_OFFSET
mov rax, [rsp + 8] ; op
mov al, byte [rax + 0] ; op.kind
mov al, byte [rax + 0] ; Operand.kind
cmp al, OPERAND_RBP_OFFSET
jne .rsp_offset_write
mov qword [rsp + 16], ' pbr'
mov qword [rsp + 16], 'rbp '
mov rdi, [rsp] ; *text
lea rsi, [rsp + 16]
mov rdx, 4
@ -625,7 +1000,7 @@ codegen_write_operand:
jmp .check_sign
.rsp_offset_write:
mov qword [rsp + 16], ' psr'
mov qword [rsp + 16], 'rsp '
mov rdi, [rsp] ; *text
lea rsi, [rsp + 16]
mov rdx, 4
@ -637,11 +1012,12 @@ codegen_write_operand:
mov rdi, [rax + 8] ; op.value
cmp rdi, 0
jl .skip_plus
mov qword [rsp + 16], ' + '
mov qword [rsp + 16], ' + '
mov rdi, [rsp] ; *text
lea rsi, [rsp + 16]
mov rdx, 3
call vec_extend
nop
.skip_plus:
; write offset
@ -668,7 +1044,7 @@ codegen_write_operand:
lea rsi, [rsp + 16]
call vec_push
mov qword [rsp + 16], ' ler'
mov qword [rsp + 16], 'rel '
mov rdi, [rsp] ; *text
lea rsi, [rsp + 16]
mov rdx, 4
@ -678,7 +1054,7 @@ codegen_write_operand:
mov rax, [rsp + 8] ; op
mov rdi, [rsp] ; *text
mov rsi, [rax + 8] ; op.value
mov rdx, [rax + 4] ; op.len
mov rdx, [rax + 2] ; op.len
mov dx, dx ; low 16 bits
call vec_extend
@ -707,11 +1083,14 @@ codegen_write_operand:
mov rax, [rsp + 8] ; op
mov rdi, [rsp] ; *text
mov rsi, [rax + 8] ; op.value
mov rdx, [rax + 4] ; op.len
mov rdx, [rax + 2] ; op.len
mov dx, dx ; low 16 bits
call vec_extend
jmp .epilogue
.label:
jmp .panic
.epilogue:
add rsp, 40
pop rbx
@ -745,7 +1124,33 @@ codegen_write_width:
call vec_extend
pop rax ; length written
ret
.panic:
call panic
;; rdi: *text
;; rsi: src: *Operand
;; rdx: rbp offset
codegen_move_rbp_slot_src:
push rbp
mov rbp, rsp
sub rsp, 16
; construct dst Operand
mov byte [rsp + 0], OPERAND_RBP_OFFSET ; Operand.kind
mov byte [rsp + 1], 0x80 ; Operand.register_and_width (width=8)
mov word [rsp + 2], 0 ; Operand.len = 0
mov dword [rsp + 4], 0 ; padding
mov qword [rsp + 8], rdx ; Operand.value = rbp offset
mov rdx, rsi
lea rsi, [rsp + 0] ; dst
call codegen_move_dst_src
add rsp, 16
pop rbp
ret
;; rdi: *text
;; rsi: dst: *Operand
@ -764,8 +1169,8 @@ codegen_move_dst_src:
jg .panic ; unsupported dst kind
; if dst.width != src.width
mov cl, byte [rsi + 2] ; dst.register_and_width
mov bl, byte [rdx + 2] ; src.register_and_width
mov cl, byte [rsi + 1] ; dst.register_and_width
mov bl, byte [rdx + 1] ; src.register_and_width
shr cl, 4
shr bl, 4
cmp cl, bl
@ -788,13 +1193,80 @@ codegen_move_dst_src:
; xchg rax, [src]
; mov [dst], rax
; xchg rax, [src]
mov rdi, [rsp] ; *text
lea rsi, [rel XCHG_RAX]
mov rdx, XCHG_RAX_LEN
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 16] ; src
call codegen_write_operand
mov rdi, [rsp] ; *text
lea rsi, [rel COMMA_RAX]
mov rdx, COMMA_RAX_LEN
call vec_extend
mov rdi, [rsp] ; *text
lea rsi, [rel MOV_RAX_COMMA]
mov rdx, 4
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; dst
call codegen_write_operand
mov rdi, [rsp] ; *text
lea rsi, [rel COMMA_RAX]
mov rdx, COMMA_RAX_LEN
call vec_extend
mov rdi, [rsp] ; *text
lea rsi, [rel XCHG_RAX]
mov rdx, XCHG_RAX_LEN
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 16] ; src
call codegen_write_operand
jmp .epilogue
.do_move:
mov rdi, [rsp] ; *text
lea rsi, [rel MOV_RAX_COMMA]
mov rdx, 4
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; dst
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] ; src
call codegen_write_operand
.epilogue:
add rsp, 24
pop rbx
pop rbp
ret
.panic:
call panic
section .rdata
XCHG_RAX db "xchg rax, "
XCHG_RAX_LEN equ $ - XCHG_RAX
MOV_RAX_COMMA db "mov rax, "
MOV_RAX_COMMA_LEN equ $ - MOV_RAX_COMMA
COMMA_RAX db ", rax"
COMMA_RAX_LEN equ $ - COMMA_RAX
; Operand { kind: REGISTER, register: 0, width: 8, len: 0, padding: 0, value: 0 }
align 8
OPERAND_RAX dq 0x0000_8001, 0

View file

@ -90,12 +90,7 @@ fn main() {
print_ast(
b"fn main(a: u32) -> void {
let y: u32 = a + 4;
{
let y: u32 = 10;
}
let y: *u32 = &y;
return *y;
return 4;
}",
|ast| unsafe { parse_func(ast) },
);