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/ssa | |
parent | 2928e5f74983f5dd33bc65f192298af87996a037 (diff) |
Add support for r8-r15 registers, pass args to registers directly (sys-v)
Diffstat (limited to 'src/ssa')
-rw-r--r-- | src/ssa/ssa.c | 48 |
1 files changed, 37 insertions, 11 deletions
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; |