def optimize_INT_ADD(self, op): arg1 = get_box_replacement(op.getarg(0)) arg2 = get_box_replacement(op.getarg(1)) if self.is_raw_ptr(arg1) or self.is_raw_ptr(arg2): return self.emit(op) v1 = self.getintbound(arg1) v2 = self.getintbound(arg2) # Optimize for addition chains in code "b = a + 1; c = b + 1" by # detecting the int_add chain, and swapping with "b = a + 1; # c = a + 2". If b is not used elsewhere, the backend eliminates # it. # either v1 or v2 can be a constant, swap the arguments around if # v1 is the constant if v1.is_constant(): arg1, arg2 = arg2, arg1 v1, v2 = v2, v1 # if both are constant, the pure optimization will deal with it if v2.is_constant() and not v1.is_constant(): arg1 = self.optimizer.as_operation(arg1) if arg1 is not None: if arg1.getopnum() == rop.INT_ADD: prod_arg1 = get_box_replacement(arg1.getarg(0)) prod_arg2 = get_box_replacement(arg1.getarg(1)) prod_v1 = self.getintbound(prod_arg1) prod_v2 = self.getintbound(prod_arg2) # same thing here: prod_v1 or prod_v2 can be a # constant if prod_v1.is_constant(): prod_arg1, prod_arg2 = prod_arg2, prod_arg1 prod_v1, prod_v2 = prod_v2, prod_v1 if prod_v2.is_constant(): sum = intmask(arg2.getint() + prod_arg2.getint()) arg1 = prod_arg1 arg2 = ConstInt(sum) op = self.replace_op_with(op, rop.INT_ADD, args=[arg1, arg2]) return self.emit(op)
def make_guards(self, op, short, optimizer): if self._known_class is not None: if not optimizer.cpu.remove_gctypeptr: short.append(ResOperation(rop.GUARD_NONNULL, [op])) short.append(ResOperation(rop.GUARD_IS_OBJECT, [op])) short.append( ResOperation(rop.GUARD_CLASS, [op, self._known_class])) else: short.append( ResOperation(rop.GUARD_NONNULL_CLASS, [op, self._known_class])) elif self.descr is not None: short.append(ResOperation(rop.GUARD_NONNULL, [op])) if not optimizer.cpu.remove_gctypeptr: short.append(ResOperation(rop.GUARD_IS_OBJECT, [op])) short.append( ResOperation(rop.GUARD_SUBCLASS, [op, ConstInt(self.descr.get_vtable())])) else: AbstractStructPtrInfo.make_guards(self, op, short, optimizer)
def _rewrite_changeable_constptrs(self, op, ops_with_movable_const_ptr, moving_obj_tracker): newops = [] for arg_i in ops_with_movable_const_ptr[op]: v = op.getarg(arg_i) # assert to make sure we got what we expected assert isinstance(v, ConstPtr) result_ptr = BoxPtr() array_index = moving_obj_tracker.get_array_index(v) load_op = ResOperation(rop.GETARRAYITEM_GC, [ moving_obj_tracker.const_ptr_gcref_array, ConstInt(array_index) ], result_ptr, descr=moving_obj_tracker.ptr_array_descr) newops.append(load_op) op.setarg(arg_i, result_ptr) # newops.append(op) return newops
def force_box(self, op, optforce=None): op = get_box_replacement(op) if optforce is None: #import pdb; pdb.set_trace() optforce = self info = op.get_forwarded() if self.optunroll and self.optunroll.potential_extra_ops: # XXX hack try: preamble_op = self.optunroll.potential_extra_ops.pop(op) except KeyError: pass else: sb = self.optunroll.short_preamble_producer sb.add_preamble_op(preamble_op) if info is not None: if op.type == 'i' and info.is_constant(): return ConstInt(info.getint()) return info.force_box(op, optforce) return op
def _optimize_CALL_INT_PY_MOD(self, op): arg1 = op.getarg(1) b1 = self.getintbound(arg1) arg2 = op.getarg(2) b2 = self.getintbound(arg2) if b1.is_constant() and b1.getint() == 0: self.make_constant_int(op, 0) self.last_emitted_operation = REMOVED return True # This is Python's integer division: 'x // (2**shift)' can always # be replaced with 'x >> shift', even for negative values of x if not b2.is_constant(): return False val = b2.getint() if val <= 0: return False if val == 1: self.make_constant_int(op, 0) self.last_emitted_operation = REMOVED return True elif val & (val - 1) == 0: # val == 2**shift from rpython.jit.metainterp.history import DONT_CHANGE # x % power-of-two ==> x & (power-of-two - 1) # with Python's modulo, this is valid even if 'x' is negative. op = self.replace_op_with( op, rop.INT_AND, args=[arg1, ConstInt(val - 1)], descr=DONT_CHANGE) # <- xxx rename? means "kill" self.optimizer.send_extra_operation(op) return True else: from rpython.jit.metainterp.optimizeopt import intdiv known_nonneg = b1.known_ge(IntBound(0, 0)) operations = intdiv.modulo_operations(arg1, val, known_nonneg) newop = None for newop in operations: self.optimizer.send_extra_operation(newop) self.make_equal_to(op, newop) return True
def test_call_aligned_with_imm_values(self): cpu = self.cpu if not cpu.supports_floats: py.test.skip('requires floats') def func(*args): return float(sum(args)) F = lltype.Float I = lltype.Signed floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] ints = [7, 11, 23, 13, -42, 1111, 95, 1] for case in range(256): result = 0.0 args = [] argslist = [] local_floats = list(floats) local_ints = list(ints) for i in range(8): if case & (1 << i): args.append(F) arg = local_floats.pop() result += arg argslist.append(constfloat(arg)) else: args.append(I) arg = local_ints.pop() result += arg argslist.append(ConstInt(arg)) FUNC = self.FuncType(args, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) res = longlong.getrealfloat(res) assert abs(res - result) < 0.0001
def make_varray(self, arraydescr, size, source_op, clear=False): if not info.reasonable_array_index(size): return False if arraydescr.is_array_of_structs(): assert clear opinfo = info.ArrayStructInfo(arraydescr, size, is_virtual=True) else: const = self.optimizer.new_const_item(arraydescr) opinfo = info.ArrayPtrInfo(arraydescr, const, size, clear, is_virtual=True) # Replace 'source_op' with a version in which the length is # given as directly a Const, without relying on forwarding. # See test_virtual_array_length_discovered_constant_2. newop = self.replace_op_with(source_op, source_op.getopnum(), args=[ConstInt(size)]) newop.set_forwarded(opinfo) return True
def gen_malloc_frame(self, frame_info): descrs = self.gc_ll_descr.getframedescrs(self.cpu) if self.gc_ll_descr.kind == 'boehm': ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_depth) if sign: size = -size args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)] size = ResOperation(rop.GC_LOAD_I, args) self.emit_op(size) frame = ResOperation(rop.NEW_ARRAY, [size], descr=descrs.arraydescr) self.handle_new_array(descrs.arraydescr, frame) return self.get_box_replacement(frame) else: # we read size in bytes here, not the length ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_size) if sign: size = -size args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)] size = ResOperation(rop.GC_LOAD_I, args) self.emit_op(size) frame = self.gen_malloc_nursery_varsize_frame(size) self.gen_initialize_tid(frame, descrs.arraydescr.tid) # we need to explicitely zero all the gc fields, because # of the unusal malloc pattern length = self.emit_getfield(ConstInt(frame_info), descr=descrs.jfi_frame_depth, raw=True) self.emit_setfield(frame, self.c_zero, descr=descrs.jf_extra_stack_depth) self.emit_setfield(frame, self.c_null, descr=descrs.jf_savedata) self.emit_setfield(frame, self.c_null, descr=descrs.jf_force_descr) self.emit_setfield(frame, self.c_null, descr=descrs.jf_descr) self.emit_setfield(frame, self.c_null, descr=descrs.jf_guard_exc) self.emit_setfield(frame, self.c_null, descr=descrs.jf_forward) self.gen_initialize_len(frame, length, descrs.arraydescr.lendescr) return self.get_box_replacement(frame)
def test_bug_rshift(): v1 = BoxInt() v2 = BoxInt() v3 = BoxInt() v4 = BoxInt() inputargs = [v1] operations = [ ResOperation(rop.INT_ADD, [v1, v1], v2), ResOperation(rop.INT_INVERT, [v2], v3), ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(1)), ] operations[-2].setfailargs([v4, v3]) cpu = CPU(None, None) cpu.setup_once() looptoken = JitCellToken() cpu.compile_loop(inputargs, operations, looptoken) deadframe = cpu.execute_token(looptoken, 9) assert cpu.get_int_value(deadframe, 0) == (9 >> 3) assert cpu.get_int_value(deadframe, 1) == (~18)
def optimize_INT_FLOORDIV(self, op): arg0 = op.getarg(0) b1 = self.getintbound(arg0) arg1 = op.getarg(1) b2 = self.getintbound(arg1) if b2.is_constant() and b2.getint() == 1: self.make_equal_to(op, arg0) return elif b1.is_constant() and b1.getint() == 0: self.make_constant_int(op, 0) return if b1.known_ge(IntBound(0, 0)) and b2.is_constant(): val = b2.getint() if val & (val - 1) == 0 and val > 0: # val == 2**shift op = self.replace_op_with( op, rop.INT_RSHIFT, args=[op.getarg(0), ConstInt(highest_bit(val))]) self.emit_operation(op)
def test_int_add(self): # random seed: 1202 # block length: 4 # AssertionError: Got 1431655764, expected 357913940 for value #3 faildescr1 = BasicFailDescr(1) faildescr2 = BasicFailDescr(2) v1 = BoxInt() v2 = BoxInt() v3 = BoxInt() v4 = BoxInt() v5 = BoxInt() v6 = BoxInt() v7 = BoxInt() v8 = BoxInt() v9 = BoxInt() v10 = BoxInt() v11 = BoxInt() tmp12 = BoxInt() cpu = CPU(None, None) cpu.setup_once() inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] operations = [ ResOperation(rop.INT_ADD, [ConstInt(-1073741825), v3], v11), ResOperation(rop.INT_IS_TRUE, [v1], tmp12), ResOperation(rop.GUARD_FALSE, [tmp12], None, descr=faildescr1), ResOperation(rop.GUARD_FALSE, [v1], None, descr=faildescr2), ] operations[2].setfailargs([v10, v3, v6, v11, v9, v2]) operations[-1].setfailargs([v8, v2, v10, v6, v7, v9, v5, v4]) looptoken = JitCellToken() cpu.compile_loop(inputargs, operations, looptoken) args = [3 , -5 , 1431655765 , 47 , 12 , 1789569706 , 15 , 939524096 , 16 , -43] deadframe = cpu.execute_token(looptoken, *args) assert cpu.get_latest_descr(deadframe).identifier == 1 assert cpu.get_int_value(deadframe, 0) == -43 assert cpu.get_int_value(deadframe, 1) == 1431655765 assert cpu.get_int_value(deadframe, 2) == 1789569706 assert cpu.get_int_value(deadframe, 3) == 357913940 assert cpu.get_int_value(deadframe, 4) == 16 assert cpu.get_int_value(deadframe, 5) == -5
def handle_malloc_operation(self, op): opnum = op.getopnum() if opnum == rop.NEW: self.handle_new_fixedsize(op.getdescr(), op) elif opnum == rop.NEW_WITH_VTABLE: descr = op.getdescr() self.handle_new_fixedsize(descr, op) if self.gc_ll_descr.fielddescr_vtable is not None: self.emit_setfield(op, ConstInt(descr.get_vtable()), descr=self.gc_ll_descr.fielddescr_vtable) elif opnum == rop.NEW_ARRAY or opnum == rop.NEW_ARRAY_CLEAR: descr = op.getdescr() assert isinstance(descr, ArrayDescr) self.handle_new_array(descr, op) elif opnum == rop.NEWSTR: self.handle_new_array(self.gc_ll_descr.str_descr, op, kind=FLAG_STR) elif opnum == rop.NEWUNICODE: self.handle_new_array(self.gc_ll_descr.unicode_descr, op, kind=FLAG_UNICODE) else: raise NotImplementedError(op.getopname())
def remove_tested_failarg(self, op): opnum = op.getopnum() if not (opnum == rop.GUARD_TRUE or opnum == rop.GUARD_FALSE): return if op.getarg(0).is_vector(): return try: i = op.getfailargs().index(op.getarg(0)) except ValueError: return # The checked value is also in the failargs. The front-end # tries not to produce it, but doesn't always succeed (and # it's hard to test all cases). Rewrite it away. value = int(opnum == rop.GUARD_FALSE) op1 = ResOperation(rop.SAME_AS_I, [ConstInt(value)]) self.emit_op(op1) lst = op.getfailargs()[:] lst[i] = op1 newop = op.copy_and_change(opnum) newop.setfailargs(lst) self._changed_op = op self._changed_op_to = newop
def test_execute_nonspec(): cpu = FakeCPU() descr = FakeDescr() # cases with a descr # arity == -1 argboxes = [InputArgInt(321), ConstInt(123)] box = _execute_arglist(cpu, FakeMetaInterp(), rop.CALL_F, argboxes, FakeCallDescr()) assert longlong.getrealfloat(box) == 42.5 # arity == 0 box = _execute_arglist(cpu, None, rop.NEW, [], descr) assert box.fakeargs == ('new', descr) # arity == 1 box1 = InputArgRef() box = _execute_arglist(cpu, None, rop.ARRAYLEN_GC, [box1], descr) assert box == 55 # arity == 2 box2 = boxfloat(222.2) fielddescr = FakeFieldDescr() _execute_arglist(cpu, None, rop.SETFIELD_GC, [box1, box2], fielddescr) assert cpu.fakesetfield == (box1.getref_base(), box2.getfloatstorage(), fielddescr) # arity == 3 box3 = InputArgInt(33) arraydescr = FakeArrayDescr() _execute_arglist(cpu, None, rop.SETARRAYITEM_GC, [box1, box3, box2], arraydescr) assert cpu.fakesetarrayitem == (box1.getref_base(), box3.getint(), box2.getfloatstorage(), arraydescr) # cases without descr # arity == 1 box = _execute_arglist(cpu, None, rop.INT_INVERT, [box3]) assert box == ~33 # arity == 2 box = _execute_arglist(cpu, None, rop.INT_LSHIFT, [box3, InputArgInt(3)]) assert box == 33 << 3 # arity == 3 _execute_arglist(cpu, None, rop.STRSETITEM, [box1, InputArgInt(3), box3]) assert cpu.fakestrsetitem == (box1.getref_base(), 3, box3.getint())
def test_execute_nonspec(): cpu = FakeCPU() descr = FakeDescr() # cases with a descr # arity == -1 argboxes = [BoxInt(321), ConstInt(123)] box = execute_nonspec(cpu, FakeMetaInterp(), rop.CALL, argboxes, FakeCallDescr()) assert box.getfloat() == 42.5 # arity == 0 box = execute_nonspec(cpu, None, rop.NEW, [], descr) assert box.value.fakeargs == ('new', descr) # arity == 1 box1 = BoxPtr() box = execute_nonspec(cpu, None, rop.ARRAYLEN_GC, [box1], descr) assert box.value == 55 # arity == 2 box2 = boxfloat(222.2) fielddescr = FakeFieldDescr() execute_nonspec(cpu, None, rop.SETFIELD_GC, [box1, box2], fielddescr) assert cpu.fakesetfield == (box1.value, box2.value, fielddescr) # arity == 3 box3 = BoxInt(33) arraydescr = FakeArrayDescr() execute_nonspec(cpu, None, rop.SETARRAYITEM_GC, [box1, box3, box2], arraydescr) assert cpu.fakesetarrayitem == (box1.value, box3.value, box2.value, arraydescr) # cases without descr # arity == 1 box = execute_nonspec(cpu, None, rop.INT_INVERT, [box3]) assert box.value == ~33 # arity == 2 box = execute_nonspec(cpu, None, rop.INT_LSHIFT, [box3, BoxInt(3)]) assert box.value == 33 << 3 # arity == 3 execute_nonspec(cpu, None, rop.STRSETITEM, [box1, BoxInt(3), box3]) assert cpu.fakestrsetitem == (box1.value, 3, box3.value)
def test_simple_read(): #b1, b2, b3 = [BoxInt(), InputArgRef(), BoxInt()] c1, c2, c3 = [ConstInt(111), ConstInt(222), ConstInt(333)] storage = Storage() storage.rd_consts = [c1, c2, c3] numb = Numbering( [ 3, tag(0, TAGBOX), tagconst(0), NULLREF, tag(0, TAGBOX), tag(1, TAGBOX) ] + [tagconst(1), tagconst(2)] + [tag(0, TAGBOX), tag(1, TAGBOX), tag(2, TAGBOX)]) storage.rd_numb = numb # cpu = MyCPU([42, gcref1, -66]) metainterp = MyMetaInterp(cpu) reader = ResumeDataDirectReader(metainterp, storage, "deadframe") _next_section(reader, 42, 111, gcrefnull, 42, gcref1) _next_section(reader, 222, 333) _next_section(reader, 42, gcref1, -66) # reader = ResumeDataBoxReader(storage, "deadframe", metainterp) bi, br, bf = [None] * 3, [None] * 2, [None] * 0 bh = MyBlackholeInterp([ lltype.Signed, lltype.Signed, llmemory.GCREF, lltype.Signed, llmemory.GCREF ]) bh.fake_consume_boxes(reader, bi, br, bf) b1s = reader.liveboxes[0] b2s = reader.liveboxes[1] assert_same(bi, [b1s, ConstInt(111), b1s]) assert_same(br, [ConstPtr(gcrefnull), b2s]) bi, br, bf = [None] * 2, [None] * 0, [None] * 0 bh = MyBlackholeInterp([lltype.Signed, lltype.Signed]) bh.fake_consume_boxes(reader, bi, br, bf) assert_same(bi, [ConstInt(222), ConstInt(333)]) bi, br, bf = [None] * 2, [None] * 1, [None] * 0 bh = MyBlackholeInterp([lltype.Signed, llmemory.GCREF, lltype.Signed]) bh.fake_consume_boxes(reader, bi, br, bf) b3s = reader.liveboxes[2] assert_same(bi, [b1s, b3s]) assert_same(br, [b2s])
def optimize_INT_MUL(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) # If one side of the op is 1 the result is the other side. if v1.is_constant() and v1.box.getint() == 1: self.make_equal_to(op.result, v2) elif v2.is_constant() and v2.box.getint() == 1: self.make_equal_to(op.result, v1) elif (v1.is_constant() and v1.box.getint() == 0) or \ (v2.is_constant() and v2.box.getint() == 0): self.make_constant_int(op.result, 0) else: for lhs, rhs in [(v1, v2), (v2, v1)]: if lhs.is_constant(): x = lhs.box.getint() # x & (x - 1) == 0 is a quick test for power of 2 if x & (x - 1) == 0: new_rhs = ConstInt(highest_bit(lhs.box.getint())) op = op.copy_and_change(rop.INT_LSHIFT, args=[rhs.box, new_rhs]) break self.emit_operation(op)
def patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable): # XXX merge with rewriting vinfo = jitdriver_sd.virtualizable_info extra_ops = [] inputargs = loop.inputargs vable_box = inputargs[jitdriver_sd.index_of_virtualizable] i = jitdriver_sd.num_red_args loop.inputargs = inputargs[:i] for descr in vinfo.static_field_descrs: assert i < len(inputargs) box = inputargs[i] opnum = OpHelpers.getfield_for_descr(descr) emit_op(extra_ops, ResOperation(opnum, [vable_box], descr=descr)) box.set_forwarded(extra_ops[-1]) i += 1 arrayindex = 0 for descr in vinfo.array_field_descrs: arraylen = vinfo.get_array_length(vable, arrayindex) arrayop = ResOperation(rop.GETFIELD_GC_R, [vable_box], descr=descr) emit_op(extra_ops, arrayop) arraydescr = vinfo.array_descrs[arrayindex] assert i + arraylen <= len(inputargs) for index in range(arraylen): opnum = OpHelpers.getarrayitem_for_descr(arraydescr) box = inputargs[i] emit_op(extra_ops, ResOperation(opnum, [arrayop, ConstInt(index)], descr=arraydescr)) i += 1 box.set_forwarded(extra_ops[-1]) arrayindex += 1 assert i == len(inputargs) for op in loop.operations: emit_op(extra_ops, op) loop.operations = extra_ops
def _optimize_CALL_INT_PY_DIV(self, op): arg1 = op.getarg(1) b1 = self.getintbound(arg1) arg2 = op.getarg(2) b2 = self.getintbound(arg2) if b1.equal(0): self.make_constant_int(op, 0) self.last_emitted_operation = REMOVED return True if not b2.is_constant(): return False val = b2.getint() if val <= 0: return False if val == 1: self.make_equal_to(op, arg1) self.last_emitted_operation = REMOVED return True elif val & (val - 1) == 0: # val == 2**shift from rpython.jit.metainterp.history import DONT_CHANGE op = self.replace_op_with( op, rop.INT_RSHIFT, args=[arg1, ConstInt(highest_bit(val))], descr=DONT_CHANGE) # <- xxx rename? means "kill" self.optimizer.send_extra_operation(op) return True else: from rpython.jit.metainterp.optimizeopt import intdiv known_nonneg = b1.known_nonnegative() operations = intdiv.division_operations(arg1, val, known_nonneg) newop = None for newop in operations: self.optimizer.send_extra_operation(newop) self.make_equal_to(op, newop) return True
def optimize_INT_MUL(self, op): arg1 = get_box_replacement(op.getarg(0)) b1 = self.getintbound(arg1) arg2 = get_box_replacement(op.getarg(1)) b2 = self.getintbound(arg2) # If one side of the op is 1 the result is the other side. if b1.equal(1): self.make_equal_to(op, arg2) elif b2.equal(1): self.make_equal_to(op, arg1) elif b1.equal(0) or b2.equal(0): self.make_constant_int(op, 0) else: for lhs, rhs in [(arg1, arg2), (arg2, arg1)]: lh_info = self.getintbound(lhs) if lh_info.is_constant(): x = lh_info.getint() # x & (x - 1) == 0 is a quick test for power of 2 if x & (x - 1) == 0: new_rhs = ConstInt(highest_bit(lh_info.getint())) op = self.replace_op_with(op, rop.INT_LSHIFT, args=[rhs, new_rhs]) break return self.emit(op)
def _really_force(self, optforce): assert self.source_op is not None if not we_are_translated(): self.source_op.name = 'FORCE ' + self.source_op.name # XXX two possible optimizations: # * if source_op is NEW_ARRAY_CLEAR, emit NEW_ARRAY if it's # immediately followed by SETARRAYITEM_GC into all items (hard?) # * if source_op is NEW_ARRAY, emit NEW_ARRAY_CLEAR if it's # followed by setting most items to zero anyway optforce.emit_operation(self.source_op) self.box = box = self.source_op.result for index in range(len(self._items)): subvalue = self._items[index] if subvalue is None: continue if self.clear: if subvalue is self.constvalue or subvalue.is_null(): continue subbox = subvalue.force_box(optforce) op = ResOperation(rop.SETARRAYITEM_GC, [box, ConstInt(index), subbox], None, descr=self.arraydescr) optforce.emit_operation(op)
def test_remove_consts_and_duplicates(): class FakeStaticData: cpu = None warmrunnerdesc = None def is_another_box_like(box, referencebox): assert box is not referencebox assert isinstance(box, referencebox.clonebox().__class__) assert box.value == referencebox.value return True metainterp = pyjitpl.MetaInterp(FakeStaticData(), None) metainterp.history = History() b1 = BoxInt(1) b2 = BoxInt(2) c3 = ConstInt(3) boxes = [b1, b2, b1, c3] dup = {} metainterp.remove_consts_and_duplicates(boxes, 4, dup) assert boxes[0] is b1 assert boxes[1] is b2 assert is_another_box_like(boxes[2], b1) assert is_another_box_like(boxes[3], c3) assert equaloplists(metainterp.history.operations, [ ResOperation(rop.SAME_AS, [b1], boxes[2]), ResOperation(rop.SAME_AS, [c3], boxes[3]), ]) assert dup == {b1: None, b2: None} # del metainterp.history.operations[:] b4 = BoxInt(4) boxes = [b2, b4, "something random"] metainterp.remove_consts_and_duplicates(boxes, 2, dup) assert is_another_box_like(boxes[0], b2) assert boxes[1] is b4 assert equaloplists(metainterp.history.operations, [ ResOperation(rop.SAME_AS, [b2], boxes[0]), ])
def test_make_jitdriver_callbacks_1(): class FakeWarmRunnerDesc: cpu = None memory_manager = None rtyper = None jitcounter = DeterministicJitCounter() class FakeJitDriverSD: jitdriver = None _green_args_spec = [lltype.Signed, lltype.Float] _get_printable_location_ptr = None _confirm_enter_jit_ptr = None _get_unique_id_ptr = None _can_never_inline_ptr = None _should_unroll_one_iteration_ptr = None red_args_types = [] class FakeCell: dont_trace_here = False state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD()) def jit_getter(build, *args): return FakeCell() state.jit_getter = jit_getter state.make_jitdriver_callbacks() res = state.get_location_str([ConstInt(5), constfloat(42.5)]) assert res == '(<unknown jitdriver>: no get_printable_location)'
def test_virtual_adder_memo_const_sharing(): b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**23), ConstInt(-65)] storage, t = make_storage(b1s, b2s, b3s) metainterp_sd = FakeMetaInterpStaticData() memo = ResumeDataLoopMemo(metainterp_sd) i = t.get_iter() modifier = ResumeDataVirtualAdder(FakeOptimizer(i), storage, storage, i, memo) modifier.finish() assert len(memo.consts) == 2 assert storage.rd_consts is memo.consts b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**24), ConstInt(-65)] storage2, t = make_storage(b1s, b2s, b3s) i = t.get_iter() modifier2 = ResumeDataVirtualAdder(FakeOptimizer(i), storage2, storage2, i, memo) modifier2.finish() assert len(memo.consts) == 3 assert storage2.rd_consts is memo.consts
def getstrlen(self, _, mode, lengthbox): if self._lengthbox is None: self._lengthbox = ConstInt(len(self._chars)) return self._lengthbox
def build_bridge(self): def exc_handling(guard_op): # operations need to start with correct GUARD_EXCEPTION if guard_op._exc_box is None: op = ResOperation(rop.GUARD_NO_EXCEPTION, []) else: op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box]) op.setdescr(self.builder.getfaildescr()) op.setfailargs([]) return op if self.dont_generate_more: return False r = self.r guard_op = self.guard_op fail_args = guard_op.getfailargs() fail_descr = guard_op.getdescr() op = self.should_fail_by if not op.getfailargs(): return False for _fail_box in fail_args: _fail_box.set_forwarded(None) # generate the branch: a sequence of operations that ends in a FINISH subloop = DummyLoop([]) self.subloops.append(subloop) # keep around for debugging if rop.is_guard_exception(guard_op.getopnum()): subloop.operations.append(exc_handling(guard_op)) bridge_builder = self.builder.fork(self.builder.cpu, subloop, op.getfailargs()[:]) self.generate_ops(bridge_builder, r, subloop, op.getfailargs()[:]) # note that 'self.guard_op' now points to the guard that will fail in # this new bridge, while 'guard_op' still points to the guard that # has just failed. if r.random() < 0.1 and self.guard_op is None: # Occasionally, instead of ending in a FINISH, we end in a jump # to another loop. We don't do it, however, if the new bridge's # execution will hit 'self.guard_op', but only if it executes # to the FINISH normally. (There is no point to the extra # complexity, as we might get the same effect by two calls # to build_bridge().) # First make up the other loop... # # New restriction: must have the same argument count and types # as the original loop subset = [] for box in self.loop.inputargs: srcbox = r.choice(fail_args) if srcbox.type != box.type: if box.type == INT: srcbox = ConstInt(r.random_integer()) elif box.type == FLOAT: srcbox = ConstFloat(r.random_float_storage()) else: raise AssertionError(box.type) subset.append(srcbox) # args = [] for x in subset: if x.type == INT: args.append(InputArgInt(getint(x))) elif x.type == FLOAT: args.append(InputArgFloat(getfloatstorage(x))) else: assert 0, x.type rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) # done self.should_fail_by = rl.should_fail_by self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) # The new bridge's execution will end normally at its FINISH. # Just replace the FINISH with the JUMP to the new loop. jump_op = ResOperation(rop.JUMP, subset, descr=rl.loop._targettoken) subloop.operations[-1] = jump_op self.guard_op = rl.guard_op self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts self.loop._jitcelltoken.record_jump_to(rl.loop._jitcelltoken) self.dont_generate_more = True if r.random() < .05: return False dump(subloop) self.builder.cpu.compile_bridge(fail_descr, fail_args, subloop.operations, self.loop._jitcelltoken) if self.output: bridge_builder.print_loop(self.output, fail_descr, fail_args) return True
def produce_into(self, builder, r): if r.random() < 0.4: UnaryOperation.produce_into(self, builder, r) else: self.put(builder, [ConstInt(r.random_integer())])
def prepare_op_guard_no_exception(self, op, fcond): loc = self.make_sure_var_in_reg(ConstInt(self.cpu.pos_exception())) arglocs = self._prepare_guard(op, [loc]) return arglocs
def produce_into(self, builder, r): v, offset = self.field_descr(builder, r) builder.do(self.opnum, [v, ConstInt(offset)], None)
def ConstAddr(addr, cpu): return ConstInt(heaptracker.adr2int(addr))