From 5de2e1fd9f426348127a66d2c51c300cb90cc3a4 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 00:20:00 -0300 Subject: gas: Generate code for if statement If statements are now working, the only exception is for the comparators || and && that will be addressed in a further commit. Checks tested: fn main(): i32 { let n: i32 = 11; if (n == 11) { if n != 12 { if n < 12 { if n <= 11 { if n > 10 { if n >= 11 { return 42; } } } } } } return n; } To compile the && and || a precedence issue must be addressed: they must have the highest precedence, witch is not working now: 1 == 2 || 3 != 2 The or should be the higher level of the tree in the example above. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 4b898ed..f63e35b 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -44,6 +44,9 @@ gas_assembly_generator_compile_variable_assignment(gas_assembly_generator_t *gen static void gas_assembly_generator_compile_block(gas_assembly_generator_t *gen, ast_block_t *block); +static void +gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stmt_t *if_stmt); + static void gas_assembly_generator_compile_variable(gas_assembly_generator_t *gen, ast_variable_t *variable); @@ -106,6 +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; } void @@ -139,6 +143,8 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) gas_assembly_generator_compile_block(gen, &ast->data.block); break; case AST_IF_STMT: + gas_assembly_generator_compile_if_stmt(gen, &ast->data.if_stmt); + break; case AST_UNKOWN_NODE: assert(false && "unreachable"); } @@ -336,5 +342,66 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar return; } + 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"); + return; + } + assert(false && "No strategy defined for binary operation"); } + +static void +gas_assembly_generator_compile_binop_if(gas_assembly_generator_t *gen, ast_node_t *binop_node) +{ + assert(binop_node->kind == AST_BINARY_OPERATION); + + 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", + }; + + char *jumper = jump_map[binop_node->data.binary_operation.kind]; + + assert(jumper != NULL); + + gas_assembly_generator_compile(gen, binop_node); + + fprintf(gen->stream, " %s .IF%ld\n", jumper, gen->label_counter); +} + +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_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); + + int if_counter = gen->label_counter++; + + gas_assembly_generator_compile(gen, if_stmt->body); + + fprintf(gen->stream, ".IF%d:\n", if_counter); + break; + } + default: + assert(false); + } +} -- cgit v1.2.3 From 88630ebbea03e85119cf9795320a83cb846bdd20 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 01:43:40 -0300 Subject: gas: Implement && and || for if statements Now if statements are complete! The function %gas_assembly_generator_compile_condition% is generic and will be used for any other flow-control statment. The only requirement to it work is having two labels: One to jump when the condition is true, and another one when the condition is false. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 109 +++++++++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 29 deletions(-) (limited to 'src/gas_assembly_generator.c') 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: -- cgit v1.2.3 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. --- src/gas_assembly_generator.c | 133 +++++++++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 35 deletions(-) (limited to 'src/gas_assembly_generator.c') 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); } -- cgit v1.2.3 From f1b1c191975581d5ef13bd04f33b6965235d00b4 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 13:53:53 -0300 Subject: gas: Abstract refs with helper functions This commit abstract the complexity of an entry so then, the users of the ref map does not need to understand how is it implemented. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 60 +++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 44467db..97ba9ce 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -105,16 +105,29 @@ ref_entry_new(void) return entry; } -static ref_entry_t * -find_ref_entry(vector_t *refs, ast_identifier_t *identifier) +static int +ref_find_variable_reference_stack_offset(vector_t *refs, ast_identifier_t *identifier) { for (int i = refs->size - 1; i >= 0; --i) { ref_entry_t *entry = (ref_entry_t *)vector_at(refs, i); if (entry->id == identifier) { - return entry; + return entry->stack_offset; } } - return NULL; + assert(false); +} + +static void +ref_set_variable_reference_stack_offset(vector_t *refs, ast_identifier_t *identifier, int stack_offset) +{ + ref_entry_t *ref_entry = ref_entry_new(); + + *ref_entry = (ref_entry_t){ + .id = identifier, + .stack_offset = stack_offset, + }; + + vector_push_back(refs, ref_entry); } void @@ -218,13 +231,13 @@ gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_re static void gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *gen, ast_node_t *expression, - ref_entry_t *entry) + int stack_offset) { if (expression->result_type == TYPE_BOOL) { if (expression->kind == AST_LITERAL) { assert(expression->data.literal.kind == AST_LITERAL_BOOL); - fprintf(gen->stream, " movq $%d, %d(%%rbp)\n", expression->data.literal.value.boolean, entry->stack_offset); + fprintf(gen->stream, " movq $%d, %d(%%rbp)\n", expression->data.literal.value.boolean, stack_offset); return; } @@ -235,11 +248,11 @@ gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *g 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, " movq $1, %d(%%rbp)\n", 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, " movq $0, %d(%%rbp)\n", stack_offset); fprintf(gen->stream, ".L_%ld:\n", after_assign_label_index); return; @@ -249,14 +262,14 @@ gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *g 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); + fprintf(gen->stream, " movq $%ld, %d(%%rbp)\n", gen->latest_evaluation.data.literal_int, stack_offset); break; case EVALUATION_RESULT_ON_RAX: - fprintf(gen->stream, " mov %%rax, %d(%%rbp)\n", entry->stack_offset); + fprintf(gen->stream, " mov %%rax, %d(%%rbp)\n", 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); + fprintf(gen->stream, " movq %%rax, %d(%%rbp)\n", stack_offset); break; case EVALUATION_RESULT_AS_LITERAL_BOOL: case EVALUATION_RESULT_VOID: @@ -270,30 +283,25 @@ gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *ge 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); + ref_set_variable_reference_stack_offset(gen->refs, &variable_declaration->identifier, gen->stack_offset); + gas_assembly_generator_compile_variable_assign_value(gen, variable_declaration->value, gen->stack_offset); } 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"); + int stack_offset = ref_find_variable_reference_stack_offset(gen->refs, variable_assignment->identifier); - gas_assembly_generator_compile_variable_assign_value(gen, variable_assignment->expression, entry); + gas_assembly_generator_compile_variable_assign_value(gen, variable_assignment->expression, stack_offset); } static void gas_assembly_generator_compile_variable(gas_assembly_generator_t *gen, ast_variable_t *variable) { - ref_entry_t *entry = find_ref_entry(gen->refs, variable->identifier); - assert(entry && "reference not found"); - gas_assembly_generator_set_latest_evaluation_on_stack(gen, entry->stack_offset); + int stack_offset = ref_find_variable_reference_stack_offset(gen->refs, variable->identifier); + + gas_assembly_generator_set_latest_evaluation_on_stack(gen, stack_offset); } static void @@ -503,16 +511,16 @@ gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stm } 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); + int stack_offset = + ref_find_variable_reference_stack_offset(gen->refs, if_stmt->condition->data.variable.identifier); - fprintf(gen->stream, " movq %d(%%rbp), %%rax\n", entry->stack_offset); + fprintf(gen->stream, " movq %d(%%rbp), %%rax\n", 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: -- cgit v1.2.3 From 2cf0bcb409f3a1fd298b664103d57c945c6349f5 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 14:26:40 -0300 Subject: gas: Removes Linux entrypoint logic from function declaration Before this commit, function declarations were making syscalls to interrupt the flow. This is a fair approach considering all our examples just have a main function. But won't work if the namespace has more then a single function. The return now always sets the return value on RAX and jumps to the function return label. The function return label, will restore RBP and jump back to callee's next instruction using RET instruction. Function labels are kept, which means that a function called my_fn will have the assembly label my_fn, so then, they can have INTEROP with other languages. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 83 +++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 20 deletions(-) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 97ba9ce..413fbb0 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -137,7 +137,8 @@ gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream) gen->stream = stream; gen->refs = vector_new(); gen->stack_offset = 0; - gen->cur_label_index = 0; + gen->counter_label_index = 1; + gen->return_label_index = 0; } void @@ -183,28 +184,40 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct { assert(func); - if (!string_view_eq(func->identifier.name, string_view_from_str("main"))) { - fprintf(stderr, "[ERROR]: no main function has been defined!\n"); - exit(EXIT_FAILURE); - } + uint64_t previous_index = gen->return_label_index; + uint64_t return_label_index = gen->return_label_index = gen->counter_label_index++; - fprintf(gen->stream, ".global _start\n"); - fprintf(gen->stream, ".text\n"); - fprintf(gen->stream, "_start:\n"); + fprintf(gen->stream, SVFMT ":\n", SVARG(&func->identifier.name)); fprintf(gen->stream, " push %%rbp\n"); fprintf(gen->stream, " mov %%rsp, %%rbp\n"); gas_assembly_generator_compile(gen, func->body); + fprintf(gen->stream, ".L%ld:\n", return_label_index); fprintf(gen->stream, " pop %%rbp\n"); + fprintf(gen->stream, " ret\n"); + + gen->return_label_index = previous_index; } -static void -gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt) +void +gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *func) { - assert(gen && return_stmt); + assert(func); + assert(func->kind == AST_FUNCTION_DECLARATION); - gas_assembly_generator_compile(gen, return_stmt->argument); + if (!string_view_eq(func->data.function.identifier.name, string_view_from_str("main"))) { + fprintf(stderr, "[ERROR]: no main function has been defined!\n"); + exit(EXIT_FAILURE); + } + + fprintf(gen->stream, ".global _start\n"); + fprintf(gen->stream, ".text\n"); + + gas_assembly_generator_compile(gen, func); + + fprintf(gen->stream, "_start:\n"); + fprintf(gen->stream, " call main\n"); switch (gen->latest_evaluation.kind) { case EVALUATION_RESULT_AS_LITERAL_INTEGER: @@ -228,6 +241,36 @@ gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_re fprintf(gen->stream, " syscall\n"); } +static void +gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt) +{ + assert(gen && return_stmt); + assert(gen->return_label_index != 0 && "There are no return label index set"); + + gas_assembly_generator_compile(gen, return_stmt->argument); + + switch (gen->latest_evaluation.kind) { + case EVALUATION_RESULT_AS_LITERAL_INTEGER: + fprintf(gen->stream, " mov $%ld, %%rax\n", gen->latest_evaluation.data.literal_int); + gas_assembly_generator_set_latest_evaluation_to_rax(gen); + break; + case EVALUATION_RESULT_ON_RAX: + gas_assembly_generator_set_latest_evaluation_to_rax(gen); + break; + case EVALUATION_RESULT_ON_STACK: + fprintf(gen->stream, " mov %d(%%rbp), %%rax\n", gen->latest_evaluation.data.stack_offset); + gas_assembly_generator_set_latest_evaluation_to_rax(gen); + break; + case EVALUATION_RESULT_VOID: + break; + case EVALUATION_RESULT_AS_LITERAL_BOOL: + assert(false && "Unexpected"); + break; + } + + fprintf(gen->stream, " jmp .L%ld\n", gen->return_label_index); +} + static void gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *gen, ast_node_t *expression, @@ -241,9 +284,9 @@ gas_assembly_generator_compile_variable_assign_value(gas_assembly_generator_t *g 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++; + uint64_t true_label_index = gen->counter_label_index++; + uint64_t false_label_index = gen->counter_label_index++; + uint64_t after_assign_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition(gen, expression, true_label_index, false, false_label_index, true); @@ -446,7 +489,7 @@ gas_assembly_generator_compile_condition(gas_assembly_generator_t *gen, } if (condition->data.binary_operation.kind == AST_BINOP_OR) { - uint64_t or_false_branch_label_index = gen->cur_label_index++; + uint64_t or_false_branch_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition( gen, condition->data.binary_operation.left, true_label_index, true, or_false_branch_label_index, false); @@ -459,7 +502,7 @@ gas_assembly_generator_compile_condition(gas_assembly_generator_t *gen, } if (condition->data.binary_operation.kind == AST_BINOP_AND) { - uint64_t and_true_branch_label_index = gen->cur_label_index++; + uint64_t and_true_branch_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition( gen, condition->data.binary_operation.left, and_true_branch_label_index, false, false_label_index, true); @@ -497,8 +540,8 @@ gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stm switch (if_stmt->condition->kind) { case AST_BINARY_OPERATION: case AST_LITERAL: { - uint64_t true_label_index = gen->cur_label_index++; - uint64_t false_label_index = gen->cur_label_index++; + uint64_t true_label_index = gen->counter_label_index++; + uint64_t false_label_index = gen->counter_label_index++; gas_assembly_generator_compile_condition( gen, if_stmt->condition, true_label_index, false, false_label_index, true); @@ -510,7 +553,7 @@ gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stm break; } case AST_VARIABLE: { - uint64_t false_label_index = gen->cur_label_index++; + uint64_t false_label_index = gen->counter_label_index++; int stack_offset = ref_find_variable_reference_stack_offset(gen->refs, if_stmt->condition->data.variable.identifier); -- cgit v1.2.3 From 75639fbf01bd6ae1212521b6cf822025eb8b598d Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 16:07:39 -0300 Subject: namespaces: Add a namespace structure that represents a file We have been always parsing a single function. Since we want to have multiple functions in a near future, this patch introduces an namespace that represents an entire file. To ensure a function is defined inside a namespace, a helper function was created. Today our ast_node structure is highly exposed, and this is something that Johnny and I have been discussed. So then, this is a first step to try to protected the code generation from our ast tree. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 413fbb0..4326b27 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -147,6 +147,9 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) gen->latest_evaluation.kind = EVALUATION_RESULT_VOID; switch (ast->kind) { + case AST_NAMESPACE: + gas_assembly_generator_compile_ns(gen, &ast->data.ns); + break; case AST_BINARY_OPERATION: gas_assembly_generator_binary_operation(gen, &ast->data.binary_operation); break; @@ -179,6 +182,14 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) } } +void +gas_assembly_generator_compile_ns(gas_assembly_generator_t *gen, ast_namespace_t *ns) +{ + for (size_t i = 0; i < ns->nodes->size; i++) { + gas_assembly_generator_compile(gen, vector_at(ns->nodes, i)); + } +} + static void gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func) { @@ -201,12 +212,9 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct } void -gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *func) +gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *ns) { - assert(func); - assert(func->kind == AST_FUNCTION_DECLARATION); - - if (!string_view_eq(func->data.function.identifier.name, string_view_from_str("main"))) { + if (ast_node_ns_get_function_node_by_name(ns, "main") == NULL) { fprintf(stderr, "[ERROR]: no main function has been defined!\n"); exit(EXIT_FAILURE); } @@ -214,7 +222,7 @@ gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_nod fprintf(gen->stream, ".global _start\n"); fprintf(gen->stream, ".text\n"); - gas_assembly_generator_compile(gen, func); + gas_assembly_generator_compile(gen, ns); fprintf(gen->stream, "_start:\n"); fprintf(gen->stream, " call main\n"); -- cgit v1.2.3 From 3129b741064c2b4f2c6c2408bd42cc83f7341ea8 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 16:53:05 -0300 Subject: gas: Generate function call This is an initial commit that enables function calls. At this point only functions with no parameters is going to work. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 4326b27..2d6b993 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -28,6 +28,9 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar static void gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func); +static void +gas_assembly_generator_compile_function_call(gas_assembly_generator_t *gen, ast_function_call_t *func_call); + static void gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_literal_t *literal); @@ -156,6 +159,9 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) case AST_FUNCTION_DECLARATION: gas_assembly_generator_compile_function(gen, &ast->data.function); break; + case AST_FUNCTION_CALL: + gas_assembly_generator_compile_function_call(gen, &ast->data.function_call); + break; case AST_LITERAL: gas_assembly_generator_compile_literal(gen, &ast->data.literal); break; @@ -211,6 +217,13 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct gen->return_label_index = previous_index; } +static void +gas_assembly_generator_compile_function_call(gas_assembly_generator_t *gen, ast_function_call_t *func_call) +{ + fprintf(gen->stream, " call " SVFMT "\n", SVARG(&func_call->identifier->name)); + gas_assembly_generator_set_latest_evaluation_to_rax(gen); +} + void gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *ns) { -- cgit v1.2.3 From 5042a4ffc1363d6f0f99a3afd79f76cf2da738d6 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 22:24:14 -0300 Subject: gas: implement function calls For now function calls are following the C's calling convention, which means they are using the following registers to pass functions' arguments: rdi, rsi, rdx, rcx, r8, r9 If a function has more then 6 parameters, the compilation will fail. To enable function with more than 6 parameters we will need to save the extra arguments on stack. Naming: parameters: function parameters are the variables a function receives. arguments: Arguments are the values passed to a function when calling it. Calling mechanism: When a function is called, all the expressions passed as argument are evaluated, after the evaluation, the result is stored on the register that represents its argument position, the first argument will be stored on rdi, the second on rsi and so on. Receiving mechanism: When a function starts, the first thing it does is store all the registers onto the stack. So rdi will be stored on -8(rbp), rsi on -16(rbp) and so on. And, a ref_entry is created making the relationship parameter-stack_offset. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 50 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 2d6b993..26bf3f9 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -22,6 +22,9 @@ #include #include +size_t available_calling_registers = 6; +char *calling_registers[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" }; + static void gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binary_operation_t *binary_operation); @@ -183,6 +186,7 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) case AST_IF_STMT: gas_assembly_generator_compile_if_stmt(gen, &ast->data.if_stmt); break; + case AST_FUNCTION_PARAMETER: case AST_UNKOWN_NODE: assert(false && "unreachable"); } @@ -204,10 +208,27 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct uint64_t previous_index = gen->return_label_index; uint64_t return_label_index = gen->return_label_index = gen->counter_label_index++; - fprintf(gen->stream, SVFMT ":\n", SVARG(&func->identifier.name)); + assert((func->prototype.parameters->size <= available_calling_registers) && + "Not enough registers to process this function. Stack parameters will come soon."); + + fprintf(gen->stream, SVFMT ":\n", SVARG(&func->prototype.identifier.name)); fprintf(gen->stream, " push %%rbp\n"); fprintf(gen->stream, " mov %%rsp, %%rbp\n"); + for (size_t i = 0; i < func->prototype.parameters->size; i++) { + char *reg = calling_registers[i]; + ast_node_t *parameter = vector_at(func->prototype.parameters, i); + + assert(parameter->kind == AST_FUNCTION_PARAMETER); + + gen->stack_offset -= 8; + + fprintf(gen->stream, " mov %%%s, %d(%%rbp)\n", reg, gen->stack_offset); + + ref_set_variable_reference_stack_offset( + gen->refs, ¶meter->data.function_parameter.identifier, gen->stack_offset); + } + gas_assembly_generator_compile(gen, func->body); fprintf(gen->stream, ".L%ld:\n", return_label_index); @@ -215,11 +236,38 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct fprintf(gen->stream, " ret\n"); gen->return_label_index = previous_index; + gen->stack_offset = 0; } static void gas_assembly_generator_compile_function_call(gas_assembly_generator_t *gen, ast_function_call_t *func_call) { + assert((func_call->arguments->size <= available_calling_registers) && + "Not enough registers to process this function. Stack parameters will come soon."); + + for (size_t i = 0; i < func_call->arguments->size; i++) { + char *reg = calling_registers[i]; + ast_node_t *argument = vector_at(func_call->arguments, i); + + gas_assembly_generator_compile(gen, argument); + + switch (gen->latest_evaluation.kind) { + case EVALUATION_RESULT_AS_LITERAL_INTEGER: + fprintf(gen->stream, " mov $%ld, %%%s\n", gen->latest_evaluation.data.literal_int, reg); + break; + case EVALUATION_RESULT_ON_RAX: + fprintf(gen->stream, " mov %%rax, %%%s\n", reg); + break; + case EVALUATION_RESULT_ON_STACK: + fprintf(gen->stream, " mov %d(%%rbp), %%%s\n", gen->latest_evaluation.data.stack_offset, reg); + break; + case EVALUATION_RESULT_AS_LITERAL_BOOL: + fprintf(gen->stream, " mov %d(%%rbp), %%%s\n", gen->latest_evaluation.data.literal_bool, reg); + break; + case EVALUATION_RESULT_VOID: + assert(false && "Unexpected"); + } + } fprintf(gen->stream, " call " SVFMT "\n", SVARG(&func_call->identifier->name)); gas_assembly_generator_set_latest_evaluation_to_rax(gen); } -- cgit v1.2.3 From ea7f65fe1250be8f49edcaaedd3410aed1401648 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Thu, 11 May 2023 15:00:10 -0300 Subject: gas: implement recursion and late evaluation Until now the below code was not valid for pipac. fn main(): i32 { return fib(13); } fn fib(n: i32): i32 { if n <= 1 { return n; } return fib(n - 1) + fib(n - 2); } Pipa's parser was adding a function to scope after they were fully parsed which means that fib's self-reference would not work. Also, functions were required to follow the be called in the order they are declared for the same scope reason so, the main function was required to be defined after fib. And how it is working now? When a TOKEN_NAME is not found in the scope, instead of returning an error, an unknown token is created as placeholder. The parser stores the node reference and the token it was trying to parse. During type checks, if the parser detects an unknown node, instead of returning an error, it stores in that node what was the expected type. After the NS is fully parsed a reevaluation is made on those unknown nodes by setting the lexer back on the node's token position and parsing the TOKEN_NAME again. Ps: There is a typo on the unknown token. It will be addressed in another commit since this issue was not introduced by this change. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 26bf3f9..7641147 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -214,6 +214,7 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct fprintf(gen->stream, SVFMT ":\n", SVARG(&func->prototype.identifier.name)); fprintf(gen->stream, " push %%rbp\n"); fprintf(gen->stream, " mov %%rsp, %%rbp\n"); + fprintf(gen->stream, " subq $16, %%rsp\n"); for (size_t i = 0; i < func->prototype.parameters->size; i++) { char *reg = calling_registers[i]; @@ -232,7 +233,7 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct gas_assembly_generator_compile(gen, func->body); fprintf(gen->stream, ".L%ld:\n", return_label_index); - fprintf(gen->stream, " pop %%rbp\n"); + fprintf(gen->stream, " leave\n"); fprintf(gen->stream, " ret\n"); gen->return_label_index = previous_index; @@ -515,7 +516,7 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar binary_operation->kind == AST_BINOP_EQUAL || binary_operation->kind == AST_BINOP_NOT_EQUAL || 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"); + fprintf(gen->stream, " cmpq %%rcx, %%rax\n"); return; } -- cgit v1.2.3