Author: Remi Meier <remi.me...@gmail.com> Branch: fix-longevity Changeset: r82464:2feb1ca9c35c Date: 2016-02-23 22:36 +0100 http://bitbucket.org/pypy/pypy/changeset/2feb1ca9c35c/
Log: (plan_rich,remi) fix broken commit 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 @@ -1,7 +1,7 @@ import os -from rpython.jit.metainterp.history import Const, Box, REF, JitCellToken +from rpython.jit.metainterp.history import Const, REF, JitCellToken from rpython.rlib.objectmodel import we_are_translated, specialize -from rpython.jit.metainterp.resoperation import rop +from rpython.jit.metainterp.resoperation import rop, AbstractValue from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.lltypesystem.lloperation import llop @@ -10,7 +10,7 @@ except ImportError: OrderedDict = dict # too bad -class TempBox(Box): +class TempVar(AbstractValue): def __init__(self): pass @@ -267,6 +267,7 @@ raise NotImplementedError("Purely abstract") class RegisterManager(object): + """ Class that keeps track of register allocations """ box_types = None # or a list of acceptable types @@ -292,19 +293,19 @@ def is_still_alive(self, v): # Check if 'v' is alive at the current position. # Return False if the last usage is strictly before. - return self.longevity[v][1] >= self.position + return self.longevity.last_use(v) >= self.position def stays_alive(self, v): # Check if 'v' stays alive after the current position. # Return False if the last usage is before or at position. - return self.longevity[v][1] > self.position + return self.longevity.last_use(v) > self.position def next_instruction(self, incr=1): self.position += incr def _check_type(self, v): if not we_are_translated() and self.box_types is not None: - assert isinstance(v, TempBox) or v.type in self.box_types + assert isinstance(v, TempVar) or v.type in self.box_types def possibly_free_var(self, v): """ If v is stored in a register and v is not used beyond the @@ -314,7 +315,7 @@ self._check_type(v) if isinstance(v, Const): return - if v not in self.longevity or self.longevity[v][1] <= self.position: + if not self.longevity.exists(v) or self.longevity.last_use(v) <= self.position: if v in self.reg_bindings: self.free_regs.append(self.reg_bindings[v]) del self.reg_bindings[v] @@ -348,7 +349,7 @@ assert len(self.temp_boxes) == 0 if self.longevity: for v in self.reg_bindings: - assert self.longevity[v][1] > self.position + assert self.longevity.last_use(v) > self.position def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): """ Try to allocate a register, if we have one free. @@ -424,7 +425,7 @@ continue if need_lower_byte and reg in self.no_lower_byte_regs: continue - max_age = self.longevity[next][1] + max_age = self.longevity.last_use(next) if cur_max_age < max_age: cur_max_age = max_age candidate = next @@ -442,8 +443,8 @@ Will not spill a variable from 'forbidden_vars'. """ self._check_type(v) - if isinstance(v, TempBox): - self.longevity[v] = (self.position, self.position) + if isinstance(v, TempVar): + self.longevity.new_live_range(v, self.position, self.position) loc = self.try_allocate_reg(v, selected_reg, need_lower_byte=need_lower_byte) if loc: @@ -553,13 +554,14 @@ loc = self.force_allocate_reg(v, forbidden_vars) self.assembler.regalloc_mov(prev_loc, loc) assert v in self.reg_bindings - if self.longevity[v][1] > self.position: + if self.longevity.last_use(v) > 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: + if self.frame_manager.get(v) is None or self.free_regs: self._move_variable_away(v, loc) + self.reg_bindings[result_v] = loc else: self._reallocate_from_to(v, result_v) @@ -581,7 +583,7 @@ 1 (save all), or 2 (save default+PTRs). """ for v, reg in self.reg_bindings.items(): - if v not in force_store and self.longevity[v][1] <= self.position: + if v not in force_store and self.longevity.last_use(v) <= self.position: # variable dies del self.reg_bindings[v] self.free_regs.append(reg) @@ -633,69 +635,79 @@ locs = [] base_ofs = self.assembler.cpu.get_baseofs_of_frame_field() for box in inputargs: - assert isinstance(box, Box) + 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 looptoken.compiled_loop_token._ll_initial_locs = locs - def can_merge_with_next_guard(self, op, i, operations): - if (op.getopnum() == rop.CALL_MAY_FORCE or - op.getopnum() == rop.CALL_ASSEMBLER or - op.getopnum() == rop.CALL_RELEASE_GIL): - assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED - return True - if not op.is_comparison(): - if op.is_ovf(): - if (operations[i + 1].getopnum() != rop.GUARD_NO_OVERFLOW and - operations[i + 1].getopnum() != rop.GUARD_OVERFLOW): - not_implemented("int_xxx_ovf not followed by " - "guard_(no)_overflow") - return True + def next_op_can_accept_cc(self, operations, i): + op = operations[i] + next_op = operations[i + 1] + opnum = next_op.getopnum() + if (opnum != rop.GUARD_TRUE and opnum != rop.GUARD_FALSE + and opnum != rop.COND_CALL): return False - if (operations[i + 1].getopnum() != rop.GUARD_TRUE and - operations[i + 1].getopnum() != rop.GUARD_FALSE): + if next_op.getarg(0) is not op: return False - if operations[i + 1].getarg(0) is not op.result: + if self.longevity[op][1] > i + 1: return False - if (self.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].getfailargs()): - return False + if opnum != rop.COND_CALL: + if op in operations[i + 1].getfailargs(): + return False + else: + if op in operations[i + 1].getarglist()[1:]: + return False return True - def locs_for_call_assembler(self, op, guard_op): + def locs_for_call_assembler(self, op): descr = op.getdescr() assert isinstance(descr, JitCellToken) if op.numargs() == 2: self.rm._sync_var(op.getarg(1)) return [self.loc(op.getarg(0)), self.fm.loc(op.getarg(1))] else: + assert op.numargs() == 1 return [self.loc(op.getarg(0))] -def compute_vars_longevity(inputargs, operations): +class LiveRanges(object): + def __init__(self, longevity, last_real_usage, dist_to_next_call): + self.longevity = longevity + self.last_real_usage = last_real_usage + self.dist_to_next_call = dist_to_next_call + + def exists(self, var): + return var in self.longevity + + def last_use(self, var): + return self.longevity[var][1] + + def new_live_range(self, var, start, end): + self.longevity[var] = (start, end) + +def compute_var_live_ranges(inputargs, operations): # compute a dictionary that maps variables to index in # operations that is a "last-time-seen" - # returns a pair longevity/useful. Non-useful variables are ones that + # returns a Longevity object with longevity/useful. Non-useful variables are ones that # never appear in the assembler or it does not matter if they appear on # stack or in registers. Main example is loop arguments that go # only to guard operations or to jump or to finish - produced = {} last_used = {} last_real_usage = {} + dist_to_next_call = [0] * len(operations) + last_call_pos = -1 for i in range(len(operations)-1, -1, -1): op = operations[i] - if op.result: - if op.result not in last_used and op.has_no_side_effect(): + if op.type != 'v': + if op not in last_used and op.has_no_side_effect(): continue - assert op.result not in produced - produced[op.result] = i opnum = op.getopnum() for j in range(op.numargs()): arg = op.getarg(j) - if not isinstance(arg, Box): + if isinstance(arg, Const): continue if arg not in last_used: last_used[arg] = i @@ -706,26 +718,40 @@ for arg in op.getfailargs(): if arg is None: # hole continue - assert isinstance(arg, Box) + assert not isinstance(arg, Const) if arg not in last_used: last_used[arg] = i + if op.is_call(): + last_call_pos = i + dist_to_next_call[i] = last_call_pos - i # longevity = {} - for arg in produced: - if arg in last_used: - assert isinstance(arg, Box) - assert produced[arg] < last_used[arg] - longevity[arg] = (produced[arg], last_used[arg]) + for i, arg in enumerate(operations): + if arg.type != 'v' and arg in last_used: + assert not isinstance(arg, Const) + assert i < last_used[arg] + longevity[arg] = (i, last_used[arg]) del last_used[arg] for arg in inputargs: - assert isinstance(arg, Box) + assert not isinstance(arg, Const) if arg not in last_used: longevity[arg] = (-1, -1) else: longevity[arg] = (0, last_used[arg]) del last_used[arg] assert len(last_used) == 0 - return longevity, last_real_usage + + if not we_are_translated(): + produced = {} + for arg in inputargs: + produced[arg] = None + for op in operations: + for arg in op.getarglist(): + if not isinstance(arg, Const): + assert arg in produced + produced[op] = None + + return LiveRanges(longevity, last_real_usage, dist_to_next_call) def is_comparison_or_ovf_op(opnum): from rpython.jit.metainterp.resoperation import opclasses @@ -734,7 +760,7 @@ # any instance field, we can use a fake object class Fake(cls): pass - op = Fake(None) + op = Fake() return op.is_comparison() or op.is_ovf() def valid_addressing_size(size): 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 @@ -515,7 +515,7 @@ # and won't be used after the current operation finishes, # then swap the role of 'x' and 'y' if (symm and isinstance(argloc, RegLoc) and - self.rm.live_ranges.last_use(y) == self.rm.position): + self.rm.longevity.last_use(y) == self.rm.position): x, y = y, x argloc = self.loc(y) # _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit