aboutsummaryrefslogtreecommitdiff
path: root/src/bytecode
diff options
context:
space:
mode:
Diffstat (limited to 'src/bytecode')
-rw-r--r--src/bytecode/bytecode.c107
1 files changed, 81 insertions, 26 deletions
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 8a41900..edc8dba 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -3,6 +3,7 @@
#include "../../include/std/log.h"
#include "../../include/ssa/ssa.h"
#include "../../include/parser.h"
+#include "../../include/ast.h"
#include "../../include/compiler.h"
#include <assert.h>
#include <stdio.h> /* TODO: Remove this */
@@ -37,8 +38,9 @@ static CHECK_RESULT usize ssa_extract_form2(u8 *instruction_data, SsaInsForm2 *r
static CHECK_RESULT usize ssa_extract_func_start(u8 *instruction_data, SsaInsFuncStart *result) {
am_memcpy(&result->func_index, instruction_data, sizeof(result->func_index));
- am_memcpy(&result->num_registers, instruction_data + sizeof(result->func_index), sizeof(result->num_registers));
- return sizeof(result->func_index) + sizeof(result->num_registers);
+ am_memcpy(&result->num_params_regs, instruction_data + sizeof(result->func_index), sizeof(result->num_params_regs));
+ am_memcpy(&result->num_local_vars_regs, instruction_data + sizeof(result->func_index) + sizeof(result->num_params_regs), sizeof(result->num_local_vars_regs));
+ return sizeof(result->func_index) + sizeof(result->num_params_regs) + sizeof(result->num_local_vars_regs);
}
static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFuncCall *result) {
@@ -48,6 +50,13 @@ static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFunc
return sizeof(u8) + sizeof(result->result) + sizeof(result->func_decl);
}
+static CHECK_RESULT usize ssa_extract_func_call_extern(u8 *instruction_data, SsaInsFuncCallExtern *result) {
+ result->num_args = instruction_data[0];
+ am_memcpy(&result->result, instruction_data + 1, sizeof(result->result));
+ am_memcpy(&result->extern_func_index, instruction_data + 1 + sizeof(result->result), sizeof(result->extern_func_index));
+ return sizeof(u8) + sizeof(result->result) + sizeof(result->extern_func_index);
+}
+
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));
@@ -107,7 +116,7 @@ static void add_strings(BytecodeCompilerContext *self) {
# String
|Type|Field|Description |
|----|----|----------------------------------------------------------------------------------------|
- |u16 |Size|The size of the string, in bytes. |
+ |u16 |Size|The size of the string, in bytes. Excluding the null-terminate character. |
|u8* |Data|The data of the string, where the size is defined by @Size. Strings are null-terminated.|
*/
@@ -115,18 +124,12 @@ static void add_strings(BytecodeCompilerContext *self) {
Buffer *instructions;
BufferView *string;
BufferView *strings_end;
- u16 num_strings;
u32 strings_size;
ssa = self->parser->ssa;
instructions = &self->bytecode.data;
string = buffer_begin(&ssa->strings);
strings_end = buffer_end(&ssa->strings);
- if(strings_end - string > UINT16_MAX) {
- amal_log_error("Too many strings in the program");
- throw(-1);
- }
- num_strings = strings_end - string;
strings_size = 0;
for(; string != strings_end; ++string) {
@@ -135,10 +138,10 @@ static void add_strings(BytecodeCompilerContext *self) {
string = buffer_begin(&ssa->strings);
throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + strings_size));
- throw_if_error(buffer_append(instructions, &num_strings, sizeof(u16)));
+ throw_if_error(buffer_append(instructions, &ssa->string_counter, sizeof(u16)));
throw_if_error(buffer_append(instructions, &strings_size, sizeof(u32)));
for(; string != strings_end; ++string) {
- char null_s = '\0';
+ const char null_s = '\0';
throw_if_error(buffer_append(instructions, &string->size, sizeof(u16)));
throw_if_error(buffer_append(instructions, string->data, string->size));
throw_if_error(buffer_append(instructions, &null_s, sizeof(char)));
@@ -157,6 +160,55 @@ static void add_functions(BytecodeCompilerContext *self) {
throw_if_error(buffer_append(&self->bytecode.data, &self->parser->ssa->func_counter, sizeof(u16)));
}
+static void add_extern_functions(BytecodeCompilerContext *self) {
+ /*doc(Bytecode external functions)
+ # External functions layout
+ |Type |Field |Description |
+ |------------------|------------------|-----------------------------------------------------------------------------------------|
+ |u16 |num_extern_func |The number of external functions. |
+ |u32 |extern_funcs_size |The size of the external functions section, in bytes. |
+ |External function*|External functions|Multiple external functions, where the number of functions is defined by @num_extern_func|
+
+ # External function
+ |Type|Field |Description |
+ |----|--------|-----------------------------------------------------------------------------------------------------|
+ |u8 |num_args|The number of arguments the functions has. |
+ |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;
+
+ 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 */
+ }
+ extern_func = buffer_begin(&ssa->extern_funcs);
+
+ throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + extern_funcs_size));
+ throw_if_error(buffer_append(instructions, &ssa->extern_func_counter, sizeof(u16)));
+ 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);
+ throw_if_error(buffer_append(instructions, &num_args, sizeof(num_args)));
+ 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)));
+ }
+
+ assert(sizeof(SsaExternFuncIndex) == sizeof(u16) && "Program decoder needs to be updated since size of extern 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);
@@ -164,7 +216,7 @@ static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const cha
}
-static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, u8 reg, const char *fmt) {
+static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, const char *fmt) {
Buffer *instructions;
size_t index;
instructions = &self->bytecode.data;
@@ -177,7 +229,7 @@ static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, u8 reg, c
fputc('\n', stderr);
}
-static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u8 src_reg, const char *fmt) {
+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;
@@ -204,7 +256,7 @@ static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data,
fputc('\n', stderr);
}
-static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u8 reg1, u8 reg2, const char *fmt) {
+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;
@@ -219,7 +271,7 @@ static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_re
fputc('\n', stderr);
}
-static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u16 data, const char *fmt) {
+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;
@@ -233,17 +285,18 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_re
fputc('\n', stderr);
}
-static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u16 idx, u8 arg, const char *fmt) {
+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;
- throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(arg)));
+ throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args) + sizeof(dst_reg)));
instructions->data[index] = opcode;
memcpy(instructions->data + index + sizeof(AmalOpcodeType), &idx, sizeof(idx));
- instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx)] = arg;
- fprintf(stderr, fmt, idx, arg);
+ instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx)] = num_args;
+ instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args)] = dst_reg;
+ fprintf(stderr, fmt, idx, num_args, dst_reg);
fputc('\n', stderr);
}
@@ -283,6 +336,7 @@ static void add_instructions(BytecodeCompilerContext *self) {
SsaInsForm2 ssa_ins_form2;
SsaInsFuncStart ssa_ins_func_start;
SsaInsFuncCall ssa_ins_func_call;
+ SsaInsFuncCallExtern ssa_ins_func_call_extern;
SsaInsJumpZero ssa_ins_jump_zero;
SsaInsJump ssa_ins_jump;
@@ -490,7 +544,7 @@ static void add_instructions(BytecodeCompilerContext *self) {
}
case SSA_FUNC_START: {
instruction += ssa_extract_func_start(instruction, &ssa_ins_func_start);
- add_ins4(self, AMAL_OP_FUNC_START, ssa_ins_func_start.num_registers, "func_start %u");
+ 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");
break;
}
case SSA_FUNC_END: {
@@ -506,10 +560,6 @@ static void add_instructions(BytecodeCompilerContext *self) {
}
case SSA_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.
@@ -518,8 +568,12 @@ static void add_instructions(BytecodeCompilerContext *self) {
is defined as the size of all previous files' number of functions.
*/
instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
- add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, "call %d, %d");
- assert(bool_false && "TODO: Assign function result (RAX for x86_64) to ssa_ins_func_call.result reg");
+ add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, ssa_ins_func_call.result, "call f%d, %d, r%d");
+ break;
+ }
+ case SSA_CALL_EXTERN: {
+ instruction += ssa_extract_func_call_extern(instruction, &ssa_ins_func_call_extern);
+ add_ins7(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.extern_func_index, ssa_ins_func_call_extern.num_args, ssa_ins_func_call_extern.result, "calle ef%d, %d, r%d");
break;
}
case SSA_JUMP_ZERO: {
@@ -558,5 +612,6 @@ void generate_bytecode_from_ssa(BytecodeCompilerContext *self) {
add_intermediates(self);
add_strings(self);
add_functions(self);
+ add_extern_functions(self);
add_instructions(self);
}