[pypy-commit] pypy default: tested & impl pair allocation. there was an edge case which caused the allocation to fail.

plan_rich pypy.commits at gmail.com
Wed Apr 13 04:17:14 EDT 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: 
Changeset: r83649:580534e4ba07
Date: 2016-04-13 10:11 +0200
http://bitbucket.org/pypy/pypy/changeset/580534e4ba07/

Log:	tested & impl pair allocation. there was an edge case which caused
	the allocation to fail.

diff --git a/rpython/jit/backend/zarch/regalloc.py b/rpython/jit/backend/zarch/regalloc.py
--- a/rpython/jit/backend/zarch/regalloc.py
+++ b/rpython/jit/backend/zarch/regalloc.py
@@ -178,6 +178,7 @@
             bind_first: the even register will be bound to bindvar,
                         if bind_first == False: the odd register will
                         be bound
+            NOTE: Calling ensure_even_odd_pair twice in a prepare function is NOT supported!
         """
         self._check_type(origvar)
         prev_loc = self.loc(origvar, must_exist=must_exist)
@@ -227,9 +228,6 @@
         i = len(self.free_regs)-1
         while i >= 0:
             even = self.free_regs[i]
-            if even.value == 13:
-                i -= 1
-                continue
             if even.is_even():
                 # found an even registers that is actually free
                 odd = r.odd_reg(even)
@@ -309,11 +307,50 @@
             self.reg_bindings[odd_var] = odd
             break
         else:
-            # no break! this is bad. really bad
-            raise NoVariableToSpill()
+            # uff! in this case, we need to move a forbidden var to another register
+            assert len(forbidden_vars) <= 8 # otherwise it is NOT possible to complete
+            even, odd = r.r2, r.r3
+            even_var = reverse_mapping.get(even, None)
+            odd_var = reverse_mapping.get(odd, None)
+            if even_var:
+                if even_var in forbidden_vars:
+                    self._relocate_forbidden_variable(even, even_var, reverse_mapping,
+                                                      forbidden_vars, odd)
+                else:
+                    self._sync_var(even_var)
+            if odd_var:
+                if odd_var in forbidden_vars:
+                    self._relocate_forbidden_variable(odd, odd_var, reverse_mapping,
+                                                      forbidden_vars, even)
+                else:
+                    self._sync_var(odd_var)
+
+            self.free_regs = [fr for fr in self.free_regs \
+                              if fr is not even and \
+                                 fr is not odd]
+            self.reg_bindings[even_var] = even
+            self.reg_bindings[odd_var] = odd
+            return even, odd
 
         return even, odd
 
+    def _relocate_forbidden_variable(self, reg, var, reverse_mapping, forbidden_vars, forbidden_reg):
+        for candidate in r.MANAGED_REGS:
+            if candidate is reg or candidate is forbidden_reg:
+                continue
+            if candidate not in forbidden_vars:
+                var = reverse_mapping.get(candidate, None)
+                if var is not None:
+                    self._sync_var(var)
+                self.assembler.regalloc_mov(reg, candidate)
+                self.reg_bindings[var] = candidate
+                reverse_mapping[reg] = var
+                self.free_regs.append(reg)
+                break
+        else:
+            raise NoVariableToSpill
+
+
 class ZARCHFrameManager(FrameManager):
     def __init__(self, base_ofs):
         FrameManager.__init__(self)
diff --git a/rpython/jit/backend/zarch/test/test_regalloc.py b/rpython/jit/backend/zarch/test/test_regalloc.py
--- a/rpython/jit/backend/zarch/test/test_regalloc.py
+++ b/rpython/jit/backend/zarch/test/test_regalloc.py
@@ -44,6 +44,20 @@
         assert self.rm.reg_bindings[a] == r.r2
         assert self.rm.reg_bindings[b] == r.r3
 
+    def test_cannot_spill_too_many_forbidden_vars(self):
+        v = temp_vars(12)
+        a, b = v[10], v[11]
+        self.rm.frame_manager.bindings[a] = self.rm.frame_manager.loc(a)
+        self.rm.frame_manager.bindings[b] = self.rm.frame_manager.loc(b)
+        # all registers are allocated
+        self.rm.allocate((2,v[0]),(3,v[1]),(4,v[2]),(5,v[3]),
+                         (6,v[4]),(7,v[5]),(8,v[6]),(9,v[7]),
+                         (10,v[8]),(11,v[9]))
+        self.rm.temp_boxes = v[:-2]
+        with py.test.raises(AssertionError):
+            # assert len(forbidden_vars) <= 8
+            self.rm.ensure_even_odd_pair(a, b, bind_first=False)
+
     def test_all_but_one_forbidden(self):
         a,b,f1,f2,f3,f4,o = temp_vars(7)
         self.rm.allocate((2,f1),(4,f2),(6,f3),(8,f4),(10,o))
@@ -51,12 +65,6 @@
         assert self.rm.reg_bindings[a] == r.r10
         assert self.rm.reg_bindings[b] == r.r11
 
-    def test_cannot_spill(self):
-        a,b,f1,f2,f3,f4,f5 = temp_vars(7)
-        self.rm.allocate((2,f1),(4,f2),(6,f3),(8,f4),(10,f5))
-        with py.test.raises(NoVariableToSpill):
-            self.rm.force_allocate_reg_pair(a, b, [f1,f2,f3,f4,f5])
-
     def test_all_but_one_forbidden_odd(self):
         a,b,f1,f2,f3,f4,f5 = temp_vars(7)
         self.rm.allocate((3,f1),(5,f2),(7,f3),(9,f4),(11,f5))
@@ -86,6 +94,25 @@
         assert a not in self.rm.reg_bindings
         assert self.rm.assembler.move_count == 2
 
+    def test_ensure_pair_fully_allocated_first_forbidden(self):
+        v = temp_vars(12)
+        a, b = v[10], v[11]
+        self.rm.frame_manager.bindings[a] = self.rm.frame_manager.loc(a)
+        self.rm.frame_manager.bindings[b] = self.rm.frame_manager.loc(b)
+        # all registers are allocated
+        self.rm.allocate((2,v[0]),(3,v[1]),(4,v[2]),(5,v[3]),
+                         (6,v[4]),(7,v[5]),(8,v[6]),(9,v[7]),
+                         (10,v[8]),(11,v[9]))
+        self.rm.temp_boxes = [v[0],v[2],v[4],v[6],v[8]]
+        e, o = self.rm.ensure_even_odd_pair(a, b, bind_first=False)
+        assert e == r.r2
+        assert o == r.r3
+
+        self.rm.temp_boxes = [v[0],v[1],v[2],v[4],v[6],v[8]]
+        e, o = self.rm.ensure_even_odd_pair(a, b, bind_first=False)
+        assert e == r.r2
+        assert o == r.r3
+
 def run(inputargs, ops):
     cpu = CPU(None, None)
     cpu.setup_once()


More information about the pypy-commit mailing list