summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2023-04-30 19:16:42 +0200
committerJohnny Richard <johnny@johnnyrichard.com>2023-04-30 19:26:30 +0200
commitb1e8b4f24927efc6ed68420e4f579fb20ab831a9 (patch)
tree119496bacb2758cee773138f0bd3a452c8b6ec60
parentefe28f579b8720ea506a4e5d24ec0290223b8745 (diff)
gas: Optimize variable reference on assembly
We were moving the stack data for variable reference to another stack position ending up with two pointer to the same value. // a: i32 = 1; mov $1, -8(%rbp) // b: i32 = a; mov -8(%rbp), %rax mov %rax, -24(%rbp) mov -24(%rbp), %rax mov %rax, -16(%rbp) After this changes, we wont create a new temp space on stack if we don't need it. See bellow the example after the optimization: // a: i32 = 1; mov $1, -8(%rbp) // b: i32 = a; mov -8(%rbp), %rax mov %rax, -16(%rbp) Signed-off-by: Johnny Richard <johnny@johnnyrichard.com> Co-authored-by: Carlos Maniero <carlosmaniero@gmail.com>
-rw-r--r--examples/variables.pipa3
-rw-r--r--src/gas_assembly_generator.c34
-rw-r--r--src/gas_assembly_generator.h2
3 files changed, 32 insertions, 7 deletions
diff --git a/examples/variables.pipa b/examples/variables.pipa
index 9c395ce..25cbd59 100644
--- a/examples/variables.pipa
+++ b/examples/variables.pipa
@@ -3,5 +3,6 @@ main(): i32 {
b: i32 = 32;
c: i32 = 2 * (b + a);
d: i32 = (c - 33) + 1;
- return d / 2;
+ e: i32 = d;
+ return e / 2;
}
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c
index b9b8537..dd5d240 100644
--- a/src/gas_assembly_generator.c
+++ b/src/gas_assembly_generator.c
@@ -54,6 +54,13 @@ gas_assembly_generator_set_latest_evaluation_to_rax(gas_assembly_generator_t *ge
gen->latest_evaluation = (evaluation_result_t){ .kind = EVALUATION_RESULT_ON_RAX };
}
+static void
+gas_assembly_generator_set_latest_evaluation_on_stack(gas_assembly_generator_t *gen, int stack_offset)
+{
+ gen->latest_evaluation =
+ (evaluation_result_t){ .kind = EVALUATION_RESULT_ON_STACK, .data = { .stack_offset = stack_offset } };
+}
+
typedef struct ref_entry_t
{
ast_identifier_t *id;
@@ -167,11 +174,15 @@ gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *ge
switch (gen->latest_evaluation.kind) {
case EVALUATION_RESULT_AS_LITERAL_INTEGER:
- fprintf(gen->stream, " mov $%ld, %d(%%rbp)\n", gen->latest_evaluation.data.literal_int, entry->stack_offset);
+ fprintf(gen->stream, " movq $%ld, %d(%%rbp)\n", gen->latest_evaluation.data.literal_int, entry->stack_offset);
break;
case EVALUATION_RESULT_ON_RAX:
fprintf(gen->stream, " mov %%rax, %d(%%rbp)\n", entry->stack_offset);
break;
+ case EVALUATION_RESULT_ON_STACK:
+ fprintf(gen->stream, " movq %d(%%rbp), %%rax\n", gen->latest_evaluation.data.stack_offset);
+ fprintf(gen->stream, " movq %%rax, %d(%%rbp)\n", entry->stack_offset);
+ break;
case EVALUATION_RESULT_VOID:
assert(false && "Unexpected void result for variable declaration");
// FIXME: store the latest node at latest evaluation and print_ast
@@ -190,8 +201,7 @@ gas_assembly_generator_compile_variable(gas_assembly_generator_t *gen, ast_varia
}
}
assert(entry && "reference not found");
- fprintf(gen->stream, " mov %d(%%rbp), %%rax\n", entry->stack_offset);
- gas_assembly_generator_set_latest_evaluation_to_rax(gen);
+ gas_assembly_generator_set_latest_evaluation_on_stack(gen, entry->stack_offset);
}
static void
@@ -228,15 +238,27 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar
fprintf(gen->stream, " mov %d(%%rbp), %%rcx\n", gen->stack_offset);
gen->stack_offset += 8;
break;
+ case EVALUATION_RESULT_ON_STACK:
+ fprintf(gen->stream, " movq %d(%%rbp), %%rcx\n", right_evaluation.data.stack_offset);
+ break;
case EVALUATION_RESULT_VOID:
- assert(false && "Unexpected void result for variable declaration");
+ assert(false && "Unexpected void result for binary operation");
// FIXME: store the latest node at latest evaluation and print_ast
}
gas_assembly_generator_set_latest_evaluation_to_rax(gen);
- if (left_evaluation.kind == EVALUATION_RESULT_AS_LITERAL_INTEGER) {
- fprintf(gen->stream, " mov $%ld, %%rax\n", left_evaluation.data.literal_int);
+ switch (left_evaluation.kind) {
+ case EVALUATION_RESULT_AS_LITERAL_INTEGER:
+ fprintf(gen->stream, " mov $%ld, %%rax\n", left_evaluation.data.literal_int);
+ break;
+ case EVALUATION_RESULT_ON_STACK:
+ fprintf(gen->stream, " movq %d(%%rbp), %%rax\n", left_evaluation.data.stack_offset);
+ break;
+ case EVALUATION_RESULT_ON_RAX:
+ break;
+ case EVALUATION_RESULT_VOID:
+ assert(false && "Unexpected void result for binary operation");
}
if (binary_operation->kind == AST_BINOP_ADITION) {
diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h
index 8501a67..92972f9 100644
--- a/src/gas_assembly_generator.h
+++ b/src/gas_assembly_generator.h
@@ -25,12 +25,14 @@ typedef enum evaluation_result_kind_t
{
EVALUATION_RESULT_VOID,
EVALUATION_RESULT_ON_RAX,
+ EVALUATION_RESULT_ON_STACK,
EVALUATION_RESULT_AS_LITERAL_INTEGER
} evaluation_result_kind_t;
typedef union evaluation_result_data_t
{
int64_t literal_int;
+ int stack_offset;
} evaluation_result_data_t;
typedef struct evaluation_result_t