def test_ops_offset(self): from pypy.rlib import debug i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() looptoken = JitCellToken() targettoken = TargetToken() operations = [ ResOperation(rop.LABEL, [i0], None, descr=targettoken), ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.JUMP, [i1], None, descr=targettoken), ] inputargs = [i0] debug._log = dlog = debug.DebugLog() info = self.cpu.compile_loop(inputargs, operations, looptoken) ops_offset = info.ops_offset debug._log = None # assert ops_offset is looptoken._x86_ops_offset # 2*(getfield_raw/int_add/setfield_raw) + ops + None assert len(ops_offset) == 2*3 + len(operations) + 1 assert (ops_offset[operations[0]] <= ops_offset[operations[1]] <= ops_offset[operations[2]] <= ops_offset[None])
def test_debugger_on(self): from pypy.tool.logparser import parse_log_file, extract_category from pypy.rlib import debug targettoken, preambletoken = TargetToken(), TargetToken() loop = """ [i0] label(i0, descr=preambletoken) debug_merge_point('xyz', 0, 0) i1 = int_add(i0, 1) i2 = int_ge(i1, 10) guard_false(i2) [] label(i1, descr=targettoken) debug_merge_point('xyz', 0, 0) i11 = int_add(i1, 1) i12 = int_ge(i11, 10) guard_false(i12) [] jump(i11, descr=targettoken) """ ops = parse(loop, namespace={ 'targettoken': targettoken, 'preambletoken': preambletoken }) debug._log = dlog = debug.DebugLog() try: self.cpu.assembler.set_debug(True) looptoken = JitCellToken() self.cpu.compile_loop(ops.inputargs, ops.operations, looptoken) self.cpu.execute_token(looptoken, 0) # check debugging info struct = self.cpu.assembler.loop_run_counters[0] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[1] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[2] assert struct.i == 9 self.cpu.finish_once() finally: debug._log = None l0 = ('debug_print', 'entry -1:1') l1 = ('debug_print', preambletoken.repr_of_descr() + ':1') l2 = ('debug_print', targettoken.repr_of_descr() + ':9') assert ('jit-backend-counts', [l0, l1, l2]) in dlog
def test_debugger_on(self): from pypy.tool.logparser import parse_log_file, extract_category from pypy.rlib import debug targettoken, preambletoken = TargetToken(), TargetToken() loop = """ [i0] label(i0, descr=preambletoken) debug_merge_point('xyz', 0) i1 = int_add(i0, 1) i2 = int_ge(i1, 10) guard_false(i2) [] label(i1, descr=targettoken) debug_merge_point('xyz', 0) i11 = int_add(i1, 1) i12 = int_ge(i11, 10) guard_false(i12) [] jump(i11, descr=targettoken) """ ops = parse(loop, namespace={'targettoken': targettoken, 'preambletoken': preambletoken}) debug._log = dlog = debug.DebugLog() try: self.cpu.assembler.set_debug(True) looptoken = JitCellToken() self.cpu.compile_loop(ops.inputargs, ops.operations, looptoken) self.cpu.execute_token(looptoken, 0) # check debugging info struct = self.cpu.assembler.loop_run_counters[0] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[1] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[2] assert struct.i == 9 self.cpu.finish_once() finally: debug._log = None l0 = ('debug_print', 'entry -1:1') l1 = ('debug_print', preambletoken.repr_of_descr() + ':1') l2 = ('debug_print', targettoken.repr_of_descr() + ':9') assert ('jit-backend-counts', [l0, l1, l2]) in dlog
def insert_label(self, loop, position, r): assert not hasattr(loop, '_targettoken') for i in range(position): op = loop.operations[i] if (not op.has_no_side_effect() or not isinstance(op.result, (BoxInt, BoxFloat))): position = i break # cannot move the LABEL later randompos = r.randrange(0, len(self.startvars) + 1) self.startvars.insert(randompos, op.result) loop._targettoken = TargetToken() loop.operations.insert( position, ResOperation(rop.LABEL, self.startvars, None, loop._targettoken))
def unroll_and_optimize(self, loop, call_pure_results=None): operations = loop.operations jumpop = operations[-1] assert jumpop.getopnum() == rop.JUMP inputargs = loop.inputargs jump_args = jumpop.getarglist()[:] operations = operations[:-1] cloned_operations = [op.clone() for op in operations] preamble = TreeLoop('preamble') preamble.inputargs = inputargs preamble.resume_at_jump_descr = FakeDescrWithSnapshot() token = JitCellToken() preamble.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(token))] + \ operations + \ [ResOperation(rop.LABEL, jump_args, None, descr=token)] self._do_optimize_loop(preamble, call_pure_results) assert preamble.operations[-1].getopnum() == rop.LABEL inliner = Inliner(inputargs, jump_args) loop.resume_at_jump_descr = preamble.resume_at_jump_descr loop.operations = [preamble.operations[-1]] + \ [inliner.inline_op(op, clone=False) for op in cloned_operations] + \ [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jump_args], None, descr=token)] #[inliner.inline_op(jumpop)] assert loop.operations[-1].getopnum() == rop.JUMP assert loop.operations[0].getopnum() == rop.LABEL loop.inputargs = loop.operations[0].getarglist() self._do_optimize_loop(loop, call_pure_results) extra_same_as = [] while loop.operations[0].getopnum() != rop.LABEL: extra_same_as.append(loop.operations[0]) del loop.operations[0] # Hack to prevent random order of same_as ops extra_same_as.sort( key=lambda op: str(preamble.operations).find(str(op.getarg(0)))) for op in extra_same_as: preamble.operations.insert(-1, op) return preamble
def test_debugger_checksum(self): loop = """ [i0] label(i0, descr=targettoken) debug_merge_point('xyz', 0) i1 = int_add(i0, 1) i2 = int_ge(i1, 10) guard_false(i2) [] jump(i1, descr=targettoken) """ ops = parse(loop, namespace={'targettoken': TargetToken()}) self.cpu.assembler.set_debug(True) looptoken = JitCellToken() self.cpu.compile_loop(ops.inputargs, ops.operations, looptoken) self.cpu.execute_token(looptoken, 0) assert looptoken._x86_debug_checksum == sum([op.getopnum() for op in ops.operations])
def propagate_all_forward(self): loop = self.optimizer.loop self.optimizer.clear_newoperations() start_label = loop.operations[0] if start_label.getopnum() == rop.LABEL: loop.operations = loop.operations[1:] # We need to emit the label op before import_state() as emitting it # will clear heap caches self.optimizer.send_extra_operation(start_label) else: start_label = None jumpop = loop.operations[-1] if jumpop.getopnum() == rop.JUMP or jumpop.getopnum() == rop.LABEL: loop.operations = loop.operations[:-1] else: jumpop = None self.import_state(start_label) self.optimizer.propagate_all_forward(clear=False) if not jumpop: return cell_token = jumpop.getdescr() assert isinstance(cell_token, JitCellToken) stop_label = ResOperation(rop.LABEL, jumpop.getarglist(), None, TargetToken(cell_token)) if jumpop.getopnum() == rop.JUMP: if self.jump_to_already_compiled_trace(jumpop): # Found a compiled trace to jump to if self.short: # Construct our short preamble assert start_label self.close_bridge(start_label) return if start_label and self.jump_to_start_label(start_label, stop_label): # Initial label matches, jump to it jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, descr=start_label.getdescr()) if self.short: # Construct our short preamble self.close_loop(start_label, jumpop) else: self.optimizer.send_extra_operation(jumpop) return if cell_token.target_tokens: limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit if cell_token.retraced_count < limit: cell_token.retraced_count += 1 debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit)) else: debug_print("Retrace count reached, jumping to preamble") assert cell_token.target_tokens[0].virtual_state is None jumpop.setdescr(cell_token.target_tokens[0]) self.optimizer.send_extra_operation(jumpop) return # Found nothing to jump to, emit a label instead if self.short: # Construct our short preamble assert start_label self.close_bridge(start_label) self.optimizer.flush() KillHugeIntBounds(self.optimizer).apply() loop.operations = self.optimizer.get_newoperations() self.export_state(stop_label) loop.operations.append(stop_label)
class BaseTestRegalloc(object): cpu = CPU(None, None) cpu.setup_once() def raising_func(i): if i: raise LLException(zero_division_error, zero_division_value) FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) raising_fptr = llhelper(FPTR, raising_func) zero_division_tp, zero_division_value = cpu.get_zero_division_error() zd_addr = cpu.cast_int_to_adr(zero_division_tp) zero_division_error = llmemory.cast_adr_to_ptr(zd_addr, lltype.Ptr(rclass.OBJECT_VTABLE)) raising_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT, EffectInfo.MOST_GENERAL) targettoken = TargetToken() targettoken2 = TargetToken() fdescr1 = BasicFailDescr(1) fdescr2 = BasicFailDescr(2) fdescr3 = BasicFailDescr(3) def setup_method(self, meth): self.targettoken._x86_loop_code = 0 self.targettoken2._x86_loop_code = 0 def f1(x): return x+1 def f2(x, y): return x*y def f10(*args): assert len(args) == 10 return sum(args) F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*2, lltype.Signed)) F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*10, lltype.Signed)) f1ptr = llhelper(F1PTR, f1) f2ptr = llhelper(F2PTR, f2) f10ptr = llhelper(F10PTR, f10) f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT, EffectInfo.MOST_GENERAL) f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT, EffectInfo.MOST_GENERAL) f10_calldescr= cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS, F10PTR.TO.RESULT, EffectInfo.MOST_GENERAL) namespace = locals().copy() type_system = 'lltype' def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, boxkinds=boxkinds) def interpret(self, ops, args, run=True): loop = self.parse(ops) looptoken = JitCellToken() self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) arguments = [] for arg in args: if isinstance(arg, int): arguments.append(arg) elif isinstance(arg, float): arg = longlong.getfloatstorage(arg) arguments.append(arg) else: assert isinstance(lltype.typeOf(arg), lltype.Ptr) llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) arguments.append(llgcref) loop._jitcelltoken = looptoken if run: self.cpu.execute_token(looptoken, *arguments) return loop def prepare_loop(self, ops): loop = self.parse(ops) regalloc = RegAlloc(self.cpu.assembler, False) regalloc.prepare_loop(loop.inputargs, loop.operations, loop.original_jitcell_token, []) return regalloc def getint(self, index): return self.cpu.get_latest_value_int(index) def getfloat(self, index): return self.cpu.get_latest_value_float(index) def getints(self, end): return [self.cpu.get_latest_value_int(index) for index in range(0, end)] def getfloats(self, end): return [longlong.getrealfloat(self.cpu.get_latest_value_float(index)) for index in range(0, end)] def getptr(self, index, T): gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) def attach_bridge(self, ops, loop, guard_op_index, **kwds): guard_op = loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) assert ([box.type for box in bridge.inputargs] == [box.type for box in guard_op.getfailargs()]) faildescr = guard_op.getdescr() self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations, loop._jitcelltoken) return bridge def run(self, loop, *arguments): return self.cpu.execute_token(loop._jitcelltoken, *arguments)
class TestRegallocMoreRegisters(BaseTestRegalloc): cpu = BaseTestRegalloc.cpu targettoken = TargetToken() S = lltype.GcStruct('S', ('field', lltype.Char)) fielddescr = cpu.fielddescrof(S, 'field') A = lltype.GcArray(lltype.Char) arraydescr = cpu.arraydescrof(A) namespace = locals().copy() def test_int_is_true(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7] i10 = int_is_true(i0) i11 = int_is_true(i1) i12 = int_is_true(i2) i13 = int_is_true(i3) i14 = int_is_true(i4) i15 = int_is_true(i5) i16 = int_is_true(i6) i17 = int_is_true(i7) finish(i10, i11, i12, i13, i14, i15, i16, i17) ''' self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333]) assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1] def test_comparison_ops(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6] i10 = int_lt(i0, i1) i11 = int_le(i2, i3) i12 = int_ge(i4, i5) i13 = int_eq(i5, i6) i14 = int_gt(i6, i2) i15 = int_ne(i2, i6) finish(i10, i11, i12, i13, i14, i15) ''' self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) assert self.getints(6) == [1, 1, 0, 0, 1, 1] def test_strsetitem(self): ops = ''' [p0, i] strsetitem(p0, 1, i) finish() ''' llstr = rstr.mallocstr(10) self.interpret(ops, [llstr, ord('a')]) assert llstr.chars[1] == 'a' def test_setfield_char(self): ops = ''' [p0, i] setfield_gc(p0, i, descr=fielddescr) finish() ''' s = lltype.malloc(self.S) self.interpret(ops, [s, ord('a')]) assert s.field == 'a' def test_setarrayitem_gc(self): ops = ''' [p0, i] setarrayitem_gc(p0, 1, i, descr=arraydescr) finish() ''' s = lltype.malloc(self.A, 3) self.interpret(ops, [s, ord('a')]) assert s[1] == 'a' def test_division_optimized(self): ops = ''' [i7, i6] label(i7, i6, descr=targettoken) i18 = int_floordiv(i7, i6) i19 = int_xor(i7, i6) i21 = int_lt(i19, 0) i22 = int_mod(i7, i6) i23 = int_is_true(i22) i24 = int_eq(i6, 4) guard_false(i24) [i18] jump(i18, i6, descr=targettoken) ''' self.interpret(ops, [10, 4]) assert self.getint(0) == 2
def test_compile_bridge_check_profile_info(self): py.test.skip("does not work, reinvestigate") class FakeProfileAgent(object): def __init__(self): self.functions = [] def native_code_written(self, name, address, size): self.functions.append((name, address, size)) self.cpu.profile_agent = agent = FakeProfileAgent() i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() targettoken = TargetToken() faildescr1 = BasicFailDescr(1) faildescr2 = BasicFailDescr(2) looptoken = JitCellToken() looptoken.number = 17 class FakeString(object): def __init__(self, val): self.val = val def _get_str(self): return self.val operations = [ ResOperation(rop.LABEL, [i0], None, descr=targettoken), ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("hello"), 0], None), ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1), ResOperation(rop.JUMP, [i1], None, descr=targettoken), ] inputargs = [i0] operations[-2].setfailargs([i1]) self.cpu.compile_loop(inputargs, operations, looptoken) name, loopaddress, loopsize = agent.functions[0] assert name == "Loop # 17: hello (loop counter 0)" assert loopaddress <= looptoken._x86_loop_code assert loopsize >= 40 # randomish number i1b = BoxInt() i3 = BoxInt() bridge = [ ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3), ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2), ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("bye"), 0], None), ResOperation(rop.JUMP, [i1b], None, descr=targettoken), ] bridge[1].setfailargs([i1b]) self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken) name, address, size = agent.functions[1] assert name == "Bridge # 0: bye (loop counter 1)" # Would be exactly ==, but there are some guard failure recovery # stubs in-between assert address >= loopaddress + loopsize assert size >= 10 # randomish number fail = self.cpu.execute_token(looptoken, 2) assert fail.identifier == 2 res = self.cpu.get_latest_value_int(0) assert res == 20
def compile_loop(metainterp, greenkey, start, inputargs, jumpargs, resume_at_jump_descr, full_preamble_needed=True): """Try to compile a new procedure by closing the current history back to the first operation. """ from pypy.jit.metainterp.optimizeopt import optimize_trace metainterp_sd = metainterp.staticdata jitdriver_sd = metainterp.jitdriver_sd history = metainterp.history jitcell_token = make_jitcell_token(jitdriver_sd) part = create_empty_loop(metainterp) part.inputargs = inputargs[:] h_ops = history.operations part.resume_at_jump_descr = resume_at_jump_descr part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \ [h_ops[i].clone() for i in range(start, len(h_ops))] + \ [ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)] try: optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: return None target_token = part.operations[0].getdescr() assert isinstance(target_token, TargetToken) all_target_tokens = [target_token] loop = create_empty_loop(metainterp) loop.inputargs = part.inputargs loop.operations = part.operations loop.quasi_immutable_deps = {} if part.quasi_immutable_deps: loop.quasi_immutable_deps.update(part.quasi_immutable_deps) while part.operations[-1].getopnum() == rop.LABEL: inliner = Inliner(inputargs, jumpargs) part.quasi_immutable_deps = None part.operations = [part.operations[-1]] + \ [inliner.inline_op(h_ops[i]) for i in range(start, len(h_ops))] + \ [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jumpargs], None, descr=jitcell_token)] target_token = part.operations[0].getdescr() assert isinstance(target_token, TargetToken) all_target_tokens.append(target_token) inputargs = jumpargs jumpargs = part.operations[-1].getarglist() try: optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts) except InvalidLoop: return None loop.operations = loop.operations[:-1] + part.operations if part.quasi_immutable_deps: loop.quasi_immutable_deps.update(part.quasi_immutable_deps) if not loop.quasi_immutable_deps: loop.quasi_immutable_deps = None for box in loop.inputargs: assert isinstance(box, Box) loop.original_jitcell_token = jitcell_token for label in all_target_tokens: assert isinstance(label, TargetToken) if label.virtual_state and label.short_preamble: metainterp_sd.logger_ops.log_short_preamble([], label.short_preamble) jitcell_token.target_tokens = all_target_tokens propagate_original_jitcell_token(loop) send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop") record_loop_or_bridge(metainterp_sd, loop) return all_target_tokens[0]
class TestRegallocGcIntegration(BaseTestRegalloc): cpu = CPU(None, None) cpu.gc_ll_descr = MockGcDescr(False) cpu.setup_once() S = lltype.GcForwardReference() S.become( lltype.GcStruct('S', ('field', lltype.Ptr(S)), ('int', lltype.Signed))) fielddescr = cpu.fielddescrof(S, 'field') struct_ptr = lltype.malloc(S) struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr) child_ptr = lltype.nullptr(S) struct_ptr.field = child_ptr descr0 = cpu.fielddescrof(S, 'int') ptr0 = struct_ref targettoken = TargetToken() namespace = locals().copy() def test_basic(self): ops = ''' [p0] p1 = getfield_gc(p0, descr=fielddescr) finish(p1) ''' self.interpret(ops, [self.struct_ptr]) assert not self.getptr(0, lltype.Ptr(self.S)) def test_rewrite_constptr(self): ops = ''' [] p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) finish(p1) ''' self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) def test_bug_0(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] label(i0, i1, i2, i3, i4, i5, i6, i7, i8, descr=targettoken) guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8] guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8] i11 = getfield_gc(i4, descr=descr0) guard_nonnull(i11) [i4, i5, i6, i7, i0, i1, i11, i8] i13 = getfield_gc(i11, descr=descr0) guard_isnull(i13) [i4, i5, i6, i7, i0, i1, i11, i8] i15 = getfield_gc(i4, descr=descr0) i17 = int_lt(i15, 0) guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i18 = getfield_gc(i11, descr=descr0) i19 = int_ge(i15, i18) guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i20 = int_lt(i15, 0) guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i21 = getfield_gc(i11, descr=descr0) i22 = getfield_gc(i11, descr=descr0) i23 = int_mul(i15, i22) i24 = int_add(i21, i23) i25 = getfield_gc(i4, descr=descr0) i27 = int_add(i25, 1) setfield_gc(i4, i27, descr=descr0) i29 = getfield_raw(144839744, descr=descr0) i31 = int_and(i29, -2141192192) i32 = int_is_true(i31) guard_false(i32) [i4, i6, i7, i0, i1, i24] i33 = getfield_gc(i0, descr=descr0) guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24] jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24, descr=targettoken) ''' self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False)