Author: Richard Plangger <planri...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit