aboutsummaryrefslogtreecommitdiff
path: root/src/ssa
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssa')
-rw-r--r--src/ssa/ssa.c99
1 files changed, 70 insertions, 29 deletions
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 5c625b2..19aa036 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -26,6 +26,8 @@ do { \
/* Max length of a string that fits in u16 */
#define MAX_STRING_LENGTH UINT16_MAX
+static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context);
+
static int compare_number(const void *a, const void *b) {
const SsaNumber *lhs = a;
const SsaNumber *rhs = b;
@@ -62,13 +64,14 @@ int ssa_init(Ssa *self, Parser *parser) {
return_if_error(hash_map_init(&self->extern_funcs_map, parser->allocator, sizeof(SsaExternFuncIndex), hash_map_compare_string, amal_hash_string));
return_if_error(buffer_init(&self->extern_funcs, parser->allocator));
return_if_error(buffer_init(&self->export_funcs, parser->allocator));
+ return_if_error(buffer_init(&self->funcs, parser->allocator));
self->intermediate_counter = 0;
self->string_counter = 0;
self->extern_func_counter = 0;
self->export_func_counter = 0;
+ self->func_counter = 0;
self->reg_counter = 0;
self->param_counter = 0;
- self->func_counter = 0;
self->label_counter = 0;
self->parser = parser;
return 0;
@@ -186,7 +189,7 @@ static CHECK_RESULT int ssa_try_add_extern_func(Ssa *self, FunctionSignature *fu
*result_index = self->extern_func_counter;
++self->extern_func_counter;
- amal_log_debug("ef%u = \"%.*s\"", *result_index, name.size, name.data);
+ amal_log_debug("extern_func%u = %.*s", *result_index, name.size, name.data);
{
SsaExternFunc extern_func;
extern_func.func_sig = func_sig;
@@ -209,7 +212,7 @@ static CHECK_RESULT int ssa_try_add_export_func(Ssa *self, FunctionSignature *fu
return -1;
}
- amal_log_debug("ef%u = \"%.*s\"", self->export_func_counter, name.size, name.data);
+ amal_log_debug("exported_func%u = %.*s", self->export_func_counter, name.size, name.data);
++self->export_func_counter;
{
SsaExportFunc export_func;
@@ -274,7 +277,7 @@ static CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaR
return ssa_add_ins_form2(self, binop_type, lhs, rhs, result);
}
-static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 func_flags, SsaFuncIndex *result, usize *func_metadata_index) {
+static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 func_flags, FunctionSignature *func_sig, SsaFuncIndex *result, usize *func_metadata_index) {
const u8 ins_type = SSA_FUNC_START;
SsaInsFuncStart ins_func_start;
@@ -285,13 +288,18 @@ static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 func_flags, SsaFuncInde
}
*result = self->func_counter++;
+ {
+ SsaFunc func;
+ func.func_sig = func_sig;
+ return_if_error(buffer_append(&self->funcs, &func, sizeof(func)));
+ }
ins_func_start.flags = func_flags;
/* Dont set number of local registers yet. That will be set by @func_metadata_index later when it's known */
/*ins_func_start.num_local_vars_regs = ---*/
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return_if_error(buffer_append(&self->instructions, &ins_func_start, sizeof(ins_func_start)));
*func_metadata_index = self->instructions.size - sizeof(ins_func_start.num_local_vars_regs);
- amal_log_debug("FUNC_START f%u", *result);
+ amal_log_debug("FUNC_START f%u(%d) %d", *result, buffer_get_size(&func_sig->parameters, FunctionParameter), buffer_get_size(&func_sig->return_types, FunctionReturnType));
return 0;
}
@@ -308,27 +316,31 @@ static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) {
return buffer_append(&self->instructions, &reg, sizeof(reg));
}
-static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, u8 num_args, SsaRegister *result) {
+static CHECK_RESULT int ssa_ins_push_ret(Ssa *self, SsaRegister reg) {
+ const u8 ins_type = SSA_PUSH_RET;
+ amal_log_debug("PUSH RET r%d", reg);
+ return_if_error(buffer_append(&self->instructions, &ins_type, 1));
+ 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) {
const u8 ins_type = SSA_CALL;
SsaInsFuncCall ins_func_call;
- return_if_error(ssa_get_unique_reg(self, result));
ins_func_call.num_args = num_args;
- ins_func_call.result = *result;
ins_func_call.func_decl = func_decl;
- amal_log_debug("r%d = CALL %d, %p", *result, num_args, func_decl);
+ ins_func_call.import_index = import_index;
+ amal_log_debug("CALL %d, f(%d,%p)", num_args, 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, SsaExternFuncIndex extern_func_index, u8 num_args, SsaRegister *result) {
+static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, int import_index, LhsExpr *func_decl_lhs, u8 num_args) {
const u8 ins_type = SSA_CALL_EXTERN;
SsaInsFuncCallExtern ins_func_call_extern;
- return_if_error(ssa_get_unique_reg(self, result));
- assert(extern_func_index < self->extern_func_counter);
ins_func_call_extern.num_args = num_args;
- ins_func_call_extern.result = *result;
- ins_func_call_extern.extern_func_index = extern_func_index;
- amal_log_debug("r%d = CALL_EXTERN %d, %d", *result, num_args, extern_func_index);
+ 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);
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern));
}
@@ -608,10 +620,11 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
amal_log_debug("SSA funcdecl %p", self);
/* Anonymous closure doesn't have lhs_expr, and neither can it have any flags (extern, export etc) */
if(self->lhs_expr) {
+ assert(!LHS_EXPR_IS_EXTERN(self->lhs_expr));
if(LHS_EXPR_IS_EXPORT(self->lhs_expr))
func_flags |= FUNC_FLAG_EXPORTED;
}
- throw_if_error(ssa_ins_func_start(context->ssa, func_flags, &self->ssa_func_index, &func_metadata_index));
+ throw_if_error(ssa_ins_func_start(context->ssa, func_flags, self->signature, &self->ssa_func_index, &func_metadata_index));
scope_generate_ssa(&self->body, context);
throw_if_error(ssa_ins_func_end(context->ssa));
@@ -624,28 +637,41 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstRes
SsaRegister reg;
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_lhs_expr = NULL;
+ if(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR)
+ func_lhs_expr = self->func.resolved_var.value.lhs_expr;
+
+ /* Push return arguments */
+ {
+ /*
+ TODO: When amalgam supports multiple return types in assignment/declaration, update this to take
+ all of them into account. Right now it only uses one return type.
+ It should also take into account the size of the type.
+ */
+ throw_if_error(ssa_ins_push_ret(context->ssa, reg));
+ }
+ /* Push parameter arguments */
{
Ast **arg = buffer_begin(&self->args);
Ast **arg_end = buffer_end(&self->args);
for(; arg != arg_end; ++arg) {
- SsaRegister arg_reg;
- arg_reg = ast_generate_ssa(*arg, context);
+ SsaRegister arg_reg = ast_generate_ssa(*arg, context);
throw_if_error(ssa_ins_push(context->ssa, arg_reg));
}
}
- func_decl = resolve_data->type.value.func_sig->func_decl;
- assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG);
- func_lhs_expr = NULL;
- if(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR)
- func_lhs_expr = self->func.resolved_var.value.lhs_expr;
-
if(func_lhs_expr && LHS_EXPR_IS_EXTERN(func_lhs_expr)) {
- throw_if_error(ssa_ins_call_extern(context->ssa, func_lhs_expr->extern_index, buffer_get_size(&self->args, Ast*), &reg));
+ throw_if_error(ssa_ins_call_extern(context->ssa, import_index, func_lhs_expr, buffer_get_size(&self->args, Ast*)));
} else {
/* rhs wont be null here because only extern variable can't have rhs */
- throw_if_error(ssa_ins_call(context->ssa, func_decl, buffer_get_size(&self->args, Ast*), &reg));
+ throw_if_error(ssa_ins_call(context->ssa, import_index, func_decl, buffer_get_size(&self->args, Ast*)));
}
return reg;
@@ -673,7 +699,7 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon
return reg;
}
-static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) {
+SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) {
/* TODO: If resolved_var refers to a variable in another file, use a cross file reference that requires no locking (not yet implemented) */
/* This is not thread-safe:*/
assert(self->resolved_var.type != NAMED_OBJECT_NONE);
@@ -699,6 +725,16 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_
return 0;
}
+/* Returns the import statement for lhs of binop dot expression, where lhs is a variable name */
+static Import* binop_lhs_get_import_or_null(Binop *self) {
+ if(self->lhs->type == AST_VARIABLE) {
+ ScopeNamedObject *resolved_var = &self->lhs->value.variable->resolved_var;
+ if(resolved_var->type == NAMED_OBJECT_LHS_EXPR && resolved_var->value.lhs_expr->rhs_expr && resolved_var->value.lhs_expr->rhs_expr->type == AST_IMPORT)
+ return resolved_var->value.lhs_expr->rhs_expr->value.import;
+ }
+ return NULL;
+}
+
static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerContext *context) {
SsaRegister reg;
@@ -707,8 +743,12 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
const std = @import("std.amal");
std.printf
*/
- if(self->type == BINOP_DOT && resolved_type_is_func_decl(self->rhs)) {
+ if(self->type == BINOP_DOT && self->rhs->resolve_data.type.type == RESOLVED_TYPE_FUNC_SIG) {
+ Import *lhs_import = binop_lhs_get_import_or_null(self);
+ if(lhs_import)
+ context->import_index = 1 + lhs_import->file_scope->import_index;
reg = ast_generate_ssa(self->rhs, context);
+ context->import_index = 0;
} else {
const SsaRegister lhs_reg = ast_generate_ssa(self->lhs, context);
const SsaRegister rhs_reg = ast_generate_ssa(self->rhs, context);
@@ -774,9 +814,10 @@ static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompiler
SsaLabelIndex before_condition_label;
SsaLabelIndex skip_body_label;
usize jump_after_condition_index;
+ SsaRegister condition_reg;
throw_if_error(ssa_ins_label(context->ssa, &before_condition_label));
- SsaRegister condition_reg = ast_generate_ssa(while_stmt->condition, context);
+ condition_reg = ast_generate_ssa(while_stmt->condition, context);
throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0, &jump_after_condition_index));
scope_generate_ssa(&while_stmt->body, context);