⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mips.cpp

📁 一个面向对像语言的编译器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
 * all registers here.
 */
void Mips::EmitIfZ(Declaration *test, const char *label)
{ 
  Register testReg = GetRegister(test);
  SpillAllDirtyRegisters();
  Emit("beqz %s, %s\t# branch if %s is zero ", regs[testReg].name, label,
	 test->GetName());
}


/* Method: EmitArg
 * ---------------
 * Used to push a parameter on the stack in anticipation of upcoming
 * function call. Decrements the stack pointer by 4. Slaves argument into
 * register and then stores contents to location just made at end of
 * stack.
 */
void Mips::EmitArg(Declaration *arg)
{ 
  Emit("subu $sp, $sp, 4\t# decrement sp to make space for param");
  Register reg = GetRegister(arg);
  Emit("sw %s, 4($sp)\t# copy param value to stack", regs[reg].name);
}


/* Method: EmitCallInstr
 * ---------------------
 * Used to effect a function call. All necessary arguments should have
 * already been pushed on the stack, this is the last step that
 * transfers control from caller to callee.  See comments on Goto method
 * above for why we spill all registers before making the jump. We issue
 * jal for a label, a jalr if address in register. Both will save the
 * return address in $ra. If there is an expected result passed, we slave
 * the var to a register and copy function return value from $v0 into that
 * register.  We also remove all parameters from the stack (the bytes
 * param tells us how much space to remove) by adjusting the stack pointer
 * upwards.
 */
void Mips::EmitCallInstr(Declaration *result, const char *fn, int bytes,
				  bool isLabel)
{
  SpillAllDirtyRegisters();
  Emit("%s %-15s\t# jump to function", isLabel? "jal": "jalr", fn);
  if (result != NULL) {
    Register r1 = GetRegisterForWrite(result);
    Emit("move %s, %s\t\t# copy function return value from $v0", regs[r1].name, regs[v0].name);
  }
  if (bytes != 0)
    Emit("add $sp, $sp, %d\t# pop params off stack", bytes);
}


// Two covers for the above method for specific LCall/ACall variants
void Mips::EmitLCall(Declaration *dst, const char *label, int bytes)
{ 
  EmitCallInstr(dst, label, bytes, true);
}

void Mips::EmitACall(Declaration *dst, Declaration *fn, int bytes)
{
  EmitCallInstr(dst, regs[GetRegister(fn)].name, bytes, false);
}


/* Method: EmitReturn
 * ------------------
 * Used to emit code for returning from a function (either from an
 * explicit return or falling off the end of the function body).
 * If there is an expression to return, we slave that variable into
 * a register and move its contents to $v0 (the standard register for
 * function result).  Before exiting, we spill dirty registers (to
 * commit contents of slaved registers to memory, necessary for
 * consistency, see comments at SpillForEndFunction above). We also
 * do the last part of the callee's job in function call protocol,
 * which is to remove our locals/temps from the stack, remove
 * saved registers ($fp and $ra) and restore previous values of
 * $fp and $ra so everything is returned to the state we entered.
 * We then emit jr to jump to the saved $ra.
 */
 void Mips::EmitReturn(Declaration *returnVal)
{ 
  if (returnVal != NULL) 
    Emit("move $v0, %s\t\t# assign return value into $v0",
	   regs[GetRegister(returnVal)].name);
  SpillForEndFunction();
  Emit("move $sp, $fp\t\t# pop callee frame off stack");
  Emit("lw $ra, -4($fp)\t# restore saved ra");
  Emit("lw $fp, 0($fp)\t# restore saved fp");
  Emit("jr $ra\t\t# return from function");
}


/* Method: EmitBeginFunction
 * -------------------------
 * Used to handle the callee's part of the function call protocol
 * upon entering a new function. We decrement the $sp to make space
 * and then save the current values of $fp and $ra (since we are
 * going to change them), then set up the $fp and bump the $sp down
 * to make space for all our locals/temps.
 */
void Mips::EmitBeginFunction(int frameSize)
{
  Assert(frameSize >= 0);
  Emit("subu $sp, $sp, 8\t# decrement sp to make space to save ra, fp");
  Emit("sw $fp, 8($sp)\t# save fp");
  Emit("sw $ra, 4($sp)\t# save ra");
  Emit("addiu $fp, $sp, 8\t# set up new fp");

  if (frameSize != 0)
    Emit("subu $sp, $sp, %d\t# decrement sp to make space for locals/temps",
	   frameSize);
}


/* Method: EmitEndFunction
 * -----------------------
 * Used to end the body of a function. Does an implicit return in fall off
 * case to clean up stack frame, return to caller etc. See comments on
 * EmitReturn above.
 */
void Mips::EmitEndFunction()
{ 
  Emit("# (below handles reaching end of fn body with no explicit return)");
  EmitReturn(NULL);
}



/* Method: EmitVTable
 * ------------------
 * Used to layout a vtable. Uses assembly directives to set up new
 * entry in data segment, emits label, and lays out the function
 * labels one after another.
 */
void Mips::EmitVTable(const char *label, DeclList *methods)
{
  Emit(".data");
  Emit(".align 2");
  Emit("%s:\t\t# label for class %s vtable", label, label);
  for (int i = 0; i < methods->NumElements(); i++)
    Emit(".word %s\n", methods->Nth(i)->GetFunctionLabel());
  Emit(".text");
}


/* Method: EmitPreamble
 * --------------------
 * Used to emit the starting sequence needed for a program. Not much
 * here, but need to indicate what follows is in text segment and
 * needs to be aligned on word boundary. main is our only global symbol.
 */
void Mips::EmitPreamble()
{
  Emit("# standard Decaf preamble ");
  Emit(".text");
  Emit(".align 2");
  Emit(".globl main");
}


/* Method: NameForTac
 * ------------------
 * Returns the appropriate MIPS instruction (add, seq, etc.) for
 * a given Tac::OpCode (Tac::Add, Tac::Equals, etc.). Assets if
 * asked for an instruction for an unset/out of bounds code.
 */
const char *Mips::NameForTac(Tac::OpCode code)
{
  Assert(code >=0 && code < Tac::NumOps);
  const char *name = mipsName[code];
  Assert(name != NULL);
  return name;
}

/* Constructor
 * ----------
 * Constructor sets up the mips names and register descriptors to
 * the initial starting state.
 */
Mips::Mips() {
  mipsName[Tac::Add] = "add";
  mipsName[Tac::Sub] = "sub";
  mipsName[Tac::Mul] = "mul";
  mipsName[Tac::Div] = "div";
  mipsName[Tac::Mod] = "rem";
  mipsName[Tac::Eq] = "seq";
  mipsName[Tac::Less] = "slt";
  mipsName[Tac::And] = "and";
  mipsName[Tac::Or] = "or";
    
  regs[zero].isDirty = false;
  regs[zero].decl = NULL;
  regs[zero].name = "$zero";
  regs[zero].isGeneralPurpose = false;

  regs[at].isDirty = false;
  regs[at].decl = NULL;
  regs[at].name = "$at";
  regs[at].isGeneralPurpose = false;

  regs[v0].isDirty = false;
  regs[v0].decl = NULL;
  regs[v0].name = "$v0";
  regs[v0].isGeneralPurpose = false;

  regs[v1].isDirty = false;
  regs[v1].decl = NULL;
  regs[v1].name = "$v1";
  regs[v1].isGeneralPurpose = false;

  regs[a0].isDirty = false;
  regs[a0].decl = NULL;
  regs[a0].name = "$a0";
  regs[a0].isGeneralPurpose = false;

  regs[a1].isDirty = false;
  regs[a1].decl = NULL;
  regs[a1].name = "$a1";
  regs[a1].isGeneralPurpose = false;

  regs[a2].isDirty = false;
  regs[a2].decl = NULL;
  regs[a2].name = "$a2";
  regs[a2].isGeneralPurpose = false;

  regs[a3].isDirty = false;
  regs[a3].decl = NULL;
  regs[a3].name = "$a3";
  regs[a3].isGeneralPurpose = false;

  regs[k0].isDirty = false;
  regs[k0].decl = NULL;
  regs[k0].name = "$k0";
  regs[k0].isGeneralPurpose = false;

  regs[k1].isDirty = false;
  regs[k1].decl = NULL;
  regs[k1].name = "$k1";
  regs[k1].isGeneralPurpose = false;

  regs[gp].isDirty = false;
  regs[gp].decl = NULL;
  regs[gp].name = "$gp";
  regs[gp].isGeneralPurpose = false;

  regs[sp].isDirty = false;
  regs[sp].decl = NULL;
  regs[sp].name = "$sp";
  regs[sp].isGeneralPurpose = false;

  regs[fp].isDirty = false;
  regs[fp].decl = NULL;
  regs[fp].name = "$fp";
  regs[fp].isGeneralPurpose = false;

  regs[ra].isDirty = false;
  regs[ra].decl = NULL;
  regs[ra].name = "$ra";
  regs[ra].isGeneralPurpose = false;

  regs[t0].isDirty = false;
  regs[t0].decl = NULL;
  regs[t0].name = "$t0";
  regs[t0].isGeneralPurpose = true;
  
  regs[t1].isDirty = false;
  regs[t1].decl = NULL;
  regs[t1].name = "$t1";
  regs[t1].isGeneralPurpose = true;
  
  regs[t2].isDirty = false;
  regs[t2].decl = NULL;
  regs[t2].name = "$t2";
  regs[t2].isGeneralPurpose = true;
  
  regs[t3].isDirty = false;
  regs[t3].decl = NULL;
  regs[t3].name = "$t3";
  regs[t3].isGeneralPurpose = true;
  
  regs[t4].isDirty = false;
  regs[t4].decl = NULL;
  regs[t4].name = "$t4";
  regs[t4].isGeneralPurpose = true;
  
  regs[t5].isDirty = false;
  regs[t5].decl = NULL;
  regs[t5].name = "$t5";
  regs[t5].isGeneralPurpose = true;
  
  regs[t6].isDirty = false;
  regs[t6].decl = NULL;
  regs[t6].name = "$t6";
  regs[t6].isGeneralPurpose = true;
  
  regs[t7].isDirty = false;
  regs[t7].decl = NULL;
  regs[t7].name = "$t7";
  regs[t7].isGeneralPurpose = true;
  
  regs[t8].isDirty = false;
  regs[t8].decl = NULL;
  regs[t8].name = "$t8";
  regs[t8].isGeneralPurpose = true;
  
  regs[t9].isDirty = false;
  regs[t9].decl = NULL;
  regs[t9].name = "$t9";
  regs[t9].isGeneralPurpose = true;
  
  
  regs[s0].isDirty = false;
  regs[s0].decl = NULL;
  regs[s0].name = "$s0";
  regs[s0].isGeneralPurpose = true;
  
  regs[s1].isDirty = false;
  regs[s1].decl = NULL;
  regs[s1].name = "$s1";
  regs[s1].isGeneralPurpose = true;
  
  regs[s2].isDirty = false;
  regs[s2].decl = NULL;
  regs[s2].name = "$s2";
  regs[s2].isGeneralPurpose = true;
  
  regs[s3].isDirty = false;
  regs[s3].decl = NULL;
  regs[s3].name = "$s3";
  regs[s3].isGeneralPurpose = true;
  
  regs[s4].isDirty = false;
  regs[s4].decl = NULL;
  regs[s4].name = "$s4";
  regs[s4].isGeneralPurpose = true;
  
  regs[s5].isDirty = false;
  regs[s5].decl = NULL;
  regs[s5].name = "$s5";
  regs[s5].isGeneralPurpose = true;
  
  regs[s6].isDirty = false;
  regs[s6].decl = NULL;
  regs[s6].name = "$s6";
  regs[s6].isGeneralPurpose = true;
  
  regs[s7].isDirty = false;
  regs[s7].decl = NULL;
  regs[s7].name = "$s7";
  regs[s7].isGeneralPurpose = true;

  lastUsed = zero;
}
const char *Mips::mipsName[Tac::NumOps];






⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -