diff options
-rw-r--r-- | examples/if.pipa | 50 | ||||
-rw-r--r-- | src/gas_assembly_generator.c | 109 | ||||
-rw-r--r-- | src/gas_assembly_generator.h | 2 |
3 files changed, 130 insertions, 31 deletions
diff --git a/examples/if.pipa b/examples/if.pipa index b7cadcb..d65fc24 100644 --- a/examples/if.pipa +++ b/examples/if.pipa @@ -7,12 +7,60 @@ fn main(): i32 { if n <= 11 { if n > 10 { if n >= 11 { - return 42; + if n >= 11 || n < 11 { + if n > 11 || n < 11 { + return 199; + } + if n > 11 || n <= 11 { + if false || false { + return 199; + } + + if true || false { + if false || true { + if true && false { + return 197; + } + if false && true { + return 196; + } + if true && true { + if n >= 11 && n < 11 || n == 11 { + if false || n == 11 && n > 11 { + return 195; + } + if false || n >= 11 && n <= 11 { + if false || false && false && false || true { + if n + 1 > 11 && n - 1 < 11 { + return 42; + } + return 13; + } + return 12; + } + return 11; + } + return 10; + } + return 9; + } + return 8; + } + return 7; + } + return 6; + } + return 5; } + return 4; } + return 3; } + return 2; } + return 1; } + return 0; } return n; diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index f63e35b..c85d7a7 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -109,7 +109,7 @@ gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream) gen->stream = stream; gen->refs = vector_new(); gen->stack_offset = 0; - gen->label_counter = 0; + gen->cur_label_index = 0; } void @@ -344,7 +344,6 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar if (binary_operation->kind == AST_BINOP_LT || binary_operation->kind == AST_BINOP_GT || binary_operation->kind == AST_BINOP_EQUAL || binary_operation->kind == AST_BINOP_NOT_EQUAL || - binary_operation->kind == AST_BINOP_AND || binary_operation->kind == AST_BINOP_OR || binary_operation->kind == AST_BINOP_GT || binary_operation->kind == AST_BINOP_LT || binary_operation->kind == AST_BINOP_LT_EQUAL || binary_operation->kind == AST_BINOP_GT_EQUAL) { fprintf(gen->stream, " cmp %%rcx, %%rax\n"); @@ -354,51 +353,103 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar assert(false && "No strategy defined for binary operation"); } +static char *jump_map[AST_BINOP_N] = { + [AST_BINOP_EQUAL] = "je", [AST_BINOP_NOT_EQUAL] = "jne", [AST_BINOP_LT] = "jl", + [AST_BINOP_LT_EQUAL] = "jle", [AST_BINOP_GT] = "jg", [AST_BINOP_GT_EQUAL] = "jge", +}; + +static char *inverse_jump_map[AST_BINOP_N] = { + [AST_BINOP_EQUAL] = "jne", [AST_BINOP_NOT_EQUAL] = "je", [AST_BINOP_LT] = "jge", + [AST_BINOP_LT_EQUAL] = "jg", [AST_BINOP_GT] = "jle", [AST_BINOP_GT_EQUAL] = "jl", +}; + static void -gas_assembly_generator_compile_binop_if(gas_assembly_generator_t *gen, ast_node_t *binop_node) +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) { - assert(binop_node->kind == AST_BINARY_OPERATION); + assert(condition->kind == AST_BINARY_OPERATION || condition->kind == AST_LITERAL); + + if (condition->kind == AST_LITERAL) { + assert(condition->data.literal.kind == AST_LITERAL_BOOL); + + if (jump_when_false && !condition->data.literal.value.boolean) { + fprintf(gen->stream, " jmp .L_%ld\n", false_label_index); + return; + } + + if (jump_when_true && condition->data.literal.value.boolean) { + fprintf(gen->stream, " jmp .L_%ld\n", true_label_index); + } + + return; + } + + if (condition->data.binary_operation.kind == AST_BINOP_OR) { + uint64_t or_false_branch_label_index = gen->cur_label_index++; + + gas_assembly_generator_compile_condition( + gen, condition->data.binary_operation.left, true_label_index, true, or_false_branch_label_index, false); + + fprintf(gen->stream, ".L_%ld:\n", or_false_branch_label_index); + + gas_assembly_generator_compile_condition( + gen, condition->data.binary_operation.right, true_label_index, false, false_label_index, true); + return; + } + + if (condition->data.binary_operation.kind == AST_BINOP_AND) { + uint64_t and_true_branch_label_index = gen->cur_label_index++; - char *jump_map[AST_BINOP_N] = { - [AST_BINOP_EQUAL] = "jne", [AST_BINOP_NOT_EQUAL] = "je", [AST_BINOP_LT] = "jge", - [AST_BINOP_LT_EQUAL] = "jg", [AST_BINOP_GT] = "jle", [AST_BINOP_GT_EQUAL] = "jl", - }; + gas_assembly_generator_compile_condition( + gen, condition->data.binary_operation.left, and_true_branch_label_index, false, false_label_index, true); - char *jumper = jump_map[binop_node->data.binary_operation.kind]; + fprintf(gen->stream, ".L_%ld:\n", and_true_branch_label_index); - assert(jumper != NULL); + gas_assembly_generator_compile_condition( + gen, condition->data.binary_operation.right, true_label_index, false, false_label_index, true); + return; + } + + gas_assembly_generator_compile(gen, condition); + + if (jump_when_false) { + char *jumper = inverse_jump_map[condition->data.binary_operation.kind]; + + assert(jumper != NULL); + + fprintf(gen->stream, " %s .L_%ld\n", jumper, false_label_index); + return; + } + + if (jump_when_true) { + char *jumper = jump_map[condition->data.binary_operation.kind]; - gas_assembly_generator_compile(gen, binop_node); + assert(jumper != NULL); - fprintf(gen->stream, " %s .IF%ld\n", jumper, gen->label_counter); + fprintf(gen->stream, " %s .L_%ld\n", jumper, true_label_index); + } } static void gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stmt_t *if_stmt) { switch (if_stmt->condition->kind) { + case AST_BINARY_OPERATION: case AST_LITERAL: { - int if_counter = gen->label_counter++; - - assert(if_stmt->condition->data.literal.kind == AST_LITERAL_BOOL); - - if (!if_stmt->condition->data.literal.value.boolean) { - fprintf(gen->stream, " jmp .IF%d\n", if_counter); - } - - gas_assembly_generator_compile(gen, if_stmt->body); - - fprintf(gen->stream, ".IF%d:\n", if_counter); - break; - } - case AST_BINARY_OPERATION: { - gas_assembly_generator_compile_binop_if(gen, if_stmt->condition); + uint64_t true_label_index = gen->cur_label_index++; + uint64_t false_label_index = gen->cur_label_index++; - int if_counter = gen->label_counter++; + gas_assembly_generator_compile_condition( + gen, if_stmt->condition, true_label_index, false, false_label_index, true); + fprintf(gen->stream, ".L_%ld:\n", true_label_index); gas_assembly_generator_compile(gen, if_stmt->body); - fprintf(gen->stream, ".IF%d:\n", if_counter); + fprintf(gen->stream, ".L_%ld:\n", false_label_index); break; } default: diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h index 3d9a43c..2e195fb 100644 --- a/src/gas_assembly_generator.h +++ b/src/gas_assembly_generator.h @@ -46,7 +46,7 @@ typedef struct gas_assembly_generator_t FILE *stream; vector_t *refs; int stack_offset; - uint64_t label_counter; + uint64_t cur_label_index; evaluation_result_t latest_evaluation; } gas_assembly_generator_t; |