Author: Carl Friedrich Bolz-Tereick <[email protected]>
Branch: regalloc-playground
Changeset: r92298:ffdf4c1bc430
Date: 2017-08-26 09:43 +0200
http://bitbucket.org/pypy/pypy/changeset/ffdf4c1bc430/

Log:    improve interaction of fixed_register, try_use_same_register and
        force_result_in_reg

diff --git a/rpython/jit/backend/llsupport/regalloc.py 
b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -63,6 +63,7 @@
 
     @specialize.arg(1)
     def foreach(self, function, arg):
+        # XXX unused?
         node = self.master_node
         while node is not None:
             function(arg, node.val)
@@ -362,6 +363,9 @@
         returns allocated register or None, if not possible.
         """
         self._check_type(v)
+        if isinstance(v, TempVar):
+            self.longevity[v] = Lifetime(self.position, self.position)
+        # YYY all subtly similar code
         assert not isinstance(v, Const)
         if selected_reg is not None:
             res = self.reg_bindings.get(v, None)
@@ -553,6 +557,7 @@
         reg = self.reg_bindings[from_v]
         del self.reg_bindings[from_v]
         self.reg_bindings[to_v] = reg
+        return reg
 
     def _move_variable_away(self, v, prev_loc):
         # YYY here we should not move it to another reg, if all uses are in
@@ -573,27 +578,35 @@
         self._check_type(result_v)
         self._check_type(v)
         if isinstance(v, Const):
-            loc = self.force_allocate_reg(result_v, forbidden_vars)
-            self.assembler.regalloc_mov(self.convert_to_imm(v), loc)
-            return loc
+            result_loc = self.force_allocate_reg(result_v, forbidden_vars)
+            self.assembler.regalloc_mov(self.convert_to_imm(v), result_loc)
+            return result_loc
         if v not in self.reg_bindings:
             # v not in a register. allocate one for result_v and move v there
-            prev_loc = self.frame_manager.loc(v)
-            loc = self.force_allocate_reg(result_v, forbidden_vars)
-            self.assembler.regalloc_mov(prev_loc, loc)
-            return loc
+            v_loc = self.frame_manager.loc(v)
+            result_loc = self.force_allocate_reg(result_v, forbidden_vars)
+            self.assembler.regalloc_mov(v_loc, result_loc)
+            return result_loc
         if self.longevity[v].last_usage > self.position:
-            # we need to find a new place for variable v and
-            # store result in the same place
-            loc = self.reg_bindings[v]
-            del self.reg_bindings[v]
-            if self.frame_manager.get(v) is None:
-                self._move_variable_away(v, loc)
-            self.reg_bindings[result_v] = loc
+            # v keeps on being live. if there is a free register, we need a
+            # move anyway, so we can use force_allocate_reg on result_v to make
+            # sure any fixed registers are used
+            if self.free_regs:
+                v_loc = self.reg_bindings[v]
+                result_loc = self.force_allocate_reg(result_v, forbidden_vars)
+                self.assembler.regalloc_mov(v_loc, result_loc)
+                return result_loc
+            else:
+                result_loc = self.reg_bindings[v]
+                if self.frame_manager.get(v) is None:
+                    v_loc = self.frame_manager.loc(v)
+                    self.assembler.regalloc_mov(result_loc, v_loc)
+                    del self.reg_bindings[v]
+                self.reg_bindings[result_v] = result_loc
+                return result_loc
         else:
-            self._reallocate_from_to(v, result_v)
-            loc = self.reg_bindings[result_v]
-        return loc
+            result_loc = self._reallocate_from_to(v, result_v)
+        return result_loc
 
     def _sync_var(self, v):
         self.assembler.num_spills += 1
diff --git a/rpython/jit/backend/llsupport/test/test_regalloc.py 
b/rpython/jit/backend/llsupport/test/test_regalloc.py
--- a/rpython/jit/backend/llsupport/test/test_regalloc.py
+++ b/rpython/jit/backend/llsupport/test/test_regalloc.py
@@ -863,13 +863,13 @@
     # use it's own class since there are so many cases
 
     def test_force_result_in_reg_1(self):
+        # var in reg, dies
         b0, b1 = newboxes(0, 0)
         longevity = {b0: Lifetime(0, 1), b1: Lifetime(1, 3)}
         fm = TFrameManager()
         asm = MockAsm()
         rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
         rm.next_instruction()
-        # first path, var is already in reg and dies
         loc0 = rm.force_allocate_reg(b0)
         rm._check_invariants()
         rm.next_instruction()
@@ -879,6 +879,7 @@
         rm._check_invariants()
 
     def test_force_result_in_reg_2(self):
+        # var in reg, survives
         b0, b1 = newboxes(0, 0)
         longevity = {b0: Lifetime(0, 2), b1: Lifetime(1, 3)}
         fm = TFrameManager()
@@ -889,12 +890,13 @@
         rm._check_invariants()
         rm.next_instruction()
         loc = rm.force_result_in_reg(b1, b0)
-        assert loc is loc0
-        assert rm.loc(b0) is not loc0
+        assert loc is not loc0
+        assert rm.loc(b0) is loc0
         assert len(asm.moves) == 1
         rm._check_invariants()
 
     def test_force_result_in_reg_3(self):
+        # var in reg, survives, no free registers
         b0, b1, b2, b3, b4 = newboxes(0, 0, 0, 0, 0)
         longevity = {b0: Lifetime(0, 2), b1: Lifetime(0, 2),
                      b3: Lifetime(0, 2), b2: Lifetime(0, 2),
@@ -929,6 +931,7 @@
         assert len(asm.moves) == 1
 
     def test_force_result_in_reg_const(self):
+        # const
         boxes, longevity = boxes_and_longevity(2)
         fm = TFrameManager()
         asm = MockAsm()
@@ -939,6 +942,50 @@
         rm.force_result_in_reg(boxes[0], c)
         rm._check_invariants()
 
+    # some tests where the result is supposed to go in a fixed register
+
+    def test_force_result_in_reg_fixed_reg_1(self):
+        # var in reg, dies
+        b0, b1 = newboxes(0, 0)
+        longevity = LifetimeManager({b0: Lifetime(0, 1), b1: Lifetime(1, 3)})
+        longevity.try_use_same_register(b0, b1)
+        longevity.fixed_register(1, r1, b1)
+        fm = TFrameManager()
+        asm = MockAsm()
+        rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
+        rm.next_instruction()
+        loc0 = rm.force_allocate_reg(b0)
+        rm._check_invariants()
+        rm.next_instruction()
+        loc = rm.force_result_in_reg(b1, b0)
+        assert loc is loc0
+        assert loc is r1
+        assert len(asm.moves) == 0
+        rm._check_invariants()
+
+    def test_force_result_in_reg_fixed_reg_2(self):
+        # var in reg, survives
+        b0, b1 = newboxes(0, 0)
+        longevity = LifetimeManager({b0: Lifetime(0, 2), b1: Lifetime(1, 3)})
+
+        # has no effect, lifetimes overlap
+        longevity.try_use_same_register(b0, b1)
+        longevity.fixed_register(1, r1, b1)
+
+        fm = TFrameManager()
+        asm = MockAsm()
+        rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
+        rm.next_instruction()
+        loc0 = rm.force_allocate_reg(b0)
+        rm._check_invariants()
+        rm.next_instruction()
+        loc = rm.force_result_in_reg(b1, b0)
+        assert loc is not loc0
+        assert rm.loc(b0) is loc0
+        assert loc is r1
+        assert len(asm.moves) == 1
+        rm._check_invariants()
+
 # _____________________________________________________
 # tests that assign registers in a mocked way for a fake CPU
 
@@ -1246,6 +1293,7 @@
             ('guard_true', r8, [])
         ]
 
+    @py.test.mark.skip("messy - later")
     def test_coalescing_first_var_already_in_different_reg(self):
         ops = '''
         [i0]
@@ -1283,8 +1331,8 @@
             ('guard_false', r0, [fp0, r7, r4, r5, r6])
         ]
 
+    @py.test.mark.skip("messy - later")
     def test_call_spill(self):
-        py.test.skip("also messy")
         # i0 dies, i1 is the argument, the other fight for caller-saved regs
         # all_regs = [r0, r1, r2, r3, r4, r5, r6, r7]
         # save_around_call_regs = [r0, r1, r2, r3]
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -508,6 +508,7 @@
         # For symmetrical operations, if 'y' is already in a register
         # and won't be used after the current operation finishes,
         # then swap the role of 'x' and 'y'
+        # XXX only do that if x is *not* in a register
         if (symm and isinstance(argloc, RegLoc) and
                 self.rm.longevity[y].last_usage == self.rm.position):
             x, y = y, x
diff --git a/rpython/jit/backend/x86/vector_ext.py 
b/rpython/jit/backend/x86/vector_ext.py
--- a/rpython/jit/backend/x86/vector_ext.py
+++ b/rpython/jit/backend/x86/vector_ext.py
@@ -695,7 +695,7 @@
                 if not candidate_to_spill:
                     raise NoVariableToSpill
                 reg = xrm.reg_bindings[candidate_to_spill]
-                xrm._spill_var(candidate_to_spill, forbidden_vars, None)
+                xrm._spill_var(forbidden_vars, reg)
                 xrm.free_regs.append(reg)
             loc = xrm.free_regs.pop()
             self.assembler.mov(selected_reg, loc)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to