def return_function(function: MCFunction) -> [List[MCInstruction]]: output = [] syscode = 10 if function.name == "main": output.append(MCInstruction("li", regs=["$v0"], imm=syscode)) output.append(MCInstruction("syscall")) else: output.append(MCInstruction("jr", regs=["$ra"])) return output
def convert_assignment(instr: IRInstruction) -> str: dest, src = instr.argument_list assert (instr.instruction_type == "val_assign") assert (not is_constant(dest)) if not is_constant(src): output = [MCInstruction("move", regs=[dest, src])] else: output = [MCInstruction("li", regs=[dest], imm=src)] return output
def convert_return(instr): assert (instr.instruction_type == "return") assert (len(instr.argument_list) == 1) ret_val = instr.argument_list[0] output = [] v0 = "$v0" if is_constant(ret_val): output.append(MCInstruction("li", regs=[v0], imm=ret_val)) else: output.append(MCInstruction("move", regs=[v0, ret_val])) output.append(MCInstruction("ret")) return output
def alloc_array(name: str, size: int, offset: int) -> List[MCInstruction]: syscode = 9 output = [] fp = "$fp" # syscall output.append(MCInstruction("li", regs=["$v0"], imm=syscode)) output.append(MCInstruction("li", regs=["$a0"], imm=size * 4)) output.append(MCInstruction("syscall")) # store pointer on the stack output.append(MCInstruction("sw", regs=["$v0", fp], offset=offset)) return output
def convert_instr(reg_map, instr: MCInstruction, offsets: Dict[str, int], epilogue, rtn, optimize=False) -> List[MCInstruction]: """ Convert a single instruction from using virtual register to physical register. Also, if this instruction is `call` or `callr`, then it's also changed to an actual machine instruction. Args: - reg_map: the register map in this basic block - instr: the instruction to be changed - offsets: offsets dictionary Return: - a list of instruction that's equivalent """ if instr.op == "ret": return epilogue + rtn fp = "$fp" if instr.op == "save_arg": reg = instr.regs[0] return [MCInstruction("sw", regs=[reg, fp], offset=offsets[reg])] if instr.op == "restore_arg": reg = instr.regs[0] return [MCInstruction("lw", regs=[reg, fp], offset=offsets[reg])] # TODO: assume the caller's stack is already even, add padding if the number of args that need to be passed through the stack is odd output = [] # physical_regs = [reg_map[virtual_reg] for virtual_reg in instr.regs] curr_temp = 0 if instr.regs is None: return [instr] prologue = [] epilogue = [] save, restore, new_regs = spill( reg_map, instr, offsets, optimize=optimize ) # it's fine to call this on non-spilling since the code arrays will be empty output += prologue output += save instr.regs = new_regs output.append(instr) output += restore output += epilogue return output
def save_and_restore( reg_name: str) -> Tuple[List[MCInstruction], List[MCInstruction]]: """ Computes the save and restore code for a single register. Args: - reg_name: the register to be saved and restored, make sure this is a physical register Returns: - a tuple of list of instructions. The first of which is the save code, the second is the restore code """ save_code = [] restore_code = [] sp = "$sp" save_code.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) save_code.append(MCInstruction("sw", regs=[reg_name, sp], offset=0)) restore_code.append(MCInstruction("lw", regs=[reg_name, sp], offset=0)) restore_code.append(MCInstruction("addiu", regs=[sp, sp], imm=4)) return save_code, restore_code
def load_and_save_locals( reg_map: Dict[str, int], offsets: Dict[str, int]) -> Tuple[List[MCInstruction], List[MCInstruction]]: load = [] save = [] fp = "$fp" # pprint.pprint(reg_map) # print(offsets) arg_pattern = re.compile(r"\$a[0123]") for virt, phys in reg_map.items(): if phys != "spill" and arg_pattern.match(phys) is None: offset = offsets[virt] load.append(MCInstruction("lw", regs=[phys, fp], offset=offset)) save.append(MCInstruction("sw", regs=[phys, fp], offset=offset)) return load, save
def convert_branch(instr: IRInstruction, func) -> str: if instr.instruction_type == "goto": target = instr.argument_list[0] return [MCInstruction("j", target="%s_%s" % (func, target))] else: branch_map = { "breq": "beq", "brneq": "bne", "brlt": "blt", "brgt": "bgt", "brgeq": "bge", "brleq": "ble" } label, src0, src1 = instr.argument_list op = branch_map[instr.instruction_type] output = [] temp = s_map["CONVERT_BRANCH_TEMP_REG"] if not is_constant(src0) and not is_constant(src1): output.append( MCInstruction(op, regs=[src0, src1], target="%s_%s" % (func, label))) elif not is_constant(src0) and is_constant(src1): output.append(MCInstruction("li", regs=[temp], imm=src1)) output.append( MCInstruction(op, regs=[src0, temp], target="%s_%s" % (func, label))) elif is_constant(src0) and not is_constant(src1): output.append(MCInstruction("li", regs=[temp], imm=src0)) output.append( MCInstruction(op, regs=[temp, src1], target="%s_%s" % (func, label))) else: raise ValueError( "Both operands of branch instruction are constants") del s_map["CONVERT_BRANCH_TEMP_REG"] return output
def convert_calls(instr: IRInstruction): # NOTE: this is temporary and should not ever end up in the final output assert (instr.instruction_type == "call" or instr.instruction_type == "callr") intrinsics = ["geti", "getf", "getc", "puti", "putf", "putc"] sp = "$sp" if instr.instruction_type == "call": function_name = instr.argument_list[0] arguments = instr.argument_list[1:] return_dest = None else: return_dest = instr.argument_list[0] function_name = instr.argument_list[1] arguments = instr.argument_list[2:] if function_name in intrinsics: return convert_intrinsic(instr, function_name, arguments, return_dest) output = [] save_arg = [] restore_arg = [] # normal function call first_section = arguments[:4] for i, arg in enumerate(first_section): arg_reg = "$a%d" % i save_arg.append(MCInstruction("save_arg", regs=[arg_reg])) restore_arg.append(MCInstruction("restore_arg", regs=[arg_reg])) if is_constant(arg): output.append( MCInstruction("li", regs=[arg_reg], imm=arg, is_call_move=True)) else: output.append( MCInstruction("move", regs=[arg_reg, arg], is_call_move=True)) second_section = arguments[4:][:-1] # pushing in reverse order temp = s_map["CONVERT_CALLS_TEMP_REG"] stack_length = 0 for arg in second_section: output.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) stack_length += 1 if is_constant(arg): output.append(MCInstruction("li", regs=[temp], imm=arg)) output.append(MCInstruction("sw", regs=[temp, sp], imm=0)) else: output.append(MCInstruction("sw", regs=[arg, sp], imm=0)) del s_map["CONVERT_CALLS_TEMP_REG"] # paddding if len(second_section) % 2 == 1: output.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) stack_length += 1 # the actual call itself output.append(MCInstruction("jal", target=function_name)) if instr.instruction_type == "callr": # reading the return value output.append(MCInstruction("move", regs=[ return_dest, "$v0" ])) # shouldn't have anything that doesn't fit in one word # popping the stack if stack_length != 0: output.append( MCInstruction("addiu", regs=[sp, sp], imm=4 * stack_length)) return save_arg + output + restore_arg
def convert_intrinsic(instr: IRInstruction, name: str, args: List[str], dest: str = None) -> List[MCInstruction]: """ Converts an intrinsic function call to use the relevant syscall. Note that v0 and a0 is always saved and restored, regardless of whether these registers are actually used in the function. Args: - instr: the instruction to be translated Returns: - a list of instructions equivalent to the intrinsic function """ sys_codes = { "print_int": 1, "print_float": 2, "print_double": 3, "print_string": 4, "read_int": 5, "raed_float": 6, "read_double": 7, "read_string": 8, "sbrk": 9, "exit": 10, "print_char": 11 } output = [] op = name if op == "geti" or op == "getc": # CHECK: does getc and geti actually work in the same way? # saving v0, CHECK: is this really needed? # save, restore = save_and_restore("$v0") # output += save # moving syscode into v0 output.append( MCInstruction("li", regs=["$v0"], imm=sys_codes["read_int"])) # syscall output.append(MCInstruction("syscall")) # moving output into destination output.append(MCInstruction("move", regs=[dest, "$v0"])) # restoring v0 # output += restore return output elif op == "getf": raise NotImplementedError( "getf() isn't implemented as floats are not supported") elif op == "puti": # arg = instr.arguments[0] arg = args[0] # saving a0 and v0 # save_a0, restore_a0 = save_and_restore("$a0") # save_v0, restore_v0 = save_and_restore("$v0") # output += save_a0 # output += save_v0 # moving argument into a0 output.append(MCInstruction("save_arg", regs=["$a0"])) if is_constant(arg): output.append(MCInstruction("li", regs=["$a0"], imm=arg)) else: output.append(MCInstruction("move", regs=["$a0", arg])) # moving syscode into v0 output.append( MCInstruction("li", regs=["$v0"], imm=sys_codes["print_int"])) # syscall output.append(MCInstruction("syscall")) output.append(MCInstruction("restore_arg", regs=["$a0"])) # restoring a0 and v0 # output += restore_v0 # output += restore_a0 return output elif op == "putf": raise NotImplementedError( "putf() isn't implemented as floats are not supported") elif op == "putc": # arg = instr.arguments[0] arg = args[0] # saving a0 and v0 # save_a0, restore_a0 = save_and_restore("$a0") # save_v0, restore_v0 = save_and_restore("$v0") # output += save_a0 # output += save_v0 # moving argument into a0 output.append(MCInstruction("save_arg", regs=["$a0"])) if is_constant(arg): output.append(MCInstruction("li", regs=["$a0"], imm=arg)) else: output.append(MCInstruction("move", regs=["$a0", arg])) # moving syscode into v0 output.append( MCInstruction("li", regs=["$v0"], imm=sys_codes["print_char"])) # syscall output.append(MCInstruction("syscall")) output.append(MCInstruction("restore_arg", regs=["$a0"])) # restoring a0 and v0 # output += restore_v0 # output += restore_a0 return output else: raise ValueError("Unexpected intrinsic function: %s" % op)
def convert_arithmetic(instr: IRInstruction) -> str: """ Converts an arithmetic instruction to assembly """ assert (instr.is_arithmetic()) assert (not is_constant(instr.argument_list[0])) global s_map dest, src0, src1 = instr.argument_list output = [] if instr.instruction_type == "add" or instr.instruction_type == "sub": if not is_constant(src0) and not is_constant(src1): # neither is constant output.append( MCInstruction(instr.instruction_type, regs=[dest, src0, src1])) elif not is_constant(src0) and is_constant(src1): # src1 is constant src1 = int(src1) if instr.instruction_type == "add": output.append( MCInstruction("addi", regs=[dest, src0], imm=src1)) else: output.append( MCInstruction("addi", regs=[dest, src0], imm=-src1)) elif is_constant(src0) and not is_constant(src1): # src0 is constant src = int(src0) if instr.instruction_type == "add": output.append( MCInstruction("addi", regs=[dest, src1], imm=src0)) else: output.append(MCInstruction("li", regs=[dest], imm=src0)) output.append(MCInstruction("sub", regs=[dest], imm=src1)) else: # both are constant src1 = int(src1) src0 = int(src0) output.append(MCInstruction("li", regs=[dest], imm=src0)) if instr.instruction_type == "add": output.append(MCInstruction("addi", regs=[dest], imm=src1)) else: output.append(MCInstruction("addi", regs=[dest], imm=-src1)) if instr.instruction_type == "mult": if is_constant(src0): output.append( MCInstruction("li", regs=[s_map["multiply_temp_reg0"]], imm=src0)) first_op = s_map["multiply_temp_reg0"] else: first_op = src0 if is_constant(src1): output.append( MCInstruction("li", regs=[s_map["multiply_temp_reg1"]], imm=src1)) second_op = s_map["multiply_temp_reg1"] else: second_op = src1 output.append(MCInstruction("mul", regs=[dest, first_op, second_op])) if instr.instruction_type == "div": if is_constant(src0): output.append( MCInstruction("li", regs=[s_map["divide_temp_reg0"]], imm=src0)) first_op = s_map["divide_temp_reg0"] else: first_op = src0 if is_constant(src1): output.append( MCInstruction("li", regs=[s_map["divide_temp_reg1"]], imm=src1)) second_op = s_map["divide_temp_reg1"] else: second_op = src1 output.append(MCInstruction("div", regs=[dest, first_op, second_op])) if instr.instruction_type in ["and", "or"]: i_type = instr.instruction_type if not is_constant(src0) and not is_constant(src1): output.append(MCInstruction(i_type, regs=[dest, src0, src1])) elif not is_constant(src0) and is_constant(src1): output.append( MCInstruction(i_type + "i", regs=[dest, src0], imm=src1)) elif is_constant(src0) and not is_constant(src1): output.append( MCInstruction(i_type + "i", regs=[dest, src1], imm=src0)) else: output.append(MCInstruction("addi", regs=[dest, "$0"], imm=src0)) output.append( MCInstruction(i_type + "i", regs=[dest, dest], imm=src1)) return output
def convert_label(instr: IRInstruction, func): assert (instr.instruction_type == "label") return [ MCInstruction("label", target="%s_%s" % (func, instr.argument_list[0])) ]
def convert_array_assign(instr, func): # TODO: implement assert (instr.instruction_type == "array_assign") assert (len(instr.argument_list) == 3) array, size, value = instr.argument_list num = func.curr_array_assign func.curr_array_assign += 1 # temp0 = s_map["array_assign_temp0"] # temp1 = s_map["array_assign_temp1"] # temp2 = s_map["array_assign_temp2"] output = [] index = s_map["array_assign_index"] if is_constant(size): output.append(MCInstruction("li", regs=[index], imm=size)) else: output.append(MCInstruction("move", regs=[index, size])) address = s_map["array_assign_address"] output.append(MCInstruction("move", regs=[address, array])) if is_constant(value): val_reg = s_map["array_assign_value"] output.append(MCInstruction("li", regs=[val_reg], imm=value)) value = val_reg # continue from here output.append( MCInstruction("label", target=func.name + "_array_assign_loop" + str(num))) output.append( MCInstruction("blez", regs=[index], target=func.name + "_array_assign_end" + str(num))) output.append(MCInstruction("sw", regs=[value, address], imm=0)) output.append(MCInstruction("addi", regs=[index, index], imm=-1)) output.append(MCInstruction("addiu", regs=[address, address], imm=4)) output.append( MCInstruction("j", target=func.name + "_array_assign_loop" + str(num))) output.append( MCInstruction("label", target=func.name + "_array_assign_end" + str(num))) # if is_constant(size) and is_constant(value): # output.append(MCInstruction("move", regs=[temp0, array])) # output.append(MCInstruction("addi", regs=[temp1, temp0], imm=size)) # output.append(MCInstruction("li", regs=[temp2], imm=value)) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("bge",regs=[temp0, temp1], target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # output.append(MCInstruction("sw", regs=[temp2, temp0])) # output.append(MCInstruction("addi", regs=[temp0, temp0], imm=4)) # output.append(MCInstruction("j", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # elif is_constant(size) and not is_constant(value): # output.append(MCInstruction("move", regs=[temp0, array])) # output.append(MCInstruction("add", regs=[temp1, temp0, size])) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("bge",regs=[temp0, temp1], target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # output.append(MCInstruction("sw", regs=[value, temp0])) # output.append(MCInstruction("addi", regs=[temp0, temp0], imm=4)) # output.append(MCInstruction("j", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # elif not is_constant(size) and is_constant(value): # output.append(MCInstruction("move", regs=[temp0, array])) # output.append(MCInstruction("add", regs=[temp1, temp0, size])) # output.append(MCInstruction("li", regs=[temp2], imm=value)) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("bge",regs=[temp0, temp1], target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # output.append(MCInstruction("sw", regs=[temp2, temp0])) # output.append(MCInstruction("addi", regs=[temp0, temp0], imm=4)) # output.append(MCInstruction("j", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # else: # output.append(MCInstruction("move", regs=[temp0, array])) # output.append(MCInstruction("add", regs=[temp1, temp0, size])) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("bge",regs=[temp0, temp1], target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # output.append(MCInstruction("sw", regs=[value, temp0])) # output.append(MCInstruction("addi", regs=[temp0, temp0], imm=4)) # output.append(MCInstruction("j", target="%s_CONVERT_ARRAY_ASSIGN_LOOP" % func)) # output.append(MCInstruction("label", target="%s_CONVERT_ARRAY_ASSIGN_END" % func)) # del s_map["array_assign_temp0"] # del s_map["array_assign_temp1"] # del s_map["array_assign_temp2"] return output
def convert_array_load_store(instr): # TODO: implement assert (instr.instruction_type in ["array_store", "array_load"]) assert (len(instr.argument_list) == 3) val, array, index = instr.argument_list array = array output = [] if instr.instruction_type == "array_load": op = "lw" else: op = "sw" if is_constant(index) and not is_constant(val): index = int(index) output.append(MCInstruction(op, regs=[val, array], offset=index * 4)) elif is_constant(index) and is_constant(val): index = int(index) output.append( MCInstruction("li", regs=[s_map["array_temp_reg"]], imm=val)) output.append( MCInstruction(op, regs=[s_map["array_temp_reg"], array], offset=index * 4)) del s_map["array_temp_reg"] elif not is_constant(index) and is_constant(val): # getting the immediate value into a register output.append( MCInstruction("li", regs=[s_map["array_temp_reg0"]], imm=val)) # address calculation output.append( MCInstruction("move", regs=[s_map["array_temp_reg1"], index])) output.append( MCInstruction( "sll", regs=[s_map["array_temp_reg1"], s_map["array_temp_reg1"]], imm=2)) output.append( MCInstruction("addu", regs=[ s_map["array_temp_reg1"], array, s_map["array_temp_reg1"] ])) output.append( MCInstruction( op, regs=[s_map["array_temp_reg0"], s_map["array_temp_reg1"]], offset=0)) del s_map["array_temp_reg0"] del s_map["array_temp_reg1"] else: output.append( MCInstruction("move", regs=[s_map["array_temp_reg"], index])) output.append( MCInstruction( "sll", regs=[s_map["array_temp_reg"], s_map["array_temp_reg"]], imm=2)) output.append( MCInstruction( "addu", regs=[s_map["array_temp_reg"], array, s_map["array_temp_reg"]])) output.append( MCInstruction(op, regs=[val, s_map["array_temp_reg"]], offset=0)) del s_map["array_temp_reg"] return output
def calling_convention( function: MCFunction ) -> (List[MCInstruction], List[MCInstruction], Dict[str, int]): """ Handles the callee portion of the calling convention for a particular function. Note that this does not handle any of the caller responsibilities. Those should be handled by the code that deals with `call` and `callr` instructions. Currently arrays are always spilled Args: function: The function whose callee saving and restoring we are doing save: Whether we should produce the saving or the restoring code Returns: A list of MCInstruction A dictionary map of spilled virtual register names to its location on the stack """ # if not function.has_data: # return None # prologue of the calling convention prologue = [] offsets = {} sp = "$sp" fp = "$fp" # prologue # make space for fp and save prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) prologue.append(MCInstruction("sw", regs=[fp, sp], offset=0)) prologue.append(MCInstruction("move", regs=[fp, sp])) curr_offset = -4 # make space for arg registers for i in range(4): arg_reg = "$a%d" % i # prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) offsets[arg_reg] = curr_offset curr_offset -= 4 # make space for arrays arr_names = [] for arr in function.int_arrs: arr_names.append(arr[0]) prologue += alloc_array(arr[0], arr[1], curr_offset) offsets[arr[0]] = curr_offset curr_offset -= 4 # make space for local variables # for greedy local alloc, need to save everything (even non-spilled) for val in function.int_vals: if val not in arr_names: # prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) offsets[val] = curr_offset curr_offset -= 4 # save all the t registers (as specified in the pdf) for i in range(10): t_reg = "$t%d" % i # if function.name != "main": # prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) # prologue.append(MCInstruction("sw", regs=[t_reg, sp], imm=0)) prologue.append( MCInstruction("sw", regs=[t_reg, fp], offset=curr_offset)) offsets[t_reg] = curr_offset curr_offset -= 4 # else: # prologue.append(MCInstruction("li", regs=[t_reg], imm=0)) # padding if needs_pad(function): # prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) curr_offset -= 4 if function.name != "main": # return address # prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) prologue.append( MCInstruction("sw", regs=["$ra", fp], offset=curr_offset)) offsets["$ra"] = curr_offset curr_offset -= 4 # s registers for s in function.saved_regs: # prologue.append(MCInstruction("addiu", regs=[sp, sp], imm=-4)) prologue.append(MCInstruction("sw", regs=[s, fp], offset=curr_offset)) offsets[s] = curr_offset curr_offset -= 4 # now, finally move the sp prologue.append(MCInstruction("addiu", regs=[sp, fp], imm=curr_offset + 4)) # epilogue epilogue = [] # restore the s registers # for s in function.saved_regs[::-1]: for s in function.saved_regs: epilogue.append(MCInstruction("lw", regs=[s, fp], offset=offsets[s])) if function.name != "main": # restore the return address epilogue.append( MCInstruction("lw", regs=["$ra", fp], offset=offsets["$ra"])) # epilogue.append(MCInstruction("addiu", regs=[sp, sp], imm=4)) # restore t registers for i in range(10): t_reg = "$t%d" % i epilogue.append( MCInstruction("lw", regs=[t_reg, fp], offset=offsets[t_reg])) # restore the fp epilogue.append(MCInstruction("move", regs=[sp, fp])) # moving sp back to fp epilogue.append(MCInstruction("lw", regs=[fp, sp], offset=0)) epilogue.append(MCInstruction("addiu", regs=[sp, sp], imm=4)) return prologue, epilogue, offsets
def spill( reg_map: Dict[str, str], instr: MCInstruction, offsets: Dict[str, int], optimize=False ) -> (List[MCInstruction], List[MCInstruction], Dict[str, str]): """ Performs spilling given a register map and the set of original virtual registers, with some additional information. At the end, outputs the spilling code as well as the complete register mapping (with every virtual register mapped to a physical register). Uses t0-t2 for spilling (since a single instruction should not have more than three registers). Args: reg_map: the register mapping given by the allocator instr: the MCInstruction to perform spilling on offsets: the map from virtual register to the frame pointer offset on the stack load: whether this is for loading or storing Returns: save: a list of MCInstructions which is the spill save code restore: a list of MCInstructions which is the spill restore code new_args: the physical registers of the instruction """ # NOTE: it's assumed that the position at $fp will be used for saving the register used here save_temp = [] load_virt = [] save_virt = [] load_temp = [] new_args = [] curr_temp = 9 # for phys, ir in zip(phys_reg, ir_regs): new_map = {} # compute used temp regs in the instruction used_temps = set() for virt in instr.regs: if virt[0] == "$": used_temps.add(virt) else: phys = reg_map[virt] if phys != "spill": used_temps.add(phys) is_spilled = False for virtual in instr.regs: if virtual not in new_map: if virtual[0] == "$": new_args.append(virtual) new_map[virtual] = virtual else: physical = reg_map[virtual] if physical == "spill": is_spilled = True temp_reg = "$t%d" % curr_temp while temp_reg in used_temps: curr_temp -= 1 assert (curr_temp < 10) temp_reg = "$t%d" % curr_temp # used_temps.add(temp_reg) if optimize: temp_needs_save = temp_reg in reg_map.values() virt_needs_load = virtual in instr.get_uses() else: temp_needs_save = True virt_needs_load = True if temp_needs_save: save_temp.append( MCInstruction("sw", regs=[temp_reg, "$fp"], offset=offsets[temp_reg])) if virt_needs_load: load_virt.append( MCInstruction("lw", regs=[temp_reg, "$fp"], offset=offsets[virtual])) save_virt.append( MCInstruction("sw", regs=[temp_reg, "$fp"], offset=offsets[virtual])) if temp_needs_save: load_temp.append( MCInstruction("lw", regs=[temp_reg, "$fp"], offset=offsets[temp_reg])) new_args.append(temp_reg) new_map[virtual] = temp_reg curr_temp -= 1 else: new_args.append(physical) new_map[virtual] = physical else: new_args.append(new_map[virtual]) prologue = save_temp + load_virt epilogue = save_virt + load_temp # if is_spilled: # print("used temps: ", used_temps) # print(reg_map) # print(offsets) # print("prologue:") # for i in prologue: # print(i) # print("instr: ") # new_instr = instr # new_instr.regs = new_args # print(new_instr) # print("epilogue:") # for i in epilogue: # print(i) # print() # print() # print() return prologue, epilogue, new_args