def test_constrained_move(self): """ Test a constrained move. Do this by creating two pre-colored registers. Move one and add the other with the copy of the first. The move can then not be coalesced, and will be frozen. """ f = Frame('tst') t1 = R0 t2 = R0 t3 = ExampleRegister('t3') t4 = ExampleRegister('t4') f.instructions.append(Def(t1)) move = Mov(t3, t1, ismove=True) f.instructions.append(move) f.instructions.append(Def(t2)) f.instructions.append(Add(t4, t2, t3)) f.instructions.append(Use(t4)) self.register_allocator.alloc_frame(f) # Check t1 and t2 are pre-colored: self.assertEqual({self.register_allocator.node(R0)}, self.register_allocator.precolored) self.assertEqual(set(), self.register_allocator.coalescedMoves) self.assertEqual({move}, self.register_allocator.constrainedMoves) self.conflict(t2, t3) self.assertEqual(set(), self.register_allocator.frozenMoves) self.assertIn(move, f.instructions)
def test_loop_cfg(self): """ Test two blocks in a loop a: t1 = t4 t2 = 0x10 jmp b b: t3 = t2 t4 = t1 jmp a """ t1 = ExampleRegister('t1') t2 = ExampleRegister('t2') t3 = ExampleRegister('t3') t4 = ExampleRegister('t4') i1 = DefUse(t1, t4) # t1 is live i3 = DefUse(t3, t2) # t2, t1, t3 live i2 = Def(t2, jumps=[i3]) # t1, t2 is live i4 = DefUse(t4, t1, jumps=[i1]) # t1, t3, t4 live instrs = [i1, i2, i3, i4] cfg = FlowGraph(instrs) cfg.calculate_liveness() ig = InterferenceGraph() ig.calculate_interference(cfg) self.assertTrue(ig.interfere(t1, t2)) self.assertFalse(ig.interfere(t2, t4))
def test_constrained_move_by_alias(self): """ Test if aliased registers work and cannot be coalesced. """ f = Frame('tst') t1 = R10 t2 = R10l t3 = ExampleRegister('t3') move = Mov(t3, t1, ismove=True) f.instructions.append(Def(t1)) f.instructions.append(move) f.instructions.append(DefHalf(t2)) f.instructions.append(UseHalf(t2)) f.instructions.append(Use(t3)) self.register_allocator.alloc_frame(f) # Check t1 and t2 are pre-colored: self.assertEqual( { self.register_allocator.node(R10), self.register_allocator.node(R10l) }, self.register_allocator.precolored) self.assertEqual(set(), self.register_allocator.coalescedMoves) self.assertEqual({move}, self.register_allocator.constrainedMoves) self.conflict(t2, t3) self.assertEqual(set(), self.register_allocator.frozenMoves) self.assertIn(move, f.instructions)
def test_register_allocation(self): f = Frame('tst') t1 = ExampleRegister('t1') t2 = ExampleRegister('t2') t3 = ExampleRegister('t3') t4 = ExampleRegister('t4') t5 = ExampleRegister('t5') f.instructions.append(Def(t1)) f.instructions.append(Def(t2)) f.instructions.append(Def(t3)) f.instructions.append(Add(t4, t1, t2)) f.instructions.append(Add(t5, t4, t3)) f.instructions.append(Use(t5)) self.register_allocator.alloc_frame(f) self.conflict(t1, t2) self.conflict(t2, t3)
def test_loop_variable(self): """ See if a variable defined at input and in block itself is marked as live out! Probably simpler variant of testMultipleDefineInLoop. I1: x = 2 I2: use x I3: x = 3 I4: jmp I5 I5: jmp I2 """ x = ExampleRegister('x') i2 = Use(x) i1 = Def(x, jumps=[i2]) i3 = Def(x) i5 = Nop(jumps=[i2]) i4 = Nop(jumps=[i5]) self.assertSequenceEqual([x], i1.defined_registers) instrs = [i1, i2, i3, i4, i5] cfg = FlowGraph(instrs) cfg.calculate_liveness() self.assertEqual(3, len(cfg)) b1 = cfg.get_node(i1) b2 = cfg.get_node(i2) b3 = cfg.get_node(i5) self.assertEqual(3, len(cfg)) self.assertEqual({x}, b1.live_out) self.assertEqual({x}, b2.live_out) self.assertEqual({x}, b3.live_out)
def test_freeze(self): """ Create a situation where no select and no coalesc is possible """ f = Frame('tst') t4 = ExampleRegister('t4') t5 = ExampleRegister('t5') f.instructions.append(Def(R0)) move = Mov(R1, R0, ismove=True) f.instructions.append(move) f.instructions.append(Def(t4)) f.instructions.append(Add(t5, t4, R1)) f.instructions.append(Use(t5)) self.register_allocator.alloc_frame(f) self.assertEqual(set(), self.register_allocator.coalescedMoves) # self.assertEqual({move}, self.register_allocator.frozenMoves) self.conflict(R1, R0)
def test_normal_use(self): """ Test if interference graph works """ t1 = ExampleRegister('t1') t2 = ExampleRegister('t2') t3 = ExampleRegister('t3') t4 = ExampleRegister('t4') instrs = [] instrs.append(Def(t1)) # t1 is live instrs.append(Def(t2)) # t1, t2 is live instrs.append(DefUse(t3, t2)) # t2, t1, t3 live instrs.append(DefUse(t4, t1)) # t1, t3, t4 live cfg = FlowGraph(instrs) cfg.calculate_liveness() ig = InterferenceGraph() ig.calculate_interference(cfg) self.assertTrue(ig.interfere(t1, t2)) self.assertFalse(ig.interfere(t2, t4))
def test_multiple_define_in_loop(self): """ Test if the following works: entry: I1: x = 2 I2: a = x I3: x = 3 I4: b = x I5: c = b I6: cjmp I2, I7 I7: nop """ a = ExampleRegister('a') b = ExampleRegister('b') c = ExampleRegister('c') x = ExampleRegister('x') i2 = DefUse(a, x) i1 = Def(x, jumps=[i2]) i3 = Def(x) i4 = DefUse(b, x) i5 = DefUse(c, b) i7 = Nop() i6 = Nop(jumps=[i2, i7]) instrs = [i1, i2, i3, i4, i5, i6, i7] cfg = FlowGraph(instrs) cfg.calculate_liveness() # Check that there are three nodes: self.assertEqual(3, len(cfg)) self.assertTrue(cfg.has_node(i1)) self.assertTrue(cfg.has_node(i2)) self.assertTrue(cfg.has_node(i7)) # Get block 2: b2 = cfg.get_node(i2) # Check that block2 has two successors: self.assertEqual(2, len(b2.successors)) self.assertEqual(2, len(b2.predecessors)) # Check that x is live at end of block 2 self.assertEqual({x}, b2.live_out)
def test_combine(self): t1 = ExampleRegister('t1') t2 = ExampleRegister('t2') t3 = ExampleRegister('t3') t4 = ExampleRegister('t4') instrs = [] instrs.append(Def(t1)) instrs.append(Def(t2)) instrs.append(Def(t3)) instrs.append(DefUse(t4, t3)) instrs.append(Use(t4)) instrs.append(Use(t1)) instrs.append(Use(t2)) cfg = FlowGraph(instrs) cfg.calculate_liveness() ig = InterferenceGraph() ig.calculate_interference(cfg) ig.combine(ig.get_node(t4), ig.get_node(t3)) self.assertIs(ig.get_node(t4), ig.get_node(t3)) # For repr called: self.assertTrue(str(ig.get_node(t4)))
def test_register_coalescing(self): """ Register coalescing happens when a move can be eliminated """ f = Frame('tst') t1 = ExampleRegister('t1') t2 = ExampleRegister('t2') t3 = ExampleRegister('t3') t4 = ExampleRegister('t4') t5 = ExampleRegister('t5') t6 = ExampleRegister('t6') f.instructions.append(Def(t1)) f.instructions.append(Def(t2)) f.instructions.append(Def(t3)) f.instructions.append(Add(t4, t2, t1)) f.instructions.append(Mov(t5, t3)) f.instructions.append(Add(t5, t4, t5)) f.instructions.append(Mov(t6, t5)) f.instructions.append(Use(t6)) self.register_allocator.alloc_frame(f) self.conflict(t1, t2) self.conflict(t2, t3) self.conflict(t1, t3)
def test_multiple_successors(self): """ Example from wikipedia about liveness """ a = ExampleRegister('a') b = ExampleRegister('b') c = ExampleRegister('c') d = ExampleRegister('d') x = ExampleRegister('x') i1 = Def(a) # a = 3 i2 = Def(b) # b = 5 i3 = Def(d) # d = 4 i4 = Def(x) # x = 100 i6 = Add(c, a, b) # c = a + b i8 = Def(c) # c = 4 i7 = Def(d, jumps=[i8]) # d = 2 i9 = Use3(b, d, c) # return b * d + c i5 = Cmp(a, b, jumps=[i6, i8]) # if a > b instrs = [i1, i2, i3, i4, i5, i6, i7, i8, i9] cfg = FlowGraph(instrs) cfg.calculate_liveness() # Get blocks: b1 = cfg.get_node(i1) b2 = cfg.get_node(i6) b3 = cfg.get_node(i8) # Should be 3 nodes: self.assertEqual(3, len(cfg)) # Check successors: self.assertEqual({b2, b3}, b1.successors) self.assertEqual({b3}, b2.successors) self.assertEqual(set(), b3.successors) # Check predecessors: self.assertEqual(set(), b1.predecessors) self.assertEqual({b1}, b2.predecessors) self.assertEqual({b2, b1}, b3.predecessors) # Check block 1: self.assertEqual(5, len(b1.instructions)) self.assertEqual(set(), b1.gen) self.assertEqual({a, b, d, x}, b1.kill) # Check block 2 gen and killl: self.assertEqual(2, len(b2.instructions)) self.assertEqual({a, b}, b2.gen) self.assertEqual({c, d}, b2.kill) # Check block 3: self.assertEqual(2, len(b3.instructions)) self.assertEqual({b, d}, b3.gen) self.assertEqual({c}, b3.kill) # Check block 1 live in and out: self.assertEqual(set(), b1.live_in) self.assertEqual({a, b, d}, b1.live_out) # Check block 2: self.assertEqual({a, b}, b2.live_in) self.assertEqual({b, d}, b2.live_out) # Check block 3: self.assertEqual({b, d}, b3.live_in) self.assertEqual(set(), b3.live_out) # Create interference graph: ig = InterferenceGraph() ig.calculate_interference(cfg)