diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-09-17 01:28:55 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-25 14:36:46 +0200 |
commit | b095aedd386e076d1f5a56b7384b836e653387d1 (patch) | |
tree | a9dd7d7cbcfba19005ce8aa9486a70d31091d5c3 /src | |
parent | 2928e5f74983f5dd33bc65f192298af87996a037 (diff) |
Add support for r8-r15 registers, pass args to registers directly (sys-v)
Diffstat (limited to 'src')
-rw-r--r-- | src/bytecode/bytecode.c | 23 | ||||
-rw-r--r-- | src/parser.c | 12 | ||||
-rw-r--r-- | src/program.c | 27 | ||||
-rw-r--r-- | src/ssa/ssa.c | 48 |
4 files changed, 70 insertions, 40 deletions
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c index 3b6d980..7dbc305 100644 --- a/src/bytecode/bytecode.c +++ b/src/bytecode/bytecode.c @@ -432,19 +432,6 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re fputc('\n', stderr); } -static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u8 import_index, u16 func_index, i8 num_args, const char *fmt) { - Buffer *instructions = &self->bytecode->data; - size_t index = instructions->size; - - throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(import_index) + sizeof(func_index) + sizeof(num_args))); - instructions->data[index] = opcode; - memcpy(instructions->data + index + sizeof(AmalOpcodeType), &import_index, sizeof(import_index)); - memcpy(instructions->data + index + sizeof(AmalOpcodeType) + sizeof(import_index), &func_index, sizeof(func_index)); - memcpy(instructions->data + index + sizeof(AmalOpcodeType) + sizeof(import_index) + sizeof(func_index), &num_args, sizeof(num_args)); - fprintf(stderr, fmt, import_index, func_index, num_args); - fputc('\n', stderr); -} - static void add_instructions(BytecodeCompilerContext *self) { /*doc(Bytecode instructions) # Instructions layout @@ -459,6 +446,7 @@ static void add_instructions(BytecodeCompilerContext *self) { SsaInsFuncStart ssa_ins_func_start; SsaInsFuncCall ssa_ins_func_call; SsaInsFuncCallExtern ssa_ins_func_call_extern; + SsaInsCallStart ssa_ins_call_start; SsaInsJumpZero ssa_ins_jump_zero; SsaInsJump ssa_ins_jump; @@ -547,14 +535,19 @@ static void add_instructions(BytecodeCompilerContext *self) { add_ins2(self, AMAL_OP_PUSH_RET, reg, "push_ret r%d"); break; } + case SSA_CALL_START: { + instruction += ssa_extract_data(instruction, &ssa_ins_call_start, sizeof(ssa_ins_call_start)); + add_ins2(self, AMAL_OP_CALL_START, ssa_ins_call_start.num_args, "call_start %d"); + break; + } case SSA_CALL: { instruction += ssa_extract_data(instruction, &ssa_ins_func_call, sizeof(ssa_ins_func_call)); - add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.import_index, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, "call f(%d,%d), %d"); + add_ins6(self, AMAL_OP_CALL, ssa_ins_func_call.import_index, ssa_ins_func_call.func_decl->ssa_func_index, "call f(%d,%d)"); break; } case SSA_CALL_EXTERN: { instruction += ssa_extract_data(instruction, &ssa_ins_func_call_extern, sizeof(ssa_ins_func_call_extern)); - add_ins7(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.import_index, ssa_ins_func_call_extern.func_decl_lhs->extern_index, ssa_ins_func_call_extern.num_args, "calle ef(%d,%d), %d"); + add_ins6(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.import_index, ssa_ins_func_call_extern.func_decl_lhs->extern_index, "calle ef(%d,%d)"); break; } case SSA_JUMP_ZERO: { diff --git a/src/parser.c b/src/parser.c index ed99eb0..9da9147 100644 --- a/src/parser.c +++ b/src/parser.c @@ -24,6 +24,7 @@ do { \ #define VAR_MAX_LEN UINT8_MAX #define FUNC_MAX_PARAMS 128 #define FUNC_MAX_RETURN_TYPES 128 +#define FUNC_MAX_ARGS FUNC_MAX_PARAMS static CHECK_RESULT Ast* parser_parse_rhs(Parser *self); static CHECK_RESULT Ast* parser_parse_body(Parser *self); @@ -425,8 +426,8 @@ static CHECK_RESULT StructDecl* parser_parse_struct_decl(Parser *self) { FUNC_ARGS = (RHS_START)? (',' RHS_START)* ')' */ static void parser_parse_function_args(Parser *self, FunctionCall *func_call) { - bool first_arg; - first_arg = bool_true; + bool first_arg = bool_true; + int arg_index = 0; for(;;) { Ast *arg_expr; @@ -442,6 +443,13 @@ static void parser_parse_function_args(Parser *self, FunctionCall *func_call) { arg_expr = parser_parse_rhs(self); throw_if_error(buffer_append(&func_call->args, &arg_expr, sizeof(arg_expr))); + ++arg_index; + if (arg_index > FUNC_MAX_ARGS) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "A closure can't take more than %d arguments", FUNC_MAX_ARGS); + throw(PARSER_ERR); + } } } diff --git a/src/program.c b/src/program.c index 63d2b6e..128f0f9 100644 --- a/src/program.c +++ b/src/program.c @@ -570,26 +570,30 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ self->read_index += 1; break; } + case AMAL_OP_CALL_START: { + u8 num_args = self->data.data[self->read_index]; + return_if_error(amal_exec_call_start(executor, num_args)); + self->read_index += 1; + break; + } case AMAL_OP_CALL: { u8 import_index; u16 func_index; - u8 num_args; BytecodeHeaderFunction func_def; i8 dst_reg; am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index)); am_memcpy(&func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(func_index)); - am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(func_index), sizeof(num_args)); amal_program_get_header_function_by_index(self, import_index, func_index, &func_def); assert(func_def.num_return_types == 1 && "TODO: Support 0 and more than 1 return values"); assert(self->return_value_index == 1); dst_reg = self->return_values_stack[0]; - self->return_value_index -= func_def.num_return_types; + self->return_value_index = 0; /* func_offset will only be non-zero when the function has been decoded (FUNC_START) */ if(func_def.func_offset != 0) { /* TODO: Instead of pushing num args, push the sum of sizeof the last num_args */ - return_if_error(amal_exec_call(executor, func_def.func_offset, num_args, dst_reg)); + return_if_error(amal_exec_call(executor, func_def.func_offset, dst_reg)); } else { /* The code for the function has not been generated yet (the function is defined after the current location). @@ -609,24 +613,23 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ return_if_error(hash_map_insert(&self->deferred_func_calls, key_mem, &new_deferred_call_list)); } /* Dummy call to offset 0, offset will be replace later when the target function hits AMAL_OP_FUNC_START */ - return_if_error(amal_exec_call(executor, 0, num_args, dst_reg)); + return_if_error(amal_exec_call(executor, 0, dst_reg)); } - self->read_index += 4; + self->read_index += 3; break; } - case AMAL_OP_CALLR: + case AMAL_OP_CALLR: { assert(bool_false && "TODO: Implement CALLR"); - self->read_index += 2; + self->read_index += 1; break; + } case AMAL_OP_CALLE: { u8 import_index; u16 extern_func_index; - u8 num_args; i8 dst_reg; am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index)); am_memcpy(&extern_func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(extern_func_index)); - am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(extern_func_index), sizeof(num_args)); assert(self->return_value_index == 1 && "TODO: Support extern functions that don't return any value"); dst_reg = self->return_values_stack[0]; self->return_value_index = 0; @@ -634,9 +637,9 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ { ProgramExternFunc extern_func; return_if_error(amal_program_get_extern_func_by_index(self, import_index, extern_func_index, &extern_func)); - return_if_error(amal_exec_calle(executor, extern_func.func, num_args, dst_reg)); + return_if_error(amal_exec_calle(executor, extern_func.func, dst_reg)); } - self->read_index += 4; + self->read_index += 3; break; } case AMAL_OP_CMP: { diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c index 19aa036..13f19a9 100644 --- a/src/ssa/ssa.c +++ b/src/ssa/ssa.c @@ -25,6 +25,7 @@ do { \ /* Max length of a string that fits in u16 */ #define MAX_STRING_LENGTH UINT16_MAX +#define FUNC_MAX_ARGS 128 static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context); @@ -323,24 +324,30 @@ static CHECK_RESULT int ssa_ins_push_ret(Ssa *self, SsaRegister reg) { return buffer_append(&self->instructions, ®, sizeof(reg)); } -static CHECK_RESULT int ssa_ins_call(Ssa *self, int import_index, FunctionDecl *func_decl, u8 num_args) { +static CHECK_RESULT int ssa_ins_call_start(Ssa *self, u8 num_args) { + const u8 ins_type = SSA_CALL_START; + SsaInsCallStart ins_call_start; + ins_call_start.num_args = num_args; + return_if_error(buffer_append(&self->instructions, &ins_type, 1)); + return buffer_append(&self->instructions, &ins_call_start, sizeof(ins_call_start)); +} + +static CHECK_RESULT int ssa_ins_call(Ssa *self, int import_index, FunctionDecl *func_decl) { const u8 ins_type = SSA_CALL; SsaInsFuncCall ins_func_call; - ins_func_call.num_args = num_args; ins_func_call.func_decl = func_decl; ins_func_call.import_index = import_index; - amal_log_debug("CALL %d, f(%d,%p)", num_args, import_index, func_decl); + amal_log_debug("CALL f(%d,%p)", import_index, func_decl); return_if_error(buffer_append(&self->instructions, &ins_type, 1)); return buffer_append(&self->instructions, &ins_func_call, sizeof(ins_func_call)); } -static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, int import_index, LhsExpr *func_decl_lhs, u8 num_args) { +static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, int import_index, LhsExpr *func_decl_lhs) { const u8 ins_type = SSA_CALL_EXTERN; SsaInsFuncCallExtern ins_func_call_extern; - ins_func_call_extern.num_args = num_args; ins_func_call_extern.func_decl_lhs = func_decl_lhs; ins_func_call_extern.import_index = import_index; - amal_log_debug("CALL_EXTERN %d, ef(%d,%p)", num_args, import_index, func_decl_lhs); + amal_log_debug("CALL_EXTERN ef(%d,%p)", import_index, func_decl_lhs); return_if_error(buffer_append(&self->instructions, &ins_type, 1)); return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern)); } @@ -635,14 +642,16 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstResolveData *resolve_data, SsaCompilerContext *context) { SsaRegister reg; + FunctionSignature *func_sig; FunctionDecl *func_decl; LhsExpr *func_lhs_expr; int import_index = context->import_index; context->import_index = 0; throw_if_error(ssa_get_unique_reg(context->ssa, ®)); - func_decl = resolve_data->type.value.func_sig->func_decl; assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG); + func_sig = resolve_data->type.value.func_sig; + func_decl = func_sig->func_decl; func_lhs_expr = NULL; if(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR) func_lhs_expr = self->func.resolved_var.value.lhs_expr; @@ -654,24 +663,41 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstRes all of them into account. Right now it only uses one return type. It should also take into account the size of the type. */ + assert(buffer_get_size(&func_sig->return_types, FunctionReturnType) <= 1); throw_if_error(ssa_ins_push_ret(context->ssa, reg)); } /* Push parameter arguments */ + assert(buffer_get_size(&self->args, Ast*) <= FUNC_MAX_ARGS); { + SsaRegister arg_regs[FUNC_MAX_ARGS]; + Ast **arg = buffer_begin(&self->args); Ast **arg_end = buffer_end(&self->args); for(; arg != arg_end; ++arg) { - SsaRegister arg_reg = ast_generate_ssa(*arg, context); - throw_if_error(ssa_ins_push(context->ssa, arg_reg)); + arg_regs[arg_end - arg] = ast_generate_ssa(*arg, context); + } + + /* + This is done in two steps since first we want the argument expressions to be generated + and then at the end, push the registers. + This allows Amalgam to push arguments directly to registers on abi that uses registers as function arguments (system-v x86_64) + instead of first pushing the registers to stack and then moving them to registers. + */ + + arg = buffer_begin(&self->args); + throw_if_error(ssa_ins_call_start(context->ssa, arg_end - arg)); + for(; arg != arg_end; ++arg) { + throw_if_error(ssa_ins_push(context->ssa, arg_regs[arg_end - arg])); } } if(func_lhs_expr && LHS_EXPR_IS_EXTERN(func_lhs_expr)) { - throw_if_error(ssa_ins_call_extern(context->ssa, import_index, func_lhs_expr, buffer_get_size(&self->args, Ast*))); + throw_if_error(ssa_ins_call_extern(context->ssa, import_index, func_lhs_expr)); } else { + assert(func_decl); /* rhs wont be null here because only extern variable can't have rhs */ - throw_if_error(ssa_ins_call(context->ssa, import_index, func_decl, buffer_get_size(&self->args, Ast*))); + throw_if_error(ssa_ins_call(context->ssa, import_index, func_decl)); } return reg; |