aboutsummaryrefslogtreecommitdiff
path: root/src/ssa/ssa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssa/ssa.c')
-rw-r--r--src/ssa/ssa.c48
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, &reg, 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, &reg));
- 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;