diff --git a/exercises/06/vslc/src/generator.c b/exercises/06/vslc/src/generator.c index e53d8db..40933cf 100644 --- a/exercises/06/vslc/src/generator.c +++ b/exercises/06/vslc/src/generator.c @@ -1,16 +1,22 @@ #include +#define ERRPRT(format, args...) fprintf(stderr, "[ERROR] "); fprintf(stderr ,format, ##args) + #define ASM(opcode, args...) puts("\t"#opcode"\t"#args) #define LABEL(label) printf("_%s:\n", (char*)label) #define COMMENT(format, args...) printf("# "format"\n", ##args) -#define PUSH(param) printf("\tpushq\t%s\t\t\t\t# Scope depth: %ld\n", #param, ++scope_depth) -#define POP(param) printf("\tpopq\t%s\t\t\t\t# Scope depth: %ld\n", #param, --scope_depth) +#define PUSH(param) printf("\tpushq\t%s\t\t\t\t# PUSH: %ld\n", #param, ++stack_depth) +#define POP(param) printf("\tpopq\t%s\t\t\t\t# POP: %ld\n", #param, --stack_depth) #define NO_REG_RECORD 6 -#define NO_CALLE_SAVED_REG 10 +//#define NO_CALLE_SAVED_REG 10 -uint64_t scope_depth = 0; +// Keep track of sequence of stack depth, ifs and whiles +static uint64_t + stack_depth, + if_seq, + while_seq; /**Generate table of strings in a rodata section. */ void generate_stringtable ( void ); @@ -32,9 +38,9 @@ static const char *record[NO_REG_RECORD] = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; -static const char *calle_saved_reg[NO_CALLE_SAVED_REG] = { - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%rsp", "%r8", "%r9", "%r10", "%r11" -}; +//static const char *calle_saved_reg[NO_CALLE_SAVED_REG] = { +// "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%rsp", "%r8", "%r9", "%r10", "%r11" +//}; // Helper funcs for generating different nodes @@ -84,6 +90,13 @@ static void generate_function_return(node_t *node); */ static void solve_statements(node_t *node, char *operator); + +static void generate_if_statement(node_t *node); + +static void generate_while_statement(node_t *node); + +static void solve_continue_statement(); + /** * Generate assembly to fetch a variable on stack * @@ -186,32 +199,38 @@ void generate_function ( symbol_t *function ) { // TODO: Generate code for declaring and entering function, then generate its body + stack_depth = 0; printf("# func %s(nparams: %ld)\n", function->name, function->nparms); puts(".section .text"); printf(".global _%s\n", function->name); LABEL(function->name); - //ASM(pushq, %rbp); PUSH(%rbp); + ASM(movq, %rsp, %rbp); // Push params to stack for (int arg = 0; arg < MIN(NO_REG_RECORD,function->nparms); arg++) - printf("\tpushq\t%s\t\t\t\t# Scope depth: %ld\n", record[arg], ++scope_depth); + { + printf("\tpushq\t%s\t\t\t\t# PUSH: %ld\n", + record[arg], + ++stack_depth + ); + } // How many local variables are inside function uint64_t no_locals = function->locals->size - function->nparms; - - // IF the stack alignment is not 16 bytes, - // add one now as all local var also is 0 - if ((MIN(6,function->nparms) + no_locals) % 2) - PUSH($0); - //ASM(pushq, $0); + //stack_depth += no_locals; // Make room for the local vars while(no_locals--) PUSH($0); - //ASM(pushq, $0); + + // IF the stack alignment is not 16 bytes, + // add one now as all local var also is 0 + if (stack_depth % 2) + PUSH($0); + // Now the stack ptr should be 16 byte aligned. @@ -234,7 +253,7 @@ generate_node ( node_t *node) case ASSIGNMENT_STATEMENT: solve_expressions(node->children[1]); //ASM(popq, %rax); - POP(%rax); + //POP(%rax); writeback_variable(node->children[0], "%rax"); break; @@ -286,11 +305,14 @@ generate_node ( node_t *node) case IF_STATEMENT: + generate_if_statement(node); + break; + case WHILE_STATEMENT: /* DO NOTHING YET */ break; case NULL_STATEMENT: - /* USED IN WHILE/IF */ + /* USED IN WHILE */ break; @@ -311,8 +333,6 @@ void generate_print(node_t* node) { // Push rdi and rsi to stack incase there are data in them - //ASM(pushq, %rdi); - //ASM(pushq, %rsi); for (uint64_t p = 0; p < node->n_children; p++) { node_t *curr_print = node->children[p]; @@ -321,8 +341,6 @@ generate_print(node_t* node) { case EXPRESSION: solve_expressions(curr_print); - //ASM(popq, %rax); - POP(%rax); ASM(movq, $.intout, %rdi); ASM(movq, %rax, %rsi); break; @@ -339,19 +357,15 @@ generate_print(node_t* node) default: break; } - PUSH(%rax); - ASM(movq, $0, %rax); - COMMENT("Actual print. Stack size: %ld", scope_depth); + //ASM(movq, $0, %rax); + COMMENT("printf call"); ASM(call, printf); - POP(%rax); } // Adds a newline - PUSH(%rax); - ASM(movq, $0, %rax); ASM(movq, $'\n', %rdi); + //ASM(movq, $0, %rax); ASM(call, putchar); - POP(%rax); } @@ -402,6 +416,7 @@ generate_var_ident(node_t *node) // This should allways push the result to stack +// no no no no, it should leave it in rax void solve_expressions(node_t *node) { @@ -423,20 +438,14 @@ solve_expressions(node_t *node) { case IDENTIFIER_DATA: fetch_variable(node, "%rax"); - PUSH(%rax); - //ASM(pushq, %rax); break; case NUMBER_DATA: printf("\tmovq\t$%ld,%%rax\n",*(int64_t*)node->data); - PUSH(%rax); - //ASM(pushq, %rax); break; } break; case 1: solve_expressions(node->children[0]); - //ASM(popq, %rax); - POP(%rax); switch (*(char*)node->data) { @@ -447,8 +456,6 @@ solve_expressions(node_t *node) ASM(notq, %rax); break; } - //ASM(pushq, %rax); - PUSH(%rax); break; case 2: @@ -456,16 +463,18 @@ solve_expressions(node_t *node) // First fetch lhs of expr and then rhs // Push results on stack for (int i = 0; i < 2; i++) + { solve_expressions(node->children[i]); + PUSH(%rax); + } // Put rhs in %r10 - //ASM(popq, %r10); POP(%r10); // put lhs in %rax - //ASM(popq, %rax); POP(%rax); + // All operators below leaves result in %rax switch (*(char*)node->data) { /* Assignments */ @@ -480,10 +489,6 @@ solve_expressions(node_t *node) ASM(idivq, %r10); // Divide %rdx:%rax by %r10 break; } - - // Push result to stack. - //ASM(pushq, %rax); - PUSH(%rax); break; } } @@ -493,6 +498,13 @@ generate_function_call(node_t *node) { printf("# Function call\n"); + bool isStack16ByteAligned = !(stack_depth % 2); + + // If the stack is 16 byte alligned here, offset + // by 1 because call pushes return addr to stack + if (isStack16ByteAligned) + PUSH($0); + node_t *arg_list = node->children[1]; if (arg_list->n_children) arg_list = arg_list->children[0]; @@ -510,52 +522,40 @@ generate_function_call(node_t *node) if (arg_list->n_children > NO_REG_RECORD) { + // If there is an odd number of args to push to stack, add 1 + if (arg_list->n_children % 2) + PUSH($0); + for (int arg = arg_list->n_children - 1; arg >= NO_REG_RECORD; arg--) { if (arg_list->children[arg]->type == NUMBER_DATA) - printf("\tpushq\t$%ld\t\t\t\t# Scope depth: %ld\n", + printf("\tpushq\t$%ld\t\t\t\t# PUSH: %ld\n", *(int64_t*)arg_list->children[arg]->data, - ++scope_depth + ++stack_depth ); else { printf("\tpushq\t"); generate_var_ident(arg_list->children[arg]); - printf("\t\t\t\t# Scope depth: %ld", ++scope_depth); + printf("\t\t\t\t# PUSH: %ld", ++stack_depth); putchar('\n'); } } - if (arg_list->n_children % 2) - PUSH($0); - //ASM(pushq, $0); } printf("\tcall\t_%s\n", (char*)node->children[0]->data); - PUSH(%rax); - //ASM(pushq, %rax); + + // Aaaand pop the stack to return back to stack alignment + if (isStack16ByteAligned) + POP(%rcx); printf("# End of function call\n"); - /* - for (int reg = 0; reg < NO_CALLE_SAVED_REG; reg++) - printf("\tpushq\t%s \t\t# Pushing %s to stack\n", - calle_saved_reg[reg], - calle_saved_reg[reg] - ); - - for (int reg = NO_CALLE_SAVED_REG; reg > 0; reg--) - printf("\tpopq\t%s \t\t# Poping %s from stack\n", - calle_saved_reg[reg], - calle_saved_reg[reg] - );*/ - } void generate_function_return(node_t *node) { solve_expressions(node->children[0]); - //ASM(popq, %rax); - POP(%rax); ASM(leave); ASM(ret); } @@ -568,11 +568,84 @@ solve_statements(node_t *node, char *operator) solve_expressions(node); - //ASM(popq, %rax); - POP(%rax); writeback_variable(node->children[0], "%rax"); } +void +generate_if_statement(node_t *node) +{ + uint64_t current_if_seq = if_seq++; + + COMMENT("Begin IF %ld", current_if_seq); + + node_t *relation_root = node->children[0]; + + switch (relation_root->type) + { + case NUMBER_DATA: + solve_expressions(relation_root); + break; + + case RELATION: + if (relation_root->n_children != 2) + { + ERRPRT("Relation requires two expressions, one lhs and one rhs\n"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < relation_root->n_children; i++) + { + solve_expressions(relation_root->children[i]); + PUSH(%rax); + } + + POP(%r10); + POP(%rax); + + ASM(cmp, %r10, %rax); + + switch (*(char*)relation_root->data) + { + case '=': + ASM(sete, %rax); + break; + case '>': + ASM(setg, %rax); + break; + case '<': + ASM(setl, %rax); + break; + } + break; + } + + ASM(cmp, $1, %rax); + printf("\tjne\t%s%03ld\n", (node->n_children > 2) ? "ELSE" : "ENDIF", current_if_seq); + solve_expressions(node->children[1]); + + if (node->n_children > 2) { + printf("\tjmp\tENDIF%03ld\n", current_if_seq); + printf("ELSE%03ld:\n", current_if_seq); + solve_expressions(node->children[2]); + } + + printf("ENDIF%03ld:\n", current_if_seq); + + COMMENT("End IF %ld", current_if_seq); +} + +void +generate_while_statement(node_t *node) +{ + +} + +void +solve_continue_statement() +{ + +} + /**Generates the main function with argument parsing and calling of our * main function (first, if no function is named main) * @param first Symbol table entry of our main function */ @@ -583,6 +656,7 @@ generate_main ( symbol_t *first ) puts ( ".globl main" ); puts ( ".section .text" ); puts ( "main:" ); + puts ( "\tpushq %rbp" ); // Added this for stack alignment puts ( "\tpushq %rbp" ); puts ( "\tmovq %rsp, %rbp" ); @@ -594,26 +668,32 @@ generate_main ( symbol_t *first ) printf ( "\tmovq\t%%rdi,%%rcx\n" ); printf ( "\taddq\t$%zu, %%rsi\n", 8*first->nparms ); - printf ( "PARSE_ARGV:\n" ); - printf ( "\tpushq\t%%rcx\n" ); - printf ( "\tpushq\t%%rsi\n" ); - printf ( "\tmovq\t(%%rsi),%%rdi\n" ); - printf ( "\tmovq\t$0,%%rsi\n" ); - printf ( "\tmovq\t$10,%%rdx\n" ); - printf ( "\tcall\tstrtol\n" ); + // Modification to mail call, remove this if no params supplied + if (first->nparms) + { + printf ( "PARSE_ARGV:\n" ); + printf ( "\tpushq\t%%rcx\n" ); + printf ( "\tpushq\t%%rsi\n" ); -/* Now a new argument is an integer in rax */ + printf ( "\tmovq\t(%%rsi),%%rdi\n" ); + printf ( "\tmovq\t$0,%%rsi\n" ); + printf ( "\tmovq\t$10,%%rdx\n" ); + printf ( "\tcall\tstrtol\n" ); - printf ( "\tpopq\t%%rsi\n" ); - printf ( "\tpopq\t%%rcx\n" ); - printf ( "\tpushq\t%%rax\n" ); - printf ( "\tsubq\t$8, %%rsi\n" ); - printf ( "\tloop\tPARSE_ARGV\n" ); + /* Now a new argument is an integer in rax */ - /* Now the arguments are in order on stack */ - for (int arg = 0; arg < MIN(6,first->nparms); arg++) - printf ( "\tpopq\t%s\n", record[arg] ); + printf ( "\tpopq\t%%rsi\n" ); + printf ( "\tpopq\t%%rcx\n" ); + printf ( "\tpushq\t%%rax\n" ); + printf ( "\tsubq\t$8, %%rsi\n" ); + printf ( "\tloop\tPARSE_ARGV\n" ); + + /* Now the arguments are in order on stack */ + for (int arg = 0; arg < MIN(6,first->nparms); arg++) + printf ( "\tpopq\t%s\n", record[arg] ); + + } printf ( "SKIP_ARGS:\n" ); printf ( "\tcall\t_%s\n", first->name );