#include #include #include #include "ast.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; if (var->initr) { CNode *initr = var->initr->chd; assert(var->initr->rec.subtype == INITR_NORM); switch (initr->ext.type->type) { case CINT: printf("\t.word %d\n", initr->ext.const_val); break; case CCHAR: printf("\t.byte %d\n", initr->ext.const_val); break; case CPTR: { CType_t ref = initr->ext.type->rec.ref; printf("\t.word "); switch (ref->type) { case CFUNC: printf("%s\n", initr->rec.strval); break; case CCHAR: printf("_str_%d\n", ((CSList_t)initr->ext.const_val)->id); break; default: assert(0); } } break; default: assert(0); } } else 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 = opr->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 = opr->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 cinterv_repr(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->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->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->type; if (t->type == CARR) offset += PTR_SIZE; else offset += calc_size(t); } } else if (i->op == CALL) { CType_t rt = i->dest->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; if (fsize < 0x8000) printf("\taddiu $sp, $sp, -%d\n", fsize); else { printf("\tli $%d, %d\n", reg_v0, -fsize); printf("\taddu $sp, $sp, $%d\n", reg_v0); } printf("\tsw $31, %d($sp) #%s\n", fsize - 4, func->name); } 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); if (fsize < 0x8000) printf("\taddiu $sp, $sp, %d\n", fsize); else { printf("\tli $%d, %d\n", reg_v0, fsize); printf("\taddu $sp, $sp, $%d\n", reg_v0); } printf("\tjr $31\n"); } void mips_generate() { CBlock_t p; mips_space_alloc(); if (strcmp(func->name, "main")) printf("_func_%s:\n",func->name); else printf("main:\n"); 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; printf("# "); cinst_print(stdout, i); 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: { CType_t type = i->src1->type; int arr = mips_to_reg(i->src1, reg_v0); int rd; const char *l; if (type->type == CARR) type = type->rec.arr.elem; else type = type->rec.ref; l = 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: { CType_t type = i->dest->type; int arr = mips_to_reg(i->dest, reg_v0); const char *s; int rs; if (type->type == CARR) type = type->rec.arr.elem; else type = type->rec.ref; s = type->type == CCHAR ? "sb" : "sw"; 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) # push\n", rs, i->offset); } break; case CALL: { int rd = i->dest->reg; if (i->src1->kind == IMMF) printf("\tjal _func_%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 && i->src2->info.imm > -0x7fff && i->src2->info.imm < 0x8000) { 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(); }