aboutsummaryrefslogtreecommitdiff
path: root/src/ir/ir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/ir.c')
-rw-r--r--src/ir/ir.c214
1 files changed, 146 insertions, 68 deletions
diff --git a/src/ir/ir.c b/src/ir/ir.c
index 62d3516..1ca154a 100644
--- a/src/ir/ir.c
+++ b/src/ir/ir.c
@@ -294,34 +294,44 @@ static CHECK_RESULT int ir_ins_assign_reg(Ir *self, IrRegister dest, IrRegister
return ir_add_ins_form1(self, IR_ASSIGN_REG, dest, src);
}
+static CHECK_RESULT int ir_ins_assign_func(Ir *self, IrRegister dest, IrFuncIndex func_index) {
+ amal_log_debug("r%d = f%d", dest, func_index);
+ return ir_add_ins_form1(self, IR_ASSIGN_FUNC, dest, func_index);
+}
+
static CHECK_RESULT int ir_ins_binop(Ir *self, IrInstruction binop_type, IrRegister lhs, IrRegister rhs, IrRegister *result) {
assert(binop_type >= IR_ADD && binop_type <= IR_GE);
return ir_add_ins_form2(self, binop_type, lhs, rhs, result);
}
-static CHECK_RESULT int ir_ins_func_start(Ir *self, u8 func_flags, FunctionSignature *func_sig, IrFuncIndex *result, usize *func_metadata_index) {
+static CHECK_RESULT int ir_ins_func_start(Ir *self, u8 func_flags, FunctionSignature *func_sig, usize *func_metadata_index) {
const u8 ins_type = IR_FUNC_START;
IrInsFuncStart ins_func_start;
+ IrFunc func;
- /* Overflow */
- if(self->func_counter + 1 <= self->func_counter) {
- amal_log_error("Ir too many closures!");
- return -1;
- }
+ func.func_sig = func_sig;
+ return_if_error(buffer_append(&self->funcs, &func, sizeof(func)));
- *result = self->func_counter++;
- {
- IrFunc func;
- func.func_sig = func_sig;
- return_if_error(buffer_append(&self->funcs, &func, sizeof(func)));
- }
ins_func_start.flags = func_flags;
/* Dont set number of local registers yet. That will be set by @func_metadata_index later when it's known */
/*ins_func_start.num_local_vars_regs = ---*/
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return_if_error(buffer_append(&self->instructions, &ins_func_start, sizeof(ins_func_start)));
*func_metadata_index = self->instructions.size - sizeof(ins_func_start.num_local_vars_regs);
- amal_log_debug("FUNC_START f%u(%d) %d", *result, buffer_get_size(&func_sig->parameters, FunctionParameter), buffer_get_size(&func_sig->return_types, FunctionReturnType));
+ amal_log_debug("FUNC_START f%d(%d) %d",
+ func_sig->func_decl ? func_sig->func_decl->ir_func_index : -1,
+ buffer_get_size(&func_sig->parameters, FunctionParameter),
+ buffer_get_size(&func_sig->return_types, FunctionReturnType));
+ return 0;
+}
+
+static CHECK_RESULT int ir_inc_func_index(Ir *self, IrFuncIndex *result) {
+ /* Overflow */
+ if(self->func_counter + 1 <= self->func_counter) {
+ amal_log_error("Ir too many closures!");
+ return -1;
+ }
+ *result = self->func_counter++;
return 0;
}
@@ -373,6 +383,13 @@ static CHECK_RESULT int ir_ins_call_extern(Ir *self, int import_index, LhsExpr *
return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern));
}
+static CHECK_RESULT int ir_ins_call_reg(Ir *self, IrRegister reg) {
+ const u8 ins_type = IR_CALLR;
+ amal_log_debug("CALLR r%d", reg);
+ return_if_error(buffer_append(&self->instructions, &ins_type, 1));
+ return buffer_append(&self->instructions, &reg, sizeof(reg));
+}
+
static CHECK_RESULT int ir_ins_jumpzero(Ir *self, IrRegister condition_reg, IrLabelIndex target_label, usize *instruction_offset) {
const u8 ins_type = IR_JUMP_ZERO;
IrInsJumpZero ins_jump_zero;
@@ -466,23 +483,6 @@ static bool ast_resolved_type_is_decl(AstResolvedType *self) {
return lhs_expr->rhs_expr->type == AST_FUNCTION_DECL || lhs_expr->rhs_expr->type == AST_STRUCT_DECL;
}
#endif
-static bool lhs_expr_is_decl(LhsExpr *self) {
- if(self->rhs_expr) {
- return self->rhs_expr->type == AST_FUNCTION_DECL || self->rhs_expr->type == AST_STRUCT_DECL;
- } else {
- switch(self->type.type) {
- case VARIABLE_TYPE_NONE:
- assert(bool_false);
- return 0;
- 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;
- }
- return 0;
- }
-}
static CHECK_RESULT IrRegister number_generate_ir(Number *self, IrCompilerContext *context) {
IrRegister reg;
@@ -501,6 +501,17 @@ static CHECK_RESULT IrRegister number_generate_ir(Number *self, IrCompilerContex
return reg;
}
+static CHECK_RESULT IrRegister ast_bool_generate_ir(AstBool *self, IrCompilerContext *context) {
+ IrRegister reg;
+ IrNumber number;
+ number.type = IR_NUMBER_TYPE_INTEGER;
+ number.value.integer = self->value;
+ throw_if_error(ir_get_unique_reg(context->ir, &reg));
+ /* TODO: Maybe bool shouldn't be a regular number? */
+ throw_if_error(ir_ins_assign_inter(context->ir, reg, number));
+ return reg;
+}
+
static CHECK_RESULT IrRegister lhsexpr_extern_generate_ir(LhsExpr *self, IrCompilerContext *context) {
/* TODO: IrRegister should be extended to include static and extern data */
if(self->type.type == VARIABLE_TYPE_SIGNATURE) {
@@ -534,6 +545,7 @@ static CHECK_RESULT IrRegister lhsexpr_extern_generate_ir(LhsExpr *self, IrCompi
return 0;
}
+#if 0
static CHECK_RESULT IrRegister lhsexpr_export_generate_ir(LhsExpr *self, IrCompilerContext *context) {
/* TODO: IrRegister should be extended to include static and export data */
if(self->rhs_expr->type == AST_FUNCTION_DECL) {
@@ -543,6 +555,7 @@ static CHECK_RESULT IrRegister lhsexpr_export_generate_ir(LhsExpr *self, IrCompi
}
return 0;
}
+#endif
static CHECK_RESULT IrRegister lhsexpr_generate_ir(LhsExpr *self, AstResolveData *resolve_data, IrCompilerContext *context) {
IrRegister reg;
@@ -552,19 +565,17 @@ static CHECK_RESULT IrRegister lhsexpr_generate_ir(LhsExpr *self, AstResolveData
if(self->rhs_expr) {
Ast *rhs_expr = self->rhs_expr;
- IrRegister rhs_reg;
- rhs_reg = ast_generate_ir(rhs_expr, context);
+ IrRegister rhs_reg = ast_generate_ir(rhs_expr, context);
+#if 0
if(LHS_EXPR_IS_EXPORT(self))
return lhsexpr_export_generate_ir(self, context);
-
+#endif
/*
- 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 IR until it's used.
TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types?
*/
- if(lhs_expr_is_decl(self) || rhs_expr->type == AST_IMPORT) {
+ if(rhs_expr->type == AST_IMPORT) {
/*assert(bool_false);*/
return 0;
}
@@ -620,12 +631,7 @@ static CHECK_RESULT void function_signature_generate_params_ir(FunctionSignature
}
}
-/*
-TODO: Each function declaration should be in separate IR instances so ast can be converted into ir
-in any order.
-*/
static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompilerContext *context) {
- /* TODO: Implement */
/*
Reset reg counter in each function, because each function has a separate register context
that is reset after function end
@@ -636,10 +642,7 @@ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompil
context->ir->param_counter = 0;
context->ir->label_counter = 0;
- /*
- Parameters need to have generated ir so the first ir registers belong to the function.
- This way we can know if a register access is for a parameter or not by checking the number
- */
+ /* All parameters need to be generated, so that the parameter matches its index... */
function_signature_generate_params_ir(self->signature, context);
amal_log_debug("IR funcdecl %p", self);
@@ -649,7 +652,7 @@ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompil
if(LHS_EXPR_IS_EXPORT(self->lhs_expr))
func_flags |= FUNC_FLAG_EXPORTED;
}
- throw_if_error(ir_ins_func_start(context->ir, func_flags, self->signature, &self->ir_func_index, &func_metadata_index));
+ throw_if_error(ir_ins_func_start(context->ir, func_flags, self->signature, &func_metadata_index));
scope_generate_ir(&self->body, context);
throw_if_error(ir_ins_func_end(context->ir));
@@ -658,27 +661,57 @@ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompil
return 0;
}
+static CHECK_RESULT IrRegister funcdecl_ref_generate_ir(FunctionDecl *self, IrCompilerContext *context) {
+ IrRegister reg;
+ if(self->lhs_expr && LHS_EXPR_IS_EXTERN(self->lhs_expr)) {
+ assert(bool_false && "TODO: Implement assign func for extern closures");
+ throw(-1);
+ }
+ throw_if_error(ir_get_unique_reg(context->ir, &reg));
+ throw_if_error(ir_ins_assign_func(context->ir, reg, self->ir_func_index));
+ return reg;
+}
+
+
static CHECK_RESULT IrRegister funccall_generate_ir(FunctionCall *self, IrCompilerContext *context) {
IrRegister reg;
FunctionSignature *func_sig;
FunctionDecl *func_decl;
LhsExpr *func_lhs_expr;
+ FunctionParameter *func_param_expr;
int import_index = context->import_index;
+
+ func_lhs_expr = NULL;
+ func_param_expr = NULL;
context->import_index = 0;
throw_if_error(ir_get_unique_reg(context->ir, &reg));
- assert(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR);
- func_lhs_expr = self->func.resolved_var.value.lhs_expr;
- if(func_lhs_expr->type.type == VARIABLE_TYPE_SIGNATURE) {
- func_sig = func_lhs_expr->type.value.signature;
- } else if(func_lhs_expr->type.type == VARIABLE_TYPE_VARIABLE) {
- AstResolveData *resolve_data = func_lhs_expr->type.value.variable->resolved_var.resolve_data;
- assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG);
- func_sig = resolve_data->type.value.func_sig;
- } else {
- assert(func_lhs_expr->rhs_expr && func_lhs_expr->rhs_expr->resolve_data.type.type == RESOLVED_TYPE_FUNC_SIG);
- func_sig = func_lhs_expr->rhs_expr->resolve_data.type.value.func_sig;
+ switch(self->func.resolved_var.type) {
+ case NAMED_OBJECT_NONE:
+ assert(bool_false);
+ break;
+ case NAMED_OBJECT_LHS_EXPR: {
+ func_lhs_expr = self->func.resolved_var.value.lhs_expr;
+ if(func_lhs_expr->type.type == VARIABLE_TYPE_SIGNATURE) {
+ func_sig = func_lhs_expr->type.value.signature;
+ } else if(func_lhs_expr->type.type == VARIABLE_TYPE_VARIABLE) {
+ AstResolveData *resolve_data = func_lhs_expr->type.value.variable->resolved_var.resolve_data;
+ assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG);
+ func_sig = resolve_data->type.value.func_sig;
+ } else {
+ assert(func_lhs_expr->rhs_expr && func_lhs_expr->rhs_expr->resolve_data.type.type == RESOLVED_TYPE_FUNC_SIG);
+ func_sig = func_lhs_expr->rhs_expr->resolve_data.type.value.func_sig;
+ }
+ break;
+ }
+ case NAMED_OBJECT_FUNC_PARAM: {
+ func_param_expr = self->func.resolved_var.value.func_param;
+ assert(func_param_expr->type.type == VARIABLE_TYPE_SIGNATURE);
+ func_sig = func_param_expr->type.value.signature;
+ break;
+ }
}
+
func_decl = func_sig->func_decl;
/* Push return arguments */
@@ -719,15 +752,16 @@ static CHECK_RESULT IrRegister funccall_generate_ir(FunctionCall *self, IrCompil
if(func_lhs_expr && LHS_EXPR_IS_EXTERN(func_lhs_expr)) {
throw_if_error(ir_ins_call_extern(context->ir, import_index, func_lhs_expr));
- } else {
- assert(func_decl);
- /* rhs wont be null here because only extern variable can't have rhs */
+ } else if(func_decl) {
throw_if_error(ir_ins_call(context->ir, import_index, func_decl));
+ } else if(func_param_expr) {
+ throw_if_error(ir_ins_call_reg(context->ir, function_parameter_generate_ir(func_param_expr, context)));
}
return reg;
}
+#if 0
static CHECK_RESULT IrRegister structdecl_generate_ir(StructDecl *self, IrCompilerContext *context) {
/* TODO: Implement */
/*assert(bool_false);*/
@@ -742,6 +776,7 @@ static CHECK_RESULT IrRegister structfield_generate_ir(StructField *self, IrComp
(void)context;
return 0;
}
+#endif
static CHECK_RESULT IrRegister string_generate_ir(String *self, IrCompilerContext *context) {
IrRegister reg;
@@ -895,24 +930,29 @@ static void return_expr_generate_ir(ReturnExpr *self, IrCompilerContext *context
}
static CHECK_RESULT IrRegister ast_generate_ir_resolve_data(void *ast_data, AstType ast_type, AstResolveData *resolve_data, IrCompilerContext *context) {
- if(resolve_data->status == AST_IR_RESOLVED)
- return resolve_data->ir_reg;
+ /*if(resolve_data->status == AST_IR_RESOLVED)
+ return resolve_data->ir_reg;*/
switch(ast_type) {
case AST_NUMBER:
resolve_data->ir_reg = number_generate_ir(ast_data, context);
break;
+ case AST_BOOL:
+ resolve_data->ir_reg = ast_bool_generate_ir(ast_data, context);
+ break;
case AST_FUNCTION_DECL:
- resolve_data->ir_reg = funcdecl_generate_ir(ast_data, context);
+ /* The IR for function declarations is done separately, in @scope_generate_functions_ir */
+ resolve_data->ir_reg = funcdecl_ref_generate_ir(ast_data, context);
break;
case AST_FUNCTION_CALL:
resolve_data->ir_reg = funccall_generate_ir(ast_data, context);
break;
case AST_STRUCT_DECL:
- resolve_data->ir_reg = structdecl_generate_ir(ast_data, context);
+ resolve_data->ir_reg = 0;/*structdecl_generate_ir(ast_data, context);*/
break;
case AST_STRUCT_FIELD:
- resolve_data->ir_reg = structfield_generate_ir(ast_data, context);
+ assert(bool_false);
+ resolve_data->ir_reg = 0;/*structfield_generate_ir(ast_data, context);*/
break;
case AST_LHS:
resolve_data->ir_reg = lhsexpr_generate_ir(ast_data, resolve_data, context);
@@ -941,7 +981,6 @@ static CHECK_RESULT IrRegister ast_generate_ir_resolve_data(void *ast_data, AstT
break;
case AST_RETURN:
return_expr_generate_ir(ast_data, context);
- resolve_data->ir_reg = 0;
break;
}
@@ -950,13 +989,13 @@ static CHECK_RESULT IrRegister ast_generate_ir_resolve_data(void *ast_data, AstT
}
CHECK_RESULT IrRegister ast_generate_ir(Ast *self, IrCompilerContext *context) {
+#ifdef DEBUG
assert(self);
- #ifdef DEBUG
if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_IR_RESOLVED) {
amal_log_error("Ast type not resolved: %d", self->type);
assert(bool_false);
}
- #endif
+#endif
return ast_generate_ir_resolve_data(self->value.data, self->type, &self->resolve_data, context);
}
@@ -980,3 +1019,42 @@ void scope_generate_ir(Scope *self, IrCompilerContext *context) {
ignore_result_int(ast_generate_ir(*ast, context));
}
}
+
+void scope_generate_function_ids(Scope *self, IrCompilerContext *context) {
+ Ast **ast = buffer_begin(&self->ast_objects);
+ Ast **ast_end = buffer_end(&self->ast_objects);
+ for(; ast != ast_end; ++ast) {
+ if((*ast)->type == AST_LHS && (*ast)->value.lhs_expr->rhs_expr->type == AST_FUNCTION_DECL) {
+ LhsExpr *lhs_expr = (*ast)->value.lhs_expr;
+ FunctionDecl *func_decl = lhs_expr->rhs_expr->value.func_decl;
+ /*
+ Going depth first will optimize scope private closures, so they are declared
+ before the function they are defined in. This means calling them wont create a deferred function call
+ in program.c
+ */
+ scope_generate_functions_ir(&func_decl->body, context);
+ /* TODO: Should this not be done for extern closures? */
+ throw_if_error(ir_inc_func_index(context->ir, &func_decl->ir_func_index));
+ }
+ }
+}
+
+void scope_generate_functions_ir(Scope *self, IrCompilerContext *context) {
+ Ast **ast = buffer_begin(&self->ast_objects);
+ Ast **ast_end = buffer_end(&self->ast_objects);
+ for(; ast != ast_end; ++ast) {
+ if((*ast)->type == AST_LHS && (*ast)->value.lhs_expr->rhs_expr->type == AST_FUNCTION_DECL) {
+ LhsExpr *lhs_expr = (*ast)->value.lhs_expr;
+ FunctionDecl *func_decl = lhs_expr->rhs_expr->value.func_decl;
+ /*
+ Going depth first will optimize scope private closures, so they are declared
+ before the function they are defined in. This means calling them wont create a deferred function call
+ in program.c
+ */
+ scope_generate_functions_ir(&func_decl->body, context);
+ ignore_result_int(funcdecl_generate_ir(func_decl, context));
+ if(LHS_EXPR_IS_EXPORT(lhs_expr))
+ throw_if_error(ir_try_add_export_func(context->ir, func_decl->signature, lhs_expr->var_name));
+ }
+ }
+}