diff --git a/exercises/06/vslc/src/generator.c b/exercises/06/vslc/src/generator.c index dadeb37..c77059f 100644 --- a/exercises/06/vslc/src/generator.c +++ b/exercises/06/vslc/src/generator.c @@ -6,11 +6,11 @@ #define LABEL(label) printf("_%s:\n", (char*)label) #define COMMENT(format, args...) printf("# "format"\n", ##args) +// The PUSH and POP macros also increments/decrements the stack_depth to keep track of the stack #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 // Keep track of sequence of stack depth, ifs and whiles static uint64_t @@ -39,10 +39,6 @@ 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" -//}; - // Helper funcs for generating different nodes /** @@ -91,11 +87,38 @@ static void generate_function_return(node_t *node); */ static void solve_statements(node_t *node, char *operator); +/** + * Solves a relation and leaves the result (1 or 0, True or False) in %rax + * If the relation node is just a number, just put the number in %rax. + * This is used with a cmp instruction to check if the relation is true. + * + * This makes it possible to compute the constant relations. + * + * @param node pointer to the node the suspected relation is in + */ +static void solve_relations(node_t *node); +/** + * Solves a node that is an if statement + * Uses the solve realtions function to solve the relations + * + * @param node pointer to the if node + */ static void generate_if_statement(node_t *node); +/** + * Solves a node that is an while statement + * Uses the solve realtions function to solve the relations + * + * @param node pointer to the while node + */ static void generate_while_statement(node_t *node); +/** + * Inserts a jump to the inner most while. + * This also works when multiple whiles are nested. + * + */ static void solve_continue_statement(); /** @@ -120,12 +143,23 @@ static uint64_t fetch_symbols(tlhash_t* symbol_table, symbol_t*** symbol_list); void generate_program ( void ) { + // Generate the string table at the top generate_stringtable(); - generate_global_variables(); + // Fetch all the global elements (functions and global vars) symbol_t **global_list; uint64_t no_globals = fetch_symbols(global_names, &global_list); + // Find the number of actual global variables + uint64_t no_global_vars = 0; + for (uint64_t g = 0; g < no_globals; g++) + if (global_list[g]->type == SYM_GLOBAL_VAR) no_global_vars++; + + // Generate globbal variables if there are any + if (no_global_vars) + generate_global_variables(); + + // Find the function called main and keep track of if it found an generated bool main_generated = false; uint64_t seq0_index = -1; for (uint64_t g = 0; g < no_globals; g++) @@ -149,6 +183,7 @@ generate_program ( void ) if (!main_generated) generate_main(global_list[seq0_index]); + // Then generate all the functions from vsl for (uint64_t g = 0; g < no_globals; g++) { if (global_list[g]->type == SYM_FUNCTION) @@ -187,10 +222,10 @@ generate_global_variables ( void ) puts(".bss"); puts(".align 8"); - for (uint64_t g = 0; g < no_globals; g++) { + for (uint64_t g = 0; g < no_globals; g++) if (global_list[g]->type == SYM_GLOBAL_VAR) printf(".%s:\n", global_list[g]->name); - } + putchar('\n'); free(global_list); @@ -199,7 +234,7 @@ generate_global_variables ( void ) void generate_function ( symbol_t *function ) { - // TODO: Generate code for declaring and entering function, then generate its body + // Keep track of the stack size in each of the functions stack_depth = 0; printf("# func %s(nparams: %ld)\n", function->name, function->nparms); @@ -212,16 +247,13 @@ generate_function ( symbol_t *function ) // Push params to stack for (int arg = 0; arg < MIN(NO_REG_RECORD,function->nparms); arg++) - { 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; - //stack_depth += no_locals; // Make room for the local vars while(no_locals--) @@ -235,6 +267,7 @@ generate_function ( symbol_t *function ) // Now the stack ptr should be 16 byte aligned. + // Then generate the body of the function generate_node(function->node); putchar('\n'); @@ -244,8 +277,6 @@ generate_function ( symbol_t *function ) void generate_node ( node_t *node) { - // TODO: Generate code corresponding to node - // All statements have the same structure. // [0] is the lhs, needs to be identifier, parser ensures this // [1] is thr rhs @@ -303,8 +334,6 @@ generate_node ( node_t *node) generate_function_return(node); break; - - case IF_STATEMENT: generate_if_statement(node); break; @@ -312,16 +341,17 @@ generate_node ( node_t *node) case WHILE_STATEMENT: generate_while_statement(node); break; + case NULL_STATEMENT: solve_continue_statement(); break; - case DECLARATION_LIST: /* List of blocks we dont need to traverse */ break; default: + // Otherwise, generate the traverse for (int c = 0; c < node->n_children; c++) generate_node(node->children[c]); break; @@ -330,10 +360,11 @@ generate_node ( node_t *node) } +// Generate the print node void generate_print(node_t* node) { - // Push rdi and rsi to stack incase there are data in them + for (uint64_t p = 0; p < node->n_children; p++) { node_t *curr_print = node->children[p]; @@ -358,14 +389,13 @@ generate_print(node_t* node) default: break; } - //ASM(movq, $0, %rax); + COMMENT("printf call"); ASM(call, printf); } // Adds a newline ASM(movq, $'\n', %rdi); - //ASM(movq, $0, %rax); ASM(call, putchar); } @@ -376,7 +406,11 @@ fetch_variable(node_t *node, const char* dest) { printf("\tmovq\t"); generate_var_ident(node); - printf(", %s\t\t# Fetched: %s\n", dest, node->entry->name); + printf(", %s\t\t# Fetched: %s and put in %s\n", + dest, + node->entry->name, + dest + ); } // This will put the value in dest to the var in node @@ -385,10 +419,16 @@ writeback_variable(node_t *node, char* src) { printf("\tmovq\t%s,", src); generate_var_ident(node); - printf("\t\t# Writeback: %s\n", node->entry->name); + printf("\t\t# Writeback '%s' from %s\n", + node->entry->name, + src + ); } - +// Generate variable identifier, +// if local var -> find offset from sb +// if parameter -> find offset from sb +// if global -> insert global tag void generate_var_ident(node_t *node) { @@ -405,7 +445,7 @@ generate_var_ident(node_t *node) printf("%ld(%%rbp)", -8 * (ident_sym->seq + 1)); else // This requires that the parameters on - // stack is in reversed order... easier to implement + // stack is in reversed order. easier to implement... printf("%ld(%%rbp)", 8 * (ident_sym->seq - 6 + 1 )); break; @@ -417,7 +457,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 +// no no no noooo, it should leave it in rax! As it does :)))) void solve_expressions(node_t *node) { @@ -445,6 +485,7 @@ solve_expressions(node_t *node) break; } break; + case 1: solve_expressions(node->children[0]); @@ -503,12 +544,15 @@ generate_function_call(node_t *node) // If the stack is 16 byte alligned here, offset // by 1 because call pushes return addr to stack + // Therefore after call, the stack is 16 byte aligned if (isStack16ByteAligned) PUSH($0); + // Arg list is allways the second children, lies within a parameter list + // Type of this is therefore PARAMETER_LIST node_t *arg_list = node->children[1]; if (arg_list->n_children) - arg_list = arg_list->children[0]; + arg_list = arg_list->children[0]; // This is the acutal parameter list for (int arg = 0; arg < MIN(NO_REG_RECORD, arg_list->n_children); arg++) { @@ -603,6 +647,7 @@ solve_relations(node_t *relation_root) switch (relation_root->type) { case NUMBER_DATA: + // Numberdata is boring, just leave value in %rax, only 1 is interperted as true solve_expressions(relation_root); break; @@ -627,15 +672,9 @@ solve_relations(node_t *relation_root) switch (*(char*)relation_root->data) { - case '=': - ASM(sete, %al); - break; - case '>': - ASM(setg, %al); - break; - case '<': - ASM(setl, %al); - break; + case '=': ASM(sete, %al); break; // Set %al (0th byte of %rax) to 1 if lhs == rhs + case '>': ASM(setg, %al); break; // Set %al (0th byte of %rax) to 1 if lhs > rhs + case '<': ASM(setl, %al); break; // Set %al (0th byte of %rax) to 1 if lhs < rhs } break; } @@ -651,14 +690,21 @@ generate_if_statement(node_t *node) // The realtion is allways in the first part of the IF solve_relations(node->children[0]); - ASM(cmp, $1, %rax); - printf("\tjne\t%s%03ld\n", (node->n_children > 2) ? "ELSE" : "ENDIF", current_if_seq); + // Compare to 0 (False) + ASM(cmp, $0, %rax); + // If False, jump to either ELSE or ENDIF based on no children in if + printf("\tje \t%s%03ld\n", (node->n_children > 2) ? "ELSE" : "ENDIF", current_if_seq); + + // Then generate body generate_node(node->children[1]); - if (node->n_children > 2) { + // If else block aswell, add that + if (node->n_children > 2) + { printf("\tjmp \tENDIF%03ld\n", current_if_seq); printf("ELSE%03ld:\n", current_if_seq); + // Generate ELSE body generate_node(node->children[2]); } @@ -669,8 +715,12 @@ generate_if_statement(node_t *node) void generate_while_statement(node_t *node) { + // Keep local var of which WHILE this is uint64_t current_while_seq = while_seq++; + // Also keep the previous closest while + // in case a continue happens after + // this (and this is inside an another while loop) uint64_t prev_closest_while = closest_while; closest_while = current_while_seq; @@ -680,16 +730,19 @@ generate_while_statement(node_t *node) // Relation is allways the first entry in a while solve_relations(node->children[0]); - ASM(cmp, $1, %rax); - - printf("\tjne\tENDWHILE%03ld\n", current_while_seq); + // Compare to 0 (False) + ASM(cmp, $0, %rax); + // If false, then exit while + printf("\tje \tENDWHILE%03ld\n", current_while_seq); + // Generate body generate_node(node->children[1]); + + // Restore the previous while closest_while = prev_closest_while; printf("\tjmp \tWHILE%03ld\n", current_while_seq); printf("ENDWHILE%03ld:\n", current_while_seq); - } void @@ -699,6 +752,16 @@ solve_continue_statement() printf("\tjmp \tWHILE%03ld\n", closest_while); } +static uint64_t +fetch_symbols(tlhash_t* symbol_table, symbol_t*** symbol_list) +{ + uint64_t no_symbols = tlhash_size(symbol_table); + *symbol_list = malloc(no_symbols * sizeof(symbol_t)); + tlhash_values(symbol_table, (void **)*symbol_list ); + + return no_symbols; +} + /**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 */ @@ -763,12 +826,4 @@ generate_main ( symbol_t *first ) } -static uint64_t -fetch_symbols(tlhash_t* symbol_table, symbol_t*** symbol_list) -{ - uint64_t no_symbols = tlhash_size(symbol_table); - *symbol_list = malloc(no_symbols * sizeof(symbol_t)); - tlhash_values(symbol_table, (void **)*symbol_list ); - return no_symbols; -}