Author: Richard Plangger <planri...@gmail.com> Branch: fix-longevity Changeset: r82494:dad960bd604f Date: 2016-02-25 12:42 +0100 http://bitbucket.org/pypy/pypy/changeset/dad960bd604f/
Log: (remi, plan_rich) missing changes that should have been commited earlier? 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 @@ -276,6 +276,64 @@ save_around_call_regs = [] frame_reg = None + free_callee_regs = [reg for reg in all_reg if reg not in save_around_call_regs] + free_caller_regs = save_around_call_regs[:] + is_callee_lookup = [True] * len(all_regs) + for reg in save_around_call_regs: + is_callee_lookup[reg.index] = False + + def get_lower_byte_free_register(self, reg): + # try to return a volatile register first! + for i, caller in enumerate(self.free_caller_regs): + if caller not in self.no_lower_byte_regs: + del self.free_caller_regs[i] + return caller + # in any case, we might want to try callee ones as well + for i, callee in enumerate(self.free_callee_regs): + if callee not in self.no_lower_byte_regs: + del self.free_callee_regs[i] + return callee + return None + + def get_free_register(self, var, callee=False, target_reg=None): + if callee: + target_pool = self.free_callee_regs + second_pool = self.free_caller_regs + else: + target_pool = self.free_caller_regs + second_pool = self.free_callee_regs + if target_pool: + return target_pool.pop() + if second_pool: + return second_pool.pop() + assert 0, "not free register, check this before calling" + + def has_free_registers(self): + return self.free_callee_regs or self.free_caller_regs + + def allocate_new(self, var): + if self.live_ranges.survives_call(var, self.position): + # we want a callee save register + return self.get_free_register(var, callee=True) + else: + return self.get_free_register(var, callee=False, target_reg=None) + + def remove_free_register(self, reg): + if is_callee_lookup[reg.index]: + self.free_callee_regs = [fr for fr in self.free_callee_regs if fr is not r] + else: + self.free_caller_regs = [fr for fr in self.free_caller_regs if fr is not r] + + def put_back_register(self, reg): + if is_callee_lookup[reg.index]: + self.free_callee_regs.push(reg) + else: + self.free_caller_regs.push(reg) + + def is_free(self, reg): + return reg in self.free_callee_regs or \ + reg in self.free_caller_regs + def __init__(self, live_ranges, frame_manager=None, assembler=None): self.free_regs = self.all_regs[:] self.free_regs.reverse() @@ -317,7 +375,7 @@ return if not self.live_ranges.exists(v) or self.live_ranges.last_use(v) <= self.position: if v in self.reg_bindings: - self.free_regs.append(self.reg_bindings[v]) + self.put_back_register(self.reg_bindings[v]) del self.reg_bindings[v] if self.frame_manager is not None: self.frame_manager.mark_as_free(v) @@ -337,17 +395,20 @@ self.temp_boxes = [] def _check_invariants(self): + free_count = len(self.free_callee_regs) + len(self.free_caller_regs) if not we_are_translated(): # make sure no duplicates assert len(dict.fromkeys(self.reg_bindings.values())) == len(self.reg_bindings) rev_regs = dict.fromkeys(self.reg_bindings.values()) - for reg in self.free_regs: + for reg in self.free_caller_regs: assert reg not in rev_regs - assert len(rev_regs) + len(self.free_regs) == len(self.all_regs) + for reg in self.free_callee_regs: + assert reg not in rev_regs + assert len(rev_regs) + free_count == len(self.all_regs) else: - assert len(self.reg_bindings) + len(self.free_regs) == len(self.all_regs) + assert len(self.reg_bindings) + free_count == len(self.all_regs) assert len(self.temp_boxes) == 0 - if self.live_ranges: + if self.live_ranges.longevity: for v in self.reg_bindings: assert self.live_ranges.last_use(v) > self.position @@ -368,32 +429,30 @@ return res else: del self.reg_bindings[v] - self.free_regs.append(res) - if selected_reg in self.free_regs: - self.free_regs = [reg for reg in self.free_regs - if reg is not selected_reg] + self.put_back_register(res) + if self.is_free(selected_reg): + self.remove_free_register(selected_reg) self.reg_bindings[v] = selected_reg return selected_reg return None + if need_lower_byte: loc = self.reg_bindings.get(v, None) if loc is not None and loc not in self.no_lower_byte_regs: + # yes, this location is a no_lower_byte_register return loc - for i in range(len(self.free_regs) - 1, -1, -1): - reg = self.free_regs[i] - if reg not in self.no_lower_byte_regs: - if loc is not None: - self.free_regs[i] = loc - else: - del self.free_regs[i] - self.reg_bindings[v] = reg - return reg - return None + # find a free register that is also a lower byte register + if loc: + self.put_back_register(loc) + reg = self.get_lower_byte_free_register(v) + self.reg_bindings[v] = reg + return reg + try: return self.reg_bindings[v] except KeyError: - if self.free_regs: - loc = self.free_regs.pop() + if self.has_free_registers(): + loc = self.allocate_new(v) self.reg_bindings[v] = loc return loc @@ -453,7 +512,7 @@ need_lower_byte=need_lower_byte) prev_loc = self.reg_bindings.get(v, None) if prev_loc is not None: - self.free_regs.append(prev_loc) + self.put_back_register(prev_loc) self.reg_bindings[v] = loc return loc @@ -466,7 +525,7 @@ try: loc = self.reg_bindings[var] del self.reg_bindings[var] - self.free_regs.append(loc) + self.put_back_register(loc) except KeyError: pass # 'var' is already not in a register @@ -493,11 +552,11 @@ assert isinstance(v, Const) immloc = self.convert_to_imm(v) if selected_reg: - if selected_reg in self.free_regs: + if self.is_free(selected_reg): self.assembler.regalloc_mov(immloc, selected_reg) return selected_reg loc = self._spill_var(v, forbidden_vars, selected_reg) - self.free_regs.append(loc) + self.put_back_register(loc) self.assembler.regalloc_mov(immloc, loc) return loc return immloc @@ -526,8 +585,8 @@ self.reg_bindings[to_v] = reg def _move_variable_away(self, v, prev_loc): - if self.free_regs: - loc = self.free_regs.pop() + if self.has_free_registers(): + loc = self.allocate_new(v) self.reg_bindings[v] = loc self.assembler.regalloc_mov(prev_loc, loc) else: @@ -542,8 +601,8 @@ self._check_type(result_v) self._check_type(v) if isinstance(v, Const): - if self.free_regs: - loc = self.free_regs.pop() + if self.has_free_registers(): + loc = self.allocate_new(v) else: loc = self._spill_var(v, forbidden_vars, None) self.assembler.regalloc_mov(self.convert_to_imm(v), loc) @@ -559,7 +618,7 @@ # store result in the same place loc = self.reg_bindings[v] del self.reg_bindings[v] - if self.frame_manager.get(v) is None or self.free_regs: + if self.frame_manager.get(v) is None or self.has_free_registers(): self._move_variable_away(v, loc) self.reg_bindings[result_v] = loc @@ -586,7 +645,7 @@ if v not in force_store and self.live_ranges.last_use(v) <= self.position: # variable dies del self.reg_bindings[v] - self.free_regs.append(reg) + self.put_back_register(reg) continue if save_all_regs != 1 and reg not in self.save_around_call_regs: if save_all_regs == 0: @@ -595,7 +654,7 @@ continue # only save GC pointers self._sync_var(v) del self.reg_bindings[v] - self.free_regs.append(reg) + self.put_back_register(reg) def after_call(self, v): """ Adjust registers according to the result of the call, @@ -606,7 +665,7 @@ if not we_are_translated(): assert r not in self.reg_bindings.values() self.reg_bindings[v] = r - self.free_regs = [fr for fr in self.free_regs if fr is not r] + self.remove_free_register(r) return r # abstract methods, override @@ -638,8 +697,7 @@ assert not isinstance(box, Const) loc = self.fm.get_new_loc(box) locs.append(loc.value - base_ofs) - if looptoken.compiled_loop_token is not None: - # for tests + if looptoken.compiled_loop_token is not None: # <- for tests looptoken.compiled_loop_token._ll_initial_locs = locs def next_op_can_accept_cc(self, operations, i): @@ -687,6 +745,15 @@ def new_live_range(self, var, start, end): self.longevity[var] = (start, end) + def survives_call(self, var, position): + start, end = self.longevity[var] + dist = self.dist_to_next_call[position] + assert end >= position + if end-position <= dist: + # it is 'live during a call' if it live range ends after the call + return True + return False + def compute_var_live_ranges(inputargs, operations): # compute a dictionary that maps variables to index in # operations that is a "last-time-seen" _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit