#include <stdio.h> #include "mcc/tac.h" #include "mcc/tac_print.h" #include "mcc/symbol_table.h" #include "mcc/assembly_gen.h" #define VARIABLE_SIZE 4 int compute_stack(int variable_size) { int stack_size = variable_size * VARIABLE_SIZE; if (stack_size % 16 != 0) { stack_size += (16 - stack_size % 16); } return stack_size; } void mcc_asm_add_constant(struct mcc_asm_constant **entries, enum mcc_asm_constant_type type, int *counter, void *value ){ struct mcc_asm_constant *add_const = (struct mcc_asm_constant *)malloc(sizeof(*add_const)); add_const->const_type = type; add_const->next = NULL; add_const->number = ++(*counter); if(type == MCC_ASM_CONST_STRING){ add_const->s_value = (char *) value; } else if (type == MCC_ASM_CONST_FLOAT){ add_const->f_value = *((double *)value); } if (*entries == NULL) { *entries = add_const; } else { struct mcc_asm_constant *constant = *entries; while (constant->next != NULL) { constant = constant->next; } constant->next = add_const; } } void mcc_asm_print_constant(FILE *out, struct mcc_asm_constant *constant) { if (constant == NULL) { return; } fprintf(out, "\t.section\t.rodata\n"); if (constant == NULL) { struct mcc_asm_constant *current = constant; while (current != NULL) { fprintf(out, ".LC%d:\n", current->number); switch (current->const_type) { case MCC_ASM_CONST_FLOAT: fprintf(out, "\t.float\t%lf\n", current->f_value); break; case MCC_ASM_CONST_STRING: fprintf(out, "\t.string\t\"%s\"\n", current->s_value); break; default: break; } current = current->next; } } char *mcc_asm_gen(FILE *out, struct mcc_tac *tac) { int const_count = 0; struct mcc_asm_constant *constants = NULL; for(int i = 0; i < tac->tac_entries->size; i++) { struct mcc_tac_entry *entry = tac->tac_entries->arr[i]; char *arg1 = entry->arg1; //TODO calculate offset and save temp offset switch (entry->tac_op) { case MCC_TAC_FUNCTION_START: fprintf(out, "\t.globl %s\n", arg1); fprintf(out, "\t.type %s, @function\n", arg1); fprintf(out, "%s:\n", arg1); fprintf(out, "\tpushl\t%%ebp\n"); fprintf(out, "\tmovl\t%%esp, %%ebp\n"); break; case MCC_TAC_CALL: fprintf(out, "\tcall\t%s\n", arg1); break; // unary case MCC_TAC_MINUS_INT_UN: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", offset); fprintf(out, "\tnegl\t%%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", offset); break; case MCC_TAC_MINUS_FLOAT_UN: break; case MCC_TAC_NOT: break; // binary case MCC_TAC_PLUS_INT: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\taddl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_MINUS_INT_BIN: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tsubl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_MUL_INT: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\timull\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_DIV_INT: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcltd\n"); fprintf(out, "\tidivl\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_PLUS_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfadds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tfstps\t%d(%%ebp)\n", result->offset); break; case MCC_TAC_MINUS_FLOAT_BIN: fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfsubs\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tfstps\t%d(%%ebp)\n", result->offset); break; case MCC_TAC_MUL_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfmuls\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tfstps\t%d(%%ebp)\n", result->offset); break; case MCC_TAC_DIV_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfdivs\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tfstps\t%d(%%ebp)\n", result->offset); break; case MCC_TAC_NOT_BOOL: fprintf(out, "\txorl\t$1, %%edx\n"); break; case MCC_TAC_AND: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tandl\t%d(%%ebp), %%edx\n", arg2->offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_OR: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\torl\t%d(%%ebp), %%edx\n", arg2->offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_EQ: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsete\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_NEQ: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsetne\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_GT: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsetg\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_LT: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsetl\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_LTEQ: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsetle\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_GTEQ: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsetge\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_LT_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfcomip\t%%st(1), %%st\n"); fprintf(out, "\tfstp\t%%st(0)\n"); fprintf(out, "\tsetb\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_LTEQ_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfcomip\t%%st(1), %%st\n"); fprintf(out, "\tfstp\t%%st(0)\n"); fprintf(out, "\tsetbe\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_GT_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfcomip\t%%st(1), %%st\n"); fprintf(out, "\tfstp\t%%st(0)\n"); fprintf(out, "\tseta\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_GTEQ_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfcomip\t%%st(1), %%st\n"); fprintf(out, "\tfstp\t%%st(0)\n"); fprintf(out, "\tsetae\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_EQ_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfcomip\t%%st(1), %%st\n"); fprintf(out, "\tfstp\t%%st(0)\n"); fprintf(out, "\tsete\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_EQ_BOOL: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsete\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_NEQ_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tfcomip\t%%st(1), %%st\n"); fprintf(out, "\tfstp\t%%st(0)\n"); fprintf(out, "\tsetne\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; case MCC_TAC_NEQ_BOOL: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tcmpl\t%d(%%ebp), %%eax\n", arg2->offset); fprintf(out, "\tsetne\t%%al\n"); fprintf(out, "\tmovzbl\t%%al, %%eax\n"); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); break; // literal case MCC_TAC_BOOL_LITERAL: //TODO parse arg1 to 0 or 1?? int bool_value = (strcmp(arg1, "true") == 0) ? 1 : 0; fprintf(out, "\tmovl\t$%s, %d(%%ebp)\n",arg1, result->offset); break; case MCC_TAC_INT_LITERAL: fprintf(out, "\tmovl\t$%s, %d(%%ebp)\n",arg1, result->offset); break; case MCC_TAC_STRING_LITERAL: mcc_asm_add_constant(&constants,MCC_ASM_CONST_STRING,&const_count, arg1 ); fprintf(out, "\tmovl\t$.LCONST%d, %d(%%ebp)\n", const_count,result->offset); break; case MCC_TAC_FLOAT_LITERAL: //TODO create new constant mcc_asm_add_constant(&constants,MCC_ASM_CONST_FLOAT,&const_count, arg1 ); fprintf(out, "\tflds\t.LCONST%d\n", const_count); fprintf(out, "\tfstps\t%d(%%ebp)\n", result->offset); break; // copy case MCC_TAC_BOOL: break; case MCC_TAC_INT: break; case MCC_TAC_STRING: break; case MCC_TAC_FLOAT: break; // push case MCC_TAC_PARAM_BOOL: case MCC_TAC_PARAM_INT: case MCC_TAC_PARAM_FLOAT: case MCC_TAC_PARAM_STRING: fprintf(out, "\tpushl\t%d(%%ebp)\n", arg1->offset); break; case MCC_TAC_PARAM_BOOL_ARR: case MCC_TAC_PARAM_INT_ARR: case MCC_TAC_PARAM_FLOAT_ARR: case MCC_TAC_PARAM_STRING_ARR: fprintf(out, "\tleal\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tpushl\t%%eax\n"); break; // pop case MCC_TAC_PARAM_POP_BOOL: case MCC_TAC_PARAM_POP_INT: case MCC_TAC_PARAM_POP_FLOAT: case MCC_TAC_PARAM_POP_STRING: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", param_offset); fprintf(out, "\tmovl\t%%eax, %d(%%ebp)\n", result->offset); //increase param offset break; case MCC_TAC_PARAM_POP_BOOL_ARR: case MCC_TAC_PARAM_POP_INT_ARR: case MCC_TAC_PARAM_POP_FLOAT_ARR: case MCC_TAC_PARAM_POP_STRING_ARR: //increase param offset break; // load case MCC_TAC_LOAD_BOOL: case MCC_TAC_LOAD_INT: case MCC_TAC_LOAD_STRING: fprintf(out, "\tmovl\t%d(%%ebp), %%edx\n", arg1->offset); fprintf(out, "\tmovl\t%d(%%ebp), %%ecx\n", arg2->offset); fprintf(out, "\tmovl\t0(%%ecx, %%edx, %d), %%eax\n", 4); break; case MCC_TAC_LOAD_FLOAT: fprintf(out, "\tmovl\t%d(%%ebp), %%edx\n", arg1->offset); fprintf(out, "\tmovl\t%d(%%ebp), %%ecx\n", arg2->offset); fprintf(out, "\tflds\t%d(%%ebp, %%edx, %d)\n", arg1->offset, 4); break; // store case MCC_TAC_STORE_BOOL: case MCC_TAC_STORE_INT: case MCC_TAC_STORE_STRING: fprintf(out, "\tmovl\t%d(%%ebp), %%eax\n", arg1->offset); fprintf(out, "\tmovl\t%d(%%ebp), %%edx\n", arg2->offset); fprintf(out, "\tmovl\t%d(%%ebp), %%ecx\n", offset); fprintf(out, "\tmovl\t%%eax, 0(%%ecx, %%edx, %d)\n", 4); break; case MCC_TAC_STORE_FLOAT: fprintf(out, "\tflds\t%d(%%ebp)\n", arg1->offset); fprintf(out, "\tmovl\t%d(%%ebp), %%edx\n", arg2->offset); fprintf(out, "\tmovl\t%d(%%ebp), %%ecx\n", offset); fprintf(out, "\tfstps\t0(%%ecx, %%edx, %d)\n", 4); break; // IR operations case MCC_TAC_JMP : fprintf(out, "\tjmp\t.%s\n", result + sizeof(char)); break; case MCC_TAC_JMP_FALSE : fprintf(out, "\tcmpl\t$0, %d(%%ebp)\n", arg1->offset); fprintf(out, "\tje\t.%s\n", result + sizeof(char)); break; case MCC_TAC_RETURN : fprintf(out, "\tleave\n"); fprintf(out, "\tret\n"); break; case MCC_TAC_ARR_DECL : // set stack offset size of pointer * elements break; case MCC_TAC_LABEL : fprintf(out, ".%s:\n", result + sizeof(char)); break; case MCC_TAC_FUNCTION_END : fprintf(out, "\tleave\n"); fprintf(out, "\tret\n"); break; case MCC_TAC_UNKNOWN: break; } } fprintf(out, "\n"); //TODO add constants mcc_asm_print_constant(out,constants); //fprintf(out, ".LCONST%d:\n", i); }