aboutsummaryrefslogtreecommitdiff
path: root/src/bytecode/bytecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bytecode/bytecode.c')
-rw-r--r--src/bytecode/bytecode.c212
1 files changed, 176 insertions, 36 deletions
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 6774a54..789a9f6 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -46,6 +46,17 @@ static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFunc
return sizeof(result->result) + sizeof(result->func_decl);
}
+static CHECK_RESULT usize ssa_extract_jump_zero(u8 *instruction_data, SsaInsJumpZero *result) {
+ am_memcpy(&result->condition_reg, instruction_data, sizeof(result->condition_reg));
+ am_memcpy(&result->jump_offset, instruction_data + sizeof(result->condition_reg), sizeof(result->jump_offset));
+ return sizeof(result->condition_reg) + sizeof(result->jump_offset);
+}
+
+static CHECK_RESULT usize ssa_extract_jump(u8 *instruction_data, SsaInsJump *result) {
+ am_memcpy(&result->jump_offset, instruction_data, sizeof(result->jump_offset));
+ return sizeof(result->jump_offset);
+}
+
static void add_intermediates(BytecodeCompilerContext *self) {
Ssa *ssa;
Buffer *instructions;
@@ -66,19 +77,44 @@ static void add_intermediates(BytecodeCompilerContext *self) {
}
}
+#if 0
#define NUM_MAX_REGS 256
+#define NUM_MAX_FUNC_ARGS 32
+
+static const char* lhs_expr_get_c_name(BytecodeCompilerContext *self, LhsExpr *lhs_expr) {
+ if(lhs_expr == self->parser->compiler->default_types.i64) {
+ return "i64";
+ } else if(lhs_expr == self->parser->compiler->default_types.f64) {
+ return "f64";
+ } else if(lhs_expr == self->parser->compiler->default_types.str) {
+ return"const char*";
+ } else {
+ amal_log_error("Invalid rhs type %p", lhs_expr);
+ assert(bool_false && "TODO: Implement");
+ return "";
+ }
+}
+#endif
static void add_instructions(BytecodeCompilerContext *self) {
Ssa *ssa;
u8 *instruction;
u8 *instructions_end;
+
SsaInsForm1 ssa_ins_form1;
SsaInsForm2 ssa_ins_form2;
SsaInsFuncStart ssa_ins_func_start;
SsaInsFuncCall ssa_ins_func_call;
+ SsaInsJumpZero ssa_ins_jump_zero;
+ SsaInsJump ssa_ins_jump;
+
FILE *file;
char *filename;
+ #ifdef COMPILE_TO_C
LhsExpr *reg_types[NUM_MAX_REGS]; /* TODO: Remove this. Encode this data in the register itself */
+ SsaRegister func_arg_stack[NUM_MAX_FUNC_ARGS]; /* TODO: Remove this? */
+ int func_arg_index;
+ #endif
ssa = self->parser->ssa;
instruction = buffer_begin(&ssa->instructions);
@@ -90,15 +126,27 @@ static void add_instructions(BytecodeCompilerContext *self) {
strcat(filename, ".z");
file = fopen(filename, "wb");
free(filename);
+ #ifdef COMPILE_TO_C
#ifdef DEBUG
am_memset(reg_types, 0, sizeof(reg_types));
#endif
+ func_arg_index = 0;
fputs("typedef i64 signed long long;\n", file);
fputs("typedef f64 double;\n", file);
+ #define ARITH_OP(op) do {\
+ const char *rhs_type_name; \
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2); \
+ assert(ssa_ins_form2.result < NUM_MAX_REGS); \
+ assert(ssa_ins_form2.lhs < NUM_MAX_REGS); \
+ rhs_type_name = lhs_expr_get_c_name(self, reg_types[ssa_ins_form2.lhs]); \
+ fprintf(file, "%s r%d = r%d %s r%d;\n", rhs_type_name, ssa_ins_form2.result, ssa_ins_form2.lhs, (op), ssa_ins_form2.rhs); \
+ reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.lhs]; \
+ } while(0)
+
while(instruction != instructions_end) {
- switch(*instruction++) {
+ switch((SsaInstruction)*instruction++) {
case SSA_ASSIGN_INTER: {
SsaNumber number;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
@@ -125,54 +173,32 @@ static void add_instructions(BytecodeCompilerContext *self) {
break;
}
case SSA_ASSIGN_REG: {
- LhsExpr *rhs_type;
const char *rhs_type_name;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
assert(ssa_ins_form1.rhs < NUM_MAX_REGS);
- rhs_type = reg_types[ssa_ins_form1.rhs];
- if(rhs_type == self->parser->compiler->default_types.i64) {
- rhs_type_name = "i64";
- } else if(rhs_type == self->parser->compiler->default_types.f64) {
- rhs_type_name = "f64";
- } else if(rhs_type == self->parser->compiler->default_types.str) {
- rhs_type_name = "const char*";
- } else {
- amal_log_error("Invalid rhs type %p for reg %d", rhs_type, ssa_ins_form1.rhs);
- assert(bool_false && "TODO: Implement");
- }
+ rhs_type_name = lhs_expr_get_c_name(self, reg_types[ssa_ins_form1.rhs]);
fprintf(file, "%s r%d = r%d;\n", rhs_type_name, ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ reg_types[ssa_ins_form1.lhs] = reg_types[ssa_ins_form1.rhs];
break;
}
case SSA_ADD: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d + r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("+");
break;
}
case SSA_SUB: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d - r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("-");
break;
}
case SSA_MUL: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d * r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("*");
break;
}
case SSA_DIV: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d / r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("/");
+ break;
+ }
+ case SSA_EQUALS: {
+ ARITH_OP("==");
break;
}
case SSA_FUNC_START: {
@@ -194,20 +220,134 @@ static void add_instructions(BytecodeCompilerContext *self) {
SsaRegister reg;
am_memcpy(&reg, instruction, sizeof(SsaRegister));
instruction += sizeof(SsaRegister);
- fprintf(file, "PUSH r%d ***\n", reg);
+ assert(func_arg_index < NUM_MAX_FUNC_ARGS);
+ func_arg_stack[func_arg_index++] = reg;
break;
}
- case SSA_CALL:
+ case SSA_CALL: {
+ int i;
instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
- fprintf(file, "r%d = CALL %p ***\n", ssa_ins_func_call.result, ssa_ins_func_call.func_decl);
+ fprintf(file, "r%d = f%p(", ssa_ins_func_call.result, ssa_ins_func_call.func_decl);
+ for(i = 0; i < func_arg_index; ++i) {
+ if(i > 0)
+ fputs(", ", file);
+ fprintf(file, "r%d", func_arg_stack[i]);
+ }
+ func_arg_index = 0;
+ fputs(");\n", file);
+ break;
+ }
+ case SSA_JUMP_ZERO: {
+ assert(bool_false && "Not implemented!");
+ instruction += ssa_extract_jump_zero(instruction, &ssa_ins_jump_zero);
+ break;
+ }
+ case SSA_JUMP: {
+ assert(bool_false && "Not implemented!");
+ instruction += ssa_extract_jump(instruction, &ssa_ins_jump);
break;
+ }
}
}
+ #else
+ #define ARITH_OP(op) do {\
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2); \
+ fprintf(stderr, "%s r%d, r%d, r%d\n", (op), ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs); \
+ } while(0)
+ while(instruction != instructions_end) {
+ SsaInstruction ins = (SsaInstruction)*instruction++;
+ switch(ins) {
+ case SSA_ASSIGN_INTER: {
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ fprintf(file, "mov r%d, i%d\n", ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ break;
+ }
+ case SSA_ASSIGN_STRING: {
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ fprintf(file, "mov r%d, s%d\n", ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ break;
+ }
+ case SSA_ASSIGN_REG: {
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ fprintf(file, "mov r%d, r%d\n", ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ break;
+ }
+ case SSA_ADD: {
+ ARITH_OP("add");
+ break;
+ }
+ case SSA_SUB: {
+ ARITH_OP("sub");
+ break;
+ }
+ case SSA_MUL: {
+ ARITH_OP("mul");
+ break;
+ }
+ case SSA_DIV: {
+ ARITH_OP("div");
+ break;
+ }
+ case SSA_EQUALS: {
+ ARITH_OP("eq");
+ break;
+ }
+ case SSA_FUNC_START: {
+ instruction += ssa_extract_func_start(instruction, &ssa_ins_func_start);
+ fprintf(file, "FUNC_START %d\n", ssa_ins_func_start.num_args);
+ break;
+ }
+ case SSA_FUNC_END: {
+ fprintf(file, "FUNC_END\n");
+ break;
+ }
+ case SSA_PUSH: {
+ SsaRegister reg;
+ am_memcpy(&reg, instruction, sizeof(SsaRegister));
+ instruction += sizeof(SsaRegister);
+ fprintf(file, "push r%d\n", reg);
+ break;
+ }
+ case SSA_CALL: {
+ /* TODO: Add args, using number of bytes to pop after function call. */
+ /*
+ TODO: Pass return register to function. The register should be a pointer that
+ has the size of the function return values so the return values can fit in it.
+ */
+ /*
+ TODO: Using ssa_func_index only works correctly if the function was defined in the same
+ file as the function call. To make this work with calling functions in other files,
+ ssa_func_index should also have an offset index or something like that.
+ So each file has it's own function list with indices and when they need to be combined in the end,
+ the function indices can be increased by their block index (ssa_func_index + block index), where block index
+ is defined as the size of all previous files' number of functions.
+ */
+ instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
+ fprintf(file, "call %d\n", ssa_ins_func_call.func_decl->ssa_func_index);
+ break;
+ }
+ case SSA_JUMP_ZERO: {
+ instruction += ssa_extract_jump_zero(instruction, &ssa_ins_jump_zero);
+ fprintf(file, "jz r%d, %d\n", ssa_ins_jump_zero.condition_reg, ssa_ins_jump_zero.jump_offset);
+ break;
+ }
+ case SSA_JUMP: {
+ instruction += ssa_extract_jump(instruction, &ssa_ins_jump);
+ fprintf(file, "jmp %d\n", ssa_ins_jump.jump_offset);
+ break;
+ }
+ default:
+ amal_log_error("Instruction not yet implemented: %d", ins);
+ assert(bool_false && "Instruction not yet implemented");
+ }
+ }
+ #endif /* COMPILE_TO_C */
fclose(file);
}
void generate_bytecode_from_ssa(BytecodeCompilerContext *self) {
add_intermediates(self);
+ /* TODO: Also add strings in ssa, so we can index them */
add_instructions(self);
}