aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-08-24 23:31:14 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commitd9f652919961a2947452ad3c4af4659f3d2fb330 (patch)
tree2db541db311a9b5a83d3f2c9b199f6d5c3341555 /src
parent40652d7dbf701eda83fa8323b42a6b5bf0ca6bdd (diff)
Add if/else/elseif/while, including the final assembly
Diffstat (limited to 'src')
-rw-r--r--src/bytecode/bytecode.c20
-rw-r--r--src/parser.c22
-rw-r--r--src/program.c20
-rw-r--r--src/ssa/ssa.c162
4 files changed, 156 insertions, 68 deletions
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index fe3dc0f..47d492c 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -77,6 +77,7 @@ static void add_intermediates(BytecodeCompilerContext *self) {
Buffer *instructions = &self->bytecode.data;
SsaNumber *intermediate = buffer_begin(&ssa->intermediates);
SsaNumber *intermediates_end = buffer_end(&ssa->intermediates);
+ int i = 0;
u32 intemediates_size = (sizeof(u8) + sizeof(u64)) * buffer_get_size(&ssa->intermediates, SsaNumber);
throw_if_error(buffer_expand(instructions, sizeof(u32) + intemediates_size));
@@ -85,6 +86,7 @@ static void add_intermediates(BytecodeCompilerContext *self) {
throw_if_error(buffer_append(instructions, &intermediate->type, sizeof(u8)));
/* TODO: Store value using an encoding that will save space when using low numbers */
throw_if_error(buffer_append(instructions, &intermediate->value.integer, sizeof(u64)));
+ fprintf(stderr, "i%d = %ld\n", i++, intermediate->value.integer);
}
}
@@ -228,11 +230,12 @@ static void add_export_functions(BytecodeCompilerContext *self) {
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);
- fputc('\n', stderr);
+ if(fmt) {
+ fprintf(stderr, fmt);
+ fputc('\n', stderr);
+ }
}
-
static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, const char *fmt) {
Buffer *instructions = &self->bytecode.data;
size_t index = instructions->size;
@@ -325,6 +328,7 @@ static void add_instructions(BytecodeCompilerContext *self) {
Ssa *ssa = self->parser->ssa;
u8 *instruction = buffer_begin(&ssa->instructions);
u8 *instructions_end = buffer_end(&ssa->instructions);
+ u16 label_counter = 0;
u32 num_instructions_index = self->bytecode.data.size;
throw_if_error(buffer_append_empty(&self->bytecode.data, sizeof(num_instructions_index)));
@@ -386,6 +390,7 @@ static void add_instructions(BytecodeCompilerContext *self) {
case SSA_FUNC_START: {
instruction += ssa_extract_data(instruction, &ssa_ins_func_start, sizeof(ssa_ins_func_start));
add_ins6(self, AMAL_OP_FUNC_START, ssa_ins_func_start.flags, ssa_ins_func_start.num_local_vars_regs, "func_start 0x%02x, %u");
+ label_counter = 0;
break;
}
case SSA_FUNC_END: {
@@ -419,12 +424,12 @@ static void add_instructions(BytecodeCompilerContext *self) {
}
case SSA_JUMP_ZERO: {
instruction += ssa_extract_data(instruction, &ssa_ins_jump_zero, sizeof(ssa_ins_jump_zero));
- add_ins6(self, AMAL_OP_JZ, ssa_ins_jump_zero.condition_reg, ssa_ins_jump_zero.jump_offset, "jz r%d, %d");
+ add_ins6(self, AMAL_OP_JZ, ssa_ins_jump_zero.condition_reg, ssa_ins_jump_zero.target_label, "jz r%d, l%d");
break;
}
case SSA_JUMP: {
instruction += ssa_extract_data(instruction, &ssa_ins_jump, sizeof(ssa_ins_jump));
- add_ins4(self, AMAL_OP_JMP, ssa_ins_jump.jump_offset, "jmp %d");
+ add_ins4(self, AMAL_OP_JMP, ssa_ins_jump.target_label, "jmp l%d");
break;
}
case SSA_RET: {
@@ -434,6 +439,11 @@ static void add_instructions(BytecodeCompilerContext *self) {
add_ins2(self, AMAL_OP_RET, reg, "ret r%d");
break;
}
+ case SSA_LABEL: {
+ add_ins1(self, AMAL_OP_LABEL, NULL);
+ fprintf(stderr, "label l%d\n", label_counter++);
+ break;
+ }
}
}
diff --git a/src/parser.c b/src/parser.c
index ff34663..a6b4ecf 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -48,6 +48,10 @@ int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator
return PARSER_OK;
}
+static bool parser_is_current_scope_file_scope(Parser *self) {
+ return self->current_scope == &self->struct_decl.body;
+}
+
/*
BODY_LOOP = BODY* @end_token
*/
@@ -359,6 +363,12 @@ static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) {
if(!signature)
return NULL;
+ /*
+ TODO: Implement function declaration inside other functions.
+ Such functions should be moved to the file scope in the bytecode generation
+ */
+ assert(parser_is_current_scope_file_scope(self));
+
throw_if_error(arena_allocator_alloc(self->allocator, sizeof(FunctionDecl), (void**)&result));
throw_if_error(funcdecl_init(result, signature, self->current_scope, self->allocator));
signature->func_decl = result;
@@ -500,16 +510,20 @@ static CHECK_RESULT ElseIfStatement* parser_parse_else_if_statement(Parser *self
}
static void parser_parse_else_if_statement_loop(Parser *self, IfStatement *if_stmt) {
- ElseIfStatement *else_if_stmt;
- else_if_stmt = if_stmt->else_if_stmt;
+ ElseIfStatement *else_if_stmt = NULL;
for(;;) {
ElseIfStatement *next_else_if;
next_else_if = parser_parse_else_if_statement(self);
if(!next_else_if)
break;
- else_if_stmt->next_else_if_stmt = next_else_if;
+
+ if(!else_if_stmt)
+ if_stmt->else_if_stmt = next_else_if;
+ else
+ else_if_stmt->next_else_if_stmt = next_else_if;
+
/* else statement that has no condition can't be followed by another else statement */
- if(!else_if_stmt->condition)
+ if(!next_else_if->condition)
break;
else_if_stmt = next_else_if;
}
diff --git a/src/program.c b/src/program.c
index 55bfda4..eef49b6 100644
--- a/src/program.c
+++ b/src/program.c
@@ -125,7 +125,7 @@ static CHECK_RESULT int amal_program_set_exported_function_instruction_offset_ad
num_args = self->exported_funcs[sizeof(instruction_offset)];
func_name_size = self->exported_funcs[sizeof(instruction_offset) + sizeof(num_args)];
self->exported_funcs += sizeof(instruction_offset) + sizeof(num_args) + sizeof(func_name_size);
- if(self->main_func_instruction_offset == ~0U && am_memeql(self->exported_funcs, "main", 4))
+ if(self->main_func_instruction_offset == ~0U && func_name_size == 4 && am_memeql(self->exported_funcs, "main", 4))
self->main_func_instruction_offset = instruction_offset;
/* +1 to skip null-termination character */
@@ -521,16 +521,18 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
break;
}
case AMAL_OP_JZ: {
- i16 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));
+ i8 reg;
+ u16 target_label;
+ reg = self->data.data[self->read_index];
+ am_memcpy(&target_label, self->data.data + self->read_index + sizeof(reg), sizeof(target_label));
+ return_if_error(amal_exec_jz(executor, reg, target_label));
self->read_index += 3;
break;
}
case AMAL_OP_JMP: {
- i16 jump_offset;
- am_memcpy(&jump_offset, &self->data.data[self->read_index], sizeof(jump_offset));
- return_if_error(amal_exec_jmp(executor, jump_offset));
+ u16 target_label;
+ am_memcpy(&target_label, self->data.data + self->read_index, sizeof(target_label));
+ return_if_error(amal_exec_jmp(executor, target_label));
self->read_index += 2;
break;
}
@@ -564,6 +566,10 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
return_if_error(amal_exec_func_end(executor));
break;
}
+ case AMAL_OP_LABEL: {
+ return_if_error(amal_exec_label(executor));
+ break;
+ }
}
}
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 940f636..5c625b2 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -69,6 +69,7 @@ int ssa_init(Ssa *self, Parser *parser) {
self->reg_counter = 0;
self->param_counter = 0;
self->func_counter = 0;
+ self->label_counter = 0;
self->parser = parser;
return 0;
}
@@ -80,6 +81,7 @@ static CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
amal_log_error("Ssa too many registers!");
return -1;
}
+ assert(self->reg_counter <= INT8_MAX && "TODO: Implement usage of reg higher than 128");
*result = self->reg_counter++;
return 0;
}
@@ -331,24 +333,33 @@ static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, SsaExternFuncIndex extern
return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern));
}
-static CHECK_RESULT int ssa_ins_jumpzero(Ssa *self, SsaRegister condition_reg, JumpOffset jump_offset) {
+static CHECK_RESULT int ssa_ins_jumpzero(Ssa *self, SsaRegister condition_reg, SsaLabelIndex target_label, usize *instruction_offset) {
const u8 ins_type = SSA_JUMP_ZERO;
SsaInsJumpZero ins_jump_zero;
ins_jump_zero.condition_reg = condition_reg;
- ins_jump_zero.jump_offset = jump_offset;
- if(jump_offset == 0)
+ ins_jump_zero.target_label = target_label;
+ if(target_label == 0)
amal_log_debug("JUMP_ZERO r%d, DUMMY", condition_reg);
else
- amal_log_debug("JUMP_ZERO r%d, %d", condition_reg, jump_offset);
+ amal_log_debug("JUMP_ZERO r%d, l%d", condition_reg, target_label);
+ *instruction_offset = self->instructions.size;
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return buffer_append(&self->instructions, &ins_jump_zero, sizeof(ins_jump_zero));
}
-static CHECK_RESULT int ssa_ins_jump(Ssa *self, JumpOffset jump_offset) {
+static CHECK_RESULT int ssa_ins_jump(Ssa *self, SsaLabelIndex target_label, usize *instruction_offset) {
const u8 ins_type = SSA_JUMP;
SsaInsJump ins_jump;
- ins_jump.jump_offset = jump_offset;
- amal_log_debug("JUMP %d", jump_offset);
+ ins_jump.target_label = target_label;
+
+ if(target_label == 0)
+ amal_log_debug("JUMP DUMMY");
+ else
+ amal_log_debug("JUMP l%d", target_label);
+
+ if(instruction_offset)
+ *instruction_offset = self->instructions.size;
+
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return buffer_append(&self->instructions, &ins_jump, sizeof(ins_jump));
}
@@ -359,21 +370,28 @@ static CHECK_RESULT int ssa_ins_return(Ssa *self, SsaRegister reg) {
return buffer_append(&self->instructions, &reg, sizeof(reg));
}
-static usize ssa_ins_get_index(Ssa *self) {
- return self->instructions.size;
+static CHECK_RESULT int ssa_ins_label(Ssa *self, u16 *label_index) {
+ const u8 ins_type = SSA_LABEL;
+ /* Overflow */
+ if(self->label_counter + 1 <= self->label_counter) {
+ amal_log_error("Ssa too many labels!");
+ return -1;
+ }
+ *label_index = self->label_counter;
+ ++self->label_counter;
+ return buffer_append(&self->instructions, &ins_type, 1);
}
-/* Set target of jump instruction to current location */
-static CHECK_RESULT int ssa_ins_jump_set_target(Ssa *self, usize jump_ins_index) {
+static CHECK_RESULT int ssa_set_jump_label(Ssa *self, usize jump_ins_index, SsaLabelIndex label) {
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 + offsetof(SsaInsJumpZero, jump_offset), &jump_offset, sizeof(JumpOffset));
+ /* +1 to skip instruction opcode */
+ am_memcpy(self->instructions.data + jump_ins_index + 1 + offsetof(SsaInsJumpZero, target_label), &label, sizeof(SsaLabelIndex));
+ break;
+ }
+ case SSA_JUMP: {
+ /* +1 to skip instruction opcode */
+ am_memcpy(self->instructions.data + jump_ins_index + 1 + offsetof(SsaInsJump, target_label), &label, sizeof(SsaLabelIndex));
break;
}
default:
@@ -386,6 +404,7 @@ 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);
+#if 0
static bool ast_resolved_type_is_decl(AstResolvedType *self) {
/* TODO: Add more types as they are introduced */
LhsExpr *lhs_expr;
@@ -406,6 +425,24 @@ static bool ast_resolved_type_is_decl(AstResolvedType *self) {
assert(lhs_expr->rhs_expr);
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 SsaRegister number_generate_ssa(Number *self, SsaCompilerContext *context) {
SsaRegister reg;
@@ -482,7 +519,7 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(LhsExpr *self, AstResolveDa
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(ast_resolved_type_is_decl(&resolve_data->type) || rhs_expr->type == AST_IMPORT) {
+ if(lhs_expr_is_decl(self) || rhs_expr->type == AST_IMPORT) {
/*assert(bool_false);*/
return 0;
}
@@ -528,6 +565,7 @@ static CHECK_RESULT SsaRegister function_parameter_generate_ssa(FunctionParamete
throw(-1);
}
reg = -1 - reg;
+ assert(reg >= INT8_MIN && "TODO: Implement more than 128 params");
self->resolve_data.status = AST_SSA_RESOLVED;
self->resolve_data.ssa_reg = reg;
return reg;
@@ -555,10 +593,9 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
that is reset after function end
*/
usize func_metadata_index;
- SsaRegister prev_reg_counter = context->ssa->reg_counter;
- SsaRegister prev_param_counter = context->ssa->param_counter;
u8 func_flags = 0;
context->ssa->reg_counter = 0;
+ context->ssa->label_counter = 0;
/*
Parameters need to have generated ssa so the first ssa registers belong to the function.
@@ -580,9 +617,6 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
/* Add the number of registers used to the function metadata (FUNC_START) */
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;
}
@@ -684,47 +718,71 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
return reg;
}
-static void else_if_statement_generate_ssa(ElseIfStatement *else_if_stmt, SsaCompilerContext *context) {
- usize jump_ins_index = 0;
+static void else_if_statement_generate_ssa(ElseIfStatement *else_if_stmt, SsaCompilerContext *context, SsaLabelIndex *skip_other_else_statements_label) {
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));
+ usize jump_ins_index;
+ usize jump_skip_else_index;
+ SsaLabelIndex skip_body_label;
+ SsaRegister condition_reg = ast_generate_ssa(else_if_stmt->condition, context);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0, &jump_ins_index));
+ scope_generate_ssa(&else_if_stmt->body, context);
+ if(else_if_stmt->next_else_if_stmt)
+ throw_if_error(ssa_ins_jump(context->ssa, 0, &jump_skip_else_index));
+
+ throw_if_error(ssa_ins_label(context->ssa, &skip_body_label));
+ throw_if_error(ssa_set_jump_label(context->ssa, jump_ins_index, skip_body_label));
+ if(else_if_stmt->next_else_if_stmt) {
+ else_if_statement_generate_ssa(else_if_stmt->next_else_if_stmt, context, skip_other_else_statements_label);
+ /* Skip over all other else if statements, since else_if_statement_generate_ssa is recursive */
+ throw_if_error(ssa_set_jump_label(context->ssa, jump_skip_else_index, *skip_other_else_statements_label));
+ return;
+ }
+ } else {
+ assert(!else_if_stmt->next_else_if_stmt);
+ scope_generate_ssa(&else_if_stmt->body, context);
}
- 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);
+
+ /* Note: The last else if statement doesn't need a jump */
+ throw_if_error(ssa_ins_label(context->ssa, skip_other_else_statements_label));
}
static void if_statement_generate_ssa(IfStatement *if_stmt, SsaCompilerContext *context) {
+ usize jump_ins_index;
+ usize jump_skip_else_index;
+ SsaLabelIndex skip_body_label;
+ SsaLabelIndex skip_else_statements_label;
+
SsaRegister condition_reg = ast_generate_ssa(if_stmt->condition, context);
- usize jump_ins_index = ssa_ins_get_index(context->ssa);
- throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0, &jump_ins_index));
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);
+ throw_if_error(ssa_ins_jump(context->ssa, 0, &jump_skip_else_index));
+
+ throw_if_error(ssa_ins_label(context->ssa, &skip_body_label));
+ throw_if_error(ssa_set_jump_label(context->ssa, jump_ins_index, skip_body_label));
+ if(if_stmt->else_if_stmt) {
+ else_if_statement_generate_ssa(if_stmt->else_if_stmt, context, &skip_else_statements_label);
+ /*
+ Skip over all else if statements, since else_if_statement_generate_ssa is recursive.
+ We want to jump since we want to skip the else if statements if we are inside the first if-statement
+ */
+ throw_if_error(ssa_set_jump_label(context->ssa, jump_skip_else_index, skip_else_statements_label));
+ }
}
static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompilerContext *context) {
- isize jump_offset;
- usize jump_back_ins_index = ssa_ins_get_index(context->ssa);
+ SsaLabelIndex before_condition_label;
+ SsaLabelIndex skip_body_label;
+ usize jump_after_condition_index;
+
+ throw_if_error(ssa_ins_label(context->ssa, &before_condition_label));
SsaRegister condition_reg = ast_generate_ssa(while_stmt->condition, context);
- usize jump_condition_ins_index = ssa_ins_get_index(context->ssa);
- throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0, &jump_after_condition_index));
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));
+
+ throw_if_error(ssa_ins_jump(context->ssa, before_condition_label, NULL));
+ throw_if_error(ssa_ins_label(context->ssa, &skip_body_label));
+ throw_if_error(ssa_set_jump_label(context->ssa, jump_after_condition_index, skip_body_label));
}
static void return_expr_generate_ssa(ReturnExpr *self, SsaCompilerContext *context) {