aboutsummaryrefslogtreecommitdiff
path: root/src/ssa/ssa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssa/ssa.c')
-rw-r--r--src/ssa/ssa.c262
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, &reg, 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, &reg, 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, &reg));
- 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, &reg));
+ /* 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*), &reg));
} 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*), &reg));
}