From a96a0cac034e16dcd7455a3b2fabf2b5b3e716bd Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 12:20:04 -0300 Subject: 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. --- examples/if.pipa | 18 +++++- src/gas_assembly_generator.c | 133 +++++++++++++++++++++++++++++++------------ src/gas_assembly_generator.h | 4 +- 3 files changed, 117 insertions(+), 38 deletions(-) diff --git a/examples/if.pipa b/examples/if.pipa index d65fc24..79f5724 100644 --- a/examples/if.pipa +++ b/examples/if.pipa @@ -1,6 +1,18 @@ fn main(): i32 { let n: i32 = 11; + let falsy: bool = false || n == 11 && n > 11; + let truth: bool = n + 1 > 11 && n - 1 < 11; + let literal_falsy: bool = false; + + if falsy { + return 201; + } + + if literal_falsy { + return 200; + } + if (n == 11) { if n != 12 { if n < 12 { @@ -15,7 +27,6 @@ fn main(): i32 { if false || false { return 199; } - if true || false { if false || true { if true && false { @@ -32,7 +43,10 @@ fn main(): i32 { if false || n >= 11 && n <= 11 { if false || false && false && false || true { if n + 1 > 11 && n - 1 < 11 { - return 42; + if truth { + return 42; + } + return 14; } return 13; } 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 @@ -57,6 +57,13 @@ gas_assembly_generator_set_latest_evaluation_as_literal(gas_assembly_generator_t (evaluation_result_t){ .kind = EVALUATION_RESULT_AS_LITERAL_INTEGER, .data = { .literal_int = value } }; } +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) { @@ -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,12 +258,26 @@ 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 } } +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) @@ -222,30 +285,7 @@ gas_assembly_generator_compile_variable_assignment(gas_assembly_generator_t *gen 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; -- cgit v1.2.3