summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-10 12:20:04 -0300
committerCarlos Maniero <carlos@maniero.me>2023-05-10 12:20:04 -0300
commita96a0cac034e16dcd7455a3b2fabf2b5b3e716bd (patch)
treefcd4d81007bba0dd934e136f78b195371e5f0326 /src
parent88630ebbea03e85119cf9795320a83cb846bdd20 (diff)
gas: Compile boolean variable assignment
When the assignment value is a literal, it just assigns zero or one to the variable stack's location. If the value is an expression, it compiles the expression and assign zeros and ones based on expression result.
Diffstat (limited to 'src')
-rw-r--r--src/gas_assembly_generator.c133
-rw-r--r--src/gas_assembly_generator.h4
2 files changed, 101 insertions, 36 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);
}
diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h
index 2e195fb..e400d2c 100644
--- a/src/gas_assembly_generator.h
+++ b/src/gas_assembly_generator.h
@@ -26,12 +26,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_AS_LITERAL_INTEGER,
+ EVALUATION_RESULT_AS_LITERAL_BOOL
} evaluation_result_kind_t;
typedef union evaluation_result_data_t
{
int64_t literal_int;
+ bool literal_bool;
int stack_offset;
} evaluation_result_data_t;