diff options
-rw-r--r-- | 05/codegen.b | 125 | ||||
-rw-r--r-- | 05/main.c | 26 | ||||
-rw-r--r-- | 05/parse.b | 1 | ||||
-rw-r--r-- | README.md | 1 |
4 files changed, 151 insertions, 2 deletions
diff --git a/05/codegen.b b/05/codegen.b index ffdf94c..d30e23d 100644 --- a/05/codegen.b +++ b/05/codegen.b @@ -108,6 +108,16 @@ function emit_mov_rbx_imm64 code_output += 8 return +function emit_add_rax_imm32 + ; 48 05 IMM32 + argument imm32 + *2code_output = 0x0548 + code_output += 2 + *4code_output = imm32 + code_output += 4 + return + + function emit_zero_rax ; 31 c0 *2code_output = 0xc031 @@ -1421,8 +1431,10 @@ function generate_push_expression type = *4type c = *1expr + ; @TODO : reorder from most to least common, probably if c == EXPRESSION_CONSTANT_INT goto generate_int if c == EXPRESSION_CONSTANT_FLOAT goto generate_float + if c == EXPRESSION_FUNCTION goto generate_function_addr if c == EXPRESSION_CAST goto generate_cast if c == EXPRESSION_UNARY_PLUS goto generate_cast ; the unary plus operator just casts to the promoted type if c == EXPRESSION_UNARY_MINUS goto generate_unary_minus @@ -1447,6 +1459,9 @@ function generate_push_expression if c == EXPRESSION_ARROW goto generate_dot_or_arrow if c == EXPRESSION_COMMA goto generate_comma if c == EXPRESSION_ASSIGN goto generate_assign + if c == EXPRESSION_CALL goto generate_call + + putnln(c) die(.str_genpushexprNI) :str_genpushexprNI @@ -1456,6 +1471,27 @@ function generate_push_expression expr += 8 expr = generate_push_expression_casted(statement, expr, type) return expr + :generate_function_addr + d = 0 + expr += 8 + if codegen_second_pass == 0 goto function_noaddr + d = ident_list_lookup(functions_addresses, *8expr) + if d == 0 goto no_such_function + :function_noaddr + expr += 8 + emit_mov_rax_imm64(d) + emit_push_rax() + return expr + + :no_such_function + print_statement_location(statement) + puts(.str_no_such_function) + putsln(*8expr) + exit(1) + :str_no_such_function + string : Error: No such function: + byte 32 + byte 0 :generate_unary_minus expr += 8 expr = generate_push_expression_casted(statement, expr, type) @@ -1724,6 +1760,93 @@ function generate_push_expression emit_add_rsp_imm32(c) ; add rsp, (size of expression value on stack) expr = generate_push_expression(statement, expr) return expr + :generate_call + expr += 8 + global 4000 expr_arg_ptrs_dat + local expr_arg_ptrs + expr_arg_ptrs = &expr_arg_ptrs_dat + local arg_idx + local call_function + local return_val_size + local args_size + + return_val_size = type_sizeof(type) + return_val_size = round_up_to_8(return_val_size) + + call_function = expr + expr = expression_get_end(expr) + + args_size = 0 + + ; we have to do a bit of work because the arguments are stored + ; left to right, but pushed right to left + arg_idx = 0 + p = expr_arg_ptrs + :find_call_args_loop + if *1expr == 0 goto find_call_args_loop_end + *8p = expr + + c = expr + 4 + c = type_sizeof(*4c) + c = round_up_to_8(c) + args_size += c + + expr = expression_get_end(expr) + p += 8 + arg_idx += 1 + goto find_call_args_loop + :find_call_args_loop_end + expr += 8 + + :push_args_loop + if arg_idx == 0 goto push_args_loop_end + p -= 8 + generate_push_expression(statement, *8p) + arg_idx -= 1 + goto push_args_loop + :push_args_loop_end + + ; create space on stack for return value + emit_sub_rsp_imm32(return_val_size) + ; put function in rax + generate_push_expression(statement, call_function) + emit_mov_rax_qword_rsp() + emit_add_rsp_imm32(8) + ; call + emit_call_rax() + + if return_val_size > 8 goto generate_big_return + emit_mov_rax_qword_rsp() ; mov rax, [rsp] + emit_add_rsp_imm32(args_size) ; add rsp, (size of arguments on stack) + emit_mov_qword_rsp_rax() ; mov [rsp], rax + return expr + + :generate_big_return + ; now we need to copy the return value to the proper place in the stack + ; this is kind of annoying because that might overlap with the current position. + ; so, we'll push a copy of the return value, then copy that over to the proper place. + local copy_offset + + ; first copy + copy_offset = 0 - return_val_size + emit_mov_reg(REG_RSI, REG_RSP) + emit_mov_reg(REG_RAX, REG_RSP) + emit_add_rax_imm32(copy_offset) + emit_mov_reg(REG_RDI, REG_RAX) + generate_copy_rsi_to_rdi_qwords(type) + + ; second copy + emit_mov_reg(REG_RAX, REG_RSP) + emit_add_rax_imm32(copy_offset) + emit_mov_reg(REG_RSI, REG_RAX) + emit_mov_reg(REG_RAX, REG_RSP) + emit_add_rax_imm32(args_size) + emit_mov_reg(REG_RDI, REG_RAX) + generate_copy_rsi_to_rdi_qwords(type) + + emit_add_rsp_imm32(args_size) + return + function generate_statement argument statement local dat1 @@ -1868,7 +1991,7 @@ function generate_functions :function_addr_mismatch ; address of function on 2nd pass doesn't line up with 1st pass puts(.str_function_addr_mismatch) - puts(function_name) + putsln(function_name) exit(1) :str_function_addr_mismatch string Function address on first pass doesn't match 2nd pass: @@ -1,4 +1,28 @@ +typedef struct { + long a; + long aah[810]; + long b; +} Structure; + +Structure mkstruct(int x, int y) { + Structure s; + s.a = x; + s.b = y; + return s; +} + +Structure mkstruct1(int x) { + return mkstruct(x, x*2); +} + +Structure mkstruct_a() { + return mkstruct1(1033.3); +} + long main(int argc, char **argv) { - return 43 >> 2; + Structure t; + t = mkstruct_a(); + return t.b; } + @@ -23,6 +23,7 @@ function token_is_type b = ident_list_lookup(typedefs, c) if b != 0 goto return_1 goto return_0 + function type_is_array argument type @@ -113,6 +113,7 @@ ax bx cx dx sp bp si di ├──────────────────────┼───────────────────┼────────────────────────────────────────┤ │ mov rax, IMM64 │ 48 b8 IMM64 │ set rax to the 64-bit value IMM64 │ │ mov rbx, IMM64 │ 48 bb IMM64 │ set rbx to the 64-bit value IMM64 │ +| add rax, IMM32 | 48 05 IMM32 | add IMM32 (signed) to rax | │ xor eax, eax │ 31 c0 │ set rax to 0 (shorter than mov rax, 0) │ │ xor edx, edx │ 31 d2 │ set rdx to 0 │ │ mov RDEST, RSRC │ 48 89 (DEST|SRC<<3|0xc0) │ set register DEST to current │ |