diff options
Diffstat (limited to 'src/ssa')
-rw-r--r-- | src/ssa/ssa.c | 262 |
1 files changed, 169 insertions, 93 deletions
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c index 0aabc15..01c4f0f 100644 --- a/src/ssa/ssa.c +++ b/src/ssa/ssa.c @@ -5,8 +5,15 @@ #include "../../include/std/thread.h" #include "../../include/ast.h" #include "../../include/compiler.h" +#include "../../include/parser.h" #include <assert.h> +/* + TODO: Instead of using memcpy to copy data to the ssa, make it cleaner by + defining all the data in structs and copying the structs. Even if it takes more space, + it might even be faster. +*/ + #define throw(result) do { longjmp(context->env, (result)); } while(0) #define throw_if_error(result) \ do { \ @@ -20,13 +27,9 @@ do { \ #define MAX_STRING_LENGTH UINT16_MAX static int compare_number(const void *a, const void *b) { - const SsaNumber *lhs; - const SsaNumber *rhs; - lhs = a; - rhs = b; - if(rhs->type == lhs->type && rhs->value.integer == lhs->value.integer) - return 0; - return 1; + const SsaNumber *lhs = a; + const SsaNumber *rhs = b; + return (rhs->type == lhs->type && rhs->value.integer == lhs->value.integer); } static usize hash_number(const u8 *data, usize size) { @@ -50,23 +53,31 @@ SsaNumber create_ssa_float(f64 value) { return result; } -int ssa_init(Ssa *self, ArenaAllocator *allocator) { - return_if_error(buffer_init(&self->instructions, allocator)); - return_if_error(hash_map_init(&self->intermediates_map, allocator, sizeof(SsaIntermediateIndex), compare_number, hash_number)); - return_if_error(buffer_init(&self->intermediates, allocator)); - return_if_error(hash_map_init(&self->strings_map, allocator, sizeof(SsaStringIndex), hash_map_compare_string, amal_hash_string)); - return_if_error(buffer_init(&self->strings, allocator)); +int ssa_init(Ssa *self, Parser *parser) { + return_if_error(buffer_init(&self->instructions, parser->allocator)); + return_if_error(hash_map_init(&self->intermediates_map, parser->allocator, sizeof(SsaIntermediateIndex), compare_number, hash_number)); + return_if_error(buffer_init(&self->intermediates, parser->allocator)); + return_if_error(hash_map_init(&self->strings_map, parser->allocator, sizeof(SsaStringIndex), hash_map_compare_string, amal_hash_string)); + return_if_error(buffer_init(&self->strings, parser->allocator)); + 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)); self->intermediate_counter = 0; self->string_counter = 0; + self->extern_func_counter = 0; self->reg_counter = 0; + self->param_counter = 0; self->func_counter = 0; + self->parser = parser; return 0; } static CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result) { + assert(result); /* Overflow */ - if(self->reg_counter + 1 < self->reg_counter) + if((u16)self->reg_counter + self->param_counter + 1 > INT16_MAX) { + amal_log_error("Ssa too many registers!"); return -1; + } *result = self->reg_counter++; return 0; } @@ -97,8 +108,10 @@ static CHECK_RESULT int ssa_try_add_intermediate(Ssa *self, SsaNumber number, Ss return 0; /* Overflow */ - if(self->intermediate_counter + 1 < self->intermediate_counter) + if(self->intermediate_counter + 1 <= self->intermediate_counter) { + amal_log_error("Ssa too many intermediates!"); return -1; + } *result_index = self->intermediate_counter; ++self->intermediate_counter; @@ -126,8 +139,10 @@ static CHECK_RESULT int ssa_try_add_string(Ssa *self, BufferView str, SsaStringI return 0; /* Overflow */ - if(self->string_counter + 1 < self->string_counter) + if(self->string_counter + 1 <= self->string_counter) { + amal_log_error("Ssa too many strings!"); return -1; + } if(str.size > MAX_STRING_LENGTH) { amal_log_error("String \"%.*s\" is longer than %d\n", str.size, str.data, MAX_STRING_LENGTH); @@ -141,10 +156,44 @@ static CHECK_RESULT int ssa_try_add_string(Ssa *self, BufferView str, SsaStringI return hash_map_insert(&self->strings_map, str, result_index); } -static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstruction ins_type, SsaRegister lhs, u16 rhs) { - usize index; - index = self->instructions.size; +/* + TODO: Right now this has the same scope as a file. This should be global, otherwise you could define multiple + extern func with the same name but different signature as long as they are defined in different files +*/ +static CHECK_RESULT int ssa_try_add_extern_func(Ssa *self, FunctionSignature *func_sig, BufferView name, SsaExternFuncIndex *result_index, BufferView *existing_func) { + bool exists; + assert(result_index); + assert(existing_func); + + exists = hash_map_get(&self->extern_funcs_map, name, result_index); + if(exists) { + const SsaExternFunc *existing_extern_func = buffer_get(&self->extern_funcs, *result_index, sizeof(SsaExternFunc)); + *existing_func = existing_extern_func->name; + if(!function_signature_equals(func_sig, existing_extern_func->func_sig)) + return SSA_ERR_EXTERN_FUNC_SIG_MISMATCH; + return 0; + } + + /* Overflow */ + if(self->extern_func_counter + 1 <= self->extern_func_counter) { + amal_log_error("Ssa too many extern closures!"); + return -1; + } + + *result_index = self->extern_func_counter; + ++self->extern_func_counter; + amal_log_debug("ef%u = \"%.*s\"", *result_index, name.size, name.data); + { + SsaExternFunc extern_func; + extern_func.func_sig = func_sig; + extern_func.name = name; + return_if_error(buffer_append(&self->extern_funcs, &extern_func, sizeof(extern_func))); + return hash_map_insert(&self->extern_funcs_map, name, result_index); + } +} +static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstruction ins_type, SsaRegister lhs, u16 rhs) { + const usize index = self->instructions.size; return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(u16))); self->instructions.data[index + 0] = ins_type; am_memcpy(self->instructions.data + index + 1, &lhs, sizeof(lhs)); @@ -165,40 +214,33 @@ static const char* binop_type_to_string(SsaInstruction binop_type) { } static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstruction ins_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) { - usize index; - index = self->instructions.size; - - /* Overflow */ - if(self->reg_counter + 1 < self->reg_counter) - return -1; - - assert(result); + const usize index = self->instructions.size; + return_if_error(ssa_get_unique_reg(self, result)); return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(SsaRegister) + sizeof(SsaRegister))); - *result = self->reg_counter++; self->instructions.data[index + 0] = ins_type; am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaRegister)); 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); + amal_log_debug("r%d = r%d %s r%d", *result, lhs, binop_type_to_string(ins_type), rhs); return 0; } static CHECK_RESULT int ssa_ins_assign_inter(Ssa *self, SsaRegister dest, SsaNumber number) { SsaIntermediateIndex index; return_if_error(ssa_try_add_intermediate(self, number, &index)); - amal_log_debug("r%u = i%u", dest, index); + amal_log_debug("r%d = i%u", dest, index); return ssa_add_ins_form1(self, SSA_ASSIGN_INTER, dest, index); } static CHECK_RESULT int ssa_ins_assign_string(Ssa *self, SsaRegister dest, BufferView str) { SsaStringIndex index; return_if_error(ssa_try_add_string(self, str, &index)); - amal_log_debug("r%u = s%u", dest, index); + amal_log_debug("r%d = s%u", dest, index); return ssa_add_ins_form1(self, SSA_ASSIGN_STRING, dest, index); } static CHECK_RESULT int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) { - amal_log_debug("r%u = r%u", dest, src); + amal_log_debug("r%d = r%d", dest, src); return ssa_add_ins_form1(self, SSA_ASSIGN_REG, dest, src); } @@ -207,79 +249,82 @@ 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, SsaFuncIndex *result, usize *func_metadata_index) { - usize index; - index = self->instructions.size; +static CHECK_RESULT int ssa_ins_func_start(Ssa *self, SsaRegister num_reg_params, SsaFuncIndex *result, usize *func_metadata_index) { + const usize index = self->instructions.size; /* Overflow */ - if(self->func_counter + 1 < self->func_counter) + if(self->func_counter + 1 <= self->func_counter) { + amal_log_error("Ssa too many closures!"); return -1; + } - return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(u16))); + return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(SsaRegister) + sizeof(u16))); *result = self->func_counter++; self->instructions.data[index + 0] = SSA_FUNC_START; am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaFuncIndex)); - *func_metadata_index = index + 1 + sizeof(SsaFuncIndex); + am_memcpy(self->instructions.data + index + 1 + sizeof(SsaFuncIndex), &num_reg_params, sizeof(SsaRegister)); + *func_metadata_index = index + 1 + sizeof(SsaFuncIndex) + sizeof(num_reg_params); /* No need to add data to instructions.data here, it can contain undefined data until we set it (@ the caller) */ - amal_log_debug("FUNC_START f%u", *result); + amal_log_debug("FUNC_START f%u, %d", *result, num_reg_params); return 0; } static CHECK_RESULT int ssa_ins_func_end(Ssa *self) { - u8 ins; - ins = SSA_FUNC_END; + const u8 ins = SSA_FUNC_END; amal_log_debug("FUNC_END"); return buffer_append(&self->instructions, &ins, 1); } static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) { - usize index; - index = self->instructions.size; - + const usize index = self->instructions.size; return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister))); self->instructions.data[index + 0] = SSA_PUSH; am_memcpy(self->instructions.data + index + 1, ®, sizeof(SsaRegister)); - amal_log_debug("PUSH r%u", reg); + amal_log_debug("PUSH r%d", reg); return 0; } static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, u8 num_args, SsaRegister *result) { - usize index; - index = self->instructions.size; - - /* Overflow */ - if(self->reg_counter + 1 < self->reg_counter) - return -1; - + const usize index = self->instructions.size; + return_if_error(ssa_get_unique_reg(self, result)); 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; 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); + amal_log_debug("r%d = CALL %d, %p", *result, num_args, func_decl); + return 0; +} + +static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, SsaExternFuncIndex extern_func_index, u8 num_args, SsaRegister *result) { + const usize index = self->instructions.size; + assert(extern_func_index < self->extern_func_counter); + return_if_error(ssa_get_unique_reg(self, result)); + return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(u8) + sizeof(SsaRegister) + sizeof(extern_func_index))); + self->instructions.data[index + 0] = SSA_CALL_EXTERN; + 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), &extern_func_index, sizeof(extern_func_index)); + amal_log_debug("r%d = CALL_EXTERN %d, %d", *result, num_args, extern_func_index); return 0; } static CHECK_RESULT int ssa_ins_jumpzero(Ssa *self, SsaRegister condition_reg, JumpOffset jump_offset) { - usize index; - index = self->instructions.size; + const usize index = self->instructions.size; return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(JumpOffset))); self->instructions.data[index + 0] = SSA_JUMP_ZERO; am_memcpy(self->instructions.data + index + 1, &condition_reg, sizeof(SsaRegister)); am_memcpy(self->instructions.data + index + 1 + sizeof(SsaRegister), &jump_offset, sizeof(JumpOffset)); if(jump_offset == 0) - amal_log_debug("JUMP_ZERO r%u, DUMMY", condition_reg); + amal_log_debug("JUMP_ZERO r%d, DUMMY", condition_reg); else - amal_log_debug("JUMP_ZERO r%u, %d", condition_reg, jump_offset); + amal_log_debug("JUMP_ZERO r%d, %d", condition_reg, jump_offset); return 0; } static CHECK_RESULT int ssa_ins_jump(Ssa *self, JumpOffset jump_offset) { - usize index; - index = self->instructions.size; - + const usize index = self->instructions.size; return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(JumpOffset))); self->instructions.data[index + 0] = SSA_JUMP; am_memcpy(self->instructions.data + index + 1, &jump_offset, sizeof(JumpOffset)); @@ -288,9 +333,7 @@ static CHECK_RESULT int ssa_ins_jump(Ssa *self, JumpOffset jump_offset) { } static CHECK_RESULT int ssa_ins_return(Ssa *self, SsaRegister reg) { - usize index; - index = self->instructions.size; - + const usize 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)); @@ -359,9 +402,34 @@ static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerCon static CHECK_RESULT SsaRegister lhsexpr_extern_generate_ssa(LhsExpr *self, SsaCompilerContext *context) { /* TODO: SsaRegister should be extended to include static and extern data */ - (void)self; - (void)context; - amal_log_error("TODO: Implement lhsexpr_extern_generate_ssa"); + if(self->type.type == VARIABLE_TYPE_SIGNATURE) { + int err; + BufferView existing_func; + + err = ssa_try_add_extern_func(context->ssa, self->type.value.signature, self->var_name, &self->extern_index, &existing_func); + if(err == SSA_ERR_EXTERN_FUNC_SIG_MISMATCH) { + Tokenizer *tokenizer; + tokenizer = &context->ssa->parser->tokenizer; + tokenizer_print_error(tokenizer, tokenizer_get_code_reference_index(tokenizer, self->var_name.data), + "Extern closure defined here with the name %.*s doesn't match extern closure with the same name defined in another location", + self->var_name.size, self->var_name.data); + /* + TODO: This wont work right now since the other location might belong to another parser. + There should be a function to get a parser from a code reference (loop all tokens and check code range). + Then the parsers that belong to scopes can also be removed. This is fine, since the lookup is only done on error. + */ + #if 0 + tokenizer_print_error(tokenizer, tokenizer_get_code_reference_index(tokenizer, self->var_name.data), + "Extern closure defined here with the name %.*s doesn't match extern closure with the same name defined in another location", + self->var_name.size, self->var_name.data); + #endif + throw(err); + } + if(err != 0) + throw(err); + } else { + assert(bool_false && "TODO: Implement lhsexpr_extern_generate_ssa for other data than functions"); + } return 0; } @@ -385,12 +453,7 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(LhsExpr *self, AstResolveDa /*assert(bool_false);*/ 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", rhs_expr->type); - } - assert(reg != rhs_reg); - throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg)); + return rhs_reg; } else { /* TODO: Do not assign if we dont want default value */ if(resolve_data->type.type == RESOLVED_TYPE_LHS_EXPR) { @@ -426,6 +489,12 @@ static CHECK_RESULT SsaRegister function_parameter_generate_ssa(FunctionParamete return self->resolve_data.ssa_reg; throw_if_error(ssa_get_unique_reg(context->ssa, ®)); + /* Parameters start at -1 and decrement */ + if((u16)reg - 1 >= (u16)reg) { + amal_log_error("Ssa too many parameters!"); + throw(-1); + } + reg = -1 - reg; self->resolve_data.status = AST_SSA_RESOLVED; self->resolve_data.ssa_reg = reg; return reg; @@ -453,9 +522,11 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom that is reset after function end */ SsaRegister prev_reg_counter; + SsaRegister prev_param_counter; usize func_metadata_index; - int num_params; + prev_reg_counter = context->ssa->reg_counter; + prev_param_counter = context->ssa->param_counter; context->ssa->reg_counter = 0; /* @@ -463,44 +534,49 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom 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); + context->ssa->param_counter = context->ssa->reg_counter; + context->ssa->reg_counter = 0; amal_log_debug("SSA funcdecl %p", self); - throw_if_error(ssa_ins_func_start(context->ssa, &self->ssa_func_index, &func_metadata_index)); + throw_if_error(ssa_ins_func_start(context->ssa, context->ssa->param_counter, &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)); + am_memcpy(context->ssa->instructions.data + func_metadata_index, &context->ssa->reg_counter, sizeof(u16)); + + context->ssa->param_counter = prev_param_counter; context->ssa->reg_counter = prev_reg_counter; return 0; } static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstResolveData *resolve_data, SsaCompilerContext *context) { - Ast **ast; - Ast **ast_end; SsaRegister reg; FunctionDecl *func_decl; - - 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)); + LhsExpr *func_lhs_expr; + + { + Ast **arg; + Ast **arg_end; + arg = buffer_begin(&self->args); + arg_end = buffer_end(&self->args); + for(; arg != arg_end; ++arg) { + SsaRegister arg_reg; + 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); - 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!"); + 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*), ®)); } else { /* rhs wont be null here because only extern variable can't have rhs */ - 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*), ®)); } |