def main(argv): mode = "optimize" if argv: mode = argv.pop(0) unit = serialize.UnitParseFromAsm(sys.stdin) if mode == "optimize": UnitCfgInit(unit) unit_stats = UnitOpt(unit, True) UnitCfgExit(unit) print("\n".join(serialize.UnitRenderToASM(unit))) elif mode == "optlite": UnitCfgInit(unit) unit_stats = UnitOptBasic(unit, True) UnitCfgExit(unit) print("\n".join(serialize.UnitRenderToASM(unit))) elif mode == "optimize_stats": UnitCfgInit(unit) unit_stats = UnitOpt(unit, True) UnitCfgExit(unit) print("\n".join(serialize.UnitRenderToASM(unit))) print(f"# STATS:") for key, val in unit_stats.items(): print(f"# {key}: {val}") elif mode == "serialize": print("\n".join(serialize.UnitRenderToASM(unit))) elif mode == "cfg": UnitCfgInit(unit) print("\n".join(serialize.UnitRenderToASM(unit))) elif mode == "cfg2": UnitCfgInit(unit) UnitCfgExit(unit) print("\n".join(serialize.UnitRenderToASM(unit))) else: assert False, f"unknown mode: [{mode}]"
def testB(self): code = io.StringIO(r""" .fun main NORMAL [S32] = [S32 A64] .bbl %start poparg argc:S32 poparg argv:A64 mov b:S32 1 add a:S32 b 1 add x:S32 a 1 blt argc 2 if_1_true bra if_1_end .bbl if_1_true pusharg 1:S32 ret .bbl if_1_end pusharg 0:S32 ret """) unit = serialize.UnitParseFromAsm(code) fun = unit.fun_syms["main"] optimize.FunCfgInit(fun, unit) liveness.FunComputeLivenessInfo(fun) liveness.FunRemoveUselessInstructions(fun) # print ("@@@@\n", "\n".join(serialize.FunRenderToAsm(fun))) for bbl in fun.bbls: for ins in bbl.inss: self.assertTrue(ins.opcode in {o.POPARG, o.PUSHARG, o.RET, o.BLT}, f"bad ins {ins}")
def main(): parser = argparse.ArgumentParser(description='CodeGenC') parser.add_argument('--trace', action='store_const', const=True, default=False, help='show info after every step') parser.add_argument('--debug_parser', action='store_const', const=True, default=False, help='dump module before starting execution') parser.add_argument('filename', type=str, help='file to execute') args = parser.parse_args() if args.filename == "-": fin = sys.stdin else: fin = open(args.filename) unit = serialize.UnitParseFromAsm(fin, args.debug_parser) assert "main" in unit.fun_syms print(PROLOG) for fun in unit.funs: if fun.kind is o.FUN_KIND.BUILTIN: continue sanity.FunCheck(fun, unit, check_push_pop=True, check_cfg=False) EmitFunctionProto(fun, True) print(";") for mem in unit.mems: EmitMemory(mem) for fun in unit.funs: if fun.kind is o.FUN_KIND.BUILTIN: continue EmitFunction(fun) print(EPILOG)
def Translate(fin): scratch = regs.FLT_CALLEE_SAVE_REGS[0] ctx = regs.EmitContext(0xfc0, 0xfc0, 0xffff0000, 0xffff0000, 66, scratch) unit = serialize.UnitParseFromAsm(fin, cpu_regs=regs.CPU_REGS) for fun in unit.funs: for bbl in fun.bbls: for ins in bbl.inss: print() HandleIns(ins, ctx)
def main(): parser = argparse.ArgumentParser(description='CodeGenA64') parser.add_argument('-mode', type=str, help='mode') parser.add_argument( '-add_startup_code', action='store_true', help= 'Add startup code (symbol _startup) which calls main and provides access to argc/argv' ) parser.add_argument('input', type=str, help='input file') parser.add_argument('output', type=str, help='output file') args = parser.parse_args() assert args.mode in _ALLOWED_MODES fin = sys.stdin if args.input == "-" else open(args.input) unit = serialize.UnitParseFromAsm(fin) opt_stats: Dict[str, int] = collections.defaultdict(int) if args.mode == "binary": # we need to legalize all functions first as this may change the signature # and fills in cpu reg usage which is used by subsequent interprocedural opts. LegalizeAll(unit, opt_stats, None) RegAllocGlobal(unit, opt_stats, None) RegAllocLocal(unit, opt_stats, None) x64unit = EmitUnitAsBinary(unit, args.add_startup_code) exe = assembler.Assemble(x64unit, True) exe.save(open(args.output, "wb")) os.chmod(args.output, stat.S_IREAD | stat.S_IEXEC | stat.S_IWRITE) return fout = sys.stdout if args.output == "-" else open(args.output, "w") # we need to legalize all functions first as this may change the signature # and fills in cpu reg usage which is used by subsequent interprocedural opts. LegalizeAll(unit, opt_stats, fout) if args.mode == "legalize": print("\n".join(serialize.UnitRenderToASM(unit)), file=fout) return RegAllocGlobal(unit, opt_stats, fout) if args.mode == "reg_alloc_global": print("\n".join(serialize.UnitRenderToASM(unit)), file=fout) return RegAllocLocal(unit, opt_stats, fout) if args.mode == "reg_alloc_local": print("\n".join(serialize.UnitRenderToASM(unit)), file=fout) return assert args.mode == "normal" EmitUnitAsText(unit, fout) if False: print(f"# STATS:") for key, val in sorted(opt_stats.items()): print(f"# {key}: {val}", file=fout)
def testBaseRegPropagation2(self): code = io.StringIO(r""" .fun foo NORMAL [] = [] .reg S32 [x] .reg U32 [y] .reg A32 [a counter] .bbl start poparg counter poparg y lea a counter 666 ld x = a 0 mul x = x 777 st a 334 = x lea a counter y ld x = a 0 mul x = x 777 st a 0 = x lea a counter y ld x = a 0 mul x = x 777 st a 0 = x mov a counter ld x = a 0 mul x = x 777 st a 334 = x ret """) unit = serialize.UnitParseFromAsm(code, False) fun = unit.fun_syms["foo"] bbl = fun.bbls[0] cfg.FunInitCFG(fun) liveness.FunComputeLivenessInfo(fun) reaching_defs.FunComputeReachingDefs(fun) reaching_defs.FunPropagateConsts(fun) reaching_defs.FunLoadStoreSimplify(fun) liveness.FunRemoveUselessInstructions(fun) print("\n".join(serialize.FunRenderToAsm(fun))) # all ld/st were re-written for ins in bbl.inss: self.assertIn(ins.opcode.name, { "ret", "mul", "poparg", "ld", "ld", "st", "st", })
def testD(self): code = io.StringIO(r""" .fun arm_syscall_write SIGNATURE [S32] = [S32 A32 U32] .fun putchar NORMAL [] = [U32] .fun writeln NORMAL [] = [A32 U32] # live_out: ['r0', 'r1'] .reg S32 [$r0_S32 dummy] .reg U32 [$r0_U32 $r1_U32 $r2_U32 len] .reg A32 [$r0_A32 $r1_A32 buf] .bbl start mov buf $r0_A32@r0 # 0 mov len $r1_U32@r1 # 1 mov $r2_U32@r2 len # 2 mov $r1_A32@r1 buf # 3 mov $r0_S32@r0 1 # 4 syscall arm_syscall_write 4:U32 # 5 mov dummy $r0_S32@r0 # 6 mov $r0_U32@r0 10 # 7 bsr putchar # 8 ret # 9 """) cpu_regs = {"r0": ir.CpuReg("r0", 0), "r1": ir.CpuReg("r1", 1), "r2": ir.CpuReg("r2", 2)} unit = serialize.UnitParseFromAsm(code, cpu_regs=cpu_regs) fun = unit.fun_syms["arm_syscall_write"] fun.cpu_live_out = {cpu_regs["r0"]} fun.cpu_live_in = {cpu_regs["r0"], cpu_regs["r1"], cpu_regs["r2"]} fun = unit.fun_syms["putchar"] fun.cpu_live_in = {cpu_regs["r0"]} fun = unit.fun_syms["writeln"] cfg.FunSplitBbls(fun) cfg.FunInitCFG(fun) cfg.FunRemoveUnconditionalBranches(fun) cfg.FunRemoveEmptyBbls(fun) liveness.FunComputeLivenessInfo(fun) ranges = liveness.BblGetLiveRanges(fun.bbls[0], fun, fun.bbls[0].live_out, False) ranges.sort() print("TestD") for lr in ranges: print(lr) self.assertEqual(ranges, [ liveness.LiveRange(liveness.BEFORE_BBL, 0, fun.reg_syms["$r0_A32"], 1), liveness.LiveRange(liveness.BEFORE_BBL, 1, fun.reg_syms["$r1_U32"], 1), liveness.LiveRange(0, 3, fun.reg_syms["buf"], 1), liveness.LiveRange(1, 2, fun.reg_syms["len"], 1), liveness.LiveRange(2, 5, fun.reg_syms["$r2_U32"], 0), liveness.LiveRange(3, 5, fun.reg_syms["$r1_A32"], 0), liveness.LiveRange(4, 5, fun.reg_syms["$r0_S32"], 0), liveness.LiveRange(5, 6, fun.reg_syms["$r0_S32"], 1), liveness.LiveRange(6, liveness.NO_USE, fun.reg_syms["dummy"], 0), liveness.LiveRange(7, 8, fun.reg_syms["$r0_U32"], 0), ])
def Translate(fin): unit = serialize.UnitParseFromAsm(fin, cpu_regs=regs.CPU_REGS_MAP) for fun in unit.funs: ctx = regs.EmitContext(0xfc0, 0xfc0, 0xffff0000, 0xffff0000, 66) if "gpr_scratch" in fun.name: ctx.scratch_cpu_reg = regs.GPR_REGS[6] fun.FinalizeStackSlots() for bbl in fun.bbls: for ins in bbl.inss: print() HandleIns(ins, ctx)
def testBacktrack(self): # this is a good example for linear scan producing pretty bad assignments code = io.StringIO(r""" .fun main NORMAL [U32 U32 U32 U32] = [U32 U32 U32 U32] .bbl start poparg w:U32 poparg x:U32 poparg y:U32 poparg z:U32 mov a:U32 1 mov b:U32 2 mov c:U32 3 mov d:U32 4 cmpeq e:U32 a b c d pusharg z pusharg y pusharg x pusharg w ret """) unit = serialize.UnitParseFromAsm(code, False) fun = unit.fun_syms["main"] bbl = fun.bbls[0] _DumpBblWithLineNumbers(bbl) live_ranges = liveness.BblGetLiveRanges(bbl, fun, set(), True) live_ranges.sort() pool = TestRegPool(MakeGenericCpuRegs(4)) reg_alloc.RegisterAssignerLinearScan(live_ranges, pool) for n, lr in enumerate(live_ranges): # print (lr) if not lr.uses: if n <= 3: assert lr.cpu_reg.no == n else: assert lr.cpu_reg is ir.CPU_REG_SPILL, f"unexpected reg {lr}" live_ranges = liveness.BblGetLiveRanges(bbl, fun, set(), True) live_ranges.sort() pool = TestRegPool(MakeGenericCpuRegs(8)) reg_alloc.RegisterAssignerLinearScanFancy(live_ranges, pool, False) for n, lr in enumerate(live_ranges): # print (lr) assert lr.cpu_reg != ir.CPU_REG_SPILL, f"unexpected reg {lr}"
def Translate(fin): unit = serialize.UnitParseFromAsm(fin, cpu_regs=regs.CPU_REGS_MAP) for fun in unit.funs: ctx = regs.EmitContext(0, 0, 0) ctx.scratch_cpu_reg = ir.CPU_REG_INVALID ctx.scratch_cpu_reg = ir.CPU_REG_INVALID fun.FinalizeStackSlots() for bbl in fun.bbls: for ins in bbl.inss: if "gpr_scratch" in fun.name: ctx.scratch_cpu_reg = regs.CPU_REGS_MAP["rax"] print() HandleIns(ins, ctx)
def main(): parser = argparse.ArgumentParser(description='inspector') parser.add_argument('-debug', help='enable webserver debugging', action='store_true') parser.add_argument('-port', type=int, help='web server port', default=5000) parser.add_argument('input', type=str, help='input file') args = parser.parse_args() opt_stats: Dict[str, int] = collections.defaultdict(int) unit = serialize.UnitParseFromAsm(open(args.input)) MODS.append(RenderCwerg("orig", unit)) if MODE == "opt": optimize.UnitCfgInit(unit) MODS.append(RenderCwerg("prepped", unit)) optimize.UnitOpt(unit, False) CleanUnit(unit) MODS.append(RenderCwerg("optimized", unit)) optimize.UnitCfgExit(unit) CleanUnit(unit) MODS.append(RenderCwerg("final", unit)) else: stats: Dict[str, int] = collections.defaultdict(int) codegen.LegalizeAll(unit, stats, None) CleanUnit(unit) MODS.append(RenderCwerg("legalized", unit)) codegen.RegAllocGlobal(unit, stats, None) CleanUnit(unit) MODS.append(RenderCwerg("global_allocated", unit)) codegen.RegAllocLocal(unit, stats, None) CleanUnit(unit) MODS.append(RenderCwerg("locals_allocated", unit)) cpu_unit = codegen.codegen(unit) MODS.append(RenderCpu("assembler", cpu_unit)) http_server = http.server.HTTPServer(('', args.port), MyRequestHandler) print(f'Starting HTTP server at http://localhost:{args.port}') try: http_server.serve_forever() except KeyboardInterrupt: pass print('Stopping HTTP server') http_server.server_close()
def main(): parser = argparse.ArgumentParser(description='inspector') parser.add_argument('-debug', help='enable webserver debugging', action='store_true') parser.add_argument('-port', type=int, help='web server port', default=5000) parser.add_argument('input', type=str, help='input file') args = parser.parse_args() opt_stats: Dict[str, int] = collections.defaultdict(int) unit = serialize.UnitParseFromAsm(open(args.input)) # Note, deepcopy has all kinds of issues and we do not expect # to use a copy in further computations MODS.append(("orig", copy.deepcopy(unit))) if True: optimize.UnitCfgInit(unit) MODS.append(("prepped", copy.deepcopy(unit))) optimize.UnitOpt(unit, False) # MODS.append(("optimized", copy.deepcopy(unit))) # optimize.UnitCfgExit(unit) # MODS.append(("final", copy.deepcopy(unit))) else: stats: Dict[str, int] = collections.defaultdict(int) codegen.optimize_all(unit, stats) MODS.append(("optimized", copy.deepcopy(unit))) codegen.legalize_all(unit, stats) MODS.append(("legalized", copy.deepcopy(unit))) codegen.reg_alloc_all(unit, stats) MODS.append(("reg_allocated", copy.deepcopy(unit))) arm_mod = codegen.codegen(unit) MODS.append(("assembler", arm_mod)) http_server = http.server.HTTPServer(('', args.port), MyRequestHandler) print(f'Starting HTTP server at http://localhost:{args.port}') try: http_server.serve_forever() except KeyboardInterrupt: pass print('Stopping HTTP server') http_server.server_close()
def testSimple(self): code = io.StringIO(r""" .fun main NORMAL [U32 U32 U32 U32] = [U32 U32 U32 U32] .bbl start poparg w:U32 poparg x:U32 poparg y:U32 poparg z:U32 pusharg z pusharg y pusharg x pusharg w ret """) unit = serialize.UnitParseFromAsm(code, False) fun = unit.fun_syms["main"] bbl = fun.bbls[0] DumpBbl(bbl) live_ranges = BblGetLiveRanges(bbl, fun, {}, True) live_ranges.sort() pool = TestRegPool(MakeGenericCpuRegs(4)) reg_alloc.RegisterAssignerLinearScan(live_ranges, pool) for n, lr in enumerate(live_ranges): # print (lr) if not lr.uses: assert lr.cpu_reg.no == n, f"unexpected reg {lr}" live_ranges = BblGetLiveRanges(bbl, fun, {}, True) live_ranges.sort() pool = TestRegPool(MakeGenericCpuRegs(3)) reg_alloc.RegisterAssignerLinearScan(live_ranges, pool) for n, lr in enumerate(live_ranges): # print (lr) if not lr.uses: if n <= 2: assert lr.cpu_reg.no == n else: assert lr.cpu_reg == ir.CPU_REG_SPILL, f"unexpected reg {lr}"
def testC(self): code = io.StringIO(r""" .fun main NORMAL [S32] = [] .bbl %start mov %out:S32 3 bra next .bbl next pusharg %out ret """) unit = serialize.UnitParseFromAsm(code) fun = unit.fun_syms["main"] optimize.FunCfgInit(fun, unit) liveness.FunComputeLivenessInfo(fun) # print ("@@@@\n", "\n".join(serialize.FunRenderToAsm(fun))) liveness.FunRemoveUselessInstructions(fun) # print ("@@@@\n", "\n".join(serialize.FunRenderToAsm(fun))) self.assertEqual(1, len(fun.bbls[0].inss)) self.assertEqual(2, len(fun.bbls[1].inss))
def testE(self): code = io.StringIO(r""" .fun test NORMAL [F32 F32 F32 F32] = [F32 F32] .reg F32 [a b add sub mul div $s0_F32 $s1_F32 $s2_F32 $s3_F32] .bbl start mov a $s0_F32@s0 mov b $s1_F32@s1 add add a b sub sub a b mul mul a b div div a b mov $s3_F32@s3 div mov $s2_F32@s2 mul mov $s1_F32@s1 sub mov $s0_F32@s0 add ret """) cpu_regs = { "s0": ir.CpuReg("s0", 0), "s1": ir.CpuReg("s1", 1), "s2": ir.CpuReg("s2", 2), "s3": ir.CpuReg("s3", 2) } unit = serialize.UnitParseFromAsm(code, cpu_regs=cpu_regs) fun = unit.fun_syms["test"] fun.cpu_live_out = { cpu_regs["s0"], cpu_regs["s1"], cpu_regs["s2"], cpu_regs["s3"] } fun.cpu_live_in = {cpu_regs["s0"], cpu_regs["s1"]} cfg.FunSplitBblsAtTerminators(fun) cfg.FunInitCFG(fun) cfg.FunRemoveUnconditionalBranches(fun) cfg.FunRemoveEmptyBbls(fun) liveness.FunComputeLivenessInfo(fun) ranges = liveness.BblGetLiveRanges(fun.bbls[0], fun, fun.bbls[0].live_out) ranges.sort() print("TestE") for lr in ranges: print(lr)
def testD(self): code = io.StringIO(r""" .fun arm_syscall_write SIGNATURE [S32] = [S32 A32 U32] .fun putchar NORMAL [] = [U32] .fun writeln NORMAL [] = [A32 U32] # live_out: ['r0', 'r1'] .reg S32 [$r0_S32 dummy] .reg U32 [$r0_U32 $r1_U32 $r2_U32 len] .reg A32 [$r0_A32 $r1_A32 buf] .bbl start mov buf $r0_A32@r0 # 0 mov len $r1_U32@r1 # 1 mov $r2_U32@r2 len # 2 mov $r1_A32@r1 buf # 3 mov $r0_S32@r0 1 # 4 syscall arm_syscall_write 4:U32 # 5 mov dummy $r0_S32@r0 # 6 mov $r0_U32@r0 10 # 7 bsr putchar # 8 ret # 9 """) cpu_regs = { "r0": ir.CpuReg("r0", 0), "r1": ir.CpuReg("r1", 1), "r2": ir.CpuReg("r2", 2) } unit = serialize.UnitParseFromAsm(code, cpu_regs=cpu_regs) fun = unit.fun_syms["arm_syscall_write"] fun.cpu_live_out = {cpu_regs["r0"]} fun.cpu_live_in = {cpu_regs["r0"], cpu_regs["r1"], cpu_regs["r2"]} fun = unit.fun_syms["putchar"] fun.cpu_live_in = {cpu_regs["r0"]} fun = unit.fun_syms["writeln"] cfg.FunSplitBblsAtTerminators(fun) cfg.FunInitCFG(fun) cfg.FunRemoveUnconditionalBranches(fun) cfg.FunRemoveEmptyBbls(fun) liveness.FunComputeLivenessInfo(fun) ranges = liveness.BblGetLiveRanges(fun.bbls[0], fun, fun.bbls[0].live_out) ranges.sort() print("TestD") for lr in ranges: print(lr) lr_r0 = liveness.LiveRange(liveness.BEFORE_BBL, 0, fun.reg_syms["$r0_A32"], 1) lr_r1 = liveness.LiveRange(liveness.BEFORE_BBL, 1, fun.reg_syms["$r1_U32"], 1) lr_buf = liveness.LiveRange(0, 3, fun.reg_syms["buf"], 1) lr_len = liveness.LiveRange(1, 2, fun.reg_syms["len"], 1) lr_r0_2 = liveness.LiveRange(5, 6, fun.reg_syms["$r0_S32"], 1) expected = [ lr_r0, lr_r1, liveness.LiveRange(0, 0, reg=ir.REG_INVALID, num_uses=1, uses=[lr_r0]), lr_buf, liveness.LiveRange(1, 1, reg=ir.REG_INVALID, num_uses=1, uses=[lr_r1]), lr_len, liveness.LiveRange(2, 2, reg=ir.REG_INVALID, num_uses=1, uses=[lr_len]), liveness.LiveRange(2, 5, fun.reg_syms["$r2_U32"], 0), liveness.LiveRange(3, 3, reg=ir.REG_INVALID, num_uses=1, uses=[lr_buf]), liveness.LiveRange(3, 5, fun.reg_syms["$r1_A32"], 0), liveness.LiveRange(4, 5, fun.reg_syms["$r0_S32"], 0), lr_r0_2, liveness.LiveRange(6, 6, reg=ir.REG_INVALID, num_uses=1, uses=[lr_r0_2]), liveness.LiveRange(6, liveness.NO_USE, fun.reg_syms["dummy"], 0), liveness.LiveRange(7, 8, fun.reg_syms["$r0_U32"], 0), ] # self.assertSequenceEqual(ranges, expected) # this does not work because of the uses field self.assertEqual(len(ranges), len(expected)) for a, b in zip(): self.assertEqual(a, b)
def testBaseRegPropagation1(self): code = io.StringIO(r""" .mem COUNTER 4 RW .data 4 [0] .fun foo NORMAL [] = [] .stk array 4 4000 .reg S32 [x] .reg U32 [y] .reg A32 [counter] .bbl start lea.mem counter = COUNTER 0 ld x = counter 0 add x = x 1 st counter 0 = x lea.mem counter = COUNTER 100 ld x = counter 100 add x = x 1 st counter 300 = x mov y 666 lea.mem counter = COUNTER 0 ld x = counter y add x = x 1 st counter y = x lea.stk counter = array 0 ld x = counter 0 add x = x 1 st counter 0 = x lea.stk counter = array 100 ld x = counter 100 add x = x 1 st counter 300 = x mov y 666 lea.stk counter = array 0 ld x = counter y add x = x 1 st counter y = x ret """) unit = serialize.UnitParseFromAsm(code, False) fun = unit.fun_syms["foo"] bbl = fun.bbls[0] cfg.FunInitCFG(fun) liveness.FunComputeLivenessInfo(fun) reaching_defs.FunComputeReachingDefs(fun) reaching_defs.FunPropagateConsts(fun) # reaching_defs.FunConstantFold(fun, True) reaching_defs.FunLoadStoreSimplify(fun) liveness.FunRemoveUselessInstructions(fun) print("\n".join(serialize.FunRenderToAsm(fun))) # all ld/st were re-written for ins in bbl.inss: self.assertIn( ins.opcode.name, {"ret", "add", "ld.mem", "st.mem", "ld.stk", "st.stk"})
def testA(self): code = io.StringIO(r""" .fun printf_u BUILTIN [] = [A32 U32] .fun multi BUILTIN [U32 U32 U32 U32 U32] = [U32 U32] .mem fmt 4 RO .data 1 "%d\n\0" .fun main NORMAL [S32] = [] .reg U32 [a s m d M x y out] .reg A64 [f] .bbl start mov x = 70 mov y = 6 pusharg y pusharg x bsr multi poparg a poparg s poparg m poparg d poparg M lea.mem f = fmt 0 pusharg a pusharg f bsr printf_u pusharg s pusharg f bsr printf_u pusharg m pusharg f bsr printf_u pusharg d pusharg f bsr printf_u pusharg M pusharg f bsr printf_u mov out = 0 pusharg out ret """) unit = serialize.UnitParseFromAsm(code, False) fun = unit.fun_syms["main"] bbl = fun.bbls[0] x = fun.reg_syms["x"] y = fun.reg_syms["y"] a = fun.reg_syms["a"] s = fun.reg_syms["s"] m = fun.reg_syms["m"] d = fun.reg_syms["d"] M = fun.reg_syms["M"] out = fun.reg_syms["out"] f = fun.reg_syms["f"] DumpBbl(bbl) live_ranges = liveness.BblGetLiveRanges(bbl, fun, bbl.live_out, False) live_ranges.sort() lr_cross_bbl = [lr for lr in live_ranges if lr.is_cross_bbl()] lr_lac = [lr for lr in live_ranges if liveness.LiveRangeFlag.LAC in lr.flags] assert len(live_ranges) == 9, f"{live_ranges}" assert len(lr_cross_bbl) == 0, f"{lr_cross_bbl}" assert len(lr_lac) == 5, f"{lr_lac}" for lr in live_ranges: print("checking LR lac:", lr) # assert lr.lac == lr.reg in {M, d, f, m, s}, f"LR {lr}" self.assertNotEqual(lr.def_pos, lr.last_use_pos) self.assertEqual(liveness.LiveRangeFlag.LAC in lr.flags, lr.reg in {M, d, f, m, s})