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 user_loop_bail_fast_path(loop, warmstate): """ In a fast path over the trace loop: try to prevent vecopt of spending time on a loop that will most probably fail. """ resop_count = 0 # the count of operations minus debug_merge_points vector_instr = 0 guard_count = 0 at_least_one_array_access = True for i,op in enumerate(loop.operations): if rop.is_jit_debug(op.opnum): continue if op.vector >= 0 and not rop.is_guard(op.opnum): vector_instr += 1 resop_count += 1 if op.is_primitive_array_access(): at_least_one_array_access = True if rop.is_call(op.opnum) or rop.is_call_assembler(op.opnum): return True if rop.is_guard(op.opnum): guard_count += 1 if not at_least_one_array_access: return True return False
def fake_allocate(self, loop): from rpython.jit.backend.x86.jump import remap_frame_layout def emit(*args): self.assembler.emitted.append(args) for i, op in enumerate(loop.operations): self.rm.position = i opnum = op.getopnum() opname = op.getopname() if rop.is_comparison(opnum): locs = [self.loc(x) for x in op.getarglist()] loc = self.force_allocate_reg_or_cc(op) emit(opname, loc, locs) elif opname.startswith("int_"): locs = [self.loc(x) for x in op.getarglist()] loc = self.rm.force_result_in_reg( op, op.getarg(0), op.getarglist()) emit(opname, loc, locs[1:]) elif op.is_guard(): fail_locs = [self.loc(x) for x in op.getfailargs()] emit(opname, self.loc(op.getarg(0)), fail_locs) elif rop.is_call(opnum): # calling convention! src_locs = [self.loc(x) for x in op.getarglist()[1:]] self.rm.before_call() loc = self.rm.after_call(op) dst_locs = [r1, r2, r3][:len(src_locs)] remap_frame_layout(self.assembler, src_locs, dst_locs, r8) emit(opname, loc, dst_locs) elif opname == "label": descr = op.getdescr() locs = [self.loc(x) for x in op.getarglist()] emit(opname, locs) descr._fake_arglocs = locs lastop = loop.operations[-1] if lastop.getopname() == "jump" and lastop.getdescr() is descr: # now we know the places, add hints for i, r in enumerate(locs): if isinstance(r, FakeReg): self.longevity.fixed_register( len(loop.operations) - 1, r, lastop.getarg(i)) elif opname == "jump": src_locs = [self.loc(x) for x in op.getarglist()] dst_locs = op.getdescr()._fake_arglocs remap_frame_layout(self.assembler, src_locs, dst_locs, r8) emit("jump", dst_locs) else: locs = [self.loc(x) for x in op.getarglist()] if op.type != "v": loc = self.rm.force_allocate_reg(op) emit(opname, loc, locs) else: emit(opname, locs) self.possibly_free_vars_for_op(op) return self.assembler.emitted
def add_op_to_short(self, sb): op = self.res arglist = [] for arg in op.getarglist(): newarg = sb.produce_arg(arg) if newarg is None: return None arglist.append(newarg) if rop.is_call(op.opnum): opnum = OpHelpers.call_pure_for_descr(op.getdescr()) else: opnum = op.getopnum() return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist))
def produce_op(self, opt, preamble_op, exported_infos, invented_name): optpure = opt.optimizer.optpure if optpure is None: return if invented_name: op = self.orig_op.copy_and_change(self.orig_op.getopnum()) op.set_forwarded(self.res) else: op = self.res if rop.is_call(preamble_op.opnum): optpure.extra_call_pure.append( PreambleOp(op, preamble_op, invented_name)) else: opt.pure(op.getopnum(), PreambleOp(op, preamble_op, invented_name))
def _add_fixed_registers(self): for i, op in enumerate(self.operations): opnum = op.getopnum() opname = op.getopname() args = op.getarglist() if rop.is_call(opnum): # calling convention! arglist = op.getarglist()[1:] for arg, reg in zip(arglist + [None] * (3 - len(arglist)), [r1, r2, r3]): self.longevity.fixed_register(i, reg, arg) self.longevity.fixed_register(i, r0, op) elif opname.startswith("int_"): if not args[0].is_constant(): self.longevity.try_use_same_register(args[0], op)
def produce_op(self, opt, preamble_op, exported_infos, invented_name): optpure = opt.optimizer.optpure if optpure is None: return if invented_name: op = self.orig_op.copy_and_change(self.orig_op.getopnum()) op.set_forwarded(self.res) else: op = self.res if rop.is_call(preamble_op.opnum): optpure.extra_call_pure.append(PreambleOp(op, preamble_op, invented_name)) else: opt.pure(op.getopnum(), PreambleOp(op, preamble_op, invented_name))
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 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)