[pypy-commit] pypy s390x-backend: regalloc has now one more pair, SPP is now r12 (was r11)

plan_rich pypy.commits at gmail.com
Tue Feb 16 08:27:01 EST 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: s390x-backend
Changeset: r82279:9a63f13fcdbd
Date: 2016-02-16 13:01 +0100
http://bitbucket.org/pypy/pypy/changeset/9a63f13fcdbd/

Log:	regalloc has now one more pair, SPP is now r12 (was r11) rewritten
	regalloc pairs. it is now simpler and easier to understand.

diff --git a/rpython/jit/backend/zarch/assembler.py b/rpython/jit/backend/zarch/assembler.py
--- a/rpython/jit/backend/zarch/assembler.py
+++ b/rpython/jit/backend/zarch/assembler.py
@@ -180,7 +180,7 @@
         mc.push_std_frame()
 
         RCS2 = r.r10
-        RCS3 = r.r12
+        RCS3 = r.r11
 
         # r10,r11,r12,r2,f0 -> makes exactly 4 words + 8 byte
         extra_stack_size = 4 * WORD + 8
@@ -330,7 +330,7 @@
         mc.LGR(r.r3, r.SCRATCH2)
 
         RCS2 = r.r10
-        RCS3 = r.r12
+        RCS3 = r.r11
 
         self._store_and_reset_exception(mc, RCS2, RCS3)
 
@@ -387,7 +387,7 @@
         come.
         """
         # signature of these cond_call_slowpath functions:
-        #   * on entry, r12 contains the function to call
+        #   * on entry, r11 contains the function to call
         #   * r2, r3, r4, r5 contain arguments for the call
         #   * r0 is the gcmap
         #   * the old value of these regs must already be stored in the jitframe
@@ -400,7 +400,7 @@
         mc.store_link()
         mc.push_std_frame()
 
-        # copy registers to the frame, with the exception of r2 to r5 and r12,
+        # copy registers to the frame, with the exception of r2 to r5 and r11,
         # because these have already been saved by the caller.  Note that
         # this is not symmetrical: these 5 registers are saved by the caller
         # but restored here at the end of this function.
@@ -413,13 +413,13 @@
                        reg is not r.r3 and
                        reg is not r.r4 and
                        reg is not r.r5 and
-                       reg is not r.r12]
+                       reg is not r.r11]
         self._push_core_regs_to_jitframe(mc, regs)
         if supports_floats:
             self._push_fp_regs_to_jitframe(mc)
 
         # allocate a stack frame!
-        mc.raw_call(r.r12)
+        mc.raw_call(r.r11)
 
         # Finish
         self._reload_frame_if_necessary(mc)
diff --git a/rpython/jit/backend/zarch/codebuilder.py b/rpython/jit/backend/zarch/codebuilder.py
--- a/rpython/jit/backend/zarch/codebuilder.py
+++ b/rpython/jit/backend/zarch/codebuilder.py
@@ -195,9 +195,9 @@
     def sync(self):
         self.BCR_rr(0xf,0)
 
-    def raw_call(self, call_reg=r.RETURN):
+    def raw_call(self, call_reg=r.r14):
         """Emit a call to the address stored in the register 'call_reg',
-        which must be either RAW_CALL_REG or r12.  This is a regular C
+        which must be either RAW_CALL_REG or r11.  This is a regular C
         function pointer, which means on big-endian that it is actually
         the address of a three-words descriptor.
         """
diff --git a/rpython/jit/backend/zarch/opassembler.py b/rpython/jit/backend/zarch/opassembler.py
--- a/rpython/jit/backend/zarch/opassembler.py
+++ b/rpython/jit/backend/zarch/opassembler.py
@@ -367,7 +367,7 @@
     def _find_nearby_operation(self, regalloc, delta):
         return regalloc.operations[regalloc.rm.position + delta]
 
-    _COND_CALL_SAVE_REGS = [r.r12, r.r2, r.r3, r.r4, r.r5]
+    _COND_CALL_SAVE_REGS = [r.r11, r.r2, r.r3, r.r4, r.r5]
 
     def emit_cond_call(self, op, arglocs, regalloc):
         fcond = self.guard_success_cc
@@ -378,7 +378,7 @@
         jmp_adr = self.mc.get_relative_pos()
         self.mc.reserve_cond_jump() # patched later to a relative branch
 
-        # save away r2, r3, r4, r5, r12 into the jitframe
+        # save away r2, r3, r4, r5, r11 into the jitframe
         should_be_saved = [
             reg for reg in self._regalloc.rm.reg_bindings.itervalues()
                 if reg in self._COND_CALL_SAVE_REGS]
@@ -388,9 +388,9 @@
         self.load_gcmap(self.mc, r.SCRATCH2, regalloc.get_gcmap())
         #
         # load the 0-to-4 arguments into these registers, with the address of
-        # the function to call into r12
+        # the function to call into r11
         remap_frame_layout(self, arglocs,
-                           [r.r12, r.r2, r.r3, r.r4, r.r5][:len(arglocs)],
+                           [r.r11, r.r2, r.r3, r.r4, r.r5][:len(arglocs)],
                            r.SCRATCH)
         #
         # figure out which variant of cond_call_slowpath to call, and call it
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
@@ -171,24 +171,29 @@
         self.temp_boxes.append(box)
         return reg
 
-    def ensure_even_odd_pair(self, var, bindvar, bind_first=True,
+    def ensure_even_odd_pair(self, origvar, bindvar, bind_first=True,
                              must_exist=True, load_loc_odd=True,
                              move_regs=True):
         """ Allocates two registers that can be used by the instruction.
-            var: is the original register holding the value
+            origvar: is the original register holding the value
             bindvar: is the variable that will be bound
                      (= self.reg_bindings[bindvar] = new register)
             bind_first: the even register will be bound to bindvar,
                         if bind_first == False: the odd register will
                         be bound
         """
-        self._check_type(var)
-        prev_loc = self.loc(var, must_exist=must_exist)
+        self._check_type(origvar)
+        prev_loc = self.loc(origvar, must_exist=must_exist)
         var2 = TempVar()
+        if bindvar is None:
+            bindvar = TempVar()
         if bind_first:
             loc, loc2 = self.force_allocate_reg_pair(bindvar, var2, self.temp_boxes)
         else:
             loc, loc2 = self.force_allocate_reg_pair(var2, bindvar, self.temp_boxes)
+        if isinstance(bindvar, TempVar):
+            self.temp_boxes.append(bindvar)
+
         self.temp_boxes.append(var2)
         assert loc.is_even() and loc2.is_odd()
         if move_regs and prev_loc is not loc2:
@@ -198,148 +203,115 @@
                 self.assembler.regalloc_mov(prev_loc, loc)
         return loc, loc2
 
-    def force_allocate_reg_pair(self, var, var2, forbidden_vars=[], selected_reg=None):
-        """ Forcibly allocate a register for the new variable var.
-        var will have an even register (var2 will have an odd register).
+    def force_allocate_reg_pair(self, even_var, odd_var, forbidden_vars):
+        """ Forcibly allocate a register for the new variable even_var.
+            even_var will have an even register (odd_var, you guessed it,
+            will have an odd register).
         """
-        self._check_type(var)
-        self._check_type(var2)
-        if isinstance(var, TempVar):
-            self.longevity[var] = (self.position, self.position)
-        if isinstance(var2, TempVar):
-            self.longevity[var2] = (self.position, self.position)
+        self._check_type(even_var)
+        self._check_type(odd_var)
+        if isinstance(even_var, TempVar):
+            self.longevity[even_var] = (self.position, self.position)
+        if isinstance(odd_var, TempVar):
+            self.longevity[odd_var] = (self.position, self.position)
+
+        # this function steps through the following:
+        # 1) maybe there is an even/odd pair that is always
+        #    free, then allocate them!
+        # 2) try to just spill one variable in either the even
+        #    or the odd reg
+        # 3) spill two variables
+
+        # start in 1)
+        SPILL_EVEN = 0
+        SPILL_ODD = 1
         even, odd = None, None
-        REGS = r.registers
+        candidates = []
         i = len(self.free_regs)-1
-        candidates = {}
         while i >= 0:
             even = self.free_regs[i]
             if even.is_even():
                 # found an even registers that is actually free
-                odd = REGS[even.value+1]
-                if odd not in r.MANAGED_REGS:
-                    # makes no sense to use this register!
-                    i -= 1
-                    continue
+                odd = r.registers[even.value+1]
                 if odd not in self.free_regs:
                     # sadly odd is not free, but for spilling
                     # we found a candidate
-                    candidates[odd] = True
+                    candidates.append((even, odd, SPILL_ODD))
                     i -= 1
                     continue
-                assert var not in self.reg_bindings
-                assert var2 not in self.reg_bindings
-                self.reg_bindings[var] = even
-                self.reg_bindings[var2] = odd
-                del self.free_regs[i]
-                i = self.free_regs.index(odd)
-                del self.free_regs[i]
-                assert even.is_even() and odd.is_odd()
+                # even is free and so is odd! allocate these
+                # two registers
+                assert even_var not in self.reg_bindings
+                assert odd_var not in self.reg_bindings
+                self.reg_bindings[even_var] = even
+                self.reg_bindings[odd_var] = odd
+                self.free_regs = [fr for fr in self.free_regs \
+                                  if fr is not even and \
+                                     fr is not odd]
                 return even, odd
             else:
                 # an odd free register, maybe the even one is
                 # a candidate?
                 odd = even
-                even = REGS[odd.value-1]
-                if even not in r.MANAGED_REGS:
-                    # makes no sense to use this register!
-                    i -= 1
-                    continue
+                even = r.registers[odd.value-1]
                 if even not in self.free_regs:
                     # yes even might be a candidate
                     # this means that odd is free, but not even
-                    candidates[even] = True
+                    candidates.append((even, odd, SPILL_EVEN))
             i -= 1
 
-        if len(candidates) != 0:
-            cur_max_age = -1
-            candidate = None
-            # pseudo step to find best spilling candidate
-            # similar to _pick_variable_to_spill, but tailored
-            # to take the even/odd register allocation in consideration
-            for next in self.reg_bindings:
-                if next in forbidden_vars:
-                    continue
-                reg = self.reg_bindings[next]
-                if reg in candidates:
-                    reg2 = None
-                    if reg.is_even():
-                        reg2 = REGS[reg.value+1]
-                    else:
-                        reg2 = REGS[reg.value-1]
-                    if reg2 not in r.MANAGED_REGS:
-                        continue
-                    max_age = self.longevity[next][1]
-                    if cur_max_age < max_age:
-                        cur_max_age = max_age
-                        candidate = next
-            if candidate is not None:
-                # well, we got away with a single spill :)
-                reg = self.reg_bindings[candidate]
-                self._sync_var(candidate)
-                del self.reg_bindings[candidate]
-                if reg.is_even():
-                    assert var is not candidate
-                    self.reg_bindings[var] = reg
-                    rmfree = REGS[reg.value+1]
-                    self.reg_bindings[var2] = rmfree
-                    self.free_regs = [fr for fr in self.free_regs if fr is not rmfree]
-                    return reg, rmfree
-                else:
-                    assert var2 is not candidate
-                    self.reg_bindings[var2] = reg
-                    rmfree = REGS[reg.value-1]
-                    self.reg_bindings[var] = rmfree
-                    self.free_regs = [fr for fr in self.free_regs if fr is not rmfree]
-                    return rmfree, reg
+        reverse_mapping = {}
+        for v, reg in self.reg_bindings.items():
+            reverse_mapping[reg] = v
+
+        # needs to spill one variable
+        for even, odd, which_to_spill in candidates:
+            # no heuristic, pick the first
+            if which_to_spill == SPILL_EVEN:
+                orig_var_even = reverse_mapping[even]
+                if orig_var_even in forbidden_vars:
+                    continue # duh!
+                self._sync_var(orig_var_even)
+                del self.reg_bindings[orig_var_even]
+            elif which_to_spill == SPILL_ODD:
+                orig_var_odd = reverse_mapping[odd]
+                if orig_var_odd in forbidden_vars:
+                    continue # duh!
+                self._sync_var(orig_var_odd)
+                del self.reg_bindings[orig_var_odd]
+            
+            # well, we got away with a single spill :)
+            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
 
         # there is no candidate pair that only would
         # require one spill, thus we need to spill two!
         # this is a rare case!
-        reverse_mapping = {}
-        for v, reg in self.reg_bindings.items():
-            reverse_mapping[reg] = v
-        # always take the first
-        for i, reg in enumerate(r.MANAGED_REGS):
-            if i % 2 == 1:
+        for even, odd in r.MANAGED_REG_PAIRS:
+            orig_var_even = reverse_mapping[even]
+            orig_var_odd = reverse_mapping[odd]
+            if orig_var_even in forbidden_vars or \
+               orig_var_odd in forbidden_vars:
                 continue
-            if i+1 < len(r.MANAGED_REGS):
-                reg2 = r.MANAGED_REGS[i+1]
-                assert reg.is_even() and reg2.is_odd()
-                ovar = reverse_mapping.get(reg,None)
-                if ovar is None:
-                    continue
-                if ovar in forbidden_vars:
-                    continue
-                ovar2 = reverse_mapping.get(reg2, None)
-                if ovar2 is not None and ovar2 in forbidden_vars:
-                    # blocked, try other register pair
-                    continue
-                even = reg
-                odd = reg2
-                self._sync_var(ovar)
-                self._sync_var(ovar2)
-                del self.reg_bindings[ovar]
-                if ovar2 is not None:
-                    del self.reg_bindings[ovar2]
-                # both are not added to free_regs! no need to do so
-                self.reg_bindings[var] = even
-                self.reg_bindings[var2] = odd
-                break
+
+            self._sync_var(orig_var_even)
+            del self.reg_bindings[orig_var_even]
+            self._sync_var(orig_var_odd)
+            del self.reg_bindings[orig_var_odd]
+
+            self.reg_bindings[even_var] = even
+            self.reg_bindings[odd_var] = odd
+            break
         else:
             # no break! this is bad. really bad
             raise NoVariableToSpill()
 
-        reverse_mapping = None
-
         return even, odd
 
-    def force_result_in_even_reg(self, result_v, loc, forbidden_vars=[]):
-        pass
-
-    def force_result_in_odd_reg(self, result_v, loc, forbidden_vars=[]):
-        pass
-
 class ZARCHFrameManager(FrameManager):
     def __init__(self, base_ofs):
         FrameManager.__init__(self)
@@ -990,11 +962,9 @@
         # args: base, start, len, scale_start, scale_len
         itemsize, ofs, _ = unpack_arraydescr(op.getdescr())
         startindex_loc = self.ensure_reg_or_16bit_imm(op.getarg(1))
-        tempvar = TempInt()
         ofs_loc = self.ensure_reg_or_16bit_imm(ConstInt(ofs))
-        base_loc, length_loc = self.rm.ensure_even_odd_pair(op.getarg(0), tempvar,
+        base_loc, length_loc = self.rm.ensure_even_odd_pair(op.getarg(0), None,
               bind_first=True, must_exist=False, load_loc_odd=False)
-        self.rm.temp_boxes.append(tempvar)
 
         length_box = op.getarg(2)
         ll = self.rm.loc(length_box)
@@ -1145,13 +1115,11 @@
             src_len: when entering the assembler, src_ofs_loc's value is contained
               in src_len register.
         """
-        src_tmp = TempVar()
         src_ptr_loc, _ = \
                 self.rm.ensure_even_odd_pair(op.getarg(0),
-                             src_tmp, bind_first=True, 
+                             None, bind_first=True, 
                              must_exist=False, load_loc_odd=False)
         src_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(2))
-        self.rm.temp_boxes.append(src_tmp)
         dst_ptr_loc = self.ensure_reg(op.getarg(1))
         dst_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(3))
         length_loc  = self.ensure_reg_or_any_imm(op.getarg(4))
diff --git a/rpython/jit/backend/zarch/registers.py b/rpython/jit/backend/zarch/registers.py
--- a/rpython/jit/backend/zarch/registers.py
+++ b/rpython/jit/backend/zarch/registers.py
@@ -7,17 +7,18 @@
 [r0,r1,r2,r3,r4,r5,r6,r7,r8,
  r9,r10,r11,r12,r13,r14,r15] = registers
 
-MANAGED_REGS = [r2,r3,r4,r5,r6,r7,r8,r9,r10,r12] # keep this list sorted (asc)!
+MANAGED_REGS = [r2,r3,r4,r5,r6,r7,r8,r9,r10,r11] # keep this list sorted (asc)!
+MANAGED_REG_PAIRS = [(r2,r3), (r4,r5), (r6,r7), (r8,r9), (r10,r11)]
 VOLATILES = [r2,r3,r4,r5,r6]
 SP = r15
 RETURN = r14
 POOL = r13
-SPP = r11
+SPP = r12
 SCRATCH = r1
 SCRATCH2 = r0
 GPR_RETURN = r2
 RES = r2
-RSZ = r12 # do not use a volatile register
+RSZ = r11 # do not use a volatile register
 
 [f0,f1,f2,f3,f4,f5,f6,f7,f8,
  f9,f10,f11,f12,f13,f14,f15] = fpregisters


More information about the pypy-commit mailing list