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.c185
1 files changed, 106 insertions, 79 deletions
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 80cc95b..fe3dc0f 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -23,6 +23,36 @@ int bytecode_init(Bytecode *self, ArenaAllocator *allocator) {
return buffer_init(&self->data, allocator);
}
+/*doc(Bytecode)
+The layout of the full bytecode is: Header (Intermediates Strings Functions External_Functions Exported_Functions Instructions)*
+*/
+
+CHECK_RESULT int buffer_append_header(Buffer *program_data) {
+ /*doc(Bytecode header)
+ # Header layout
+ |Type|Field |Description |
+ |----|-------------|----------------------------------------------------------------------------|
+ |u32 |Magic number |The magic number used to identify an amalgam bytecode file. |
+ |u8 |Major version|The major version of the bytecode. Updates in this is a breaking change. |
+ |u8 |Minor version|The minor version of the bytecode. Updates in this are backwards compatible.|
+ |u8 |Patch version|The patch version of the bytecode. Updates in this are only minor bug fixes.|
+
+ The versions in the header only changes for every release, not every change.
+ */
+
+ const u32 magic_number = AMAL_BYTECODE_MAGIC_NUMBER;
+ const u8 major_version = AMAL_BYTECODE_MAJOR_VERSION;
+ const u8 minor_version = AMAL_BYTECODE_MINOR_VERSION;
+ const u8 patch_version = AMAL_BYTECODE_PATCH_VERSION;
+
+ return_if_error(buffer_append(program_data, &magic_number, 4));
+ return_if_error(buffer_append(program_data, &major_version, 1));
+ return_if_error(buffer_append(program_data, &minor_version, 1));
+ return_if_error(buffer_append(program_data, &patch_version, 1));
+
+ return 0;
+}
+
static CHECK_RESULT usize ssa_extract_data(u8 *instruction_data, void *result, usize size) {
am_memcpy(result, instruction_data, size);
return size;
@@ -43,18 +73,12 @@ static void add_intermediates(BytecodeCompilerContext *self) {
|u64 |Value|The type of the value depends on the value of @Type.|
*/
- Ssa *ssa;
- Buffer *instructions;
- SsaNumber *intermediate;
- SsaNumber *intermediates_end;
- u32 intemediates_size;
-
- ssa = self->parser->ssa;
- instructions = &self->bytecode.data;
- intermediate = buffer_begin(&ssa->intermediates);
- intermediates_end = buffer_end(&ssa->intermediates);
+ Ssa *ssa = self->parser->ssa;
+ Buffer *instructions = &self->bytecode.data;
+ SsaNumber *intermediate = buffer_begin(&ssa->intermediates);
+ SsaNumber *intermediates_end = buffer_end(&ssa->intermediates);
- intemediates_size = (sizeof(u8) + sizeof(u64)) * buffer_get_size(&ssa->intermediates, SsaNumber);
+ u32 intemediates_size = (sizeof(u8) + sizeof(u64)) * buffer_get_size(&ssa->intermediates, SsaNumber);
throw_if_error(buffer_expand(instructions, sizeof(u32) + intemediates_size));
throw_if_error(buffer_append(instructions, &intemediates_size, sizeof(u32)));
for(; intermediate != intermediates_end; ++intermediate) {
@@ -80,17 +104,11 @@ static void add_strings(BytecodeCompilerContext *self) {
|u8* |Data|The data of the string, where the size is defined by @Size. Strings are null-terminated.|
*/
- Ssa *ssa;
- Buffer *instructions;
- BufferView *string;
- BufferView *strings_end;
- u32 strings_size;
-
- ssa = self->parser->ssa;
- instructions = &self->bytecode.data;
- string = buffer_begin(&ssa->strings);
- strings_end = buffer_end(&ssa->strings);
- strings_size = 0;
+ Ssa *ssa = self->parser->ssa;
+ Buffer *instructions = &self->bytecode.data;
+ BufferView *string = buffer_begin(&ssa->strings);
+ BufferView *strings_end = buffer_end(&ssa->strings);
+ u32 strings_size = 0;
for(; string != strings_end; ++string) {
strings_size += sizeof(u16) + string->size + 1; /* +1 for null-termination of string */
@@ -136,17 +154,11 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
|u8 |name_len|The length of the external function name, in bytes. Excluding the null-terminate character. |
|u8* |name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.|
*/
-
- Ssa *ssa;
- Buffer *instructions;
- SsaExternFunc *extern_func, *extern_func_end;
- u32 extern_funcs_size;
-
- ssa = self->parser->ssa;
- instructions = &self->bytecode.data;
- extern_func = buffer_begin(&ssa->extern_funcs);
- extern_func_end = buffer_end(&ssa->extern_funcs);
- extern_funcs_size = 0;
+ Ssa *ssa = self->parser->ssa;
+ Buffer *instructions = &self->bytecode.data;
+ SsaExternFunc *extern_func = buffer_begin(&ssa->extern_funcs);
+ SsaExternFunc *extern_func_end = buffer_end(&ssa->extern_funcs);
+ u32 extern_funcs_size = 0;
for(; extern_func != extern_func_end; ++extern_func) {
extern_funcs_size += sizeof(u8) + sizeof(u8) + extern_func->name.size + 1; /* +1 for null-termination of string */
@@ -158,9 +170,9 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
throw_if_error(buffer_append(instructions, &extern_funcs_size, sizeof(u32)));
for(; extern_func != extern_func_end; ++extern_func) {
const char null_s = '\0';
- u8 num_args;
- num_args = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter);
+ u8 num_args = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter);
throw_if_error(buffer_append(instructions, &num_args, sizeof(num_args)));
+ /* TODO: Add namespace to the function name */
throw_if_error(buffer_append(instructions, &extern_func->name.size, sizeof(u8)));
throw_if_error(buffer_append(instructions, extern_func->name.data, extern_func->name.size));
throw_if_error(buffer_append(instructions, &null_s, sizeof(char)));
@@ -169,6 +181,51 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
assert(sizeof(SsaExternFuncIndex) == sizeof(u16) && "Program decoder needs to be updated since size of extern func index has changed");
}
+static void add_export_functions(BytecodeCompilerContext *self) {
+ /*doc(Bytecode exported functions)
+ # Exported functions layout
+ |Type |Field |Description |
+ |-----------------|------------------|-----------------------------------------------------------------------------------------|
+ |u16 |num_export_func |The number of exported functions. |
+ |u32 |export_funcs_size |The size of the exported functions section, in bytes. |
+ |Exported function|Exported functions|Multiple exported functions, where the number of functions is defined by @num_export_func|
+
+ # Exported function
+ |Type|Field |Description |
+ |----|------------------|--------------------------------------------------------------------------------------------------------------------------|
+ |u32 |instruction_offset|The offset in the instruction data where the exported function is defined. Is always 0 until the program has been started.|
+ |u8 |num_args |The number of arguments the functions has. |
+ |u8 |name_len |The length of the exported function name, in bytes. Excluding the null-terminate character. |
+ |u8* |name |The name of the exported function, where the size is defined by @name_len. Names are null-terminated. |
+ */
+ Ssa *ssa = self->parser->ssa;
+ Buffer *instructions = &self->bytecode.data;
+ SsaExportFunc *export_func = buffer_begin(&ssa->export_funcs);
+ SsaExportFunc *export_func_end = buffer_end(&ssa->export_funcs);
+ u32 export_funcs_size = 0;
+
+ for(; export_func != export_func_end; ++export_func) {
+ export_funcs_size += sizeof(u32) + sizeof(u8) + sizeof(u8) + export_func->name.size + 1; /* +1 for null-termination of string */
+ }
+ export_func = buffer_begin(&ssa->export_funcs);
+
+ throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + export_funcs_size));
+ throw_if_error(buffer_append(instructions, &ssa->export_func_counter, sizeof(u16)));
+ throw_if_error(buffer_append(instructions, &export_funcs_size, sizeof(u32)));
+ for(; export_func != export_func_end; ++export_func) {
+ const char null_s = '\0';
+ const u32 instruction_offset = 0;
+ u8 num_args = buffer_get_size(&export_func->func_sig->parameters, FunctionParameter);
+ throw_if_error(buffer_append(instructions, &instruction_offset, sizeof(instruction_offset)));
+ throw_if_error(buffer_append(instructions, &num_args, sizeof(num_args)));
+ throw_if_error(buffer_append(instructions, &export_func->name.size, sizeof(u8)));
+ throw_if_error(buffer_append(instructions, export_func->name.data, export_func->name.size));
+ throw_if_error(buffer_append(instructions, &null_s, sizeof(char)));
+ }
+
+ assert(sizeof(SsaExportFuncIndex) == sizeof(u16) && "Program decoder needs to be updated since size of export func index has changed");
+}
+
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);
@@ -177,10 +234,8 @@ static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const cha
static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, const char *fmt) {
- Buffer *instructions;
- size_t index;
- instructions = &self->bytecode.data;
- index = instructions->size;
+ Buffer *instructions = &self->bytecode.data;
+ size_t index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(reg)));
instructions->data[index] = opcode;
@@ -190,10 +245,8 @@ static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, c
}
static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 src_reg, const char *fmt) {
- Buffer *instructions;
- size_t index;
- instructions = &self->bytecode.data;
- index = instructions->size;
+ Buffer *instructions = &self->bytecode.data;
+ size_t index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(src_reg)));
instructions->data[index] = opcode;
@@ -204,10 +257,8 @@ static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re
}
static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data, const char *fmt) {
- Buffer *instructions;
- size_t index;
- instructions = &self->bytecode.data;
- index = instructions->size;
+ Buffer *instructions = &self->bytecode.data;
+ size_t index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(data)));
instructions->data[index] = opcode;
@@ -217,10 +268,8 @@ static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data,
}
static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 reg1, i8 reg2, const char *fmt) {
- Buffer *instructions;
- size_t index;
- instructions = &self->bytecode.data;
- index = instructions->size;
+ Buffer *instructions = &self->bytecode.data;
+ size_t index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(reg1) + sizeof(reg2)));
instructions->data[index] = opcode;
@@ -232,10 +281,8 @@ static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re
}
static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, u16 data, const char *fmt) {
- Buffer *instructions;
- size_t index;
- instructions = &self->bytecode.data;
- index = instructions->size;
+ Buffer *instructions = &self->bytecode.data;
+ size_t index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(data)));
instructions->data[index] = opcode;
@@ -246,10 +293,8 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re
}
static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u16 idx, i8 num_args, i8 dst_reg, const char *fmt) {
- Buffer *instructions;
- size_t index;
- instructions = &self->bytecode.data;
- index = instructions->size;
+ Buffer *instructions = &self->bytecode.data;
+ size_t index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args) + sizeof(dst_reg)));
instructions->data[index] = opcode;
@@ -260,25 +305,6 @@ static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u16 idx,
fputc('\n', stderr);
}
-#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) {
/*doc(Bytecode instructions)
# Instructions layout
@@ -359,7 +385,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.num_params_regs, ssa_ins_func_start.num_local_vars_regs, "func_start %d, %u");
+ 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");
break;
}
case SSA_FUNC_END: {
@@ -424,5 +450,6 @@ void generate_bytecode_from_ssa(BytecodeCompilerContext *self) {
add_strings(self);
add_functions(self);
add_extern_functions(self);
+ add_export_functions(self);
add_instructions(self);
}