From 81c5f8e750fcda6a2451fb54604130431434f88f Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 17 Aug 2019 02:57:08 +0200 Subject: Implement more instructions, implement function parameters and arguments --- src/ssa/ssa.c | 239 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 161 insertions(+), 78 deletions(-) (limited to 'src/ssa') diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c index f3679aa..0aabc15 100644 --- a/src/ssa/ssa.c +++ b/src/ssa/ssa.c @@ -243,7 +243,7 @@ static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) { return 0; } -static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) { +static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, u8 num_args, SsaRegister *result) { usize index; index = self->instructions.size; @@ -251,12 +251,13 @@ static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegi if(self->reg_counter + 1 < self->reg_counter) return -1; - return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(func_decl))); + return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(u8) + sizeof(SsaRegister) + sizeof(func_decl))); *result = self->reg_counter++; self->instructions.data[index + 0] = SSA_CALL; - am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaRegister)); - am_memcpy(self->instructions.data + index + 1 + sizeof(SsaRegister), &func_decl, sizeof(func_decl)); - amal_log_debug("r%u = CALL %p", *result, func_decl); + self->instructions.data[index + 1] = num_args; + am_memcpy(self->instructions.data + index + 2, result, sizeof(SsaRegister)); + am_memcpy(self->instructions.data + index + 2 + sizeof(SsaRegister), &func_decl, sizeof(func_decl)); + amal_log_debug("r%u = CALL %d, %p", *result, num_args, func_decl); return 0; } @@ -286,6 +287,16 @@ static CHECK_RESULT int ssa_ins_jump(Ssa *self, JumpOffset jump_offset) { return 0; } +static CHECK_RESULT int ssa_ins_return(Ssa *self, SsaRegister reg) { + usize index; + index = self->instructions.size; + + return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister))); + self->instructions.data[index + 0] = SSA_RET; + am_memcpy(self->instructions.data + index + 1, ®, sizeof(SsaRegister)); + return 0; +} + static usize ssa_ins_get_index(Ssa *self) { return self->instructions.size; } @@ -311,6 +322,28 @@ static CHECK_RESULT int ssa_ins_jump_set_target(Ssa *self, usize jump_ins_index) } static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context); +static CHECK_RESULT SsaRegister scope_named_object_generate_ssa(ScopeNamedObject *self, SsaCompilerContext *context); + +static bool ast_resolved_type_is_decl(AstResolvedType *self) { + /* TODO: Add more types as they are introduced */ + LhsExpr *lhs_expr; + if(self->type != RESOLVED_TYPE_LHS_EXPR) + return bool_false; + + lhs_expr = self->value.lhs_expr; + switch(lhs_expr->type.type) { + case VARIABLE_TYPE_NONE: + break; + case VARIABLE_TYPE_VARIABLE: + return bool_false; + case VARIABLE_TYPE_SIGNATURE: + /* TODO: This should return bool_false when it's possible to use signature in expressions */ + return bool_true; + } + + assert(lhs_expr->rhs_expr); + return lhs_expr->rhs_expr->type == AST_FUNCTION_DECL || lhs_expr->rhs_expr->type == AST_STRUCT_DECL; +} static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerContext *context) { SsaRegister reg; @@ -332,27 +365,23 @@ static CHECK_RESULT SsaRegister lhsexpr_extern_generate_ssa(LhsExpr *self, SsaCo return 0; } -static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerContext *context) { - LhsExpr *lhs_expr; +static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(LhsExpr *self, AstResolveData *resolve_data, SsaCompilerContext *context) { SsaRegister reg; - assert(self->type == AST_LHS); - lhs_expr = self->value.lhs_expr; - - if(LHS_EXPR_IS_EXTERN(lhs_expr)) - return lhsexpr_extern_generate_ssa(lhs_expr, context); + if(LHS_EXPR_IS_EXTERN(self)) + return lhsexpr_extern_generate_ssa(self, context); - if(lhs_expr->rhs_expr) { - Ast *rhs_expr = lhs_expr->rhs_expr; + if(self->rhs_expr) { + Ast *rhs_expr = self->rhs_expr; SsaRegister rhs_reg; rhs_reg = ast_generate_ssa(rhs_expr, context); /* - Declarations (struct and function declaration) resolves to itself and in that case this expression - is just a compile-time name for the declaration. - Import expression also has no meaning in SSA until it's used. - TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types? + Declarations (struct and function declaration) resolves to itself and in that case this expression + is just a compile-time name for the declaration. + Import expression also has no meaning in SSA until it's used. + TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types? */ - if(self->resolve_data.type == lhs_expr || rhs_expr->type == AST_IMPORT) { + if(ast_resolved_type_is_decl(&resolve_data->type) || rhs_expr->type == AST_IMPORT) { /*assert(bool_false);*/ return 0; } @@ -364,32 +393,55 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg)); } else { /* TODO: Do not assign if we dont want default value */ - SsaNumber number; - if(self->resolve_data.type == (LhsExpr*)context->compiler->default_types.i64) - number = create_ssa_integer(0); - else if(self->resolve_data.type == (LhsExpr*)context->compiler->default_types.f64) - number = create_ssa_float(0.0); - else - assert(bool_false && "TODO: assign default value to reg depending on LhsExpr type"); - throw_if_error(ssa_get_unique_reg(context->ssa, ®)); - throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number)); + if(resolve_data->type.type == RESOLVED_TYPE_LHS_EXPR) { + SsaNumber number; + if(resolve_data->type.value.lhs_expr == (LhsExpr*)context->compiler->default_types.i64) + number = create_ssa_integer(0); + else if(resolve_data->type.value.lhs_expr == (LhsExpr*)context->compiler->default_types.f64) + number = create_ssa_float(0.0); + else + assert(bool_false && "TODO: assign default value to reg depending on LhsExpr type"); + throw_if_error(ssa_get_unique_reg(context->ssa, ®)); + throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number)); + } else if(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG) { + assert(bool_false && "TODO: Implement this when variable can be null. Then the function pointer should be null"); + } else { + assert(bool_false); + } } return reg; } -static CHECK_RESULT SsaRegister assignmentexpr_generate_ssa(Ast *ast, SsaCompilerContext *context) { - AssignmentExpr *self; +static CHECK_RESULT SsaRegister assignmentexpr_generate_ssa(AssignmentExpr *self, SsaCompilerContext *context) { SsaRegister lhs_reg, rhs_reg; - - assert(ast->type == AST_ASSIGN); - self = ast->value.assign_expr; - lhs_reg = ast_generate_ssa(self->lhs_expr, context); rhs_reg = ast_generate_ssa(self->rhs_expr, context); throw_if_error(ssa_ins_assign_reg(context->ssa, lhs_reg, rhs_reg)); return lhs_reg; } +static CHECK_RESULT SsaRegister function_parameter_generate_ssa(FunctionParameter *self, SsaCompilerContext *context) { + SsaRegister reg; + if(self->resolve_data.status == AST_SSA_RESOLVED) + return self->resolve_data.ssa_reg; + + throw_if_error(ssa_get_unique_reg(context->ssa, ®)); + self->resolve_data.status = AST_SSA_RESOLVED; + self->resolve_data.ssa_reg = reg; + return reg; +} + +static CHECK_RESULT void function_signature_generate_params_ssa(FunctionSignature *self, SsaCompilerContext *context) { + FunctionParameter *param, *param_end; + param = buffer_begin(&self->parameters); + param_end = buffer_end(&self->parameters); + for(; param != param_end; ++param) { + SsaRegister reg; + reg = function_parameter_generate_ssa(param, context); + (void)reg; + } +} + /* TODO: Each function declaration should be in separate SSA instances so ast can be converted into ssa in any order. @@ -402,49 +454,54 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom */ SsaRegister prev_reg_counter; usize func_metadata_index; + int num_params; prev_reg_counter = context->ssa->reg_counter; context->ssa->reg_counter = 0; + /* + Parameters need to have generated ssa so the first ssa registers belong to the function. + This way we can know if a register access is for a parameter or not by checking the number + */ + function_signature_generate_params_ssa(self->signature, context); + num_params = buffer_get_size(&self->signature->parameters, FunctionParameter); + amal_log_debug("SSA funcdecl %p", self); throw_if_error(ssa_ins_func_start(context->ssa, &self->ssa_func_index, &func_metadata_index)); scope_generate_ssa(&self->body, context); throw_if_error(ssa_ins_func_end(context->ssa)); /* Add the number of registers used to the function metadata (FUNC_START) */ + context->ssa->reg_counter -= num_params; am_memcpy(&context->ssa->instructions.data[func_metadata_index], &context->ssa->reg_counter, sizeof(u16)); context->ssa->reg_counter = prev_reg_counter; return 0; } -static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerContext *context) { - /* TODO: Implement */ - FunctionCall *func_call; +static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstResolveData *resolve_data, SsaCompilerContext *context) { Ast **ast; Ast **ast_end; SsaRegister reg; + FunctionDecl *func_decl; - assert(self->type == AST_FUNCTION_CALL); - func_call = self->value.func_call; - ast = buffer_begin(&func_call->args); - ast_end = buffer_end(&func_call->args); + ast = buffer_begin(&self->args); + ast_end = buffer_end(&self->args); for(; ast != ast_end; ++ast) { SsaRegister arg_reg; arg_reg = ast_generate_ssa(*ast, context); throw_if_error(ssa_ins_push(context->ssa, arg_reg)); } - assert((self->resolve_data.type->rhs_expr && self->resolve_data.type->rhs_expr->type == AST_FUNCTION_DECL) || - self->resolve_data.type->type.type == VARIABLE_TYPE_SIGNATURE); - if(LHS_EXPR_IS_EXTERN(self->resolve_data.type)) { - amal_log_error("TODO: Implement extern function call (extern function %.*s was called)", func_call->func.name.size, func_call->func.name.data); + func_decl = resolve_data->type.value.func_sig->func_decl; + assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG); + assert(func_decl && "TODO: Implement function call for anonymous closures"); + if(func_decl && func_decl->lhs_expr && LHS_EXPR_IS_EXTERN(func_decl->lhs_expr)) { + amal_log_error("TODO: Implement extern function call (extern function %.*s was called)", self->func.name.size, self->func.name.data); reg = 0; assert(bool_false && "TODO: Implement extern function call!"); } else { - FunctionDecl *func_to_call; /* rhs wont be null here because only extern variable can't have rhs */ - func_to_call = self->resolve_data.type->rhs_expr->value.func_decl; - amal_log_debug("SSA funccall %.*s, func index ptr: %p", func_call->func.name.size, func_call->func.name.data, func_to_call); - throw_if_error(ssa_ins_call(context->ssa, func_to_call, ®)); + amal_log_debug("SSA funccall %.*s, func index ptr: %p", self->func.name.size, self->func.name.data, func_decl); + throw_if_error(ssa_ins_call(context->ssa, func_decl, buffer_get_size(&self->args, Ast*), ®)); } return reg; @@ -475,8 +532,8 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon static CHECK_RESULT 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); - return ast_generate_ssa(self->resolved_var, context); + assert(self->resolved_var.type != NAMED_OBJECT_NONE); + return scope_named_object_generate_ssa(&self->resolved_var, context); } static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_type *type) { @@ -511,7 +568,8 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte } else { const SsaRegister lhs_reg = ast_generate_ssa(self->lhs, context); const SsaRegister rhs_reg = ast_generate_ssa(self->rhs, context); - throw_if_error(ssa_ins_binop(context->ssa, binop_type_to_ssa_type(self->type, (amal_default_type*)self->lhs->resolve_data.type), lhs_reg, rhs_reg, ®)); + assert(self->lhs->resolve_data.type.type == RESOLVED_TYPE_LHS_EXPR && "TODO: Implement binop_generate_ssa for function signature"); + throw_if_error(ssa_ins_binop(context->ssa, binop_type_to_ssa_type(self->type, (amal_default_type*)self->lhs->resolve_data.type.value.lhs_expr), lhs_reg, rhs_reg, ®)); } return reg; } @@ -567,63 +625,88 @@ static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompiler throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_condition_ins_index)); } -static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) { - assert(self); - #ifdef DEBUG - if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_SSA_RESOLVED) { - amal_log_error("Ast type not resolved: %d", self->type); - assert(bool_false); - } - #endif +static void return_expr_generate_ssa(ReturnExpr *self, SsaCompilerContext *context) { + const SsaRegister reg = ast_generate_ssa(self->rhs_expr, context); + throw_if_error(ssa_ins_return(context->ssa, reg)); +} - if(self->resolve_data.status == AST_SSA_RESOLVED) - return self->ssa_reg; +static CHECK_RESULT SsaRegister ast_generate_ssa_resolve_data(void *ast_data, AstType ast_type, AstResolveData *resolve_data, SsaCompilerContext *context) { + if(resolve_data->status == AST_SSA_RESOLVED) + return resolve_data->ssa_reg; - switch(self->type) { + switch(ast_type) { case AST_NUMBER: - self->ssa_reg = number_generate_ssa(self->value.number, context); + resolve_data->ssa_reg = number_generate_ssa(ast_data, context); break; case AST_FUNCTION_DECL: - self->ssa_reg = funcdecl_generate_ssa(self->value.func_decl, context); + resolve_data->ssa_reg = funcdecl_generate_ssa(ast_data, context); break; case AST_FUNCTION_CALL: - self->ssa_reg = funccall_generate_ssa(self, context); + resolve_data->ssa_reg = funccall_generate_ssa(ast_data, resolve_data, context); break; case AST_STRUCT_DECL: - self->ssa_reg = structdecl_generate_ssa(self->value.struct_decl, context); + resolve_data->ssa_reg = structdecl_generate_ssa(ast_data, context); break; case AST_STRUCT_FIELD: - self->ssa_reg = structfield_generate_ssa(self->value.struct_field, context); + resolve_data->ssa_reg = structfield_generate_ssa(ast_data, context); break; case AST_LHS: - self->ssa_reg = lhsexpr_generate_ssa(self, context); + resolve_data->ssa_reg = lhsexpr_generate_ssa(ast_data, resolve_data, context); break; case AST_ASSIGN: - self->ssa_reg = assignmentexpr_generate_ssa(self, context); + resolve_data->ssa_reg = assignmentexpr_generate_ssa(ast_data, context); break; case AST_IMPORT: /* TODO: Implement cross file references */ - self->ssa_reg = 0; + resolve_data->ssa_reg = 0; break; case AST_STRING: - self->ssa_reg = string_generate_ssa(self->value.string, context); + resolve_data->ssa_reg = string_generate_ssa(ast_data, context); break; case AST_VARIABLE: - self->ssa_reg = variable_generate_ssa(self->value.variable, context); + resolve_data->ssa_reg = variable_generate_ssa(ast_data, context); break; case AST_BINOP: - self->ssa_reg = binop_generate_ssa(self->value.binop, context); + resolve_data->ssa_reg = binop_generate_ssa(ast_data, context); break; case AST_IF_STATEMENT: - if_statement_generate_ssa(self->value.if_stmt, context); + if_statement_generate_ssa(ast_data, context); break; case AST_WHILE_STATEMENT: - while_statement_generate_ssa(self->value.while_stmt, context); + while_statement_generate_ssa(ast_data, context); + break; + case AST_RETURN: + return_expr_generate_ssa(ast_data, context); + resolve_data->ssa_reg = 0; break; } - self->resolve_data.status = AST_SSA_RESOLVED; - return self->ssa_reg; + resolve_data->status = AST_SSA_RESOLVED; + return resolve_data->ssa_reg; +} + +CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) { + assert(self); + #ifdef DEBUG + if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_SSA_RESOLVED) { + amal_log_error("Ast type not resolved: %d", self->type); + assert(bool_false); + } + #endif + return ast_generate_ssa_resolve_data(self->value.data, self->type, &self->resolve_data, context); +} + +CHECK_RESULT SsaRegister scope_named_object_generate_ssa(ScopeNamedObject *self, SsaCompilerContext *context) { + switch(self->type) { + case NAMED_OBJECT_NONE: + assert(bool_false); + return 0; + case NAMED_OBJECT_LHS_EXPR: + return ast_generate_ssa_resolve_data(self->value.lhs_expr, AST_LHS, self->resolve_data, context); + case NAMED_OBJECT_FUNC_PARAM: + return function_parameter_generate_ssa(self->value.func_param, context); + } + return 0; } void scope_generate_ssa(Scope *self, SsaCompilerContext *context) { -- cgit v1.2.3