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 _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 produce_potential_short_preamble_ops(self, sb): ops = self.optimizer._newoperations for i, op in enumerate(ops): if rop.is_always_pure(op.opnum): sb.add_pure_op(op) if rop.is_ovf( op.opnum) and ops[i + 1].getopnum() == rop.GUARD_NO_OVERFLOW: sb.add_pure_op(op) for i in self.call_pure_positions: op = ops[i] # don't move call_pure_with_exception in the short preamble... # issue #2015 # Also, don't move cond_call_value in the short preamble. # The issue there is that it's usually pointless to try to # because the 'value' argument is typically not a loop # invariant, and would really need to be in order to end up # in the short preamble. Maybe the code works anyway in the # other rare case, but better safe than sorry and don't try. effectinfo = op.getdescr().get_extra_info() if not effectinfo.check_can_raise(ignore_memoryerror=True): assert rop.is_call(op.opnum) if not OpHelpers.is_cond_call_value(op.opnum): sb.add_pure_op(op)
def emit(self, op): self.emitting_operation(op) self.emit_postponed_op() opnum = op.opnum if (rop.is_comparison(opnum) or rop.is_call_may_force(opnum) or rop.is_ovf(opnum)): self.postponed_op = op else: return Optimization.emit(self, op)
def emit_operation(self, op): self.emitting_operation(op) self.emit_postponed_op() opnum = op.opnum if (rop.is_comparison(opnum) or rop.is_call_may_force(opnum) or rop.is_ovf(opnum)): self.postponed_op = op else: Optimization.emit_operation(self, op)
def could_merge_with_next_guard(self, op, i, operations): # return True in cases where the operation and the following guard # should likely remain together. Simplified version of # can_merge_with_next_guard() in llsupport/regalloc.py. if not rop.is_comparison(op.opnum): return rop.is_ovf(op.opnum) # int_xxx_ovf() / guard_no_overflow() if i + 1 >= len(operations): return False next_op = operations[i + 1] opnum = next_op.getopnum() if not (opnum == rop.GUARD_TRUE or opnum == rop.GUARD_FALSE or opnum == rop.COND_CALL): return False if next_op.getarg(0) is not op: return False self.remove_tested_failarg(next_op) return True
def produce_potential_short_preamble_ops(self, sb): ops = self.optimizer._newoperations for i, op in enumerate(ops): if rop.is_always_pure(op.opnum): sb.add_pure_op(op) if rop.is_ovf( op.opnum) and ops[i + 1].getopnum() == rop.GUARD_NO_OVERFLOW: sb.add_pure_op(op) for i in self.call_pure_positions: op = ops[i] # don't move call_pure_with_exception in the short preamble... # issue #2015 effectinfo = op.getdescr().get_extra_info() if not effectinfo.check_can_raise(ignore_memoryerror=True): assert rop.is_call(op.opnum) sb.add_pure_op(op)
def optimize_default(self, op): canfold = rop.is_always_pure(op.opnum) if rop.is_ovf(op.opnum): self.postponed_op = op return if self.postponed_op: nextop = op op = self.postponed_op self.postponed_op = None canfold = nextop.getopnum() == rop.GUARD_NO_OVERFLOW else: nextop = None save = False if canfold: for i in range(op.numargs()): if self.get_constant_box(op.getarg(i)) is None: break else: # all constant arguments: constant-fold away resbox = self.optimizer.constant_fold(op) # note that INT_xxx_OVF is not done from here, and the # overflows in the INT_xxx operations are ignored self.optimizer.make_constant(op, resbox) return # did we do the exact same operation already? recentops = self.getrecentops(op.getopnum()) save = True oldop = recentops.lookup(self.optimizer, op) if oldop is not None: self.optimizer.make_equal_to(op, oldop) return # otherwise, the operation remains self.emit_operation(op) if rop.returns_bool_result(op.opnum): self.getintbound(op).make_bool() if save: recentops = self.getrecentops(op.getopnum()) recentops.add(op) if nextop: self.emit_operation(nextop)
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()
def produce_potential_short_preamble_ops(self, sb): ops = self.optimizer._newoperations for i, op in enumerate(ops): if rop.is_always_pure(op.opnum): sb.add_pure_op(op) if rop.is_ovf(op.opnum) and ops[i + 1].getopnum() == rop.GUARD_NO_OVERFLOW: sb.add_pure_op(op) for i in self.call_pure_positions: op = ops[i] # don't move call_pure_with_exception in the short preamble... # issue #2015 # Also, don't move cond_call_value in the short preamble. # The issue there is that it's usually pointless to try to # because the 'value' argument is typically not a loop # invariant, and would really need to be in order to end up # in the short preamble. Maybe the code works anyway in the # other rare case, but better safe than sorry and don't try. effectinfo = op.getdescr().get_extra_info() if not effectinfo.check_can_raise(ignore_memoryerror=True): assert rop.is_call(op.opnum) if not OpHelpers.is_cond_call_value(op.opnum): sb.add_pure_op(op)
def optimize_default(self, op): canfold = rop.is_always_pure(op.opnum) if rop.is_ovf(op.opnum): self.postponed_op = op return if self.postponed_op: nextop = op op = self.postponed_op self.postponed_op = None canfold = nextop.getopnum() == rop.GUARD_NO_OVERFLOW else: nextop = None save = False if canfold: for i in range(op.numargs()): if self.get_constant_box(op.getarg(i)) is None: break else: # all constant arguments: constant-fold away resbox = self.optimizer.constant_fold(op) # note that INT_xxx_OVF is not done from here, and the # overflows in the INT_xxx operations are ignored self.optimizer.make_constant(op, resbox) return # did we do the exact same operation already? recentops = self.getrecentops(op.getopnum()) save = True oldop = recentops.lookup(self.optimizer, op) if oldop is not None: self.optimizer.make_equal_to(op, oldop) return # otherwise, the operation remains return self.emit_result(DefaultOptimizationResult(self, op, save, nextop))
def is_comparison_or_ovf_op(opnum): return rop.is_comparison(opnum) or rop.is_ovf(opnum)