generating code for casts!
This commit is contained in:
parent
bba56d2b51
commit
017a70ee7e
8 changed files with 423 additions and 101 deletions
398
05/codegen.b
398
05/codegen.b
|
@ -21,6 +21,7 @@ global codegen_second_pass ; = 0 on first global pass, 1 on second global pass
|
||||||
global functions_addresses ; ident list of addresses
|
global functions_addresses ; ident list of addresses
|
||||||
global functions_labels ; ident list of ident lists of label addresses
|
global functions_labels ; ident list of ident lists of label addresses
|
||||||
global curr_function_labels ; ident list of labels for current function (written to in 1st pass, read from in 2nd pass)
|
global curr_function_labels ; ident list of labels for current function (written to in 1st pass, read from in 2nd pass)
|
||||||
|
global curr_function_return_type
|
||||||
|
|
||||||
#define REG_RAX 0
|
#define REG_RAX 0
|
||||||
#define REG_RBX 3
|
#define REG_RBX 3
|
||||||
|
@ -77,6 +78,71 @@ function emit_mov_reg
|
||||||
code_output += 1
|
code_output += 1
|
||||||
return
|
return
|
||||||
|
|
||||||
|
function emit_mov_rax_imm64
|
||||||
|
argument imm64
|
||||||
|
; 48 b8 IMM64
|
||||||
|
*2code_output = 0xb848
|
||||||
|
code_output += 2
|
||||||
|
*8code_output = imm64
|
||||||
|
code_output += 8
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movsx_rax_al
|
||||||
|
; 48 0f be c0
|
||||||
|
*4code_output = 0xc0be0f48
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movsx_rax_ax
|
||||||
|
; 48 0f bf c0
|
||||||
|
*4code_output = 0xc0bf0f48
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movsx_rax_eax
|
||||||
|
; 48 63 c0
|
||||||
|
*2code_output = 0x6348
|
||||||
|
code_output += 2
|
||||||
|
*1code_output = 0xc0
|
||||||
|
code_output += 1
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movzx_rax_al
|
||||||
|
; 48 0f b6 c0
|
||||||
|
*4code_output = 0xc0b60f48
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movzx_rax_ax
|
||||||
|
; 48 0f b7 c0
|
||||||
|
*4code_output = 0xc0b70f48
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_mov_eax_eax
|
||||||
|
; 89 c0
|
||||||
|
*2code_output = 0xc089
|
||||||
|
code_output += 2
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_mov_qword_rsp_plus_imm32_rax
|
||||||
|
argument imm32
|
||||||
|
; 48 89 84 24 IMM32
|
||||||
|
*4code_output = 0x24848948
|
||||||
|
code_output += 4
|
||||||
|
*4code_output = imm32
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_mov_rax_qword_rsp_plus_imm32
|
||||||
|
argument imm32
|
||||||
|
; 48 8b 84 24 IMM32
|
||||||
|
*4code_output = 0x24848b48
|
||||||
|
code_output += 4
|
||||||
|
*4code_output = imm32
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
function emit_sub_rsp_imm32
|
function emit_sub_rsp_imm32
|
||||||
argument imm32
|
argument imm32
|
||||||
|
@ -117,33 +183,6 @@ function emit_ret
|
||||||
code_output += 1
|
code_output += 1
|
||||||
return
|
return
|
||||||
|
|
||||||
function emit_mov_qword_rsp_plus_imm32_rax
|
|
||||||
argument imm32
|
|
||||||
; 48 89 84 24 IMM32
|
|
||||||
*4code_output = 0x24848948
|
|
||||||
code_output += 4
|
|
||||||
*4code_output = imm32
|
|
||||||
code_output += 4
|
|
||||||
return
|
|
||||||
|
|
||||||
function emit_mov_rax_qword_rsp_plus_imm32
|
|
||||||
argument imm32
|
|
||||||
; 48 8b 84 24 IMM32
|
|
||||||
*4code_output = 0x24848b48
|
|
||||||
code_output += 4
|
|
||||||
*4code_output = imm32
|
|
||||||
code_output += 4
|
|
||||||
return
|
|
||||||
|
|
||||||
function emit_mov_rax_imm64
|
|
||||||
argument imm64
|
|
||||||
; 48 b8 IMM64
|
|
||||||
*2code_output = 0xb848
|
|
||||||
code_output += 2
|
|
||||||
*8code_output = imm64
|
|
||||||
code_output += 8
|
|
||||||
return
|
|
||||||
|
|
||||||
function emit_call_rax
|
function emit_call_rax
|
||||||
; ff d0
|
; ff d0
|
||||||
*2code_output = 0xd0ff
|
*2code_output = 0xd0ff
|
||||||
|
@ -185,6 +224,59 @@ function emit_movsq
|
||||||
code_output += 2
|
code_output += 2
|
||||||
return
|
return
|
||||||
|
|
||||||
|
function emit_movss_xmm0_dword_rax
|
||||||
|
; f3 0f 10 00
|
||||||
|
*4code_output = 0x00100ff3
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movsd_xmm0_qword_rax
|
||||||
|
; f2 0f 10 00
|
||||||
|
*4code_output = 0x00100ff2
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movss_dword_rax_xmm0
|
||||||
|
; f3 0f 11 00
|
||||||
|
*4code_output = 0x00110ff3
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_movsd_qword_rax_xmm0
|
||||||
|
; f2 0f 11 00
|
||||||
|
*4code_output = 0x00110ff2
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_cvtss2sd_xmm0_xmm0
|
||||||
|
; f3 0f 5a c0
|
||||||
|
*4code_output = 0xc05a0ff3
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_cvtsd2ss_xmm0_xmm0
|
||||||
|
; f2 0f 5a c0
|
||||||
|
*4code_output = 0xc05a0ff2
|
||||||
|
code_output += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_cvttsd2si_rax_xmm0
|
||||||
|
; f2 48 0f 2c c0
|
||||||
|
*4code_output = 0x2c0f48f2
|
||||||
|
code_output += 4
|
||||||
|
*1code_output = 0xc0
|
||||||
|
code_output += 1
|
||||||
|
return
|
||||||
|
|
||||||
|
function emit_cvtsi2sd_xmm0_rax
|
||||||
|
; f2 48 0f 2a c0
|
||||||
|
*4code_output = 0x2a0f48f2
|
||||||
|
code_output += 4
|
||||||
|
*1code_output = 0xc0
|
||||||
|
code_output += 1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
; make sure you put the return value in the proper place before calling this
|
; make sure you put the return value in the proper place before calling this
|
||||||
function generate_return
|
function generate_return
|
||||||
emit_mov_reg(REG_RSP, REG_RBP)
|
emit_mov_reg(REG_RSP, REG_RBP)
|
||||||
|
@ -193,24 +285,6 @@ function generate_return
|
||||||
emit_ret()
|
emit_ret()
|
||||||
return
|
return
|
||||||
|
|
||||||
; returns pointer to end of expression
|
|
||||||
function generate_push_expression
|
|
||||||
argument expr
|
|
||||||
local c
|
|
||||||
c = *1expr
|
|
||||||
if c == EXPRESSION_CONSTANT_INT goto generate_push_int
|
|
||||||
|
|
||||||
die(.str_genpushexprNI)
|
|
||||||
:str_genpushexprNI
|
|
||||||
string generate_push_expression not implemented.
|
|
||||||
byte 0
|
|
||||||
:generate_push_int
|
|
||||||
expr += 8
|
|
||||||
emit_mov_rax_imm64(*8expr)
|
|
||||||
emit_push_rax()
|
|
||||||
expr += 8
|
|
||||||
return expr
|
|
||||||
|
|
||||||
; copy sizeof(type) bytes, rounded up to the nearest 8, from rsi to rdi
|
; copy sizeof(type) bytes, rounded up to the nearest 8, from rsi to rdi
|
||||||
function generate_copy_rsi_to_rdi_qwords
|
function generate_copy_rsi_to_rdi_qwords
|
||||||
argument type
|
argument type
|
||||||
|
@ -230,6 +304,225 @@ function generate_copy_rsi_to_rdi_qwords
|
||||||
emit_movsq()
|
emit_movsq()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
; cast whatever was just pushed onto the stack from from_type to to_type
|
||||||
|
; `statement` is used for errors
|
||||||
|
function generate_cast_top_of_stack
|
||||||
|
argument statement
|
||||||
|
argument from_type
|
||||||
|
argument to_type
|
||||||
|
local from
|
||||||
|
local to
|
||||||
|
local c
|
||||||
|
local d
|
||||||
|
|
||||||
|
from = types + from_type
|
||||||
|
to = types + to_type
|
||||||
|
|
||||||
|
if *1to == TYPE_VOID goto return_0 ; cast to void my ass
|
||||||
|
if *1from == TYPE_VOID goto bad_gen_cast ; cast from void to something - that's bad
|
||||||
|
if *1from == TYPE_ARRAY goto bad_gen_cast ; cast array (this probably won't ever happen because of decaying)
|
||||||
|
if *1to == TYPE_ARRAY goto bad_gen_cast ; cast to array
|
||||||
|
if *1from == TYPE_FUNCTION goto bad_gen_cast ; shouldn't happen
|
||||||
|
if *1to == TYPE_FUNCTION goto bad_gen_cast ; shouldn't happen
|
||||||
|
if *1to == TYPE_STRUCT goto gen_cast_to_struct
|
||||||
|
if *1from == TYPE_STRUCT goto bad_gen_cast ; cast from struct to something else
|
||||||
|
if *1to < TYPE_FLOAT goto gen_cast_to_integer
|
||||||
|
if *1to == TYPE_POINTER goto gen_cast_to_integer ; pointers are basically integers
|
||||||
|
|
||||||
|
; cast to float/double
|
||||||
|
if *1from == TYPE_POINTER goto bad_gen_cast ; pointer to float/double
|
||||||
|
if *1to == *1from goto return_0
|
||||||
|
if *1from == TYPE_DOUBLE goto gen_cast_double_to_float
|
||||||
|
if *1from == TYPE_FLOAT goto gen_cast_float_to_double
|
||||||
|
; int to float/double
|
||||||
|
if *1to == TYPE_FLOAT goto gen_cast_int_to_float
|
||||||
|
if *1to == TYPE_DOUBLE goto gen_cast_int_to_double
|
||||||
|
|
||||||
|
goto bad_gen_cast ; in theory we shouldn't get here
|
||||||
|
|
||||||
|
:gen_cast_to_integer
|
||||||
|
if *1from == *1to goto return_0 ; casting from type to same type
|
||||||
|
if *1from == TYPE_POINTER goto return_0 ; no need to do anything
|
||||||
|
; cast float/double to integer
|
||||||
|
if *1from == TYPE_FLOAT goto gen_cast_float_to_int
|
||||||
|
if *1from == TYPE_DOUBLE goto gen_cast_double_to_int
|
||||||
|
|
||||||
|
c = type_sizeof(*1from)
|
||||||
|
d = type_sizeof(*1to)
|
||||||
|
if d > c goto return_0 ; casting to bigger type, so we're good
|
||||||
|
if c == 8 goto return_0 ; casting from unsigned/signed long to unsigned/signed long, we're good
|
||||||
|
|
||||||
|
; mov rax, [rsp]
|
||||||
|
emit_mov_rax_qword_rsp_plus_imm32(0)
|
||||||
|
|
||||||
|
; now sign/zero extend the lower part of rax to the whole of rax
|
||||||
|
if *1to == TYPE_CHAR goto gen_cast_integer_to_signed_char
|
||||||
|
if *1to == TYPE_UNSIGNED_CHAR goto gen_cast_integer_to_unsigned_char
|
||||||
|
if *1to == TYPE_SHORT goto gen_cast_integer_to_signed_short
|
||||||
|
if *1to == TYPE_UNSIGNED_SHORT goto gen_cast_integer_to_unsigned_short
|
||||||
|
if *1to == TYPE_INT goto gen_cast_integer_to_signed_int
|
||||||
|
if *1to == TYPE_UNSIGNED_INT goto gen_cast_integer_to_unsigned_int
|
||||||
|
|
||||||
|
goto bad_gen_cast ; in theory we shouldn't get here
|
||||||
|
|
||||||
|
:int2int_cast_cont
|
||||||
|
; mov [rsp], rax
|
||||||
|
emit_mov_qword_rsp_plus_imm32_rax(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
:gen_cast_integer_to_signed_char
|
||||||
|
emit_movsx_rax_al()
|
||||||
|
goto int2int_cast_cont
|
||||||
|
:gen_cast_integer_to_unsigned_char
|
||||||
|
emit_movzx_rax_al()
|
||||||
|
goto int2int_cast_cont
|
||||||
|
:gen_cast_integer_to_signed_short
|
||||||
|
emit_movsx_rax_ax()
|
||||||
|
goto int2int_cast_cont
|
||||||
|
:gen_cast_integer_to_unsigned_short
|
||||||
|
emit_movzx_rax_ax()
|
||||||
|
goto int2int_cast_cont
|
||||||
|
:gen_cast_integer_to_signed_int
|
||||||
|
emit_movsx_rax_eax()
|
||||||
|
goto int2int_cast_cont
|
||||||
|
:gen_cast_integer_to_unsigned_int
|
||||||
|
emit_mov_eax_eax()
|
||||||
|
goto int2int_cast_cont
|
||||||
|
:gen_cast_to_struct
|
||||||
|
; this is necessary because we add an implicit cast for return values
|
||||||
|
; so if we didn't have this, we wouldn't be able to return structs.
|
||||||
|
if *1from != TYPE_STRUCT goto bad_gen_cast
|
||||||
|
from += 1
|
||||||
|
to += 1
|
||||||
|
if *8from != *8to goto bad_gen_cast
|
||||||
|
return ; no casting needed; these are the same type
|
||||||
|
:gen_cast_double_to_float
|
||||||
|
; mov rax, rsp
|
||||||
|
emit_mov_reg(REG_RAX, REG_RSP)
|
||||||
|
; movsd xmm0, [rax]
|
||||||
|
emit_movsd_xmm0_qword_rax()
|
||||||
|
; cvtsd2ss xmm0, xmm0
|
||||||
|
emit_cvtsd2ss_xmm0_xmm0()
|
||||||
|
; movsd [rax], xmm0
|
||||||
|
emit_movsd_qword_rax_xmm0()
|
||||||
|
return
|
||||||
|
:gen_cast_float_to_double
|
||||||
|
; mov rax, rsp
|
||||||
|
emit_mov_reg(REG_RAX, REG_RSP)
|
||||||
|
; movss xmm0, [rax]
|
||||||
|
emit_movss_xmm0_dword_rax()
|
||||||
|
; cvtss2sd xmm0, xmm0
|
||||||
|
emit_cvtss2sd_xmm0_xmm0()
|
||||||
|
; movss [rax], xmm0
|
||||||
|
emit_movss_dword_rax_xmm0()
|
||||||
|
return
|
||||||
|
:gen_cast_int_to_float
|
||||||
|
; to reduce # of instructions, we first convert int to double, then double to float
|
||||||
|
; mov rax, [rsp]
|
||||||
|
emit_mov_rax_qword_rsp_plus_imm32(0)
|
||||||
|
; cvtsi2sd xmm0, rax
|
||||||
|
emit_cvtsi2sd_xmm0_rax()
|
||||||
|
; cvtsd2ss xmm0, xmm0
|
||||||
|
emit_cvtsd2ss_xmm0_xmm0()
|
||||||
|
; mov rax, rsp
|
||||||
|
emit_mov_reg(REG_RAX, REG_RSP)
|
||||||
|
; movss [rax], xmm0
|
||||||
|
emit_movss_dword_rax_xmm0()
|
||||||
|
; it shouldn't matter that there's junk at [rsp+4]
|
||||||
|
return
|
||||||
|
:gen_cast_int_to_double
|
||||||
|
; mov rax, [rsp]
|
||||||
|
emit_mov_rax_qword_rsp_plus_imm32(0)
|
||||||
|
; cvtsi2sd xmm0, rax
|
||||||
|
emit_cvtsi2sd_xmm0_rax()
|
||||||
|
; mov rax, rsp
|
||||||
|
emit_mov_reg(REG_RAX, REG_RSP)
|
||||||
|
; movsd [rax], xmm0
|
||||||
|
emit_movsd_qword_rax_xmm0()
|
||||||
|
return
|
||||||
|
:gen_cast_float_to_int
|
||||||
|
; mov rax, rsp
|
||||||
|
emit_mov_reg(REG_RAX, REG_RSP)
|
||||||
|
; movss xmm0, [rax]
|
||||||
|
emit_movss_xmm0_dword_rax()
|
||||||
|
; convert float to double, then double to int
|
||||||
|
; cvtss2sd xmm0, xmm0
|
||||||
|
emit_cvtss2sd_xmm0_xmm0()
|
||||||
|
; cvttsd2si rax, xmm0
|
||||||
|
emit_cvttsd2si_rax_xmm0()
|
||||||
|
; mov [rsp], rax
|
||||||
|
emit_mov_qword_rsp_plus_imm32_rax(0)
|
||||||
|
return
|
||||||
|
:gen_cast_double_to_int
|
||||||
|
; mov rax, rsp
|
||||||
|
emit_mov_reg(REG_RAX, REG_RSP)
|
||||||
|
; movsd xmm0, [rax]
|
||||||
|
emit_movsd_xmm0_qword_rax()
|
||||||
|
; cvttsd2si rax, xmm0
|
||||||
|
emit_cvttsd2si_rax_xmm0()
|
||||||
|
; mov [rsp], rax
|
||||||
|
emit_mov_qword_rsp_plus_imm32_rax(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
:bad_gen_cast
|
||||||
|
print_statement_location(statement)
|
||||||
|
puts(.str_bad_gen_cast1)
|
||||||
|
print_type(from_type)
|
||||||
|
puts(.str_bad_gen_cast2)
|
||||||
|
print_type(to_type)
|
||||||
|
putc(10)
|
||||||
|
exit(1)
|
||||||
|
:str_bad_gen_cast1
|
||||||
|
string : Error: Cannot convert type
|
||||||
|
byte 32
|
||||||
|
byte 0
|
||||||
|
:str_bad_gen_cast2
|
||||||
|
string to type
|
||||||
|
byte 32
|
||||||
|
byte 0
|
||||||
|
; `statement` is used for errors
|
||||||
|
; returns pointer to end of expression
|
||||||
|
function generate_push_expression
|
||||||
|
argument statement
|
||||||
|
argument expr
|
||||||
|
local b
|
||||||
|
local c
|
||||||
|
local type
|
||||||
|
type = expr + 4
|
||||||
|
type = *4type
|
||||||
|
|
||||||
|
c = *1expr
|
||||||
|
if c == EXPRESSION_CONSTANT_INT goto generate_push_int
|
||||||
|
if c == EXPRESSION_CONSTANT_FLOAT goto generate_push_float
|
||||||
|
if c == EXPRESSION_CAST goto generate_cast
|
||||||
|
|
||||||
|
die(.str_genpushexprNI)
|
||||||
|
:str_genpushexprNI
|
||||||
|
string generate_push_expression not implemented.
|
||||||
|
byte 0
|
||||||
|
:generate_cast
|
||||||
|
expr += 4
|
||||||
|
c = *4expr ; cast type
|
||||||
|
expr += 8
|
||||||
|
b = *4expr ; original type
|
||||||
|
expr -= 4
|
||||||
|
expr = generate_push_expression(statement, expr)
|
||||||
|
generate_cast_top_of_stack(statement, b, c)
|
||||||
|
return expr
|
||||||
|
:generate_push_float
|
||||||
|
expr += 8
|
||||||
|
emit_mov_rax_imm64(*8expr)
|
||||||
|
emit_push_rax()
|
||||||
|
generate_cast_top_of_stack(statement, TYPE_DOUBLE, type)
|
||||||
|
expr += 8
|
||||||
|
return expr
|
||||||
|
:generate_push_int
|
||||||
|
expr += 8
|
||||||
|
emit_mov_rax_imm64(*8expr)
|
||||||
|
emit_push_rax()
|
||||||
|
expr += 8
|
||||||
|
return expr
|
||||||
|
|
||||||
function generate_statement
|
function generate_statement
|
||||||
argument statement
|
argument statement
|
||||||
local dat1
|
local dat1
|
||||||
|
@ -268,22 +561,29 @@ function generate_statement
|
||||||
return
|
return
|
||||||
:gen_return
|
:gen_return
|
||||||
if dat1 == 0 goto gen_return_noexpr
|
if dat1 == 0 goto gen_return_noexpr
|
||||||
generate_push_expression(dat1)
|
generate_push_expression(statement, dat1)
|
||||||
|
p = dat1 + 4 ; pointer to dat1 type
|
||||||
|
generate_cast_top_of_stack(statement, *4p, curr_function_return_type)
|
||||||
; copy sizeof(return expression) rounded up to 8 bytes from [rsp] to [rbp+16]
|
; copy sizeof(return expression) rounded up to 8 bytes from [rsp] to [rbp+16]
|
||||||
emit_mov_reg(REG_RSI, REG_RSP)
|
emit_mov_reg(REG_RSI, REG_RSP)
|
||||||
emit_lea_rax_rbp_plus_imm32(16)
|
emit_lea_rax_rbp_plus_imm32(16)
|
||||||
emit_mov_reg(REG_RDI, REG_RAX)
|
emit_mov_reg(REG_RDI, REG_RAX)
|
||||||
p = dat1 + 4
|
|
||||||
generate_copy_rsi_to_rdi_qwords(*4p)
|
generate_copy_rsi_to_rdi_qwords(*4p)
|
||||||
|
|
||||||
:gen_return_noexpr
|
:gen_return_noexpr
|
||||||
generate_return()
|
generate_return()
|
||||||
return
|
return
|
||||||
|
|
||||||
function generate_function
|
function generate_function
|
||||||
argument function_name
|
argument function_name
|
||||||
argument function_statement
|
argument function_statement
|
||||||
|
local function_type
|
||||||
local out0
|
local out0
|
||||||
|
|
||||||
|
function_type = ident_list_lookup(function_types, function_name)
|
||||||
|
|
||||||
|
curr_function_return_type = functype_return_type(function_type)
|
||||||
|
|
||||||
if codegen_second_pass != 0 goto genf_second_pass
|
if codegen_second_pass != 0 goto genf_second_pass
|
||||||
curr_function_labels = ident_list_create(4000) ; ~ 200 labels per function should be plenty
|
curr_function_labels = ident_list_create(4000) ; ~ 200 labels per function should be plenty
|
||||||
ident_list_add(functions_labels, function_name, curr_function_labels)
|
ident_list_add(functions_labels, function_name, curr_function_labels)
|
||||||
|
@ -334,8 +634,8 @@ function generate_functions
|
||||||
|
|
||||||
:function_addr_mismatch
|
:function_addr_mismatch
|
||||||
; address of function on 2nd pass doesn't line up with 1st pass
|
; address of function on 2nd pass doesn't line up with 1st pass
|
||||||
fputs(2, .str_function_addr_mismatch)
|
puts(.str_function_addr_mismatch)
|
||||||
fputs(2, function_name)
|
puts(function_name)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_function_addr_mismatch
|
:str_function_addr_mismatch
|
||||||
string Function address on first pass doesn't match 2nd pass:
|
string Function address on first pass doesn't match 2nd pass:
|
||||||
|
|
48
05/main.b
48
05/main.b
|
@ -110,25 +110,29 @@ function types_init
|
||||||
*8ptypes_bytes_used = p - types
|
*8ptypes_bytes_used = p - types
|
||||||
return
|
return
|
||||||
|
|
||||||
function fprint_token_location
|
function print_token_location
|
||||||
argument fd
|
|
||||||
argument token
|
argument token
|
||||||
token += 2
|
token += 2
|
||||||
fprint_filename(fd, *2token)
|
print_filename(*2token)
|
||||||
token += 2
|
token += 2
|
||||||
fputc(fd, ':)
|
putc(':)
|
||||||
fputn(fd, *4token)
|
putn(*4token)
|
||||||
|
return
|
||||||
|
|
||||||
|
function print_statement_location
|
||||||
|
argument statement
|
||||||
|
; statements & tokens have the same format for locations!
|
||||||
|
print_token_location(statement)
|
||||||
return
|
return
|
||||||
|
|
||||||
; accepts EITHER file index OR pointer to filename
|
; accepts EITHER file index OR pointer to filename
|
||||||
function fprint_filename
|
function print_filename
|
||||||
argument fd
|
|
||||||
argument file
|
argument file
|
||||||
if file ] 65535 goto print_filename_string
|
if file ] 65535 goto print_filename_string
|
||||||
file = file_get(file)
|
file = file_get(file)
|
||||||
; (fallthrough)
|
; (fallthrough)
|
||||||
:print_filename_string
|
:print_filename_string
|
||||||
fputs(2, file)
|
puts(file)
|
||||||
return
|
return
|
||||||
|
|
||||||
; accepts EITHER file index OR pointer to filename
|
; accepts EITHER file index OR pointer to filename
|
||||||
|
@ -136,12 +140,12 @@ function compile_error
|
||||||
argument file
|
argument file
|
||||||
argument line
|
argument line
|
||||||
argument message
|
argument message
|
||||||
fprint_filename(2, file)
|
print_filename(file)
|
||||||
fputc(2, ':)
|
putc(':)
|
||||||
fputn(2, line)
|
putn(line)
|
||||||
fputs(2, .str_error_prefix)
|
puts(.str_error_prefix)
|
||||||
fputs(2, message)
|
puts(message)
|
||||||
fputc(2, 10)
|
putc(10)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
function token_error
|
function token_error
|
||||||
|
@ -161,12 +165,12 @@ function compile_warning
|
||||||
argument file
|
argument file
|
||||||
argument line
|
argument line
|
||||||
argument message
|
argument message
|
||||||
fprint_filename(2, file)
|
print_filename(file)
|
||||||
fputc(2, ':)
|
putc(':)
|
||||||
fputn(2, line)
|
putn(line)
|
||||||
fputs(2, .str_warning_prefix)
|
puts(.str_warning_prefix)
|
||||||
fputs(2, message)
|
puts(message)
|
||||||
fputc(2, 10)
|
putc(10)
|
||||||
return
|
return
|
||||||
|
|
||||||
:str_error_prefix
|
:str_error_prefix
|
||||||
|
@ -306,7 +310,7 @@ function main
|
||||||
byte 0
|
byte 0
|
||||||
|
|
||||||
:mmap_output_fd_failed
|
:mmap_output_fd_failed
|
||||||
fputs(2, .str_mmap_output_fd_failed)
|
puts(.str_mmap_output_fd_failed)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_mmap_output_fd_failed
|
:str_mmap_output_fd_failed
|
||||||
string Couldn't mmap output file.
|
string Couldn't mmap output file.
|
||||||
|
@ -314,7 +318,7 @@ function main
|
||||||
byte 0
|
byte 0
|
||||||
|
|
||||||
:usage_error
|
:usage_error
|
||||||
fputs(2, .str_usage_error)
|
puts(.str_usage_error)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
:str_usage_error
|
:str_usage_error
|
||||||
|
|
|
@ -14,5 +14,5 @@ struct B { struct A *blah; }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
return 42;
|
return (float)(long)"hello";
|
||||||
}
|
}
|
||||||
|
|
22
05/parse.b
22
05/parse.b
|
@ -843,7 +843,9 @@ function parse_statement
|
||||||
if *1token == SYMBOL_SEMICOLON goto return_no_expr
|
if *1token == SYMBOL_SEMICOLON goto return_no_expr
|
||||||
n = token_next_semicolon_not_in_brackets(token)
|
n = token_next_semicolon_not_in_brackets(token)
|
||||||
*8out = expressions_end
|
*8out = expressions_end
|
||||||
|
p = expressions_end + 4 ; type of expression
|
||||||
expressions_end = parse_expression(token, n, expressions_end)
|
expressions_end = parse_expression(token, n, expressions_end)
|
||||||
|
type_decay_array_to_pointer_in_place(*4p)
|
||||||
token = n + 16
|
token = n + 16
|
||||||
:return_no_expr
|
:return_no_expr
|
||||||
out += 32
|
out += 32
|
||||||
|
@ -2400,7 +2402,7 @@ function type_length
|
||||||
type += type_length(type)
|
type += type_length(type)
|
||||||
return type - start
|
return type - start
|
||||||
:type_length_not_function
|
:type_length_not_function
|
||||||
fputs(2, .str_type_length_bad_type)
|
puts(.str_type_length_bad_type)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_type_length_bad_type
|
:str_type_length_bad_type
|
||||||
string Bad type passed to type_length. This shouldn't happen.
|
string Bad type passed to type_length. This shouldn't happen.
|
||||||
|
@ -2606,7 +2608,7 @@ function parse_expression
|
||||||
if c == EXPRESSION_DIV goto type_binary_usual
|
if c == EXPRESSION_DIV goto type_binary_usual
|
||||||
if c == EXPRESSION_REMAINDER goto type_binary_usual_integer
|
if c == EXPRESSION_REMAINDER goto type_binary_usual_integer
|
||||||
|
|
||||||
fputs(2, .str_binop_this_shouldnt_happen)
|
puts(.str_binop_this_shouldnt_happen)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_binop_this_shouldnt_happen
|
:str_binop_this_shouldnt_happen
|
||||||
string Bad binop symbol (this shouldn't happen).
|
string Bad binop symbol (this shouldn't happen).
|
||||||
|
@ -2769,7 +2771,7 @@ function parse_expression
|
||||||
if c == EXPRESSION_DEREFERENCE goto unary_dereference
|
if c == EXPRESSION_DEREFERENCE goto unary_dereference
|
||||||
if c == EXPRESSION_PRE_INCREMENT goto unary_type_scalar_nopromote
|
if c == EXPRESSION_PRE_INCREMENT goto unary_type_scalar_nopromote
|
||||||
if c == EXPRESSION_PRE_DECREMENT goto unary_type_scalar_nopromote
|
if c == EXPRESSION_PRE_DECREMENT goto unary_type_scalar_nopromote
|
||||||
fputs(2, .str_unop_this_shouldnt_happen)
|
puts(.str_unop_this_shouldnt_happen)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_unop_this_shouldnt_happen
|
:str_unop_this_shouldnt_happen
|
||||||
string Bad unary symbol (this shouldn't happen).
|
string Bad unary symbol (this shouldn't happen).
|
||||||
|
@ -2798,7 +2800,9 @@ function parse_expression
|
||||||
*4out = a
|
*4out = a
|
||||||
out += 4
|
out += 4
|
||||||
p += 16
|
p += 16
|
||||||
|
a = out + 4 ; pointer to casted expression type
|
||||||
out = parse_expression(p, tokens_end, out)
|
out = parse_expression(p, tokens_end, out)
|
||||||
|
type_decay_array_to_pointer_in_place(*4a)
|
||||||
return out
|
return out
|
||||||
:bad_cast
|
:bad_cast
|
||||||
token_error(tokens, .str_bad_cast)
|
token_error(tokens, .str_bad_cast)
|
||||||
|
@ -2840,7 +2844,7 @@ function parse_expression
|
||||||
*4type = a
|
*4type = a
|
||||||
return out
|
return out
|
||||||
:unary_bad_type
|
:unary_bad_type
|
||||||
fprint_token_location(1, tokens)
|
print_token_location(tokens)
|
||||||
puts(.str_unary_bad_type)
|
puts(.str_unary_bad_type)
|
||||||
print_type(a)
|
print_type(a)
|
||||||
putc(10)
|
putc(10)
|
||||||
|
@ -3244,7 +3248,7 @@ function type_sizeof
|
||||||
if c == TYPE_ARRAY goto sizeof_array
|
if c == TYPE_ARRAY goto sizeof_array
|
||||||
if c == TYPE_STRUCT goto sizeof_struct
|
if c == TYPE_STRUCT goto sizeof_struct
|
||||||
|
|
||||||
fputs(2, .str_sizeof_bad)
|
puts(.str_sizeof_bad)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_sizeof_bad
|
:str_sizeof_bad
|
||||||
string type_sizeof bad type.
|
string type_sizeof bad type.
|
||||||
|
@ -3309,7 +3313,7 @@ function type_alignof
|
||||||
if c == TYPE_ARRAY goto alignof_array
|
if c == TYPE_ARRAY goto alignof_array
|
||||||
if c == TYPE_STRUCT goto alignof_struct
|
if c == TYPE_STRUCT goto alignof_struct
|
||||||
|
|
||||||
fputs(2, .str_alignof_bad)
|
puts(.str_alignof_bad)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_alignof_bad
|
:str_alignof_bad
|
||||||
string type_alignof bad type.
|
string type_alignof bad type.
|
||||||
|
@ -3637,7 +3641,7 @@ function fit_to_type
|
||||||
if c == TYPE_LONG goto fit_to_type_long
|
if c == TYPE_LONG goto fit_to_type_long
|
||||||
if c == TYPE_UNSIGNED_LONG goto fit_to_type_ulong
|
if c == TYPE_UNSIGNED_LONG goto fit_to_type_ulong
|
||||||
if c == TYPE_POINTER goto fit_to_type_ulong
|
if c == TYPE_POINTER goto fit_to_type_ulong
|
||||||
fputs(2, .str_bad_fit_to_type)
|
puts(.str_bad_fit_to_type)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_bad_fit_to_type
|
:str_bad_fit_to_type
|
||||||
string Bad type passed to fit_to_type.
|
string Bad type passed to fit_to_type.
|
||||||
|
@ -3726,7 +3730,7 @@ function bad_types_to_operator
|
||||||
argument type1
|
argument type1
|
||||||
argument type2
|
argument type2
|
||||||
|
|
||||||
fprint_token_location(1, token)
|
print_token_location(token)
|
||||||
puts(.str_bad_types_to_operator)
|
puts(.str_bad_types_to_operator)
|
||||||
print_type(type1)
|
print_type(type1)
|
||||||
puts(.str_space_and_space)
|
puts(.str_space_and_space)
|
||||||
|
@ -4276,7 +4280,7 @@ function print_type
|
||||||
if c == TYPE_ARRAY goto print_type_array
|
if c == TYPE_ARRAY goto print_type_array
|
||||||
if c == TYPE_STRUCT goto print_type_struct
|
if c == TYPE_STRUCT goto print_type_struct
|
||||||
if c == TYPE_FUNCTION goto print_type_function
|
if c == TYPE_FUNCTION goto print_type_function
|
||||||
fputs(2, .str_bad_print_type)
|
puts(.str_bad_print_type)
|
||||||
putnln(type)
|
putnln(type)
|
||||||
putnln(c)
|
putnln(c)
|
||||||
putnln(types_bytes_used)
|
putnln(types_bytes_used)
|
||||||
|
|
|
@ -603,10 +603,10 @@ function translation_phase_4
|
||||||
if b != 0 goto pp_directive_endif
|
if b != 0 goto pp_directive_endif
|
||||||
goto unrecognized_directive
|
goto unrecognized_directive
|
||||||
:pp_directive_error
|
:pp_directive_error
|
||||||
fputs(2, filename)
|
puts(filename)
|
||||||
fputc(2, ':)
|
putc(':)
|
||||||
fputn(2, line_number)
|
putn(line_number)
|
||||||
fputs(2, .str_directive_error)
|
puts(.str_directive_error)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_directive_error
|
:str_directive_error
|
||||||
string : #error
|
string : #error
|
||||||
|
|
|
@ -15,7 +15,7 @@ function file_get
|
||||||
:file_got
|
:file_got
|
||||||
return p
|
return p
|
||||||
:file_uhoh
|
:file_uhoh
|
||||||
fputs(2, .str_bad_file_index)
|
puts(.str_bad_file_index)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_bad_file_index
|
:str_bad_file_index
|
||||||
string Bad file index. This shouldn't happen.
|
string Bad file index. This shouldn't happen.
|
||||||
|
@ -609,7 +609,7 @@ function print_tokens
|
||||||
if *1p == TOKEN_STRING_LITERAL goto print_token_string_literal
|
if *1p == TOKEN_STRING_LITERAL goto print_token_string_literal
|
||||||
if *1p == TOKEN_IDENTIFIER goto print_token_identifier
|
if *1p == TOKEN_IDENTIFIER goto print_token_identifier
|
||||||
if *1p == TOKEN_EOF goto print_token_eof
|
if *1p == TOKEN_EOF goto print_token_eof
|
||||||
fputs(2, .str_print_bad_token)
|
puts(.str_print_bad_token)
|
||||||
exit(1)
|
exit(1)
|
||||||
:print_token_keyword
|
:print_token_keyword
|
||||||
s = get_keyword_str(*1p)
|
s = get_keyword_str(*1p)
|
||||||
|
|
16
05/util.b
16
05/util.b
|
@ -137,9 +137,9 @@ function max_signed
|
||||||
|
|
||||||
function file_error
|
function file_error
|
||||||
argument name
|
argument name
|
||||||
fputs(2, .str_file_error)
|
puts(.str_file_error)
|
||||||
fputs(2, name)
|
puts(name)
|
||||||
fputc(2, 10)
|
putc(10)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
:str_file_error
|
:str_file_error
|
||||||
|
@ -149,8 +149,8 @@ function file_error
|
||||||
|
|
||||||
function die
|
function die
|
||||||
argument message
|
argument message
|
||||||
fputs(2, message)
|
puts(message)
|
||||||
fputc(2, 10)
|
putc(10)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
function ftruncate
|
function ftruncate
|
||||||
|
@ -162,7 +162,7 @@ function ftruncate
|
||||||
return
|
return
|
||||||
|
|
||||||
:ftruncate_failed
|
:ftruncate_failed
|
||||||
fputs(2, .str_ftruncate_failed)
|
puts(.str_ftruncate_failed)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_ftruncate_failed
|
:str_ftruncate_failed
|
||||||
string ftruncated failed.
|
string ftruncated failed.
|
||||||
|
@ -200,7 +200,7 @@ function malloc
|
||||||
return memory + 8
|
return memory + 8
|
||||||
|
|
||||||
:malloc_failed
|
:malloc_failed
|
||||||
fputs(2, .str_out_of_memory)
|
puts(.str_out_of_memory)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
:str_out_of_memory
|
:str_out_of_memory
|
||||||
|
@ -768,7 +768,7 @@ function leftmost_1bit
|
||||||
:leftmost1bit_found
|
:leftmost1bit_found
|
||||||
return i
|
return i
|
||||||
:leftmost1bit_0
|
:leftmost1bit_0
|
||||||
fputs(2, .str_leftmost1bit_0)
|
puts(.str_leftmost1bit_0)
|
||||||
exit(1)
|
exit(1)
|
||||||
:str_leftmost1bit_0
|
:str_leftmost1bit_0
|
||||||
string 0 passed to leftmost_1bit.
|
string 0 passed to leftmost_1bit.
|
||||||
|
|
14
README.md
14
README.md
|
@ -119,6 +119,12 @@ ax bx cx dx sp bp si di
|
||||||
│ mov r8, rax │ 49 89 c0 │ set r8 to rax (only used for syscalls) │
|
│ mov r8, rax │ 49 89 c0 │ set r8 to rax (only used for syscalls) │
|
||||||
│ mov r9, rax │ 49 89 c1 │ set r9 to rax (only used for syscalls) │
|
│ mov r9, rax │ 49 89 c1 │ set r9 to rax (only used for syscalls) │
|
||||||
│ mov r10, rax │ 49 89 c2 │ set r10 to rax (only used for syscalls)│
|
│ mov r10, rax │ 49 89 c2 │ set r10 to rax (only used for syscalls)│
|
||||||
|
| movsx rax, al | 48 0f be c0 | sign-extend al to rax |
|
||||||
|
| movsx rax, ax | 48 0f bf c0 | sign-extend ax to rax |
|
||||||
|
| movsx rax, eax | 48 63 c0 | sign-extend eax to rax |
|
||||||
|
| movzx rax, al | 48 0f b6 c0 | zero-extend al to rax |
|
||||||
|
| movzx rax, ax | 48 0f b7 c0 | zero-extend ax to rax |
|
||||||
|
| mov eax, eax | 89 c0 | zero-extend eax to rax |
|
||||||
│ xchg rax, rbx │ 48 93 │ exchange the values of rax and rbx │
|
│ xchg rax, rbx │ 48 93 │ exchange the values of rax and rbx │
|
||||||
│ mov [rbx], rax │ 48 89 03 │ store rax as 8 bytes at address rbx │
|
│ mov [rbx], rax │ 48 89 03 │ store rax as 8 bytes at address rbx │
|
||||||
│ mov rax, [rbx] │ 48 8b 03 │ load 8 bytes from address rbx into rax │
|
│ mov rax, [rbx] │ 48 8b 03 │ load 8 bytes from address rbx into rax │
|
||||||
|
@ -175,6 +181,14 @@ ax bx cx dx sp bp si di
|
||||||
│ ja IMM32 │ 0f 87 IMM32 │ jump if "above" (like jg but unsigned) │
|
│ ja IMM32 │ 0f 87 IMM32 │ jump if "above" (like jg but unsigned) │
|
||||||
│ jbe IMM32 │ 0f 86 IMM32 │ jump if below or equal to │
|
│ jbe IMM32 │ 0f 86 IMM32 │ jump if below or equal to │
|
||||||
│ jae IMM32 │ 0f 83 IMM32 │ jump if above or equal to │
|
│ jae IMM32 │ 0f 83 IMM32 │ jump if above or equal to │
|
||||||
|
│ movss xmm0, [rax] │ f3 0f 10 00 │ load the float at *rax into xmm0 │
|
||||||
|
│ movsd xmm0, [rax] │ f2 0f 10 00 │ load the double at *rax into xmm0 │
|
||||||
|
│ movss [rax], xmm0 │ f3 0f 11 00 │ store the float in xmm0 at *rax │
|
||||||
|
│ movsd [rax], xmm0 │ f2 0f 11 00 │ store the double in xmm0 at *rax │
|
||||||
|
| cvtss2sd xmm0, xmm0 | f3 0f 5a c0 | convert xmm0 from float to double |
|
||||||
|
| cvtsd2ss xmm0, xmm0 | f2 0f 5a c0 | convert xmm0 from double to float |
|
||||||
|
| cvttsd2si rax, xmm0 | f2 48 0f 2c c0 | convert double in xmm0 to int in rax |
|
||||||
|
| cvtsi2sd xmm0, rax | f2 48 0f 2a c0 | convert int in rax to double in xmm0 |
|
||||||
│ call rax │ ff d0 │ call the function at address rax │
|
│ call rax │ ff d0 │ call the function at address rax │
|
||||||
│ ret │ c3 │ return from function │
|
│ ret │ c3 │ return from function │
|
||||||
│ syscall │ 0f 05 │ execute a system call │
|
│ syscall │ 0f 05 │ execute a system call │
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue