From 16aaaa19a3ef4220726007d3e644ced0c9e06513 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 9 Sep 2019 01:08:34 +0200 Subject: Allow referencing code in imported file (right now for function calls, allow calling a function in another file) --- src/ssa/ssa.c | 99 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 29 deletions(-) (limited to 'src/ssa') 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, ®, 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, ®, 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, ®)); + + 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*), ®)); + 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*), ®)); + 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); -- cgit v1.2.3