def _BblRemoveUnreachableIns(bbl: ir.Bbl): n = 0 for n, ins in enumerate(bbl.inss): if ins.opcode.kind in {o.OPC_KIND.RET, o.OPC_KIND.BRA}: break if n != len(bbl.inss): bbl.inss = bbl.inss[:n + 1]
def _BblRemoveUselessInstructions(bbl: ir.Bbl, fun: ir.Fun) -> int: live_out = bbl.live_out.copy() old_count = len(bbl.inss) keep = [] for ins in reversed(bbl.inss): if _InsUpdateLiveness(ins, fun, live_out): keep.append(ins) bbl.inss = list(reversed(keep)) return old_count - len(keep)
def BblSplit(ins: ir.Ins, orig_bbl: ir.Bbl, fun: ir.Fun, prefix) -> ir.Bbl: """Create a new bbl BEFORE orig_bbl containing all the instruction up to and including ins""" assert ins.opcode.kind is not o.OPC_KIND.COND_BRA ins_pos = orig_bbl.index(ins) bbl_pos = fun.bbls.index(orig_bbl) count = 1 while True: name = f"{prefix}{count}" if name not in fun.bbl_syms: break count += 1 new_bbl = ir.Bbl(name) for x in orig_bbl.edge_in[:]: if x.inss: InsMaybePatchNewSuccessor(x.inss[-1], orig_bbl, new_bbl) # patch ins/jtb x.ReplaceEdgeOut(orig_bbl, new_bbl) new_bbl.AddEdgeOut(orig_bbl) new_bbl.inss = orig_bbl.inss[:ins_pos + 1] orig_bbl.inss = orig_bbl.inss[ins_pos + 1:] fun.bbls.insert(bbl_pos, new_bbl) fun.bbl_syms[name] = new_bbl return new_bbl
def _BblMergeMoveWithSrcDef(bbl: ir.Bbl, _fun: ir.Fun) -> int: """ This transformation will make certain MOVs obsolete. op x = a b [stuff] mov y = x will become op y = a b mov x = y [stuff] [deleted] """ last_def_pos: Dict[ir.Reg, int] = {} last_use_pos: Dict[ir.Reg, int] = {} inss: List[ir.Ins] = [] def update_def_use(ins: ir.Ins, pos): num_defs = ins.opcode.def_ops_count() for n, op in enumerate(ins.operands): if not isinstance(op, ir.Reg): continue if n < num_defs: last_def_pos[op] = pos else: last_use_pos[op] = pos def is_suitable_mov(mov: ir.Ins) -> bool: ops = mov.operands if mov.opcode is not o.MOV or not isinstance( ops[1], ir.Reg) or ops[0] == ops[1]: return False src_def_pos = last_def_pos.get(ops[1], -1) if src_def_pos < 0: return False # avoid inserting MOVs inbetween POPARGs - this could be improved if len(inss) > src_def_pos + 1 and inss[src_def_pos + 1].opcode is o.POPARG: return False # no intervening use of ops[0] dst_def_pos = last_def_pos.get(ops[0], -1) if dst_def_pos > src_def_pos: return False dst_use_pos = last_use_pos.get(ops[0], -1) if dst_use_pos > src_def_pos: return False return True count = 0 for ins in bbl.inss: if is_suitable_mov(ins): count += 1 dst_reg, src_reg = ins.operands src_def_pos = last_def_pos[src_reg] ins_src_def = inss[src_def_pos] assert ins_src_def.operands[0] == src_reg ins_src_def.operands[0] = dst_reg last_def_pos[dst_reg] = src_def_pos ir.InsSwapOps(ins, 0, 1) inss.insert(src_def_pos + 1, ins) for pos in range(src_def_pos + 1, len(inss)): update_def_use(inss[pos], pos) else: update_def_use(ins, len(inss)) inss.append(ins) bbl.inss = inss return count