diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast.c | 72 | ||||
-rw-r--r-- | src/bytecode/bytecode.c | 107 | ||||
-rw-r--r-- | src/compiler.c | 59 | ||||
-rw-r--r-- | src/parser.c | 38 | ||||
-rw-r--r-- | src/program.c | 225 | ||||
-rw-r--r-- | src/ssa/ssa.c | 262 | ||||
-rw-r--r-- | src/std/arena_allocator.c | 3 | ||||
-rw-r--r-- | src/std/hash_map.c | 10 | ||||
-rw-r--r-- | src/tokenizer.c | 1 |
9 files changed, 559 insertions, 218 deletions
@@ -21,7 +21,7 @@ static BufferView variable_type_get_name(VariableType *self); static void scope_named_object_init(ScopeNamedObject *self) { self->type = NAMED_OBJECT_NONE; - self->value.lhs_expr = NULL; + self->value.data = NULL; self->resolve_data = NULL; } @@ -75,13 +75,23 @@ static BufferView ast_resolved_type_get_name(AstResolvedType *self) { } static void ast_resolved_type_init(AstResolvedType *self) { - self->value.lhs_expr = NULL; + self->value.data = NULL; self->type = RESOLVED_TYPE_NONE; } static bool ast_resolved_type_equals(AstResolvedType *self, AstResolvedType *other) { - /* This should be fine, without checking AstResolvedType type, since they are only equal if the types are equal as well */ - return self->value.lhs_expr == other->value.lhs_expr; + if(self->type != other->type) + return bool_false; + + switch(self->type) { + case RESOLVED_TYPE_NONE: + return bool_true; + case RESOLVED_TYPE_LHS_EXPR: + return self->value.lhs_expr == other->value.lhs_expr; + case RESOLVED_TYPE_FUNC_SIG: + return function_signature_equals(self->value.func_sig, other->value.func_sig); + } + return bool_false; } static AstResolvedType lhs_expr_get_resolved_type(LhsExpr *self, AstCompilerContext *context) { @@ -214,6 +224,59 @@ int function_signature_add_return_type(FunctionSignature *self, const VariableTy return buffer_append(&self->return_types, &return_type, sizeof(return_type)); } +static CHECK_RESULT bool function_parameter_equals(FunctionParameter *self, FunctionParameter *other) { + /* It's fine if the name of the parameter is different. Only the type matters */ + return ast_resolved_type_equals(&self->resolve_data.type, &other->resolve_data.type); +} + +static CHECK_RESULT bool function_parameters_equals(Buffer *func_params, Buffer *other_func_params) { + FunctionParameter *func_param, *func_param_end; + FunctionParameter *other_func_param, *other_func_param_end; + + func_param = buffer_begin(func_params); + func_param_end = buffer_end(func_params); + other_func_param = buffer_begin(other_func_params); + other_func_param_end = buffer_end(other_func_params); + /* Different number of arguments */ + if(func_param_end - func_param != other_func_param_end - other_func_param) + return bool_false; + + for(; func_param != func_param_end; ++func_param, ++other_func_param) { + if(!function_parameter_equals(func_param, other_func_param)) + return bool_false; + } + return bool_true; +} + +static CHECK_RESULT bool function_return_type_equals(FunctionReturnType *self, FunctionReturnType *other) { + return ast_resolved_type_equals(&self->resolved_type, &other->resolved_type); +} + +static CHECK_RESULT bool function_return_types_equals(Buffer *func_return_types, Buffer *other_func_return_types) { + FunctionReturnType *func_return_type, *func_return_type_end; + FunctionReturnType *other_func_return_type, *other_func_return_type_end; + + func_return_type = buffer_begin(func_return_types); + func_return_type_end = buffer_end(func_return_types); + other_func_return_type = buffer_begin(other_func_return_types); + other_func_return_type_end = buffer_end(other_func_return_types); + /* Different number of arguments */ + if(func_return_type_end - func_return_type != other_func_return_type_end - other_func_return_type) + return bool_false; + + for(; func_return_type != func_return_type_end; ++func_return_type, ++other_func_return_type) { + if(!function_return_type_equals(func_return_type, other_func_return_type)) + return bool_false; + } + return bool_true; +} + +bool function_signature_equals(FunctionSignature *self, FunctionSignature *other) { + if(!function_parameters_equals(&self->parameters, &other->parameters)) + return bool_false; + return function_return_types_equals(&self->return_types, &other->return_types); +} + void function_parameter_init(FunctionParameter *self) { self->name = create_buffer_view_null(); self->type.type = VARIABLE_TYPE_NONE; @@ -256,6 +319,7 @@ void lhsexpr_init(LhsExpr *self, DeclFlag decl_flag, BufferView var_name) { self->type.value.variable = NULL; self->var_name = var_name; self->rhs_expr = NULL; + self->extern_index = 0; } void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr) { diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c index 8a41900..edc8dba 100644 --- a/src/bytecode/bytecode.c +++ b/src/bytecode/bytecode.c @@ -3,6 +3,7 @@ #include "../../include/std/log.h" #include "../../include/ssa/ssa.h" #include "../../include/parser.h" +#include "../../include/ast.h" #include "../../include/compiler.h" #include <assert.h> #include <stdio.h> /* TODO: Remove this */ @@ -37,8 +38,9 @@ static CHECK_RESULT usize ssa_extract_form2(u8 *instruction_data, SsaInsForm2 *r static CHECK_RESULT usize ssa_extract_func_start(u8 *instruction_data, SsaInsFuncStart *result) { am_memcpy(&result->func_index, instruction_data, sizeof(result->func_index)); - am_memcpy(&result->num_registers, instruction_data + sizeof(result->func_index), sizeof(result->num_registers)); - return sizeof(result->func_index) + sizeof(result->num_registers); + am_memcpy(&result->num_params_regs, instruction_data + sizeof(result->func_index), sizeof(result->num_params_regs)); + am_memcpy(&result->num_local_vars_regs, instruction_data + sizeof(result->func_index) + sizeof(result->num_params_regs), sizeof(result->num_local_vars_regs)); + return sizeof(result->func_index) + sizeof(result->num_params_regs) + sizeof(result->num_local_vars_regs); } static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFuncCall *result) { @@ -48,6 +50,13 @@ static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFunc return sizeof(u8) + sizeof(result->result) + sizeof(result->func_decl); } +static CHECK_RESULT usize ssa_extract_func_call_extern(u8 *instruction_data, SsaInsFuncCallExtern *result) { + result->num_args = instruction_data[0]; + am_memcpy(&result->result, instruction_data + 1, sizeof(result->result)); + am_memcpy(&result->extern_func_index, instruction_data + 1 + sizeof(result->result), sizeof(result->extern_func_index)); + return sizeof(u8) + sizeof(result->result) + sizeof(result->extern_func_index); +} + static CHECK_RESULT usize ssa_extract_jump_zero(u8 *instruction_data, SsaInsJumpZero *result) { am_memcpy(&result->condition_reg, instruction_data, sizeof(result->condition_reg)); am_memcpy(&result->jump_offset, instruction_data + sizeof(result->condition_reg), sizeof(result->jump_offset)); @@ -107,7 +116,7 @@ static void add_strings(BytecodeCompilerContext *self) { # String |Type|Field|Description | |----|----|----------------------------------------------------------------------------------------| - |u16 |Size|The size of the string, in bytes. | + |u16 |Size|The size of the string, in bytes. Excluding the null-terminate character. | |u8* |Data|The data of the string, where the size is defined by @Size. Strings are null-terminated.| */ @@ -115,18 +124,12 @@ static void add_strings(BytecodeCompilerContext *self) { Buffer *instructions; BufferView *string; BufferView *strings_end; - u16 num_strings; u32 strings_size; ssa = self->parser->ssa; instructions = &self->bytecode.data; string = buffer_begin(&ssa->strings); strings_end = buffer_end(&ssa->strings); - if(strings_end - string > UINT16_MAX) { - amal_log_error("Too many strings in the program"); - throw(-1); - } - num_strings = strings_end - string; strings_size = 0; for(; string != strings_end; ++string) { @@ -135,10 +138,10 @@ static void add_strings(BytecodeCompilerContext *self) { string = buffer_begin(&ssa->strings); throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + strings_size)); - throw_if_error(buffer_append(instructions, &num_strings, sizeof(u16))); + throw_if_error(buffer_append(instructions, &ssa->string_counter, sizeof(u16))); throw_if_error(buffer_append(instructions, &strings_size, sizeof(u32))); for(; string != strings_end; ++string) { - char null_s = '\0'; + const char null_s = '\0'; throw_if_error(buffer_append(instructions, &string->size, sizeof(u16))); throw_if_error(buffer_append(instructions, string->data, string->size)); throw_if_error(buffer_append(instructions, &null_s, sizeof(char))); @@ -157,6 +160,55 @@ static void add_functions(BytecodeCompilerContext *self) { throw_if_error(buffer_append(&self->bytecode.data, &self->parser->ssa->func_counter, sizeof(u16))); } +static void add_extern_functions(BytecodeCompilerContext *self) { + /*doc(Bytecode external functions) + # External functions layout + |Type |Field |Description | + |------------------|------------------|-----------------------------------------------------------------------------------------| + |u16 |num_extern_func |The number of external functions. | + |u32 |extern_funcs_size |The size of the external functions section, in bytes. | + |External function*|External functions|Multiple external functions, where the number of functions is defined by @num_extern_func| + + # External function + |Type|Field |Description | + |----|--------|-----------------------------------------------------------------------------------------------------| + |u8 |num_args|The number of arguments the functions has. | + |u8 |name_len|The length of the external function name, in bytes. Excluding the null-terminate character. | + |u8* |name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.| + */ + + Ssa *ssa; + Buffer *instructions; + SsaExternFunc *extern_func, *extern_func_end; + u32 extern_funcs_size; + + ssa = self->parser->ssa; + instructions = &self->bytecode.data; + extern_func = buffer_begin(&ssa->extern_funcs); + extern_func_end = buffer_end(&ssa->extern_funcs); + extern_funcs_size = 0; + + for(; extern_func != extern_func_end; ++extern_func) { + extern_funcs_size += sizeof(u8) + sizeof(u8) + extern_func->name.size + 1; /* +1 for null-termination of string */ + } + extern_func = buffer_begin(&ssa->extern_funcs); + + throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + extern_funcs_size)); + throw_if_error(buffer_append(instructions, &ssa->extern_func_counter, sizeof(u16))); + throw_if_error(buffer_append(instructions, &extern_funcs_size, sizeof(u32))); + for(; extern_func != extern_func_end; ++extern_func) { + const char null_s = '\0'; + u8 num_args; + num_args = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter); + throw_if_error(buffer_append(instructions, &num_args, sizeof(num_args))); + throw_if_error(buffer_append(instructions, &extern_func->name.size, sizeof(u8))); + throw_if_error(buffer_append(instructions, extern_func->name.data, extern_func->name.size)); + throw_if_error(buffer_append(instructions, &null_s, sizeof(char))); + } + + assert(sizeof(SsaExternFuncIndex) == sizeof(u16) && "Program decoder needs to be updated since size of extern func index has changed"); +} + static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const char *fmt) { throw_if_error(buffer_append(&self->bytecode.data, &opcode, sizeof(AmalOpcodeType))); fprintf(stderr, fmt); @@ -164,7 +216,7 @@ static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const cha } -static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, u8 reg, const char *fmt) { +static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, const char *fmt) { Buffer *instructions; size_t index; instructions = &self->bytecode.data; @@ -177,7 +229,7 @@ static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, u8 reg, c fputc('\n', stderr); } -static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u8 src_reg, const char *fmt) { +static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 src_reg, const char *fmt) { Buffer *instructions; size_t index; instructions = &self->bytecode.data; @@ -204,7 +256,7 @@ static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data, fputc('\n', stderr); } -static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u8 reg1, u8 reg2, const char *fmt) { +static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 reg1, i8 reg2, const char *fmt) { Buffer *instructions; size_t index; instructions = &self->bytecode.data; @@ -219,7 +271,7 @@ static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_re fputc('\n', stderr); } -static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u16 data, const char *fmt) { +static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, u16 data, const char *fmt) { Buffer *instructions; size_t index; instructions = &self->bytecode.data; @@ -233,17 +285,18 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_re fputc('\n', stderr); } -static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u16 idx, u8 arg, const char *fmt) { +static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u16 idx, i8 num_args, i8 dst_reg, const char *fmt) { Buffer *instructions; size_t index; instructions = &self->bytecode.data; index = instructions->size; - throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(arg))); + throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args) + sizeof(dst_reg))); instructions->data[index] = opcode; memcpy(instructions->data + index + sizeof(AmalOpcodeType), &idx, sizeof(idx)); - instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx)] = arg; - fprintf(stderr, fmt, idx, arg); + instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx)] = num_args; + instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args)] = dst_reg; + fprintf(stderr, fmt, idx, num_args, dst_reg); fputc('\n', stderr); } @@ -283,6 +336,7 @@ static void add_instructions(BytecodeCompilerContext *self) { SsaInsForm2 ssa_ins_form2; SsaInsFuncStart ssa_ins_func_start; SsaInsFuncCall ssa_ins_func_call; + SsaInsFuncCallExtern ssa_ins_func_call_extern; SsaInsJumpZero ssa_ins_jump_zero; SsaInsJump ssa_ins_jump; @@ -490,7 +544,7 @@ static void add_instructions(BytecodeCompilerContext *self) { } case SSA_FUNC_START: { instruction += ssa_extract_func_start(instruction, &ssa_ins_func_start); - add_ins4(self, AMAL_OP_FUNC_START, ssa_ins_func_start.num_registers, "func_start %u"); + add_ins6(self, AMAL_OP_FUNC_START, ssa_ins_func_start.num_params_regs, ssa_ins_func_start.num_local_vars_regs, "func_start %d, %u"); break; } case SSA_FUNC_END: { @@ -506,10 +560,6 @@ static void add_instructions(BytecodeCompilerContext *self) { } case SSA_CALL: { /* - TODO: Pass return register to function. The register should be a pointer that - has the size of the function return values so the return values can fit in it. - */ - /* TODO: Using ssa_func_index only works correctly if the function was defined in the same file as the function call. To make this work with calling functions in other files, ssa_func_index should also have an offset index or something like that. @@ -518,8 +568,12 @@ static void add_instructions(BytecodeCompilerContext *self) { is defined as the size of all previous files' number of functions. */ instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call); - add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, "call %d, %d"); - assert(bool_false && "TODO: Assign function result (RAX for x86_64) to ssa_ins_func_call.result reg"); + add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, ssa_ins_func_call.result, "call f%d, %d, r%d"); + break; + } + case SSA_CALL_EXTERN: { + instruction += ssa_extract_func_call_extern(instruction, &ssa_ins_func_call_extern); + add_ins7(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.extern_func_index, ssa_ins_func_call_extern.num_args, ssa_ins_func_call_extern.result, "calle ef%d, %d, r%d"); break; } case SSA_JUMP_ZERO: { @@ -558,5 +612,6 @@ void generate_bytecode_from_ssa(BytecodeCompilerContext *self) { add_intermediates(self); add_strings(self); add_functions(self); + add_extern_functions(self); add_instructions(self); } diff --git a/src/compiler.c b/src/compiler.c index 228cb74..803515b 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -273,7 +273,7 @@ static CHECK_RESULT int thread_generate_ssa(Parser *parser) { int result; return_if_error(arena_allocator_alloc(parser->allocator, sizeof(Ssa), (void**)&compiler_context.ssa)); - return_if_error(ssa_init(compiler_context.ssa, parser->allocator)); + return_if_error(ssa_init(compiler_context.ssa, parser)); compiler_context.compiler = parser->compiler; parser->ssa = compiler_context.ssa; amal_log_debug("Generating SSA for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); @@ -549,6 +549,36 @@ int amal_compiler_load_file(amal_compiler_options *options, amal_program *progra return result; } +/* TODO: Verify main func has correct signature */ +static CHECK_RESULT int validate_main_func(FileScopeReference *main_file_scope, LhsExpr **main_func) { + const BufferView main_func_name = { "main", 4 }; + LhsExpr *main_func_expr; + + main_func_expr = structdecl_get_field_by_name(&main_file_scope->parser->struct_decl, main_func_name); + if(!main_func_expr) { + amal_log_error("main function missing from start file \"%.*s\"", main_file_scope->canonical_path.size, main_file_scope->canonical_path.data); + return AMAL_COMPILER_ERR; + } + *main_func = main_func_expr; + + if(!main_func_expr->rhs_expr || main_func_expr->rhs_expr->type != AST_FUNCTION_DECL) { + amal_log_error("main exists in start file \"%.*s\" but it's not an non-extern function", main_file_scope->canonical_path.size, main_file_scope->canonical_path.data); + return AMAL_COMPILER_ERR; + } + + if(!LHS_EXPR_IS_CONST(main_func_expr)) { + amal_log_error("main function in start file \"%.*s\" has to be const", main_file_scope->canonical_path.size, main_file_scope->canonical_path.data); + return AMAL_COMPILER_ERR; + } + + if(LHS_EXPR_IS_EXTERN(main_func_expr)) { + amal_log_error("main function in start file \"%.*s\" can't be declared as extern", main_file_scope->canonical_path.size, main_file_scope->canonical_path.data); + return AMAL_COMPILER_ERR; + } + + return 0; +} + int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) { int result; ParserThreadData *parser_thread_data; @@ -587,39 +617,18 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, and writing it to a file, which is an IO bottlenecked operation and it won't benefit from multithreading and may even lose performance because of it. */ - const BufferView main_func_name = { "main", 4 }; - LhsExpr *main_func_expr; + LhsExpr *main_func; return_if_error(amal_compiler_load_file_join_threads(self)); assert(amal_compiler_check_all_threads_done(self)); amal_log_info("Finished parsing all files, resolving AST"); - main_func_expr = structdecl_get_field_by_name(&(*file_scope)->parser->struct_decl, main_func_name); - if(!main_func_expr) { - amal_log_error("main function missing from start file \"%.*s\"", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data); - return AMAL_COMPILER_ERR; - } - - if(!main_func_expr->rhs_expr || main_func_expr->rhs_expr->type != AST_FUNCTION_DECL) { - amal_log_error("main exists in start file \"%.*s\" but it's not an non-extern function", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data); - return AMAL_COMPILER_ERR; - } - - if(!LHS_EXPR_IS_CONST(main_func_expr)) { - amal_log_error("main function in start file \"%.*s\" has to be const", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data); - return AMAL_COMPILER_ERR; - } - - if(LHS_EXPR_IS_EXTERN(main_func_expr)) { - amal_log_error("main function in start file \"%.*s\" can't be declared as extern", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data); - return AMAL_COMPILER_ERR; - } - + return_if_error(validate_main_func(*file_scope, &main_func)); /* The main function is the start file needs to be exported, so it's accessible in the program execution to find the entry (main) function. */ - main_func_expr->decl_flags |= DECL_FLAG_EXPORT; + main_func->decl_flags |= DECL_FLAG_EXPORT; return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_RESOLVE_AST)); assert(amal_compiler_check_all_threads_done(self)); diff --git a/src/parser.c b/src/parser.c index 33e9146..cdf7c5b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -20,6 +20,8 @@ do { \ throw(return_if_result); \ } while(0) +#define VAR_MAX_LEN UINT8_MAX + static CHECK_RESULT Ast* parser_parse_rhs(Parser *self); static CHECK_RESULT Ast* parser_parse_body(Parser *self); static CHECK_RESULT Ast* parser_parse_struct_body(Parser *self); @@ -193,21 +195,27 @@ static void parser_parse_function_parameters(Parser *self, FunctionSignature *fu FUNC_RETURN_TYPES = VAR_TYPE (',' VAR_TYPE)* */ static void parser_parse_function_return_types(Parser *self, FunctionSignature *func_sig) { + int return_type_index; + return_type_index = 0; for(;;) { VariableType var_type; bool match; parser_parse_var_type(self, &var_type); if(var_type.type == VARIABLE_TYPE_NONE) { + /* If function has no return types */ + if(return_type_index == 0) + return; self->error = tokenizer_create_error(&self->tokenizer, tokenizer_get_error_index(&self->tokenizer), - "Expected closure return type"); + "Expected type or closure signature"); throw(PARSER_UNEXPECTED_TOKEN); } throw_if_error(function_signature_add_return_type(func_sig, &var_type)); throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match)); if(!match) return; + ++return_type_index; } } @@ -256,14 +264,9 @@ void parser_parse_var_type(Parser *self, VariableType *result) { return; } - result->type = VARIABLE_TYPE_SIGNATURE; result->value.signature = parser_parse_function_signature(self); - if(!result->value.signature) { - self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data), - "Expected type or closure signature"); - throw(PARSER_UNEXPECTED_TOKEN); - } + if(result->value.signature) + result->type = VARIABLE_TYPE_SIGNATURE; } /* @@ -280,6 +283,12 @@ void parser_parse_var_type_def(Parser *self, VariableType *result) { } parser_parse_var_type(self, result); + if(result->type == VARIABLE_TYPE_NONE) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "Expected type or closure signature"); + throw(PARSER_UNEXPECTED_TOKEN); + } } /* @@ -339,6 +348,13 @@ static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) { throw_if_error(arena_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&result)); lhsexpr_init(result, decl_flag, var_name); + if(var_name.size > VAR_MAX_LEN) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_code_reference_index(&self->tokenizer, var_name.data), + "Variable name can't be longer than %d", VAR_MAX_LEN); + throw(PARSER_ERR); + } + parser_parse_var_type_def(self, &result->type); return result; } @@ -741,6 +757,12 @@ static Ast* parser_parse_lhs_rhs(Parser *self, LhsExpr *lhs_expr) { func_decl = parser_parse_closure(self); if(func_decl) { + if(buffer_get_size(&func_decl->signature->return_types, FunctionReturnType) > 1 && LHS_EXPR_IS_EXTERN(lhs_expr)) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_code_reference_index(&self->tokenizer, lhs_expr->var_name.data), + "Extern closure can only have one return value"); + throw(PARSER_ERR); + } throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &result)); func_decl->lhs_expr = lhs_expr; return result; diff --git a/src/program.c b/src/program.c index a73cf72..9ec1b41 100644 --- a/src/program.c +++ b/src/program.c @@ -1,5 +1,6 @@ #include "../include/program.h" #include "../include/std/mem.h" +#include "../include/std/hash.h" #include "../include/std/alloc.h" #include "../include/std/log.h" #include "../include/std/buffer_view.h" @@ -26,7 +27,7 @@ typedef struct { } Number; /*doc(Bytecode) -The layout of the full bytecode is: Header (Intermediates Strings Functions Instructions)* +The layout of the full bytecode is: Header (Intermediates Strings Functions External_Functions Instructions)* */ static CHECK_RESULT int amal_program_append_header(amal_program *self) { @@ -58,13 +59,18 @@ static CHECK_RESULT int amal_program_append_header(amal_program *self) { int amal_program_init(amal_program *self) { ignore_result_int(buffer_init(&self->data, NULL)); self->string_indices = NULL; + self->extern_func_indices = NULL; self->intermediates_start = NULL; self->strings_start = NULL; + self->extern_funcs_start = NULL; self->read_index = 0; self->num_intermediates = 0; self->num_strings = 0; self->num_functions = 0; + self->num_extern_functions = 0; + cleanup_if_error(arena_allocator_init(&self->allocator)); + cleanup_if_error(hash_map_init(&self->extern_funcs_map, &self->allocator, sizeof(ProgramExternFunc), hash_map_compare_string, amal_hash_string)); cleanup_if_error(amal_program_append_header(self)); return 0; @@ -74,9 +80,51 @@ int amal_program_init(amal_program *self) { } void amal_program_deinit(amal_program *self) { - buffer_deinit(&self->data); + arena_allocator_deinit(&self->allocator); + am_free(self->extern_func_indices); am_free(self->string_indices); - self->string_indices = NULL; + if(self->data.data) + buffer_deinit(&self->data); +} + +int amal_program_add_extern_func(amal_program *self, BufferView name, void *func_ptr, int args_byte_size) { + ProgramExternFunc extern_func; + extern_func.func = func_ptr; + extern_func.args_byte_size = args_byte_size; + return hash_map_insert(&self->extern_funcs_map, name, &extern_func); +} + +static CHECK_RESULT int amal_program_get_extern_func_by_index(amal_program *self, u16 index, ProgramExternFunc *result) { + u8 *extern_func_ptr; + u8 num_args; + u8 func_name_len; + BufferView func_name; + + if(index >= self->num_extern_functions) { + result->func = NULL; + result->args_byte_size = 0; + amal_log_error("Extern func index index %ld is out of range (%ld)", index, self->num_extern_functions); + return AMAL_PROGRAM_INSTRUCTION_INVALID_EXTERN_FUNC_INDEX; + } + + extern_func_ptr = self->extern_funcs_start + self->extern_func_indices[index]; + + am_memcpy(&num_args, extern_func_ptr, sizeof(num_args)); + am_memcpy(&func_name_len, extern_func_ptr + sizeof(num_args), sizeof(func_name_len)); + func_name.size = func_name_len; + func_name.data = (const char*)(extern_func_ptr + sizeof(num_args) + sizeof(func_name_len)); + + if(!hash_map_get(&self->extern_funcs_map, func_name, result)) { + amal_log_error("No such extern function: %.*s", func_name.size, func_name.data); + return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION; + } + + /* TODO: This assumes all arguments are of size sizeof(isize) */ + if(result->args_byte_size != -1 && result->args_byte_size != num_args * (int)sizeof(isize)) { + amal_log_error("Extern function %.*s was registered to take %d byte(s), but the program says it takes %d byte(s)", func_name.size, func_name.data, result->args_byte_size, num_args * sizeof(isize)); + return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION; + } + return 0; } int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode) { @@ -119,6 +167,14 @@ static CHECK_RESULT int amal_program_read_header(amal_program *self) { return AMAL_PROGRAM_OK; } +static CHECK_RESULT bool amal_program_read_advance(amal_program *self, void *output, usize bytes_to_read) { + if(bytes_left_to_read(self) < bytes_to_read) + return bool_false; + am_memcpy(output, self->data.data + self->read_index, bytes_to_read); + self->read_index += bytes_to_read; + return bool_true; +} + static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) { u32 intermediates_size; /*u32 read_end;*/ @@ -136,7 +192,7 @@ static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) { return AMAL_PROGRAM_INVALID_INTERMEDIATES_SIZE; } - self->intermediates_start = &self->data.data[self->read_index]; + self->intermediates_start = (u8*)(self->data.data + self->read_index); self->num_intermediates = intermediates_size / (sizeof(u8) + sizeof(u64)); self->read_index += intermediates_size; @@ -144,61 +200,98 @@ static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) { } static CHECK_RESULT int amal_program_read_strings(amal_program *self) { - u16 num_strings; u32 strings_size; - u32 read_start; - u32 read_end; u32 *string_index_ptr; - if(bytes_left_to_read(self) < sizeof(num_strings)) + if(!amal_program_read_advance(self, &self->num_strings, sizeof(u16))) return AMAL_PROGRAM_INVALID_STRINGS; - am_memcpy(&num_strings, &self->data.data[self->read_index], sizeof(num_strings)); - self->read_index += sizeof(num_strings); - self->num_strings = num_strings; - - if(am_malloc(sizeof(u32) * num_strings, (void**)&self->string_indices) != 0) - return AMAL_PROGRAM_STRING_ALLOC_FAILURE; - string_index_ptr = self->string_indices; - - if(bytes_left_to_read(self) < sizeof(strings_size)) + if(!amal_program_read_advance(self, &strings_size, sizeof(strings_size))) return AMAL_PROGRAM_INVALID_STRINGS; - am_memcpy(&strings_size, &self->data.data[self->read_index], sizeof(strings_size)); - self->read_index += sizeof(strings_size); - if(bytes_left_to_read(self) < strings_size) return AMAL_PROGRAM_INVALID_STRINGS_SIZE; - read_start = self->read_index; - read_end = read_start + strings_size; - self->strings_start = &self->data.data[self->read_index]; - while(self->read_index < read_end) { - u16 string_size; + if(am_malloc(sizeof(u32) * self->num_strings, (void**)&self->string_indices) != 0) + return AMAL_PROGRAM_ALLOC_FAILURE; + string_index_ptr = self->string_indices; + + { + const u32 read_start = self->read_index; + const u32 read_end = read_start + strings_size; + self->strings_start = (u8*)(self->data.data + self->read_index); + while(self->read_index < read_end) { + u16 string_size; - if(bytes_left_to_read(self) < sizeof(string_size)) - return AMAL_PROGRAM_INVALID_STRINGS; + if(bytes_left_to_read(self) < sizeof(string_size)) + return AMAL_PROGRAM_INVALID_STRINGS; - *string_index_ptr = self->read_index - read_start; - ++string_index_ptr; - am_memcpy(&string_size, &self->data.data[self->read_index], sizeof(string_size)); - self->read_index += sizeof(string_size); + *string_index_ptr = self->read_index - read_start; + ++string_index_ptr; + am_memcpy(&string_size, &self->data.data[self->read_index], sizeof(string_size)); + self->read_index += sizeof(string_size); - if(bytes_left_to_read(self) < string_size) - return AMAL_PROGRAM_INVALID_STRINGS; + /* +1 to skip null-termination character */ + if(bytes_left_to_read(self) < string_size + 1U) + return AMAL_PROGRAM_INVALID_STRINGS; - self->read_index += string_size + 1; /* +1 to skip null-termination character */ + self->read_index += string_size + 1; /* +1 to skip null-termination character */ + } + assert(self->read_index == read_end); } - assert(self->read_index == read_end); return AMAL_PROGRAM_OK; } static CHECK_RESULT int amal_program_read_functions(amal_program *self) { - if(bytes_left_to_read(self) < sizeof(u16)) + if(!amal_program_read_advance(self, &self->num_functions, sizeof(u16))) return AMAL_PROGRAM_INVALID_FUNCTIONS; - am_memcpy(&self->num_functions, &self->data.data[self->read_index], sizeof(u16)); - self->read_index += sizeof(u16); + return AMAL_PROGRAM_OK; +} + +static CHECK_RESULT int amal_program_read_external_functions(amal_program *self) { + u32 extern_funcs_size; + u32 *extern_func_index_ptr; + + if(!amal_program_read_advance(self, &self->num_extern_functions, sizeof(u16))) + return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS; + + if(!amal_program_read_advance(self, &extern_funcs_size, sizeof(extern_funcs_size))) + return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS; + + if(bytes_left_to_read(self) < extern_funcs_size) + return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS_SIZE; + + if(am_malloc(sizeof(u32) * self->num_extern_functions, (void**)&self->extern_func_indices) != 0) + return AMAL_PROGRAM_ALLOC_FAILURE; + extern_func_index_ptr = self->extern_func_indices; + + { + const u32 read_start = self->read_index; + const u32 read_end = read_start + extern_funcs_size; + self->extern_funcs_start = (u8*)(self->data.data + self->read_index); + while(self->read_index < read_end) { + u8 num_args; + u8 func_name_size; + + if(bytes_left_to_read(self) < sizeof(num_args) + sizeof(func_name_size)) + return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS; + + *extern_func_index_ptr = self->read_index - read_start; + ++extern_func_index_ptr; + num_args = self->data.data[self->read_index]; + func_name_size = self->data.data[self->read_index + sizeof(num_args)]; + self->read_index += sizeof(num_args) + sizeof(func_name_size); + + /* +1 to skip null-termination character */ + if(bytes_left_to_read(self) < func_name_size + 1U) + return AMAL_PROGRAM_INVALID_STRINGS; + + self->read_index += func_name_size + 1; /* +1 to skip null-termination character */ + } + assert(self->read_index == read_end); + } + return AMAL_PROGRAM_OK; } @@ -212,7 +305,7 @@ static CHECK_RESULT int amal_program_get_intermediate_by_index(amal_program *sel } static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 index, BufferView *result) { - char *str_ptr; + u8 *str_ptr; if(index >= self->num_strings) { amal_log_error("Data index %ld is out of range (%ld)", index, self->num_strings); @@ -221,7 +314,7 @@ static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 i str_ptr = self->strings_start + self->string_indices[index]; am_memcpy(&result->size, str_ptr, sizeof(u16)); - result->data = str_ptr + sizeof(u16); + result->data = (const char*)(str_ptr + sizeof(u16)); return 0; } @@ -236,12 +329,9 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ (void)inside_func; func_counter = 0; - if(bytes_left_to_read(self) < sizeof(instructions_size)) + if(!amal_program_read_advance(self, &instructions_size, sizeof(instructions_size))) return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE; - am_memcpy(&instructions_size, &self->data.data[self->read_index], sizeof(instructions_size)); - self->read_index += sizeof(instructions_size); - if(bytes_left_to_read(self) < instructions_size) return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE; @@ -278,7 +368,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ u16 intermediate_index; Number number; - am_memcpy(&intermediate_index, &self->data.data[self->read_index + sizeof(u8)], sizeof(intermediate_index)); + am_memcpy(&intermediate_index, &self->data.data[self->read_index + sizeof(i8)], sizeof(intermediate_index)); return_if_error(amal_program_get_intermediate_by_index(self, intermediate_index, &number)); return_if_error(amal_exec_movi(executor, self->data.data[self->read_index], number.value.integer)); @@ -289,7 +379,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ u16 data_index; BufferView data_ptr; - am_memcpy(&data_index, &self->data.data[self->read_index + sizeof(u8)], sizeof(data_index)); + am_memcpy(&data_index, &self->data.data[self->read_index + sizeof(i8)], sizeof(data_index)); return_if_error(amal_program_get_data_by_index(self, data_index, &data_ptr)); return_if_error(amal_exec_movd(executor, self->data.data[self->read_index], data_ptr)); @@ -355,16 +445,34 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ case AMAL_OP_CALL: { u16 func_index; u8 num_args; + i8 dst_reg; am_memcpy(&func_index, self->data.data + self->read_index, sizeof(func_index)); - am_memcpy(&num_args, self->data.data + self->read_index + sizeof(func_index), sizeof(num_args)); - return_if_error(amal_exec_call(executor, func_index, num_args)); - self->read_index += 3; + num_args = self->data.data[self->read_index + sizeof(func_index)]; + dst_reg = self->data.data[self->read_index + sizeof(func_index) + sizeof(num_args)]; + return_if_error(amal_exec_call(executor, func_index, num_args, dst_reg)); + self->read_index += 4; break; } case AMAL_OP_CALLR: assert(bool_false && "TODO: Implement CALLR"); self->read_index += 2; break; + case AMAL_OP_CALLE: { + u16 extern_func_index; + u8 num_args; + i8 dst_reg; + am_memcpy(&extern_func_index, self->data.data + self->read_index, sizeof(extern_func_index)); + num_args = self->data.data[self->read_index + sizeof(extern_func_index)]; + dst_reg = self->data.data[self->read_index + sizeof(extern_func_index) + sizeof(num_args)]; + + { + ProgramExternFunc extern_func; + return_if_error(amal_program_get_extern_func_by_index(self, extern_func_index, &extern_func)); + return_if_error(amal_exec_calle(executor, extern_func.func, num_args, dst_reg)); + } + self->read_index += 4; + break; + } case AMAL_OP_CMP: { return_if_error(amal_exec_cmp(executor, self->data.data[self->read_index], self->data.data[self->read_index + 1], self->data.data[self->read_index + 2])); self->read_index += 3; @@ -372,7 +480,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ } case AMAL_OP_JZ: { i16 jump_offset; - am_memcpy(&jump_offset, &self->data.data[self->read_index + sizeof(u8)], sizeof(jump_offset)); + am_memcpy(&jump_offset, &self->data.data[self->read_index + sizeof(i8)], sizeof(jump_offset)); return_if_error(amal_exec_jz(executor, self->data.data[self->read_index], jump_offset)); self->read_index += 3; break; @@ -385,21 +493,25 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ break; } case AMAL_OP_RET: { - const u8 reg = self->data.data[self->read_index]; + const i8 reg = self->data.data[self->read_index]; return_if_error(amal_exec_ret(executor, reg)); self->read_index += 1; break; } case AMAL_OP_FUNC_START: { - u16 func_num_registers; + u8 func_num_param_regs; + u16 func_num_local_var_regs; + assert(!inside_func); inside_func = bool_true; assert(func_counter < self->num_functions); ++func_counter; - am_memcpy(&func_num_registers, &self->data.data[self->read_index], sizeof(func_num_registers)); - return_if_error(amal_exec_func_start(executor, func_num_registers)); - self->read_index += 2; + func_num_param_regs = self->data.data[self->read_index]; + (void)func_num_param_regs; + am_memcpy(&func_num_local_var_regs, self->data.data + self->read_index + sizeof(func_num_param_regs), sizeof(func_num_local_var_regs)); + return_if_error(amal_exec_func_start(executor, func_num_local_var_regs)); + self->read_index += 3; break; } case AMAL_OP_FUNC_END: { @@ -420,7 +532,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ int amal_program_run(amal_program *self) { int result; amal_executor *executor; - result = 0; + result = AMAL_PROGRAM_ERR; return_if_error(amal_executor_init(&executor)); cleanup_if_error(amal_program_read_header(self)); @@ -428,6 +540,7 @@ int amal_program_run(amal_program *self) { cleanup_if_error(amal_program_read_intermediates(self)); cleanup_if_error(amal_program_read_strings(self)); cleanup_if_error(amal_program_read_functions(self)); + cleanup_if_error(amal_program_read_external_functions(self)); cleanup_if_error(amal_program_read_instructions(self, executor)); } result = amal_executor_run(executor); 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*), ®)); } diff --git a/src/std/arena_allocator.c b/src/std/arena_allocator.c index 73111dd..4934925 100644 --- a/src/std/arena_allocator.c +++ b/src/std/arena_allocator.c @@ -25,9 +25,10 @@ void arena_allocator_node_deinit(ArenaAllocatorNode *self) { } int arena_allocator_init(ArenaAllocator *self) { + ignore_result_int(buffer_init(&self->mems, NULL)); return_if_error(arena_allocator_node_init(&self->head)); self->current = &self->head; - return buffer_init(&self->mems, NULL); + return 0; } static void arena_allocator_deinit_buffers(ArenaAllocator *self) { diff --git a/src/std/hash_map.c b/src/std/hash_map.c index c2e42c1..2b29f2e 100644 --- a/src/std/hash_map.c +++ b/src/std/hash_map.c @@ -74,14 +74,14 @@ static void* bucket_node_get_value(HashMapBucketNode *self) { } int hash_map_init(HashMap *self, ArenaAllocator *allocator, usize value_type_size, - HashMapCompare compare_func, HashMapHash hash_func) { - assert(compare_func); - assert(hash_func); + HashMapCompare key_compare_func, HashMapHash key_hash_func) { + assert(key_compare_func); + assert(key_hash_func); self->allocator = allocator; self->value_type_size = value_type_size; self->num_elements = 0; - self->compare_func = compare_func; - self->hash_func = hash_func; + self->compare_func = key_compare_func; + self->hash_func = key_hash_func; return_if_error(buffer_init(&self->buckets, self->allocator)); assert(self->buckets.size == 0); return_if_error(buffer_append_empty(&self->buckets, sizeof(HashMapBucket) * HASH_MAP_INITIAL_SIZE)); diff --git a/src/tokenizer.c b/src/tokenizer.c index 1586691..556a20b 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -91,6 +91,7 @@ static CHECK_RESULT int find_end_of_string(BufferView buf, int index) { } /* TODO: Optimize string to integer and string to float */ +/* TODO: Correctly check multiplication overflow */ #define I64_OVERFLOW_ERROR -1 static CHECK_RESULT int string_to_integer_unchecked(BufferView str, i64 *result) { |