Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
assembly_gen.c 15.16 KiB
#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 mcc_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_contant_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);
   
}