aboutsummaryrefslogtreecommitdiff
path: root/src/ssa
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssa')
-rw-r--r--src/ssa/ssa.c239
1 files changed, 161 insertions, 78 deletions
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index f3679aa..0aabc15 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -243,7 +243,7 @@ static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) {
return 0;
}
-static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
+static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, u8 num_args, SsaRegister *result) {
usize index;
index = self->instructions.size;
@@ -251,12 +251,13 @@ static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegi
if(self->reg_counter + 1 < self->reg_counter)
return -1;
- return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(func_decl)));
+ 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;
- am_memcpy(self->instructions.data + index + 1, result, sizeof(SsaRegister));
- am_memcpy(self->instructions.data + index + 1 + sizeof(SsaRegister), &func_decl, sizeof(func_decl));
- amal_log_debug("r%u = CALL %p", *result, func_decl);
+ 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);
return 0;
}
@@ -286,6 +287,16 @@ static CHECK_RESULT int ssa_ins_jump(Ssa *self, JumpOffset jump_offset) {
return 0;
}
+static CHECK_RESULT int ssa_ins_return(Ssa *self, SsaRegister reg) {
+ usize index;
+ 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));
+ return 0;
+}
+
static usize ssa_ins_get_index(Ssa *self) {
return self->instructions.size;
}
@@ -311,6 +322,28 @@ static CHECK_RESULT int ssa_ins_jump_set_target(Ssa *self, usize jump_ins_index)
}
static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context);
+static CHECK_RESULT SsaRegister scope_named_object_generate_ssa(ScopeNamedObject *self, SsaCompilerContext *context);
+
+static bool ast_resolved_type_is_decl(AstResolvedType *self) {
+ /* TODO: Add more types as they are introduced */
+ LhsExpr *lhs_expr;
+ if(self->type != RESOLVED_TYPE_LHS_EXPR)
+ return bool_false;
+
+ lhs_expr = self->value.lhs_expr;
+ switch(lhs_expr->type.type) {
+ case VARIABLE_TYPE_NONE:
+ break;
+ case VARIABLE_TYPE_VARIABLE:
+ return bool_false;
+ case VARIABLE_TYPE_SIGNATURE:
+ /* TODO: This should return bool_false when it's possible to use signature in expressions */
+ return bool_true;
+ }
+
+ assert(lhs_expr->rhs_expr);
+ return lhs_expr->rhs_expr->type == AST_FUNCTION_DECL || lhs_expr->rhs_expr->type == AST_STRUCT_DECL;
+}
static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerContext *context) {
SsaRegister reg;
@@ -332,27 +365,23 @@ static CHECK_RESULT SsaRegister lhsexpr_extern_generate_ssa(LhsExpr *self, SsaCo
return 0;
}
-static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerContext *context) {
- LhsExpr *lhs_expr;
+static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(LhsExpr *self, AstResolveData *resolve_data, SsaCompilerContext *context) {
SsaRegister reg;
- assert(self->type == AST_LHS);
- lhs_expr = self->value.lhs_expr;
-
- if(LHS_EXPR_IS_EXTERN(lhs_expr))
- return lhsexpr_extern_generate_ssa(lhs_expr, context);
+ if(LHS_EXPR_IS_EXTERN(self))
+ return lhsexpr_extern_generate_ssa(self, context);
- if(lhs_expr->rhs_expr) {
- Ast *rhs_expr = lhs_expr->rhs_expr;
+ if(self->rhs_expr) {
+ Ast *rhs_expr = self->rhs_expr;
SsaRegister rhs_reg;
rhs_reg = ast_generate_ssa(rhs_expr, context);
/*
- Declarations (struct and function declaration) resolves to itself and in that case this expression
- is just a compile-time name for the declaration.
- Import expression also has no meaning in SSA until it's used.
- TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types?
+ Declarations (struct and function declaration) resolves to itself and in that case this expression
+ is just a compile-time name for the declaration.
+ Import expression also has no meaning in SSA until it's used.
+ TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types?
*/
- if(self->resolve_data.type == lhs_expr || rhs_expr->type == AST_IMPORT) {
+ if(ast_resolved_type_is_decl(&resolve_data->type) || rhs_expr->type == AST_IMPORT) {
/*assert(bool_false);*/
return 0;
}
@@ -364,32 +393,55 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg));
} else {
/* TODO: Do not assign if we dont want default value */
- SsaNumber number;
- if(self->resolve_data.type == (LhsExpr*)context->compiler->default_types.i64)
- number = create_ssa_integer(0);
- else if(self->resolve_data.type == (LhsExpr*)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));
+ if(resolve_data->type.type == RESOLVED_TYPE_LHS_EXPR) {
+ SsaNumber number;
+ if(resolve_data->type.value.lhs_expr == (LhsExpr*)context->compiler->default_types.i64)
+ number = create_ssa_integer(0);
+ else if(resolve_data->type.value.lhs_expr == (LhsExpr*)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));
+ } else if(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG) {
+ assert(bool_false && "TODO: Implement this when variable can be null. Then the function pointer should be null");
+ } else {
+ assert(bool_false);
+ }
}
return reg;
}
-static CHECK_RESULT SsaRegister assignmentexpr_generate_ssa(Ast *ast, SsaCompilerContext *context) {
- AssignmentExpr *self;
+static CHECK_RESULT SsaRegister assignmentexpr_generate_ssa(AssignmentExpr *self, SsaCompilerContext *context) {
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;
}
+static CHECK_RESULT SsaRegister function_parameter_generate_ssa(FunctionParameter *self, SsaCompilerContext *context) {
+ SsaRegister reg;
+ if(self->resolve_data.status == AST_SSA_RESOLVED)
+ return self->resolve_data.ssa_reg;
+
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ self->resolve_data.ssa_reg = reg;
+ return reg;
+}
+
+static CHECK_RESULT void function_signature_generate_params_ssa(FunctionSignature *self, SsaCompilerContext *context) {
+ FunctionParameter *param, *param_end;
+ param = buffer_begin(&self->parameters);
+ param_end = buffer_end(&self->parameters);
+ for(; param != param_end; ++param) {
+ SsaRegister reg;
+ reg = function_parameter_generate_ssa(param, context);
+ (void)reg;
+ }
+}
+
/*
TODO: Each function declaration should be in separate SSA instances so ast can be converted into ssa
in any order.
@@ -402,49 +454,54 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
*/
SsaRegister prev_reg_counter;
usize func_metadata_index;
+ int num_params;
prev_reg_counter = context->ssa->reg_counter;
context->ssa->reg_counter = 0;
+ /*
+ Parameters need to have generated ssa so the first ssa registers belong to the function.
+ 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);
+
amal_log_debug("SSA funcdecl %p", self);
throw_if_error(ssa_ins_func_start(context->ssa, &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));
context->ssa->reg_counter = prev_reg_counter;
return 0;
}
-static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerContext *context) {
- /* TODO: Implement */
- FunctionCall *func_call;
+static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstResolveData *resolve_data, SsaCompilerContext *context) {
Ast **ast;
Ast **ast_end;
SsaRegister reg;
+ FunctionDecl *func_decl;
- assert(self->type == AST_FUNCTION_CALL);
- func_call = self->value.func_call;
- ast = buffer_begin(&func_call->args);
- ast_end = buffer_end(&func_call->args);
+ 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));
}
- assert((self->resolve_data.type->rhs_expr && self->resolve_data.type->rhs_expr->type == AST_FUNCTION_DECL) ||
- self->resolve_data.type->type.type == VARIABLE_TYPE_SIGNATURE);
- if(LHS_EXPR_IS_EXTERN(self->resolve_data.type)) {
- amal_log_error("TODO: Implement extern function call (extern function %.*s was called)", func_call->func.name.size, func_call->func.name.data);
+ 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!");
} else {
- FunctionDecl *func_to_call;
/* rhs wont be null here because only extern variable can't have rhs */
- func_to_call = self->resolve_data.type->rhs_expr->value.func_decl;
- amal_log_debug("SSA funccall %.*s, func index ptr: %p", func_call->func.name.size, func_call->func.name.data, func_to_call);
- throw_if_error(ssa_ins_call(context->ssa, func_to_call, &reg));
+ 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));
}
return reg;
@@ -475,8 +532,8 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon
static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) {
/* 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);
+ assert(self->resolved_var.type != NAMED_OBJECT_NONE);
+ return scope_named_object_generate_ssa(&self->resolved_var, context);
}
static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_type *type) {
@@ -511,7 +568,8 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
} else {
const SsaRegister lhs_reg = ast_generate_ssa(self->lhs, context);
const SsaRegister rhs_reg = ast_generate_ssa(self->rhs, context);
- throw_if_error(ssa_ins_binop(context->ssa, binop_type_to_ssa_type(self->type, (amal_default_type*)self->lhs->resolve_data.type), lhs_reg, rhs_reg, &reg));
+ assert(self->lhs->resolve_data.type.type == RESOLVED_TYPE_LHS_EXPR && "TODO: Implement binop_generate_ssa for function signature");
+ throw_if_error(ssa_ins_binop(context->ssa, binop_type_to_ssa_type(self->type, (amal_default_type*)self->lhs->resolve_data.type.value.lhs_expr), lhs_reg, rhs_reg, &reg));
}
return reg;
}
@@ -567,63 +625,88 @@ static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompiler
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) {
- amal_log_error("Ast type not resolved: %d", self->type);
- assert(bool_false);
- }
- #endif
+static void return_expr_generate_ssa(ReturnExpr *self, SsaCompilerContext *context) {
+ const SsaRegister reg = ast_generate_ssa(self->rhs_expr, context);
+ throw_if_error(ssa_ins_return(context->ssa, reg));
+}
- if(self->resolve_data.status == AST_SSA_RESOLVED)
- return self->ssa_reg;
+static CHECK_RESULT SsaRegister ast_generate_ssa_resolve_data(void *ast_data, AstType ast_type, AstResolveData *resolve_data, SsaCompilerContext *context) {
+ if(resolve_data->status == AST_SSA_RESOLVED)
+ return resolve_data->ssa_reg;
- switch(self->type) {
+ switch(ast_type) {
case AST_NUMBER:
- self->ssa_reg = number_generate_ssa(self->value.number, context);
+ resolve_data->ssa_reg = number_generate_ssa(ast_data, context);
break;
case AST_FUNCTION_DECL:
- self->ssa_reg = funcdecl_generate_ssa(self->value.func_decl, context);
+ resolve_data->ssa_reg = funcdecl_generate_ssa(ast_data, context);
break;
case AST_FUNCTION_CALL:
- self->ssa_reg = funccall_generate_ssa(self, context);
+ resolve_data->ssa_reg = funccall_generate_ssa(ast_data, resolve_data, context);
break;
case AST_STRUCT_DECL:
- self->ssa_reg = structdecl_generate_ssa(self->value.struct_decl, context);
+ resolve_data->ssa_reg = structdecl_generate_ssa(ast_data, context);
break;
case AST_STRUCT_FIELD:
- self->ssa_reg = structfield_generate_ssa(self->value.struct_field, context);
+ resolve_data->ssa_reg = structfield_generate_ssa(ast_data, context);
break;
case AST_LHS:
- self->ssa_reg = lhsexpr_generate_ssa(self, context);
+ resolve_data->ssa_reg = lhsexpr_generate_ssa(ast_data, resolve_data, context);
break;
case AST_ASSIGN:
- self->ssa_reg = assignmentexpr_generate_ssa(self, context);
+ resolve_data->ssa_reg = assignmentexpr_generate_ssa(ast_data, context);
break;
case AST_IMPORT:
/* TODO: Implement cross file references */
- self->ssa_reg = 0;
+ resolve_data->ssa_reg = 0;
break;
case AST_STRING:
- self->ssa_reg = string_generate_ssa(self->value.string, context);
+ resolve_data->ssa_reg = string_generate_ssa(ast_data, context);
break;
case AST_VARIABLE:
- self->ssa_reg = variable_generate_ssa(self->value.variable, context);
+ resolve_data->ssa_reg = variable_generate_ssa(ast_data, context);
break;
case AST_BINOP:
- self->ssa_reg = binop_generate_ssa(self->value.binop, context);
+ resolve_data->ssa_reg = binop_generate_ssa(ast_data, context);
break;
case AST_IF_STATEMENT:
- if_statement_generate_ssa(self->value.if_stmt, context);
+ if_statement_generate_ssa(ast_data, context);
break;
case AST_WHILE_STATEMENT:
- while_statement_generate_ssa(self->value.while_stmt, context);
+ while_statement_generate_ssa(ast_data, context);
+ break;
+ case AST_RETURN:
+ return_expr_generate_ssa(ast_data, context);
+ resolve_data->ssa_reg = 0;
break;
}
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ resolve_data->status = AST_SSA_RESOLVED;
+ return resolve_data->ssa_reg;
+}
+
+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) {
+ amal_log_error("Ast type not resolved: %d", self->type);
+ assert(bool_false);
+ }
+ #endif
+ return ast_generate_ssa_resolve_data(self->value.data, self->type, &self->resolve_data, context);
+}
+
+CHECK_RESULT SsaRegister scope_named_object_generate_ssa(ScopeNamedObject *self, SsaCompilerContext *context) {
+ switch(self->type) {
+ case NAMED_OBJECT_NONE:
+ assert(bool_false);
+ return 0;
+ case NAMED_OBJECT_LHS_EXPR:
+ return ast_generate_ssa_resolve_data(self->value.lhs_expr, AST_LHS, self->resolve_data, context);
+ case NAMED_OBJECT_FUNC_PARAM:
+ return function_parameter_generate_ssa(self->value.func_param, context);
+ }
+ return 0;
}
void scope_generate_ssa(Scope *self, SsaCompilerContext *context) {