def _emit_operation(self, op): assert not rop.is_call_pure(op.getopnum()) orig_op = op op = self.get_box_replacement(op) if op.is_constant(): return # can happen e.g. if we postpone the operation that becomes # constant # XXX kill, requires thinking #op = self.replace_op_with(op, op.opnum) for i in range(op.numargs()): arg = self.force_box(op.getarg(i)) op.setarg(i, arg) self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS) if rop.is_guard(op.opnum): assert isinstance(op, GuardResOp) self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields self.pendingfields = None if self.replaces_guard and orig_op in self.replaces_guard: self.replace_guard_op(self.replaces_guard[orig_op], op) del self.replaces_guard[orig_op] return else: op = self.emit_guard_operation(op, pendingfields) opnum = op.opnum if ((rop.has_no_side_effect(opnum) or rop.is_guard(opnum) or rop.is_jit_debug(opnum) or rop.is_ovf(opnum)) and not self.is_call_pure_pure_canraise(op)): pass else: self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) self._emittedoperations[op] = None
def compute_vars_longevity(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 # 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 last_used = {} last_real_usage = {} for i in range(len(operations) - 1, -1, -1): op = operations[i] if op.type != 'v': if op not in last_used and rop.has_no_side_effect(op.opnum): continue opnum = op.getopnum() for j in range(op.numargs()): arg = op.getarg(j) if isinstance(arg, Const): continue if arg not in last_used: last_used[arg] = i if opnum != rop.JUMP and opnum != rop.LABEL: if arg not in last_real_usage: last_real_usage[arg] = i if rop.is_guard(op.opnum): for arg in op.getfailargs(): if arg is None: # hole continue assert not isinstance(arg, Const) if arg not in last_used: last_used[arg] = i # longevity = {} 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 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 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 longevity, last_real_usage
def add_hints(self, longevity, inputargs, operations): self.longevity = longevity for i in range(len(operations)): op = operations[i] if rop.has_no_side_effect(op.opnum) and op not in self.longevity: continue oplist[op.getopnum()](self, op, i)
def _emit_operation(self, op): assert not rop.is_call_pure(op.getopnum()) orig_op = op op = self.get_box_replacement(op) if op.is_constant(): return # can happen e.g. if we postpone the operation that becomes # constant # XXX kill, requires thinking #op = self.replace_op_with(op, op.opnum) for i in range(op.numargs()): arg = self.force_box(op.getarg(i)) op.setarg(i, arg) self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS) if rop.is_guard(op.opnum): assert isinstance(op, GuardResOp) self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields self.pendingfields = None if self.replaces_guard and orig_op in self.replaces_guard: self.replace_guard_op(self.replaces_guard[orig_op], op) del self.replaces_guard[orig_op] return else: op = self.emit_guard_operation(op, pendingfields) elif op.can_raise(): self.exception_might_have_happened = True opnum = op.opnum if ((rop.has_no_side_effect(opnum) or rop.is_guard(opnum) or rop.is_jit_debug(opnum) or rop.is_ovf(opnum)) and not self.is_call_pure_pure_canraise(op)): pass else: self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op)
def compute_vars_longevity(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 # 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 last_used = {} last_real_usage = {} for i in range(len(operations) - 1, -1, -1): op = operations[i] if op.type != "v": if op not in last_used and rop.has_no_side_effect(op.opnum): continue opnum = op.getopnum() for j in range(op.numargs()): arg = op.getarg(j) if isinstance(arg, Const): continue if arg not in last_used: last_used[arg] = i if opnum != rop.JUMP and opnum != rop.LABEL: if arg not in last_real_usage: last_real_usage[arg] = i if rop.is_guard(op.opnum): for arg in op.getfailargs(): if arg is None: # hole continue assert not isinstance(arg, Const) if arg not in last_used: last_used[arg] = i # longevity = {} 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 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 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 longevity, last_real_usage
def compute_vars_longevity(inputargs, operations): # compute a dictionary that maps variables to Lifetime information # if a variable is not in the dictionary, it's operation is dead because # it's side-effect-free and the result is unused longevity = {} for i in range(len(operations) - 1, -1, -1): op = operations[i] opnum = op.getopnum() if op not in longevity: if op.type != 'v' and rop.has_no_side_effect(opnum): # result not used, operation has no side-effect, it can be # removed continue longevity[op] = Lifetime(definition_pos=i, last_usage=i) else: longevity[op].definition_pos = i for j in range(op.numargs()): arg = op.getarg(j) if isinstance(arg, Const): continue if arg not in longevity: lifetime = longevity[arg] = Lifetime(last_usage=i) else: lifetime = longevity[arg] if opnum != rop.JUMP and opnum != rop.LABEL: if lifetime.real_usages is None: lifetime.real_usages = [] lifetime.real_usages.append(i) if rop.is_guard(op.opnum): for arg in op.getfailargs(): if arg is None: # hole continue assert not isinstance(arg, Const) if arg not in longevity: longevity[arg] = Lifetime(last_usage=i) # for arg in inputargs: assert not isinstance(arg, Const) if arg not in longevity: longevity[arg] = Lifetime(-1, -1) 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 for lifetime in longevity.itervalues(): if lifetime.real_usages is not None: lifetime.real_usages.reverse() if not we_are_translated(): lifetime._check_invariants() return LifetimeManager(longevity)
def walk_operations(self, inputargs, operations): from rpython.jit.backend.ppc.ppc_assembler import (operations as asm_operations) i = 0 self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) self.operations = operations while i < len(operations): op = operations[i] self.assembler.mc.mark_op(op) self.rm.position = i self.fprm.position = i self.vrm.position = i opnum = op.opnum if rop.has_no_side_effect(opnum) and op not in self.longevity: i += 1 self.possibly_free_vars_for_op(op) continue # for j in range(op.numargs()): box = op.getarg(j) if box.is_vector(): if box.type != VOID: self.vrm.temp_boxes.append(box) elif box.type != FLOAT: self.rm.temp_boxes.append(box) else: self.fprm.temp_boxes.append(box) # if not we_are_translated() and opnum == rop.FORCE_SPILL: self._consider_force_spill(op) else: arglocs = oplist[opnum](self, op) asm_operations[opnum](self.assembler, op, arglocs, self) self.free_op_vars() self.possibly_free_var(op) self.rm._check_invariants() self.fprm._check_invariants() self.vrm._check_invariants() if self.assembler.mc.get_relative_pos() > self.limit_loop_break: self.assembler.break_long_loop(self) self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) i += 1 assert not self.rm.reg_bindings assert not self.fprm.reg_bindings if not we_are_translated(): self.assembler.mc.trap() self.flush_loop() self.assembler.mc.mark_op(None) # end of the loop self.operations = None for arg in inputargs: self.possibly_free_var(arg)
def walk_operations(self, inputargs, operations): from rpython.jit.backend.ppc.ppc_assembler import ( operations as asm_operations) i = 0 self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) self.operations = operations while i < len(operations): op = operations[i] self.assembler.mc.mark_op(op) self.rm.position = i self.fprm.position = i self.vrm.position = i opnum = op.opnum if rop.has_no_side_effect(opnum) and op not in self.longevity: i += 1 self.possibly_free_vars_for_op(op) continue # for j in range(op.numargs()): box = op.getarg(j) if box.is_vector(): if box.type != VOID: self.vrm.temp_boxes.append(box) elif box.type != FLOAT: self.rm.temp_boxes.append(box) else: self.fprm.temp_boxes.append(box) # if not we_are_translated() and opnum == rop.FORCE_SPILL: self._consider_force_spill(op) else: arglocs = oplist[opnum](self, op) asm_operations[opnum](self.assembler, op, arglocs, self) self.free_op_vars() self.possibly_free_var(op) self.rm._check_invariants() self.fprm._check_invariants() self.vrm._check_invariants() if self.assembler.mc.get_relative_pos() > self.limit_loop_break: self.assembler.break_long_loop(self) self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) i += 1 assert not self.rm.reg_bindings assert not self.fprm.reg_bindings if not we_are_translated(): self.assembler.mc.trap() self.flush_loop() self.assembler.mc.mark_op(None) # end of the loop self.operations = None for arg in inputargs: self.possibly_free_var(arg)
def insert_label(self, loop, position, r): assert not hasattr(loop, '_targettoken') for i in range(position): op = loop.operations[i] if (not rop.has_no_side_effect(op.opnum) or op.type not in (INT, FLOAT)): position = i break # cannot move the LABEL later randompos = r.randrange(0, len(self.startvars)+1) self.startvars.insert(randompos, op) loop._targettoken = TargetToken() loop.operations.insert(position, ResOperation(rop.LABEL, self.startvars, loop._targettoken))
def insert_label(self, loop, position, r): assert not hasattr(loop, '_targettoken') for i in range(position): op = loop.operations[i] if (not rop.has_no_side_effect(op.opnum) or op.type not in (INT, FLOAT)): position = i break # cannot move the LABEL later randompos = r.randrange(0, len(self.startvars) + 1) self.startvars.insert(randompos, op) loop._targettoken = TargetToken() loop.operations.insert( position, ResOperation(rop.LABEL, self.startvars, loop._targettoken))
def emitting_operation(self, op): if rop.has_no_side_effect(op.opnum): return if rop.is_ovf(op.opnum): return if rop.is_guard(op.opnum): self.optimizer.pendingfields = (self.force_lazy_sets_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially opnum == rop.SETFIELD_RAW or # no effect on GC struct/array opnum == rop.SETARRAYITEM_GC or # handled specially opnum == rop.SETARRAYITEM_RAW or # no effect on GC struct opnum == rop.SETINTERIORFIELD_RAW or # no effect on GC struct opnum == rop.RAW_STORE or # no effect on GC struct opnum == rop.STRSETITEM or # no effect on GC struct/array opnum == rop.UNICODESETITEM or # no effect on GC struct/array opnum == rop.DEBUG_MERGE_POINT or # no effect whatsoever opnum == rop.JIT_DEBUG or # no effect whatsoever opnum == rop.ENTER_PORTAL_FRAME or # no effect whatsoever opnum == rop.LEAVE_PORTAL_FRAME or # no effect whatsoever opnum == rop.COPYSTRCONTENT or # no effect on GC struct/array opnum == rop.COPYUNICODECONTENT or # no effect on GC struct/array opnum == rop.CHECK_MEMORY_ERROR): # may only abort the whole loop return if rop.is_call(op.opnum): if rop.is_call_assembler(op.getopnum()): self._seen_guard_not_invalidated = False else: effectinfo = op.getdescr().get_extra_info() if effectinfo.check_can_invalidate(): self._seen_guard_not_invalidated = False if not effectinfo.has_random_effects(): self.force_from_effectinfo(effectinfo) return self.force_all_lazy_sets() self.clean_caches()
def emitting_operation(self, op): if rop.has_no_side_effect(op.opnum): return if rop.is_ovf(op.opnum): return if rop.is_guard(op.opnum): self.optimizer.pendingfields = ( self.force_lazy_sets_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially opnum == rop.SETFIELD_RAW or # no effect on GC struct/array opnum == rop.SETARRAYITEM_GC or # handled specially opnum == rop.SETARRAYITEM_RAW or # no effect on GC struct opnum == rop.SETINTERIORFIELD_RAW or # no effect on GC struct opnum == rop.RAW_STORE or # no effect on GC struct opnum == rop.STRSETITEM or # no effect on GC struct/array opnum == rop.UNICODESETITEM or # no effect on GC struct/array opnum == rop.DEBUG_MERGE_POINT or # no effect whatsoever opnum == rop.JIT_DEBUG or # no effect whatsoever opnum == rop.ENTER_PORTAL_FRAME or # no effect whatsoever opnum == rop.LEAVE_PORTAL_FRAME or # no effect whatsoever opnum == rop.COPYSTRCONTENT or # no effect on GC struct/array opnum == rop.COPYUNICODECONTENT or # no effect on GC struct/array opnum == rop.CHECK_MEMORY_ERROR): # may only abort the whole loop return if rop.is_call(op.opnum): if rop.is_call_assembler(op.getopnum()): self._seen_guard_not_invalidated = False else: effectinfo = op.getdescr().get_extra_info() if effectinfo.check_can_invalidate(): self._seen_guard_not_invalidated = False if not effectinfo.has_random_effects(): self.force_from_effectinfo(effectinfo) return self.force_all_lazy_sets() self.clean_caches()