diff options
Diffstat (limited to 'mips.c')
-rw-r--r-- | mips.c | 413 |
1 files changed, 413 insertions, 0 deletions
@@ -0,0 +1,413 @@ +#include <stdio.h> +#include <assert.h> +#include "ssa.h" +#include "mips.h" + +int reg_v0 = 2; +int reg_v1 = 3; + +void mips_prologue() { + CVList_t v; + CSList_t s; + printf(".data 0x10000000\n"); + for (v = gvars; v; v = v->next) + { + CVar_t var = v->var; + printf("\t.align 2\n"); + printf("_%s:\n", var->name); + var->start = -1; + printf("\t.space %d\n", calc_size(var->type)); + } + for (s = cstrs; s; s = s->next) + { + printf("_str_%d:\n", s->id); + printf("\t.asciiz \"%s\"\n", s->str); + } + /* pre-calc done */ + printf(".text\n"); +} + +void mips_load(int reg, COpr_t opr) { + CVar_t var = cinterv_repr(opr)->info.var; + CType_t type = var->type; + if (type->type == CSTRUCT || + type->type == CUNION || + type->type == CARR) + { + if (var->global) + printf("\tla $%d, _%s\n", reg, var->name); + else + printf("\taddi $%d, $sp, %d\n", reg, var->start); + } + else + { + const char *l = type->type == CCHAR ? "lb" : "lw"; + if (var->global) + printf("\t%s $%d, _%s\n", l, reg, var->name); + else + printf("\t%s $%d, %d($sp)\t#%s\n", l, reg, var->start, var->name); + } +} + +void mips_store(int reg, COpr_t opr) { + CVar_t var = cinterv_repr(opr)->info.var; + CType_t type = var->type; + const char *l = type->type == CCHAR ? "sb" : "sw"; + /* TODO: struct */ + if (var->global) + printf("\t%s $%d, _%s\n", l, reg, var->name); + else + printf("\t%s $%d, %d($sp)\t#%s\n", l, reg, var->start, var->name); +} + +int mips_to_reg(COpr_t opr, int reg0) { + if (opr->kind == IMM) + { + printf("\tli $%d, %d\n", reg0, opr->info.imm); + return reg0; + } + else if (opr->kind == IMMS) + { + printf("\tla $%d, _str_%d\n", reg0, opr->info.cstr->id); + return reg0; + } + else if (opr->kind == IMMF) + { + printf("\tla $%d, %s\n", reg0, opr->info.str); + return reg0; + } + if (opr->reg != -1) return opr->reg; + mips_load(reg0, opr); + return reg0; +} + +void mips_space_alloc() { + int local_size = func->rec.func.local_size; + int arg_size = 0; + int bret_size = 0; + int tmp_size = 0; + int offset = 0; + int prev = 0; + CBlock_t p; + COList_t d; + CVar_t v; + for (d = defs; d; d = d->next) + { + COpr_t opr = d->opr; + if (opr->kind == TMP && opr->par == opr) + { + int t = opr->info.var->type->type; + tmp_size += align_shift(tmp_size); + opr->info.var->start = tmp_size; + if (t == CSTRUCT || t == CUNION || t == CARR) + tmp_size += PTR_SIZE; + else if (t == CVOID) + tmp_size += INT_SIZE; + else + tmp_size += calc_size(opr->info.var->type); + } + } + for (p = entry; p; p = p->next) + { + CInst_t i, ih = p->insts; + for (i = ih->next; i != ih; i = i->next) + { + if (i->op == PUSH) + { + COpr_t arg = i->src1; + offset += align_shift(offset); + i->offset = offset; + if (arg->kind == IMM) + offset += INT_SIZE; + else if (arg->kind == IMMS) + offset += PTR_SIZE; + else if (arg->kind == IMMF) + offset += PTR_SIZE; + else + { + CType_t t = arg->info.var->type; + if (t->type == CARR) + offset += PTR_SIZE; + else + offset += calc_size(t); + } + } + else if (i->op == CALL) + { + CType_t rt = i->dest->info.var->type; + if (offset > arg_size) + arg_size = offset; + offset = 0; + if (rt->type == CSTRUCT || rt->type == CUNION) + { + bret_size += align_shift(bret_size); + i->bret = bret_size; + bret_size += calc_size(rt); + } + } + } + } + prev += arg_size; + prev += align_shift(prev); + /* adjust offset for local variables */ + for (v = func->rec.func.local; v; v = v->next) + v->start += prev; + prev += local_size; + prev += align_shift(prev); + /* adjust offset for spilled temporaries */ + for (d = defs; d; d = d->next) + { + COpr_t opr = d->opr; + if (opr->kind == TMP && opr->par == opr) + opr->info.var->start += prev; + } + prev += tmp_size; + prev += align_shift(prev); + for (p = entry; p; p = p->next) + { + CInst_t i, ih = p->insts; + for (i = ih->next; i != ih; i = i->next) + if (i->op == CALL) + i->bret += prev; + } + prev += bret_size; + prev += align_shift(prev); + prev += 4; /* return address */ + for (v = func->rec.func.params; v; v = v->next) + v->start += prev; /* skip the whole frame to reach args */ + func->rec.func.frame_size = prev; +} + +void mips_func_begin() { + int fsize = func->rec.func.frame_size; + printf("\taddiu $sp, $sp, -%d\n", fsize); + printf("\tsw $31, %d($sp)\n", fsize - 4); +} + +void mips_func_end() { + int fsize = func->rec.func.frame_size; + printf("_ret_%s:\n", func->name); + printf("\tlw $31, %d($sp)\n", fsize - 4); + printf("\taddiu $sp, $sp, %d\n", fsize); + printf("\tjr $31\n"); +} + +void mips_generate() { + CBlock_t p; + mips_space_alloc(); + printf("%s:\n", func->name); + mips_func_begin(); + for (p = entry; p; p = p->next) + { + if (p->ref) printf("_L%d:\n", p->id + gbbase); + CInst_t i, ih = p->insts; + const char *bop; + for (i = ih->next; i != ih; i = i->next) + { + int flag = 1, swap; + switch (i->op) + { + case LOAD: + if (i->dest->reg != -1) + mips_load(i->dest->reg, i->dest); + break; + case MOVE: + { + /* TODO: struct */ + int rs = mips_to_reg(i->src1, reg_v0); + int rd = i->dest->reg; + if (rd != -1) + printf("\tmove $%d $%d\n", rd, rs); + else + rd = rs; + if (i->dest->reg == -1 || i->dest->kind == VAR) + mips_store(rd, i->dest); + } + break; + case BEQZ: + { + int rs = mips_to_reg(i->src1, reg_v0); + printf("\tbeqz $%d, _L%d\n", rs, i->dest->info.imm); + } + break; + case BNEZ: + { + int rs = mips_to_reg(i->src1, reg_v0); + printf("\tbnez $%d, _L%d\n", rs, i->dest->info.imm); + } + break; + case GOTO: + printf("\tj _L%d\n", i->dest->info.imm); + break; + case ARR: + { + int arr = mips_to_reg(i->src1, reg_v0); + int rd; + const char *l = i->dest->info.var->type->type == CCHAR ? "lb" : "lw"; + if (i->src2->kind == IMM) + { + rd = i->dest->reg; + if (rd == -1) rd = reg_v1; + printf("\t%s $%d, %d($%d)\n", l, rd, i->src2->info.imm, arr); + } + else + { + int index = mips_to_reg(i->src2, reg_v1); + printf("\taddu $%d, $%d, $%d\n", index, arr, index); + rd = i->dest->reg; + if (rd == -1) rd = reg_v0; + printf("\t%s $%d, 0($%d)\n", l, rd, index); + } + if (i->dest->reg == -1 || i->dest->kind == VAR) + mips_store(rd, i->dest); + } + break; + case WARR: + { + int arr = mips_to_reg(i->dest, reg_v0); + const char *s = i->dest->info.var->type->type == CCHAR ? "sb" : "sw"; + int rs; + if (i->src2->kind == IMM) + { + rs = mips_to_reg(i->src1, reg_v1); + printf("\t%s $%d, %d($%d)\n", s, rs, i->src2->info.imm, arr); + } + else + { + int index = mips_to_reg(i->src2, reg_v1); + printf("\taddu $%d, $%d, $%d\n", index, arr, index); + rs = mips_to_reg(i->src1, reg_v0); + printf("\t%s $%d, 0($%d)\n", s, rs, index); + } + } + break; + case PUSH: + { + int rs = mips_to_reg(i->src1, reg_v0); + /* TODO: push struct */ + printf("\tsw $%d, %d($sp)\n", rs, i->offset); + } + break; + case CALL: + { + int rd = i->dest->reg; + if (i->src1->kind == IMMF) + printf("\tjal %s\n", i->src1->info.str); + else + printf("\tjalr $%d\n", mips_to_reg(i->src1, reg_v0)); + if (rd != -1) + printf("\tmove $%d, $%d\n", rd, reg_v0); + else + rd = reg_v0; + if (i->dest->reg == -1 || i->dest->kind == VAR) + mips_store(reg_v0, i->dest); + } + break; + case RET: + { + if (i->src1->reg != -1) + printf("\tmove $%d, $%d\n", reg_v0, mips_to_reg(i->src1, reg_v1)); + else + mips_to_reg(i->src1, reg_v0); + printf("\tj _ret_%s\n", func->name); + } + break; + case ADDR: + { + assert(i->src1->kind == VAR || + i->src1->kind == IMMF); + int rd = i->dest->reg; + if (rd == -1) rd = reg_v0; + if (i->src1->kind == IMMF) + printf("\tla $%d, %s\n", rd, i->src1->info.str); + else + { + CVar_t var = i->src1->info.var; + if (var->global) + printf("\tla $%d, _%s\n", rd, var->name); + else + printf("\taddiu $%d, $sp, %d\n", rd, var->start); + if (i->dest->reg == -1 || i->dest->kind == VAR) + mips_store(rd, i->dest); + } + } + break; + default: flag = 0; + } + if (flag) continue; + flag = 1; + swap = 0; + switch (i->op) + { + case MUL: bop = "mul"; break; + case DIV: bop = "divu"; break; + case MOD: bop = "rem"; break; + case ADD: bop = "addu"; swap = 1; break; + case SUB: bop = "subu"; break; + case SHL: bop = "sllv"; break; + case SHR: bop = "srlv"; break; + case AND: bop = "and"; swap = 1; break; + case XOR: bop = "xor"; swap = 1; break; + case OR: bop = "or"; swap = 1; break; + case NOR: bop = "nor"; break; + case EQ: bop = "seq"; break; + case NE: bop = "sne"; break; + case LT: bop = "slt"; break; + case GT: bop = "sgt"; break; + case LE: bop = "sle"; break; + case GE: bop = "sge"; break; + default: flag = 0; + } + if (flag) + { + int rs, rt; + int rd = i->dest->reg; + if (rd == -1) rd = reg_v0; + if (swap) + { + COpr_t t; + if (i->src1->kind == IMM) + { + t = i->src1; + i->src1 = i->src2; + i->src2 = t; + } + if (i->src2->kind == IMM) + { + switch (i->op) + { + case ADD: bop = "addiu"; break; + case AND: bop = "andi"; break; + case XOR: bop = "xori"; break; + case OR: bop = "ori"; break; + default: ; + } + rs = mips_to_reg(i->src1, reg_v0); + printf("\t%s $%d, $%d, %d\n", + bop, rd, rs, i->src2->info.imm); + } + else swap = 0; + } + if (!swap) + { + rs = mips_to_reg(i->src1, reg_v0); + rt = mips_to_reg(i->src2, reg_v1); + printf("\t%s $%d, $%d, $%d\n", bop, rd, rs, rt); + } + if (i->dest->reg == -1 || i->dest->kind == VAR) + mips_store(rd, i->dest); + continue; + } + if (i->op == NEG) + { + int rs = mips_to_reg(i->src1, reg_v0); + int rd = i->dest->reg; + if (rd == -1) rd = reg_v0; + printf("\tnegu $%d, $%d\n", rd, rs); + if (i->dest->reg == -1 || i->dest->kind == VAR) + mips_store(rd, i->dest); + } + } + } + mips_func_end(); +} |