aboutsummaryrefslogtreecommitdiff
path: root/src/ssa
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssa')
-rw-r--r--src/ssa/ssa.c233
1 files changed, 185 insertions, 48 deletions
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index c4ed0d3..91ba185 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -4,6 +4,7 @@
#include "../../include/std/hash.h"
#include "../../include/std/thread.h"
#include "../../include/ast.h"
+#include "../../include/compiler.h"
#include <assert.h>
#define throw(result) do { longjmp(context->env, (result)); } while(0)
@@ -59,7 +60,7 @@ int ssa_init(Ssa *self, ScopedAllocator *allocator) {
return 0;
}
-int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
+static CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
/* Overflow */
if(self->reg_counter + 1 < self->reg_counter)
return -1;
@@ -144,12 +145,13 @@ static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstruction ins_type, Ss
}
static const char* binop_type_to_string(SsaInstruction binop_type) {
- assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
+ assert(binop_type >= SSA_ADD && binop_type <= SSA_EQUALS);
switch(binop_type) {
case SSA_ADD: return "+";
case SSA_SUB: return "-";
case SSA_MUL: return "*";
case SSA_DIV: return "/";
+ case SSA_EQUALS: return "==";
default: return "";
}
}
@@ -173,31 +175,31 @@ static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstruction ins_type, Ss
return 0;
}
-int ssa_ins_assign_inter(Ssa *self, SsaRegister dest, SsaNumber number) {
+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);
return ssa_add_ins_form1(self, SSA_ASSIGN_INTER, dest, index);
}
-int ssa_ins_assign_string(Ssa *self, SsaRegister dest, BufferView str) {
+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);
return ssa_add_ins_form1(self, SSA_ASSIGN_STRING, dest, index);
}
-int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) {
+static CHECK_RESULT int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) {
amal_log_debug("r%u = r%u", dest, src);
return ssa_add_ins_form1(self, SSA_ASSIGN_REG, dest, src);
}
-int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
- assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
+static CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
+ assert(binop_type >= SSA_ADD && binop_type <= SSA_EQUALS);
return ssa_add_ins_form2(self, binop_type, lhs, rhs, result);
}
-int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
+static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
usize index;
index = self->instructions.size;
@@ -214,14 +216,14 @@ int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
return 0;
}
-int ssa_ins_func_end(Ssa *self) {
+static CHECK_RESULT int ssa_ins_func_end(Ssa *self) {
u8 ins;
ins = SSA_FUNC_END;
amal_log_debug("FUNC_END");
return buffer_append(&self->instructions, &ins, 1);
}
-int ssa_ins_push(Ssa *self, SsaRegister reg) {
+static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) {
usize index;
index = self->instructions.size;
@@ -232,7 +234,7 @@ int ssa_ins_push(Ssa *self, SsaRegister reg) {
return 0;
}
-int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
+static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
usize index;
index = self->instructions.size;
@@ -249,31 +251,88 @@ int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
return 0;
}
+static CHECK_RESULT int ssa_ins_jumpzero(Ssa *self, SsaRegister condition_reg, JumpOffset jump_offset) {
+ usize index;
+ 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);
+ else
+ amal_log_debug("JUMP_ZERO r%u, %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;
+
+ 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));
+ amal_log_debug("JUMP %d", jump_offset);
+ return 0;
+}
+
+static usize ssa_ins_get_index(Ssa *self) {
+ return self->instructions.size;
+}
+
+/* Set target of jump instruction to current location */
+static CHECK_RESULT int ssa_ins_jump_set_target(Ssa *self, usize jump_ins_index) {
+ switch(self->instructions.data[jump_ins_index]) {
+ case SSA_JUMP_ZERO: {
+ isize jump_offset = (isize)ssa_ins_get_index(self) - (isize)jump_ins_index;
+ /* TODO: Should something be done about this? */
+ if(jump_offset < -0x7FFF || jump_offset > 0x7FFF) {
+ amal_log_error("Unexpected error. Jump offset has to be less than +-32767, was %d", jump_offset);
+ return 1;
+ }
+ am_memcpy(self->instructions.data + jump_ins_index + 1 + sizeof(SsaRegister), &jump_offset, sizeof(JumpOffset));
+ break;
+ }
+ default:
+ assert(bool_false && "Unexpected error... jump_ins_index doesn't point to a valid index to a jump instruction");
+ break;
+ }
+ return 0;
+}
+
static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context);
static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerContext *context) {
SsaRegister reg;
SsaNumber number;
- if(self->is_integer) {
+ if(self->is_integer)
number = create_ssa_integer(self->value.integer);
- throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
- throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
- } else {
+ else
number = create_ssa_float(self->value.floating);
- throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
- throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
- }
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
return reg;
}
+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");
+ return 0;
+}
+
static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerContext *context) {
- /* TODO: Implement */
LhsExpr *lhs_expr;
SsaRegister reg;
assert(self->type == AST_LHS);
lhs_expr = self->value.lhs_expr;
+ if(lhs_expr->is_extern)
+ return lhsexpr_extern_generate_ssa(lhs_expr, context);
+
if(lhs_expr->rhs_expr) {
SsaRegister rhs_reg;
rhs_reg = ast_generate_ssa(lhs_expr->rhs_expr, context);
@@ -283,8 +342,10 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
Import expression also has no meaning in SSA until it's used.
TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types?
*/
- if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT)
+ if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT) {
+ /*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", lhs_expr->rhs_expr->type);
@@ -292,12 +353,33 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
assert(reg != rhs_reg);
throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg));
} else {
- /* TODO: assign default value to reg depending on LhsExpr type */
- reg = 0;
+ /* TODO: Do not assign if we dont want default value */
+ SsaNumber number;
+ if(self->resolve_data.type == context->compiler->default_types.i64)
+ number = create_ssa_integer(0);
+ else if(self->resolve_data.type == context->compiler->default_types.f64)
+ number = create_ssa_float(0.0);
+ else
+ assert(bool_false && "TODO: assign default value to reg depending on LhsExpr type");
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
}
return reg;
}
+static CHECK_RESULT SsaRegister assignmentexpr_generate_ssa(Ast *ast, SsaCompilerContext *context) {
+ AssignmentExpr *self;
+ SsaRegister lhs_reg, rhs_reg;
+
+ assert(ast->type == AST_ASSIGN);
+ self = ast->value.assign_expr;
+
+ lhs_reg = ast_generate_ssa(self->lhs_expr, context);
+ rhs_reg = ast_generate_ssa(self->rhs_expr, context);
+ throw_if_error(ssa_ins_assign_reg(context->ssa, lhs_reg, rhs_reg));
+ return lhs_reg;
+}
+
/*
TODO: Each function declaration should be in separate SSA instances so ast can be converted into ssa
in any order.
@@ -314,6 +396,7 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
throw_if_error(ssa_ins_func_end(context->ssa));
context->ssa->reg_counter = prev_reg_counter;
+ /*assert(bool_false);*/
return 0;
}
@@ -348,12 +431,14 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
static CHECK_RESULT SsaRegister structdecl_generate_ssa(StructDecl *self, SsaCompilerContext *context) {
/* TODO: Implement */
+ /*assert(bool_false);*/
scope_generate_ssa(&self->body, context);
return 0;
}
static CHECK_RESULT SsaRegister structfield_generate_ssa(StructField *self, SsaCompilerContext *context) {
/* TODO: Implement */
+ /*assert(bool_false);*/
(void)self;
(void)context;
return 0;
@@ -367,10 +452,10 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon
}
static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) {
- /* TODO: Implement, and with cross field references */
- (void)self;
- (void)context;
- return 0;
+ /* TODO: If resolved_var refers to a variable in another file, use a cross file reference that requires no locking (not yet implemented) */
+ /* This is not thread-safe:*/
+ assert(self->resolved_var);
+ return ast_generate_ssa(self->resolved_var, context);
}
static SsaInstruction binop_type_to_ssa_type(BinopType binop_type) {
@@ -386,6 +471,8 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type) {
case BINOP_DOT:
assert(bool_false && "Binop dot not valid for arithmetic operation and requires special functionality");
return 0;
+ case BINOP_EQUALS:
+ return SSA_EQUALS;
}
return 0;
}
@@ -405,7 +492,57 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
return reg;
}
-CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) {
+static void else_if_statement_generate_ssa(ElseIfStatement *else_if_stmt, SsaCompilerContext *context) {
+ usize jump_ins_index;
+ if(else_if_stmt->condition) {
+ SsaRegister condition_reg;
+ condition_reg = ast_generate_ssa(else_if_stmt->condition, context);
+ jump_ins_index = ssa_ins_get_index(context->ssa);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ }
+ scope_generate_ssa(&else_if_stmt->body, context);
+ if(else_if_stmt->condition)
+ throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_ins_index));
+ if(else_if_stmt->next_else_if_stmt)
+ else_if_statement_generate_ssa(else_if_stmt->next_else_if_stmt, context);
+}
+
+static void if_statement_generate_ssa(IfStatement *if_stmt, SsaCompilerContext *context) {
+ SsaRegister condition_reg;
+ usize jump_ins_index;
+
+ condition_reg = ast_generate_ssa(if_stmt->condition, context);
+ jump_ins_index = ssa_ins_get_index(context->ssa);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ scope_generate_ssa(&if_stmt->body, context);
+ throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_ins_index));
+ if(if_stmt->else_if_stmt)
+ else_if_statement_generate_ssa(if_stmt->else_if_stmt, context);
+}
+
+static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompilerContext *context) {
+ SsaRegister condition_reg;
+ usize jump_back_ins_index;
+ usize jump_condition_ins_index;
+ isize jump_offset;
+
+ jump_back_ins_index = ssa_ins_get_index(context->ssa);
+ condition_reg = ast_generate_ssa(while_stmt->condition, context);
+ jump_condition_ins_index = ssa_ins_get_index(context->ssa);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ scope_generate_ssa(&while_stmt->body, context);
+ /* Jump back and check condition again before running the content of the loop again */
+ jump_offset = (isize)jump_back_ins_index - (isize)ssa_ins_get_index(context->ssa);
+ /* TODO: Should something be done about this? */
+ if(jump_offset < -0x7FFF || jump_offset > 0x7FFF) {
+ amal_log_error("Unexpected error. Jump offset has to be less than +-32767, was %d", jump_offset);
+ throw(1);
+ }
+ throw_if_error(ssa_ins_jump(context->ssa, (JumpOffset)jump_offset));
+ throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_condition_ins_index));
+}
+
+static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) {
assert(self);
#ifdef DEBUG
if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_SSA_RESOLVED) {
@@ -420,48 +557,48 @@ CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context
switch(self->type) {
case AST_NUMBER:
self->ssa_reg = number_generate_ssa(self->value.number, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_FUNCTION_DECL:
self->ssa_reg = funcdecl_generate_ssa(self->value.func_decl, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_FUNCTION_CALL:
self->ssa_reg = funccall_generate_ssa(self, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_STRUCT_DECL:
self->ssa_reg = structdecl_generate_ssa(self->value.struct_decl, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_STRUCT_FIELD:
self->ssa_reg = structfield_generate_ssa(self->value.struct_field, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_LHS:
self->ssa_reg = lhsexpr_generate_ssa(self, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
+ case AST_ASSIGN:
+ self->ssa_reg = assignmentexpr_generate_ssa(self, context);
+ break;
case AST_IMPORT:
/* TODO: Implement cross file references */
self->ssa_reg = 0;
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_STRING:
self->ssa_reg = string_generate_ssa(self->value.string, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_VARIABLE:
self->ssa_reg = variable_generate_ssa(self->value.variable, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_BINOP:
self->ssa_reg = binop_generate_ssa(self->value.binop, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
+ case AST_IF_STATEMENT:
+ if_statement_generate_ssa(self->value.if_stmt, context);
+ break;
+ case AST_WHILE_STATEMENT:
+ while_statement_generate_ssa(self->value.while_stmt, context);
+ break;
}
- return 0;
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
}
void scope_generate_ssa(Scope *self, SsaCompilerContext *context) {