Example #1
0
 def remove_placeholders(self):
     ''' 
     replace Prolog/Epilog/SaveRegisters/RestoreRegisters with real instructions
     now that we know what registers are used
     '''
     cfg = flow.make_cfg(self.insts)
     outs = flow.get_lives(cfg)
     # t registers that need to be saved
     tregs = []
     for node in sorted(cfg.get_calls()): 
         tregs.append(sorted({reg for reg in outs[node]
             if reg.typ == 't'}))
     space = (max(len(regs) for regs in tregs) * 4
             if len(tregs) > 0
             else 0) 
     t_offset = self.alloc(size=space)
     s_offset = self.alloc(size=len(self.sregs)*4+4)
     # replace prologs/epilogs with stores and loads
     insts = []
     i = 0
     if i < len(tregs):
         regs = tregs[i]
         i += 1
     for inst in self.insts:
         inst_type = type(inst)
         if inst_type == Call:
             store_regs(regs, t_offset, insts)
             insts.append(
                 new_ir('add', rd=REG_SP, rs=REG_SP, rt=grammar.Int(-mulof4(inst.extra))))
             insts.append(new_ir('jal', rs=funcname_to_branch(inst.name), rt=None, rd=None))
             insts.append(
                 new_ir('add', rd=REG_SP, rs=REG_SP, rt=grammar.Int(mulof4(inst.extra))))
             load_regs(regs, t_offset, insts)
             if i < len(tregs):
                 regs = tregs[i]
                 i += 1
         elif inst_type == Prolog:
             # grow stack and store needed s registers
             grow = new_ir('add',
                     rd=REG_SP,
                     rs=REG_SP,
                     rt=grammar.Int(-self.stack_size()))
             insts.extend([
                     new_ir('move', rd=REG_FP, rs=REG_SP, rt=None),
                     grow
                     ])
             store_regs(self.sregs+[REG_RA], s_offset, insts)
         elif inst_type == Epilog:
             # restore used registers
             load_regs(self.sregs+[REG_RA], s_offset, insts)
             shrink = new_ir('add',
                     rd=REG_SP,
                     rs=REG_SP,
                     rt=grammar.Int(self.stack_size()))
             insts.extend([ 
                 shrink,
                 new_ir('jr', rs=Register('ra', None), rt=None, rd=None)
                 ])
         else:
             insts.append(inst)
     self.insts = insts 
Example #2
0
def alloc(compiler):
    '''
    given a function compiler, allocate registers for its registers
    '''
    # only use temporary registers for now
    k = 18 # s0 - s7 and t0 - t9
    insts = compiler.insts
    cfg = flow.make_cfg(insts)
    int_graph, liveouts = make_int_graph(cfg)
    coloring, uncolored = color(int_graph, k) 
    while len(uncolored) > 0: # have to spill 
        spilled = set(uncolored)
        new_insts = []
        addrs = {}
        for reg in uncolored:
            addrs[reg] = compiler.alloc(size=4)
        for inst in insts:
            defed, used = flow.get_defuse(inst)
            for reg in used:
                if reg in spilled: # load spilled from memory 
                    new_insts.append(IR('lw', rt=reg, rs=REG_SP, rd=addrs[reg]))
            new_insts.append(inst)
            if defed in spilled: # store def
                new_insts.append(IR('sw', rt=defed, rs=REG_SP, rd=addrs[defed]))
        insts = new_insts
        cfg = flow.make_cfg(insts)
        int_graph, liveouts = make_int_graph(cfg)
        coloring, uncolored = color(int_graph, k) 

    # keep register living across function calls
    # in saved register and the rest in temporarys 
    calls = cfg.get_calls()
    # colors that should be mapped in saved registers
    saved = {coloring[reg] for call in calls
            for reg in liveouts[call]
            if reg in coloring}
    # there are only 8 saved registers
    # we need to use some t registers to hold values that
    # live across function calls
    saved_tregs = []
    while len(saved) > 8:
        saved_tregs.append(saved.pop())
    # $s0 - $s7
    sregs = [Register('s', i) for i in range(7+1, -1, -1)]
    # $t0 - $t9
    tregs = [Register('t', i) for i in range(9+1, -1, -1)] 
    # mapping: colors -> registers
    translations = {
            color: sregs.pop() if color in saved else tregs.pop()
            for color in set(coloring.values())} 
    # replace virtual registers with physical registers
    compiler.insts = []
    for inst in insts: 
        if type(inst) == IR:
            opcode, rs, rt, rd = inst
            if rs in coloring:
                rs = translations[coloring[rs]]
            if rt in coloring:
                rt = translations[coloring[rt]]
            if rd in coloring:
                rd = translations[coloring[rd]]
            if opcode == 'move' and rs == rd:
                continue
            inst = IR(opcode, rs, rt, rd)
            if any(type(u) == Register and u.typ == 'virtual' for u in (rs, rt)):
                # if there's any virtual registers left
                # it means it's a dead value hence the instruction is dead code
                continue
        compiler.insts.append(inst)
    compiler.sregs = [translations[c] for c in saved]