summaryrefslogtreecommitdiff
path: root/src/gas_assembly_generator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gas_assembly_generator.c')
-rw-r--r--src/gas_assembly_generator.c133
1 files changed, 98 insertions, 35 deletions
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c
index c85d7a7..44467db 100644
--- a/src/gas_assembly_generator.c
+++ b/src/gas_assembly_generator.c
@@ -58,6 +58,13 @@ gas_assembly_generator_set_latest_evaluation_as_literal(gas_assembly_generator_t
}
static void
+gas_assembly_generator_set_latest_evaluation_as_literal_boolean(gas_assembly_generator_t *gen, bool value)
+{
+ gen->latest_evaluation =
+ (evaluation_result_t){ .kind = EVALUATION_RESULT_AS_LITERAL_BOOL, .data = { .literal_bool = value } };
+}
+
+static void
gas_assembly_generator_set_latest_evaluation_to_rax(gas_assembly_generator_t *gen)
{
gen->latest_evaluation = (evaluation_result_t){ .kind = EVALUATION_RESULT_ON_RAX };
@@ -70,6 +77,14 @@ gas_assembly_generator_set_latest_evaluation_on_stack(gas_assembly_generator_t *
(evaluation_result_t){ .kind = EVALUATION_RESULT_ON_STACK, .data = { .stack_offset = stack_offset } };
}
+static void
+gas_assembly_generator_compile_condition(gas_assembly_generator_t *gen,
+ ast_node_t *condition,
+ uint64_t true_label_index,
+ bool jump_when_true,
+ uint64_t false_label_index,
+ bool jump_when_false);
+
typedef struct ref_entry_t
{
ast_identifier_t *id;
@@ -178,25 +193,59 @@ gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_re
gas_assembly_generator_compile(gen, return_stmt->argument);
- if (gen->latest_evaluation.kind == EVALUATION_RESULT_AS_LITERAL_INTEGER) {
- fprintf(gen->stream, " mov $%ld, %%rdi\n", gen->latest_evaluation.data.literal_int);
- } else {
- fprintf(gen->stream, " mov %%rax, %%rdi\n");
+ switch (gen->latest_evaluation.kind) {
+ case EVALUATION_RESULT_AS_LITERAL_INTEGER:
+ fprintf(gen->stream, " mov $%ld, %%rdi\n", gen->latest_evaluation.data.literal_int);
+ break;
+ case EVALUATION_RESULT_ON_RAX:
+ fprintf(gen->stream, " mov %%rax, %%rdi\n");
+ break;
+ case EVALUATION_RESULT_ON_STACK:
+ fprintf(gen->stream, " mov %d(%%rbp), %%rdi\n", gen->latest_evaluation.data.stack_offset);
+ break;
+ case EVALUATION_RESULT_VOID:
+ fprintf(gen->stream, " xor %%rdi, %%rdi\n");
+ break;
+ case EVALUATION_RESULT_AS_LITERAL_BOOL:
+ assert(false && "Unexpected");
+ break;
}
+
fprintf(gen->stream, " mov $60, %%rax\n");
fprintf(gen->stream, " syscall\n");
}
static void
-gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *gen,
- ast_variable_declaration_t *variable_declaration)
+gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *gen,
+ ast_node_t *expression,
+ ref_entry_t *entry)
{
- gen->stack_offset -= 8;
- gas_assembly_generator_compile(gen, variable_declaration->value);
+ if (expression->result_type == TYPE_BOOL) {
+ if (expression->kind == AST_LITERAL) {
+ assert(expression->data.literal.kind == AST_LITERAL_BOOL);
- ref_entry_t *entry = ref_entry_new();
- *entry = (ref_entry_t){ .id = &variable_declaration->identifier, .stack_offset = gen->stack_offset };
- vector_push_back(gen->refs, entry);
+ fprintf(gen->stream, " movq $%d, %d(%%rbp)\n", expression->data.literal.value.boolean, entry->stack_offset);
+ return;
+ }
+
+ uint64_t true_label_index = gen->cur_label_index++;
+ uint64_t false_label_index = gen->cur_label_index++;
+ uint64_t after_assign_label_index = gen->cur_label_index++;
+
+ gas_assembly_generator_compile_condition(gen, expression, true_label_index, false, false_label_index, true);
+
+ fprintf(gen->stream, ".L_%ld:\n", true_label_index);
+ fprintf(gen->stream, " movq $1, %d(%%rbp)\n", entry->stack_offset);
+ fprintf(gen->stream, " jmp .L_%ld\n", after_assign_label_index);
+
+ fprintf(gen->stream, ".L_%ld:\n", false_label_index);
+ fprintf(gen->stream, " movq $0, %d(%%rbp)\n", entry->stack_offset);
+
+ fprintf(gen->stream, ".L_%ld:\n", after_assign_label_index);
+ return;
+ }
+
+ gas_assembly_generator_compile(gen, expression);
switch (gen->latest_evaluation.kind) {
case EVALUATION_RESULT_AS_LITERAL_INTEGER:
@@ -209,6 +258,7 @@ gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *ge
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_AS_LITERAL_BOOL:
case EVALUATION_RESULT_VOID:
assert(false && "Unexpected void result for variable declaration");
// FIXME: store the latest node at latest evaluation and print_ast
@@ -216,36 +266,26 @@ gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *ge
}
static void
+gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *gen,
+ ast_variable_declaration_t *variable_declaration)
+{
+ gen->stack_offset -= 8;
+
+ ref_entry_t *entry = ref_entry_new();
+ *entry = (ref_entry_t){ .id = &variable_declaration->identifier, .stack_offset = gen->stack_offset };
+ vector_push_back(gen->refs, entry);
+
+ gas_assembly_generator_compile_variable_assign_value(gen, variable_declaration->value, entry);
+}
+
+static void
gas_assembly_generator_compile_variable_assignment(gas_assembly_generator_t *gen,
ast_variable_assignment_t *variable_assignment)
{
ref_entry_t *entry = find_ref_entry(gen->refs, variable_assignment->identifier);
assert(entry && "reference not found");
- gas_assembly_generator_compile(gen, variable_assignment->expression);
-
- switch (gen->latest_evaluation.kind) {
- case EVALUATION_RESULT_AS_LITERAL_INTEGER:
- 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
- }
- // Today we dont't support chain-assignment like this:
- //
- // a = b = 1;
- //
- // If we start supporting it, we need to change the latest evaluation kind to
- // stack.
- gen->latest_evaluation.kind = EVALUATION_RESULT_VOID;
+ gas_assembly_generator_compile_variable_assign_value(gen, variable_assignment->expression, entry);
}
static void
@@ -263,6 +303,9 @@ gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_litera
case AST_LITERAL_INTEGER:
gas_assembly_generator_set_latest_evaluation_as_literal(gen, literal->value.integer);
return;
+ case AST_LITERAL_BOOL:
+ gas_assembly_generator_set_latest_evaluation_as_literal_boolean(gen, literal->value.boolean);
+ return;
default:
assert(false && "no code generation strategy.");
}
@@ -301,6 +344,9 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar
case EVALUATION_RESULT_ON_STACK:
fprintf(gen->stream, " movq %d(%%rbp), %%rcx\n", right_evaluation.data.stack_offset);
break;
+ case EVALUATION_RESULT_AS_LITERAL_BOOL:
+ fprintf(gen->stream, " mov $%d, %%rcx\n", right_evaluation.data.literal_bool);
+ break;
case EVALUATION_RESULT_VOID:
assert(false && "Unexpected void result for binary operation");
// FIXME: store the latest node at latest evaluation and print_ast
@@ -317,6 +363,9 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar
break;
case EVALUATION_RESULT_ON_RAX:
break;
+ case EVALUATION_RESULT_AS_LITERAL_BOOL:
+ fprintf(gen->stream, " mov $%d, %%rax\n", left_evaluation.data.literal_bool);
+ break;
case EVALUATION_RESULT_VOID:
assert(false && "Unexpected void result for binary operation");
}
@@ -452,6 +501,20 @@ gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stm
fprintf(gen->stream, ".L_%ld:\n", false_label_index);
break;
}
+ case AST_VARIABLE: {
+ uint64_t false_label_index = gen->cur_label_index++;
+ ref_entry_t *entry = find_ref_entry(gen->refs, if_stmt->condition->data.variable.identifier);
+
+ fprintf(gen->stream, " movq %d(%%rbp), %%rax\n", entry->stack_offset);
+ fprintf(gen->stream, " cmpq $1, %%rax\n");
+ fprintf(gen->stream, " jne .L_%ld\n", false_label_index);
+
+ gas_assembly_generator_compile(gen, if_stmt->body);
+
+ fprintf(gen->stream, ".L_%ld:\n", false_label_index);
+ assert(entry);
+ break;
+ }
default:
assert(false);
}