diff options
Diffstat (limited to '05')
-rw-r--r-- | 05/codegen.b | 31 | ||||
-rw-r--r-- | 05/constants.b | 3 | ||||
-rw-r--r-- | 05/main.b | 2 | ||||
-rw-r--r-- | 05/main.c | 5 | ||||
-rw-r--r-- | 05/parse.b | 41 | ||||
-rw-r--r-- | 05/util.b | 38 |
6 files changed, 98 insertions, 22 deletions
diff --git a/05/codegen.b b/05/codegen.b index 1507e6d..2cd000c 100644 --- a/05/codegen.b +++ b/05/codegen.b @@ -1,7 +1,18 @@ ; CALLING CONVENTION: -; arguments are pushed onto the stack by the caller, from right to left -; caller must also reserve space on stack for return value -; so the function puts the return value at [rbp+8] (+8 for stored return address) +; Here is the process for calling a function: +; - the caller pushes the arguments on to the stack, from right to left +; - the caller subtracts sizeof(return type) from rsp +; - the caller calls the function +; - the caller stores away the return value +; - the caller adds (sizeof(return type) + sizeof arg0 + ... + sizeof argn) to rsp +; STACK LAYOUT: +; arg n +; ... +; arg 0 +; return value [rbp+16] +; return address [rbp+8] +; old rbp [rbp] +; local variables @@ -191,5 +202,19 @@ function generate_code codegen_second_pass = 1 generate_functions() ; generate code at the entry point of the executable + local main_addr + main_addr = ident_list_lookup(functions_addresses, .str_main) + if main_addr == 0 goto no_main_function + + ; on entry, we will have: + ; argc = *rsp + ; argv = rsp + 8 + + ; @TODO return + :no_main_function + die(.str_no_main_function) + :str_no_main_function + string Error: No main function. + byte 0 diff --git a/05/constants.b b/05/constants.b index b719375..c6555ee 100644 --- a/05/constants.b +++ b/05/constants.b @@ -783,3 +783,6 @@ :str_default string default byte 0 +:str_main + string main + byte 0 @@ -64,7 +64,7 @@ global statement_datas_ends ; block_static_variables[1] = static variables inside this block inside this function ; etc. global block_static_variables -; ident lists of (type << 32) | rbp offset; one per block depth +; ident lists of (type << 32) | rbp offset; one per block depth -- note that rbp offset may be negative! global local_variables global block_depth global expressions @@ -13,5 +13,8 @@ struct A { struct B *blah; } struct B { struct A *blah; } */ -int main(void) { +int main(int argc, char **Argv) { + int i,j; + Argv+argc+i; + j; } @@ -239,21 +239,31 @@ function parse_toplevel_declaration string Functions should not have initializers. byte 0 :parse_function_definition + local ret_type + local param_offset + if block_depth != 0 goto nested_function if function_param_has_no_name != 0 goto function_no_param_name p = types + type if *1p != TYPE_FUNCTION goto lbrace_after_declaration + ret_type = functype_return_type(type) + global function_stmt_data ; initialized in main global function_stmt_data_bytes_used - - local_var_rbp_offset = 0 - + out = function_stmt_data + function_stmt_data_bytes_used out0 = out ident_list_add(function_statements, name, out) ; deal with function parameters + ; function parameters go above return value on the stack + n = type_sizeof(ret_type) + n += 7 + n >= 3 + n <= 3 + param_offset = n + 16 ; + 16 for old rbp and return address + p = type + 1 name = function_param_names list = local_variables @@ -261,18 +271,21 @@ function parse_toplevel_declaration list = *8list :fn_params_loop if *1name == 0 goto fn_params_loop_end - local_var_rbp_offset += type_sizeof(p) - local_var_rbp_offset += 7 - local_var_rbp_offset >= 3 - local_var_rbp_offset <= 3 c = p < 32 - c |= local_var_rbp_offset + c |= param_offset ident_list_add(list, name, c) + param_offset += type_sizeof(p) + param_offset += 7 + param_offset >= 3 + param_offset <= 3 p += type_length(p) name = memchr(name, 0) name += 1 goto fn_params_loop :fn_params_loop_end + + local_var_rbp_offset = 0 + ; NOTE: it's the caller's responsibility to properly set rsp to accomodate all the arguments. ; it needs to be this way because of varargs functions (the function doesn't know how many arguments there are). parse_statement(&token, &out) @@ -698,8 +711,9 @@ function parse_statement out += 24 p = local_variables p += block_depth < 3 - l_offset = local_var_rbp_offset - c = l_offset + ; local variables are stored below rbp + l_offset = 0 - local_var_rbp_offset + c = l_offset & 0xffffffff c |= l_type < 32 ident_list_set(*8p, l_name, c) @@ -3080,7 +3094,8 @@ function parse_expression out += 4 *4out = c > 32 ; extract type out += 4 - *8out = c & 0xffffffff ; extract rbp offset + c &= 0xffffffff + *8out = sign_extend_32_to_64(c) ; extract rbp offset out += 8 return out :expression_integer @@ -4074,12 +4089,12 @@ function print_expression :print_local_variable puts(.str_local_prefix) expression += 8 - putn(*8expression) + putn_with_sign(*8expression) putc(']) expression += 8 return expression :str_local_prefix - string [rbp- + string [rbp byte 0 :print_expr_function expression += 8 @@ -1,3 +1,11 @@ +function sign_extend_32_to_64 + argument n + local c + c = n > 31 + n |= c * 0xffffffff00000000 + return n + + ; multiply two 64-bit signed numbers to a 128-bit number function full_multiply_signed argument a @@ -456,15 +464,27 @@ function fputn_signed argument fd argument n if n < 0 goto fputn_negative - - fputn(fd, n) - return - + fputn(fd, n) + return :fputn_negative fputc(fd, '-) n = 0 - n fputn(fd, n) return + +; like fputn_signed, but include the sign even if it's zero or positive +function fputn_with_sign + argument fd + argument n + if n < 0 goto fputn_with_sign_negative + fputc(fd, '+) + fputn(fd, n) + return + :fputn_with_sign_negative + fputc(fd, '-) + n = 0 - n + fputn(fd, n) + return :hex_digits string 0123456789abcdef @@ -527,6 +547,11 @@ function putn_signed fputn_signed(1, n) return +function putn_with_sign + argument n + fputn_with_sign(1, n) + return + function putnln argument n fputn(1, n) @@ -539,6 +564,11 @@ function putnln_signed fputc(1, 10) return +function putnln_with_sign + argument n + fputn_with_sign(1, n) + fputc(1, 10) + return function fputc argument fd |