diff options
-rw-r--r-- | include/ast.h | 1 | ||||
-rw-r--r-- | include/ssa/ssa.h | 5 | ||||
-rw-r--r-- | src/ast.c | 104 | ||||
-rw-r--r-- | src/compiler.c | 2 | ||||
-rw-r--r-- | src/ssa/ssa.c | 66 | ||||
-rw-r--r-- | src/std/hash_map.c | 4 |
6 files changed, 105 insertions, 77 deletions
diff --git a/include/ast.h b/include/ast.h index 580ca24..d37fcb3 100644 --- a/include/ast.h +++ b/include/ast.h @@ -148,7 +148,6 @@ struct Binop { typedef struct { jmp_buf env; - Parser *parser; amal_compiler *compiler; Scope *scope; } AstCompilerContext; diff --git a/include/ssa/ssa.h b/include/ssa/ssa.h index c374ffb..16ceb25 100644 --- a/include/ssa/ssa.h +++ b/include/ssa/ssa.h @@ -38,7 +38,7 @@ typedef struct { typedef u16 SsaRegister; typedef u16 SsaIntermediateIndex; typedef u16 SsaStringIndex; -typedef u32 SsaFuncIndex; +typedef usize SsaFuncIndex; typedef struct { Buffer/*instruction data*/ instructions; @@ -63,12 +63,11 @@ CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstructionType binop_type, SsaRegi CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result); CHECK_RESULT int ssa_ins_func_end(Ssa *self); CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg); -CHECK_RESULT int ssa_ins_call(Ssa *self, SsaFuncIndex func, SsaRegister *result); +CHECK_RESULT int ssa_ins_call(Ssa *self, void *func, SsaRegister *result); typedef struct { jmp_buf env; - Parser *parser; Ssa ssa; } SsaCompilerContext; @@ -180,6 +180,16 @@ void scope_resolve(Scope *self, AstCompilerContext *context) { context->scope = self->parent; } +static Parser* scope_get_parser(Scope *scope) { + while(scope) { + if(scope->parser) + return scope->parser; + scope = scope->parent; + } + assert(bool_false && "BUG: At least some scope parent is supposed to have a parser"); + return NULL; +} + static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { Ast *result; bool exists; @@ -188,11 +198,13 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context assert(self); exists = hash_map_get(&self->named_objects, name, &result); if(!exists) { + Parser *parser; if(self->parent) return scope_get_resolved_variable(self->parent, context, name); - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, name.data), + parser = scope_get_parser(self); + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, name.data), "Undefined reference to variable \"%.*s\"", name.size, name.data); throw(AST_ERR); } @@ -216,13 +228,13 @@ static void variable_resolve(Variable *self, AstCompilerContext *context, AstRes resolve_data->type = scope_get_resolved_variable(context->scope, context, self->name)->resolve_data.type; } -static LhsExpr* lhsexpr_resolve_rhs(Ast *ast, AstCompilerContext *context, LhsExpr *lhs_expr) { +static LhsExpr* lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context) { LhsExpr *rhs_resolved_type; - ast_resolve(ast, context); - if(ast_is_decl(ast)) - rhs_resolved_type = lhs_expr; + ast_resolve(self->rhs_expr, context); + if(ast_is_decl(self->rhs_expr)) + rhs_resolved_type = self; else - rhs_resolved_type = ast->resolve_data.type; + rhs_resolved_type = self->rhs_expr->resolve_data.type; return rhs_resolved_type; } @@ -246,14 +258,14 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { if(self->rhs_expr->type == AST_FUNCTION_DECL) ast->resolve_data.status = AST_RESOLVED; - rhs_resolve_type = lhsexpr_resolve_rhs(self->rhs_expr, context, self); + rhs_resolve_type = lhsexpr_resolve_rhs(self, context); /* self->rhs_expr can be null here because this is valid: var num: i32; */ - if(ast->resolve_data.type && - self->rhs_expr && - ast->resolve_data.type != rhs_resolve_type) { - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, self->type.name.data), + if(ast->resolve_data.type && self->rhs_expr && ast->resolve_data.type != rhs_resolve_type) { + Parser *parser; + parser = scope_get_parser(context->scope); + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, self->type.name.data), "Variable type and variable assignment type (right-hand side) do not match"); throw(AST_ERR); } @@ -289,17 +301,10 @@ static Scope* lhsexpr_get_scope(LhsExpr *self) { return NULL; } -/* @self has to be resolved before calling this */ +/* @self has to have a resolved type before calling this */ static Parser* get_resolved_type_parser(Ast *self) { - Scope *scope; - scope = lhsexpr_get_scope(self->resolve_data.type); - while(scope) { - if(scope->parser) - return scope->parser; - scope = scope->parent; - } - assert(bool_false && "BUG: At least some parent is supposed to have a parser"); - return NULL; + assert(self->resolve_data.type); + return scope_get_parser(lhsexpr_get_scope(self->resolve_data.type)); } static void funcdecl_resolve(FunctionDecl *self, AstCompilerContext *context) { @@ -315,17 +320,20 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) { func_call = self->value.func_call; variable_resolve(&func_call->func, context, &self->resolve_data); if(self->resolve_data.type->rhs_expr->type != AST_FUNCTION_DECL) { + Parser *caller_parser; Parser *callee_parser; BufferView callee_code_ref; + + caller_parser = scope_get_parser(context->scope); callee_parser = get_resolved_type_parser(self); callee_code_ref = self->resolve_data.type->var_name; - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, func_call->func.name.data), + tokenizer_print_error(&caller_parser->tokenizer, + tokenizer_get_code_reference_index(&caller_parser->tokenizer, func_call->func.name.data), "\"%.*s\" is not a function. Only functions can be called", func_call->func.name.size, func_call->func.name.data); /* TODO: use tokenizer_print_note, once it has been added */ /* TODO: Print type */ - tokenizer_print_error(&context->parser->tokenizer, + tokenizer_print_error(&callee_parser->tokenizer, tokenizer_get_code_reference_index(&callee_parser->tokenizer, callee_code_ref.data), "Type was declared here"); throw(AST_ERR); @@ -354,19 +362,21 @@ static void structfield_resolve(Ast *self, AstCompilerContext *context) { static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { Binop *self; Scope *lhs_scope; + Parser *caller_parser; Parser *callee_parser; BufferView caller_code_ref; BufferView callee_code_ref; assert(ast->type == AST_BINOP); self = ast->value.binop; + caller_parser = scope_get_parser(context->scope); if(self->lhs->type != AST_VARIABLE) { /* TODO: Allow field access for numbers and string as well */ BufferView code_ref; code_ref = ast_get_code_reference(self->lhs); - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, code_ref.data), + tokenizer_print_error(&caller_parser->tokenizer, + tokenizer_get_code_reference_index(&caller_parser->tokenizer, code_ref.data), "Accessing fields is only applicable for variables"); throw(AST_ERR); } @@ -379,24 +389,24 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { callee_code_ref = self->rhs->resolve_data.type->var_name; if(self->lhs->resolve_data.type->rhs_expr->type != AST_STRUCT_DECL) { - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, caller_code_ref.data), + tokenizer_print_error(&caller_parser->tokenizer, + tokenizer_get_code_reference_index(&caller_parser->tokenizer, caller_code_ref.data), "Can only access field of structs"); /* TODO: use tokenizer_print_note, once it has been added */ /* TODO: Print type */ - tokenizer_print_error(&context->parser->tokenizer, + tokenizer_print_error(&callee_parser->tokenizer, tokenizer_get_code_reference_index(&callee_parser->tokenizer, callee_code_ref.data), "Type was declared here"); throw(AST_ERR); } if(!self->rhs->resolve_data.type->is_pub) { - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, caller_code_ref.data), + tokenizer_print_error(&caller_parser->tokenizer, + tokenizer_get_code_reference_index(&caller_parser->tokenizer, caller_code_ref.data), "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data); /* TODO: use tokenizer_print_note, once it has been added */ /* TODO: Print type */ - tokenizer_print_error(&context->parser->tokenizer, + tokenizer_print_error(&callee_parser->tokenizer, tokenizer_get_code_reference_index(&callee_parser->tokenizer, callee_code_ref.data), "Type was declared non-public here"); throw(AST_ERR); @@ -425,17 +435,19 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) { TODO: For this first error, only print the line without a reference to code. This requires change in tokenizer_print_error to be able to take a line as reference. */ - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self->rhs).data), + Parser *parser; + parser = scope_get_parser(context->scope); + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self->rhs).data), "Can't cast type \"%.*s\" to type \"%.*s\"", self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data, self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data); - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self->lhs).data), + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self->lhs).data), "Left-hand side is of type %.*s", self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data); - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self->rhs).data), + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self->rhs).data), "Right-hand side is of type %.*s", self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data); throw(AST_ERR); @@ -460,8 +472,10 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { if(self->resolve_data.status == AST_RESOLVED) { return; } else if(self->resolve_data.status == AST_RESOLVING) { - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self).data), + Parser *parser; + parser = scope_get_parser(context->scope); + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self).data), "Found recursive dependency"); throw(AST_ERR); } @@ -472,9 +486,11 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { amal_mutex_tryunlock(self->value.lhs_expr->mutex); return; } else if(self->resolve_data.status == AST_RESOLVING) { + Parser *parser; + parser = scope_get_parser(context->scope); amal_mutex_tryunlock(self->value.lhs_expr->mutex); - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self).data), + tokenizer_print_error(&parser->tokenizer, + tokenizer_get_code_reference_index(&parser->tokenizer, ast_get_code_reference(self).data), "Found recursive dependency"); throw(AST_ERR); } diff --git a/src/compiler.c b/src/compiler.c index 1feaf86..c9ae09a 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -208,7 +208,6 @@ static void* thread_callback_parse_file(void *userdata) { static CHECK_RESULT int thread_resolve_ast(amal_compiler *compiler, Parser *parser) { AstCompilerContext compiler_context; int result; - compiler_context.parser = parser; compiler_context.compiler = compiler; compiler_context.scope = NULL; result = setjmp(compiler_context.env); @@ -222,7 +221,6 @@ static CHECK_RESULT int thread_resolve_ast(amal_compiler *compiler, Parser *pars static CHECK_RESULT int thread_generate_ssa(Parser *parser) { SsaCompilerContext compiler_context; int result; - compiler_context.parser = parser; result = setjmp(compiler_context.env); if(result == 0) { return_if_error(ssa_init(&compiler_context.ssa, parser->allocator)); diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c index 3fffb63..2391778 100644 --- a/src/ssa/ssa.c +++ b/src/ssa/ssa.c @@ -119,8 +119,8 @@ static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstructionType ins_type return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister) + sizeof(u16))); self->instructions.data[index + 0] = ins_type; - *(SsaRegister*)&self->instructions.data[index + 1] = lhs; - *(u16*)&self->instructions.data[index + 3] = rhs; + am_memcpy(self->instructions.data + index + 1, &lhs, sizeof(lhs)); + am_memcpy(self->instructions.data + index + 3, &rhs, sizeof(rhs)); return 0; } @@ -147,9 +147,9 @@ static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstructionType ins_type return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister) + sizeof(SsaRegister) + sizeof(SsaRegister))); *result = self->reg_counter++; self->instructions.data[index + 0] = ins_type; - *(SsaRegister*)&self->instructions.data[index + 1] = *result; - *(SsaRegister*)&self->instructions.data[index + 3] = lhs; - *(SsaRegister*)&self->instructions.data[index + 5] = rhs; + am_memcpy(self->instructions.data + index + 1, &result, sizeof(*result)); + am_memcpy(self->instructions.data + index + 3, &lhs, sizeof(lhs)); + am_memcpy(self->instructions.data + index + 5, &rhs, sizeof(rhs)); amal_log_debug("r%u = r%u %s r%u", *result, lhs, binop_type_to_string(ins_type), rhs); return 0; } @@ -170,7 +170,7 @@ int ssa_ins_assign_string(Ssa *self, SsaRegister dest, BufferView str) { int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) { amal_log_debug("r%u = r%u", dest, src); - return ssa_add_ins_form1(self, SSA_ASSIGN_INTER, dest, src); + return ssa_add_ins_form1(self, SSA_ASSIGN_REG, dest, src); } int ssa_ins_binop(Ssa *self, SsaInstructionType binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) { @@ -189,7 +189,7 @@ int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) { return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(u8))); *result = self->func_counter++; self->instructions.data[index + 0] = SSA_FUNC_START; - *(SsaFuncIndex*)&self->instructions.data[index + 1] = *result; + am_memcpy(self->instructions.data + index + 1, result, sizeof(*result)); self->instructions.data[index + 3] = num_args; amal_log_debug("FUNC_START f%u(%u)", *result, num_args); return 0; @@ -208,12 +208,12 @@ int ssa_ins_push(Ssa *self, SsaRegister reg) { return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister))); self->instructions.data[index + 0] = SSA_PUSH; - *(SsaRegister*)&self->instructions.data[index + 1] = reg; + am_memcpy(self->instructions.data + index + 1, ®, sizeof(reg)); amal_log_debug("PUSH r%u", reg); return 0; } -int ssa_ins_call(Ssa *self, SsaFuncIndex func, SsaRegister *result) { +int ssa_ins_call(Ssa *self, void *func, SsaRegister *result) { usize index; index = self->instructions.size; @@ -224,9 +224,9 @@ int ssa_ins_call(Ssa *self, SsaFuncIndex func, SsaRegister *result) { return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(SsaRegister))); *result = self->reg_counter++; self->instructions.data[index + 0] = SSA_CALL; - *(SsaFuncIndex*)&self->instructions.data[index + 1] = func; - *(SsaRegister*)&self->instructions.data[index + 3] = *result; - amal_log_debug("r%u = CALL f%u", *result, func); + am_memcpy(self->instructions.data + index + 1, &func, sizeof(func)); + am_memcpy(self->instructions.data + index + 3, result, sizeof(*result)); + amal_log_debug("r%u = CALL %p", *result, func); return 0; } @@ -247,20 +247,34 @@ static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerCon return reg; } - -static CHECK_RESULT SsaRegister lhs_generate_ssa(LhsExpr *self, SsaCompilerContext *context) { +static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerContext *context) { /* TODO: Implement */ + LhsExpr *lhs_expr; SsaRegister reg; - throw_if_error(amal_mutex_lock(self->mutex, "lhs_generate_ssa")); - throw_if_error(ssa_get_unique_reg(&context->ssa, ®)); - if(self->rhs_expr) { + + assert(self->type == AST_LHS); + lhs_expr = self->value.lhs_expr; + + if(lhs_expr->rhs_expr) { SsaRegister rhs_reg; - rhs_reg = ast_generate_ssa(self->rhs_expr, context); + rhs_reg = ast_generate_ssa(lhs_expr->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? + */ + if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT) + return 0; + throw_if_error(ssa_get_unique_reg(&context->ssa, ®)); + if(reg == rhs_reg) { + amal_log_error("rhs_expr is same as reg.. rhs type: %d", lhs_expr->rhs_expr->type); + } + assert(reg != rhs_reg); throw_if_error(ssa_ins_assign_reg(&context->ssa, reg, rhs_reg)); } else { /* TODO: assign default value to reg depending on LhsExpr type */ } - throw_if_error(amal_mutex_unlock(self->mutex)); return reg; } @@ -270,6 +284,7 @@ in any order. */ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCompilerContext *context) { /* TODO: Implement */ + amal_log_debug("SSA funcdecl %p", self); throw_if_error(ssa_ins_func_start(&context->ssa, 0, &self->ssa_func_index)); scope_generate_ssa(&self->body, context); throw_if_error(ssa_ins_func_end(&context->ssa)); @@ -279,6 +294,7 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerContext *context) { /* TODO: Implement */ FunctionCall *func_call; + FunctionDecl *func_to_call; Ast **ast; Ast **ast_end; SsaRegister reg; @@ -294,9 +310,13 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont } assert(self->resolve_data.type->rhs_expr->type == AST_FUNCTION_DECL); - ignore_result_int(lhs_generate_ssa(self->resolve_data.type, context)); - amal_log_debug("SSA funccall %.*s, func index: %d", func_call->func.name.size, func_call->func.name.data, self->resolve_data.type->rhs_expr->value.func_decl->ssa_func_index); - throw_if_error(ssa_ins_call(&context->ssa, self->resolve_data.type->rhs_expr->value.func_decl->ssa_func_index, ®)); + func_to_call = self->resolve_data.type->rhs_expr->value.func_decl; + /* + TODO: Implement func reference instead of using 0. Perhaps the best way is to use function declaration pointer value? + then there is no need for mutex locks. + */ + 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, ®)); return reg; } @@ -379,7 +399,7 @@ CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context case AST_STRUCT_FIELD: return structfield_generate_ssa(self->value.struct_field, context); case AST_LHS: - return lhs_generate_ssa(self->value.lhs_expr, context); + return lhsexpr_generate_ssa(self, context); case AST_IMPORT: /* TODO: When @import(...).data syntax is added, implement the generate ssa for it */ return 0; diff --git a/src/std/hash_map.c b/src/std/hash_map.c index ab580ba..d9914e7 100644 --- a/src/std/hash_map.c +++ b/src/std/hash_map.c @@ -142,10 +142,6 @@ static void hash_map_reorder_nodes(HashMap *self, usize end_index) { bucket_node = bucket_node_get_next(bucket_node); } } - - /* All nodes removed in bucket */ - if(!prev_bucket_node) - bucket->start = NULL; } } |