aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-09-17 01:28:55 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commitb095aedd386e076d1f5a56b7384b836e653387d1 (patch)
treea9dd7d7cbcfba19005ce8aa9486a70d31091d5c3 /src
parent2928e5f74983f5dd33bc65f192298af87996a037 (diff)
Add support for r8-r15 registers, pass args to registers directly (sys-v)
Diffstat (limited to 'src')
-rw-r--r--src/bytecode/bytecode.c23
-rw-r--r--src/parser.c12
-rw-r--r--src/program.c27
-rw-r--r--src/ssa/ssa.c48
4 files changed, 70 insertions, 40 deletions
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 3b6d980..7dbc305 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -432,19 +432,6 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re
fputc('\n', stderr);
}
-static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u8 import_index, u16 func_index, i8 num_args, const char *fmt) {
- Buffer *instructions = &self->bytecode->data;
- size_t index = instructions->size;
-
- throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(import_index) + sizeof(func_index) + sizeof(num_args)));
- instructions->data[index] = opcode;
- memcpy(instructions->data + index + sizeof(AmalOpcodeType), &import_index, sizeof(import_index));
- memcpy(instructions->data + index + sizeof(AmalOpcodeType) + sizeof(import_index), &func_index, sizeof(func_index));
- memcpy(instructions->data + index + sizeof(AmalOpcodeType) + sizeof(import_index) + sizeof(func_index), &num_args, sizeof(num_args));
- fprintf(stderr, fmt, import_index, func_index, num_args);
- fputc('\n', stderr);
-}
-
static void add_instructions(BytecodeCompilerContext *self) {
/*doc(Bytecode instructions)
# Instructions layout
@@ -459,6 +446,7 @@ static void add_instructions(BytecodeCompilerContext *self) {
SsaInsFuncStart ssa_ins_func_start;
SsaInsFuncCall ssa_ins_func_call;
SsaInsFuncCallExtern ssa_ins_func_call_extern;
+ SsaInsCallStart ssa_ins_call_start;
SsaInsJumpZero ssa_ins_jump_zero;
SsaInsJump ssa_ins_jump;
@@ -547,14 +535,19 @@ static void add_instructions(BytecodeCompilerContext *self) {
add_ins2(self, AMAL_OP_PUSH_RET, reg, "push_ret r%d");
break;
}
+ case SSA_CALL_START: {
+ instruction += ssa_extract_data(instruction, &ssa_ins_call_start, sizeof(ssa_ins_call_start));
+ add_ins2(self, AMAL_OP_CALL_START, ssa_ins_call_start.num_args, "call_start %d");
+ break;
+ }
case SSA_CALL: {
instruction += ssa_extract_data(instruction, &ssa_ins_func_call, sizeof(ssa_ins_func_call));
- add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.import_index, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, "call f(%d,%d), %d");
+ add_ins6(self, AMAL_OP_CALL, ssa_ins_func_call.import_index, ssa_ins_func_call.func_decl->ssa_func_index, "call f(%d,%d)");
break;
}
case SSA_CALL_EXTERN: {
instruction += ssa_extract_data(instruction, &ssa_ins_func_call_extern, sizeof(ssa_ins_func_call_extern));
- add_ins7(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.import_index, ssa_ins_func_call_extern.func_decl_lhs->extern_index, ssa_ins_func_call_extern.num_args, "calle ef(%d,%d), %d");
+ add_ins6(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.import_index, ssa_ins_func_call_extern.func_decl_lhs->extern_index, "calle ef(%d,%d)");
break;
}
case SSA_JUMP_ZERO: {
diff --git a/src/parser.c b/src/parser.c
index ed99eb0..9da9147 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -24,6 +24,7 @@ do { \
#define VAR_MAX_LEN UINT8_MAX
#define FUNC_MAX_PARAMS 128
#define FUNC_MAX_RETURN_TYPES 128
+#define FUNC_MAX_ARGS FUNC_MAX_PARAMS
static CHECK_RESULT Ast* parser_parse_rhs(Parser *self);
static CHECK_RESULT Ast* parser_parse_body(Parser *self);
@@ -425,8 +426,8 @@ static CHECK_RESULT StructDecl* parser_parse_struct_decl(Parser *self) {
FUNC_ARGS = (RHS_START)? (',' RHS_START)* ')'
*/
static void parser_parse_function_args(Parser *self, FunctionCall *func_call) {
- bool first_arg;
- first_arg = bool_true;
+ bool first_arg = bool_true;
+ int arg_index = 0;
for(;;) {
Ast *arg_expr;
@@ -442,6 +443,13 @@ static void parser_parse_function_args(Parser *self, FunctionCall *func_call) {
arg_expr = parser_parse_rhs(self);
throw_if_error(buffer_append(&func_call->args, &arg_expr, sizeof(arg_expr)));
+ ++arg_index;
+ if (arg_index > FUNC_MAX_ARGS) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "A closure can't take more than %d arguments", FUNC_MAX_ARGS);
+ throw(PARSER_ERR);
+ }
}
}
diff --git a/src/program.c b/src/program.c
index 63d2b6e..128f0f9 100644
--- a/src/program.c
+++ b/src/program.c
@@ -570,26 +570,30 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
self->read_index += 1;
break;
}
+ case AMAL_OP_CALL_START: {
+ u8 num_args = self->data.data[self->read_index];
+ return_if_error(amal_exec_call_start(executor, num_args));
+ self->read_index += 1;
+ break;
+ }
case AMAL_OP_CALL: {
u8 import_index;
u16 func_index;
- u8 num_args;
BytecodeHeaderFunction func_def;
i8 dst_reg;
am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index));
am_memcpy(&func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(func_index));
- am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(func_index), sizeof(num_args));
amal_program_get_header_function_by_index(self, import_index, func_index, &func_def);
assert(func_def.num_return_types == 1 && "TODO: Support 0 and more than 1 return values");
assert(self->return_value_index == 1);
dst_reg = self->return_values_stack[0];
- self->return_value_index -= func_def.num_return_types;
+ self->return_value_index = 0;
/* func_offset will only be non-zero when the function has been decoded (FUNC_START) */
if(func_def.func_offset != 0) {
/* TODO: Instead of pushing num args, push the sum of sizeof the last num_args */
- return_if_error(amal_exec_call(executor, func_def.func_offset, num_args, dst_reg));
+ return_if_error(amal_exec_call(executor, func_def.func_offset, dst_reg));
} else {
/*
The code for the function has not been generated yet (the function is defined after the current location).
@@ -609,24 +613,23 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
return_if_error(hash_map_insert(&self->deferred_func_calls, key_mem, &new_deferred_call_list));
}
/* Dummy call to offset 0, offset will be replace later when the target function hits AMAL_OP_FUNC_START */
- return_if_error(amal_exec_call(executor, 0, num_args, dst_reg));
+ return_if_error(amal_exec_call(executor, 0, dst_reg));
}
- self->read_index += 4;
+ self->read_index += 3;
break;
}
- case AMAL_OP_CALLR:
+ case AMAL_OP_CALLR: {
assert(bool_false && "TODO: Implement CALLR");
- self->read_index += 2;
+ self->read_index += 1;
break;
+ }
case AMAL_OP_CALLE: {
u8 import_index;
u16 extern_func_index;
- u8 num_args;
i8 dst_reg;
am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index));
am_memcpy(&extern_func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(extern_func_index));
- am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(extern_func_index), sizeof(num_args));
assert(self->return_value_index == 1 && "TODO: Support extern functions that don't return any value");
dst_reg = self->return_values_stack[0];
self->return_value_index = 0;
@@ -634,9 +637,9 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
{
ProgramExternFunc extern_func;
return_if_error(amal_program_get_extern_func_by_index(self, import_index, extern_func_index, &extern_func));
- return_if_error(amal_exec_calle(executor, extern_func.func, num_args, dst_reg));
+ return_if_error(amal_exec_calle(executor, extern_func.func, dst_reg));
}
- self->read_index += 4;
+ self->read_index += 3;
break;
}
case AMAL_OP_CMP: {
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 19aa036..13f19a9 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -25,6 +25,7 @@ do { \
/* Max length of a string that fits in u16 */
#define MAX_STRING_LENGTH UINT16_MAX
+#define FUNC_MAX_ARGS 128
static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context);
@@ -323,24 +324,30 @@ static CHECK_RESULT int ssa_ins_push_ret(Ssa *self, SsaRegister reg) {
return buffer_append(&self->instructions, &reg, sizeof(reg));
}
-static CHECK_RESULT int ssa_ins_call(Ssa *self, int import_index, FunctionDecl *func_decl, u8 num_args) {
+static CHECK_RESULT int ssa_ins_call_start(Ssa *self, u8 num_args) {
+ const u8 ins_type = SSA_CALL_START;
+ SsaInsCallStart ins_call_start;
+ ins_call_start.num_args = num_args;
+ return_if_error(buffer_append(&self->instructions, &ins_type, 1));
+ return buffer_append(&self->instructions, &ins_call_start, sizeof(ins_call_start));
+}
+
+static CHECK_RESULT int ssa_ins_call(Ssa *self, int import_index, FunctionDecl *func_decl) {
const u8 ins_type = SSA_CALL;
SsaInsFuncCall ins_func_call;
- ins_func_call.num_args = num_args;
ins_func_call.func_decl = func_decl;
ins_func_call.import_index = import_index;
- amal_log_debug("CALL %d, f(%d,%p)", num_args, import_index, func_decl);
+ amal_log_debug("CALL f(%d,%p)", import_index, func_decl);
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return buffer_append(&self->instructions, &ins_func_call, sizeof(ins_func_call));
}
-static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, int import_index, LhsExpr *func_decl_lhs, u8 num_args) {
+static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, int import_index, LhsExpr *func_decl_lhs) {
const u8 ins_type = SSA_CALL_EXTERN;
SsaInsFuncCallExtern ins_func_call_extern;
- ins_func_call_extern.num_args = num_args;
ins_func_call_extern.func_decl_lhs = func_decl_lhs;
ins_func_call_extern.import_index = import_index;
- amal_log_debug("CALL_EXTERN %d, ef(%d,%p)", num_args, import_index, func_decl_lhs);
+ amal_log_debug("CALL_EXTERN ef(%d,%p)", import_index, func_decl_lhs);
return_if_error(buffer_append(&self->instructions, &ins_type, 1));
return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern));
}
@@ -635,14 +642,16 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstResolveData *resolve_data, SsaCompilerContext *context) {
SsaRegister reg;
+ FunctionSignature *func_sig;
FunctionDecl *func_decl;
LhsExpr *func_lhs_expr;
int import_index = context->import_index;
context->import_index = 0;
throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
- func_decl = resolve_data->type.value.func_sig->func_decl;
assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG);
+ func_sig = resolve_data->type.value.func_sig;
+ func_decl = func_sig->func_decl;
func_lhs_expr = NULL;
if(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR)
func_lhs_expr = self->func.resolved_var.value.lhs_expr;
@@ -654,24 +663,41 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstRes
all of them into account. Right now it only uses one return type.
It should also take into account the size of the type.
*/
+ assert(buffer_get_size(&func_sig->return_types, FunctionReturnType) <= 1);
throw_if_error(ssa_ins_push_ret(context->ssa, reg));
}
/* Push parameter arguments */
+ assert(buffer_get_size(&self->args, Ast*) <= FUNC_MAX_ARGS);
{
+ SsaRegister arg_regs[FUNC_MAX_ARGS];
+
Ast **arg = buffer_begin(&self->args);
Ast **arg_end = buffer_end(&self->args);
for(; arg != arg_end; ++arg) {
- SsaRegister arg_reg = ast_generate_ssa(*arg, context);
- throw_if_error(ssa_ins_push(context->ssa, arg_reg));
+ arg_regs[arg_end - arg] = ast_generate_ssa(*arg, context);
+ }
+
+ /*
+ This is done in two steps since first we want the argument expressions to be generated
+ and then at the end, push the registers.
+ This allows Amalgam to push arguments directly to registers on abi that uses registers as function arguments (system-v x86_64)
+ instead of first pushing the registers to stack and then moving them to registers.
+ */
+
+ arg = buffer_begin(&self->args);
+ throw_if_error(ssa_ins_call_start(context->ssa, arg_end - arg));
+ for(; arg != arg_end; ++arg) {
+ throw_if_error(ssa_ins_push(context->ssa, arg_regs[arg_end - arg]));
}
}
if(func_lhs_expr && LHS_EXPR_IS_EXTERN(func_lhs_expr)) {
- throw_if_error(ssa_ins_call_extern(context->ssa, import_index, func_lhs_expr, buffer_get_size(&self->args, Ast*)));
+ throw_if_error(ssa_ins_call_extern(context->ssa, import_index, func_lhs_expr));
} else {
+ assert(func_decl);
/* rhs wont be null here because only extern variable can't have rhs */
- throw_if_error(ssa_ins_call(context->ssa, import_index, func_decl, buffer_get_size(&self->args, Ast*)));
+ throw_if_error(ssa_ins_call(context->ssa, import_index, func_decl));
}
return reg;