def test_loop_1(): v1 = BoxInt(); v2 = BoxInt(); v3 = BoxInt() v4 = BoxInt(); v5 = BoxInt(); v6 = BoxInt() loop = TreeLoop('loop_1') loop.inputargs = [v1, v2, v3] loop.operations = [ ResOperation(rop.INT_IS_TRUE, [v1], v4), ResOperation(rop.GUARD_TRUE, [v4], None), ResOperation(rop.INT_ADD, [v2, v3], v5), ResOperation(rop.INT_SUB, [v1, ConstInt(1)], v6), ResOperation(rop.JUMP, [v6, v2, v5], None), ] loop.operations[-1].jump_target = loop loop.operations[1].suboperations = [ ResOperation(rop.FAIL, [v3], None), ] cpu = LLVMCPU(None) cpu.setup_once() cpu.compile_operations(loop) cpu.set_future_value_int(0, 2**11) cpu.set_future_value_int(1, 3) cpu.set_future_value_int(2, 0) cpu.execute_operations(loop) assert cpu.get_latest_value_int(0) == 3*(2**11) cpu.set_future_value_int(0, 2**29) cpu.set_future_value_int(1, 3) cpu.set_future_value_int(2, 0) cpu.execute_operations(loop) assert cpu.get_latest_value_int(0) == 3*(2**29)
def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, operations, original_loop_token): n = metainterp_sd.cpu.get_fail_descr_number(faildescr) if not we_are_translated(): show_procedures(metainterp_sd) seen = dict.fromkeys(inputargs) TreeLoop.check_consistency_of_branch(operations, seen) if metainterp_sd.warmrunnerdesc is not None: hooks = metainterp_sd.warmrunnerdesc.hooks debug_info = JitDebugInfo( jitdriver_sd, metainterp_sd.logger_ops, original_loop_token, operations, "bridge", fail_descr_no=n ) hooks.before_compile_bridge(debug_info) else: hooks = None debug_info = None operations = get_deep_immutable_oplist(operations) metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, original_loop_token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if hooks is not None: debug_info.asminfo = asminfo hooks.after_compile_bridge(debug_info) if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") # if asminfo is not None: ops_offset = asminfo.ops_offset else: ops_offset = None metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset)
def convert_old_style_to_targets(loop, jump): newloop = TreeLoop(loop.name) newloop.inputargs = loop.inputargs newloop.operations = [ResOperation(rop.LABEL, loop.inputargs, None, descr=FakeDescr())] + \ loop.operations if not jump: assert newloop.operations[-1].getopnum() == rop.JUMP newloop.operations[-1] = ResOperation(rop.LABEL, newloop.operations[-1].getarglist(), None, descr=FakeDescr()) return newloop
def test_debug_merge_point(): loop = TreeLoop('test') loop.inputargs = [] loop.operations = [ ResOperation(rop.DEBUG_MERGE_POINT, [], None), ResOperation(rop.FAIL, [], None), ] cpu = LLVMCPU(None) cpu.setup_once() cpu.compile_operations(loop) cpu.execute_operations(loop)
def build_random_loop(self, cpu, builder_factory, r, startvars): loop = TreeLoop('test_random_function') loop.inputargs = startvars[:] loop.operations = [] loop.token = LoopToken() builder = builder_factory(cpu, loop, startvars[:]) self.generate_ops(builder, r, loop, startvars) self.builder = builder self.loop = loop cpu.compile_loop(loop.inputargs, loop.operations, loop.token)
def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): n = faildescr.get_index() metainterp_sd.logger_ops.log_bridge(inputargs, operations, n) metainterp_sd.profiler.start_backend() if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) pass metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations) metainterp_sd.profiler.end_backend() if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge")
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 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 send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): n = metainterp_sd.cpu.get_fail_descr_number(faildescr) metainterp_sd.logger_ops.log_bridge(inputargs, operations, n) if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) pass metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge")
def build_random_loop(self, cpu, builder_factory, r, startvars, allow_delay): loop = TreeLoop('test_random_function') loop.inputargs = startvars[:] loop.operations = [] loop._jitcelltoken = JitCellToken() builder = builder_factory(cpu, loop, startvars[:]) if allow_delay: needs_a_label = True else: self.insert_label(loop, 0, r) needs_a_label = False self.generate_ops(builder, r, loop, startvars, needs_a_label=needs_a_label) self.builder = builder self.loop = loop dump(loop) cpu.compile_loop(loop.inputargs, loop.operations, loop._jitcelltoken)
def test_simple_case(): v1 = BoxInt() v2 = BoxInt() v3 = BoxInt() v4 = BoxInt() loop = TreeLoop('test') loop.inputargs = [v1] loop.operations = [ ResOperation(rop.INT_ADD, [v1, v1], v2), ResOperation(rop.INT_INVERT, [v2], v3), ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), ResOperation(rop.FAIL, [v4, v3], None), ] cpu = LLVMCPU(None) cpu.setup_once() cpu.compile_operations(loop) cpu.set_future_value_int(0, 19) cpu.execute_operations(loop) assert cpu.get_latest_value_int(0) == (19 >> 3) assert cpu.get_latest_value_int(1) == (~38)
def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, operations, original_loop_token): n = metainterp_sd.cpu.get_fail_descr_number(faildescr) if not we_are_translated(): show_procedures(metainterp_sd) seen = dict.fromkeys(inputargs) TreeLoop.check_consistency_of_branch(operations, seen) if metainterp_sd.warmrunnerdesc is not None: hooks = metainterp_sd.warmrunnerdesc.hooks debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops, original_loop_token, operations, 'bridge', fail_descr_no=n) hooks.before_compile_bridge(debug_info) else: hooks = None debug_info = None operations = get_deep_immutable_oplist(operations) metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, original_loop_token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if hooks is not None: debug_info.asminfo = asminfo hooks.after_compile_bridge(debug_info) if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") # if asminfo is not None: ops_offset = asminfo.ops_offset else: ops_offset = None metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset)
def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, operations, original_loop_token): n = metainterp_sd.cpu.get_fail_descr_number(faildescr) jitdriver_sd.on_compile_bridge(metainterp_sd.logger_ops, original_loop_token, operations, n) if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) metainterp_sd.profiler.start_backend() operations = get_deep_immutable_oplist(operations) debug_start("jit-backend") try: ops_offset = metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations, original_loop_token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") # metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset) # if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_loop_token)
def test_loop_2(): cpu = LLVMCPU(None) cpu.setup_once() # v1 = BoxInt(); v2 = BoxInt() loop1 = TreeLoop('loop1') loop1.inputargs = [v1] loop1.operations = [ ResOperation(rop.INT_ADD, [ConstInt(1), v1], v2), ResOperation(rop.FAIL, [v2], None), ] cpu.compile_operations(loop1) # cpu.set_future_value_int(0, 123) cpu.execute_operations(loop1) assert cpu.get_latest_value_int(0) == 124 # v3 = BoxInt(); v4 = BoxInt(); v5 = BoxInt() loop2 = TreeLoop('loop2') loop2.inputargs = [v3, v4] loop2.operations = [ ResOperation(rop.INT_SUB, [v3, v4], v5), ResOperation(rop.JUMP, [v5], None), ] loop2.operations[-1].jump_target = loop1 cpu.compile_operations(loop2) # cpu.set_future_value_int(0, 1500) cpu.set_future_value_int(1, 60) cpu.execute_operations(loop2) assert cpu.get_latest_value_int(0) == 1441 # # Now try to change the definition of loop1... loop1.operations = [ ResOperation(rop.INT_ADD, [ConstInt(3), v1], v2), ResOperation(rop.FAIL, [v2], None), ] cpu.compile_operations(loop1) # cpu.set_future_value_int(0, 1500) cpu.set_future_value_int(1, 60) cpu.execute_operations(loop2) assert cpu.get_latest_value_int(0) == 1443 # should see the change
def propagate_all_forward(self): loop = self.optimizer.loop jumpop = loop.operations[-1] if jumpop.getopnum() == rop.JUMP: loop.operations = loop.operations[:-1] else: loopop = None self.optimizer.propagate_all_forward() if jumpop: assert jumpop.getdescr() is loop.token jump_args = jumpop.getarglist() jumpop.initarglist([]) self.optimizer.flush() KillHugeIntBounds(self.optimizer).apply() loop.preamble.operations = self.optimizer.newoperations jump_args = [self.getvalue(a).get_key_box() for a in jump_args] start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() self.start_resumedescr = start_resumedescr assert isinstance(start_resumedescr, ResumeGuardDescr) start_resumedescr.rd_snapshot = self.fix_snapshot(loop, jump_args, start_resumedescr.rd_snapshot) modifier = VirtualStateAdder(self.optimizer) virtual_state = modifier.get_virtual_state(jump_args) values = [self.getvalue(arg) for arg in jump_args] inputargs = virtual_state.make_inputargs(values) short_inputargs = virtual_state.make_inputargs(values, keyboxes=True) self.constant_inputargs = {} for box in jump_args: const = self.get_constant_box(box) if const: self.constant_inputargs[box] = const sb = ShortBoxes(self.optimizer, inputargs + self.constant_inputargs.keys()) self.short_boxes = sb preamble_optimizer = self.optimizer loop.preamble.quasi_immutable_deps = self.optimizer.quasi_immutable_deps self.optimizer = self.optimizer.new() loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps logops = self.optimizer.loop.logops if logops: args = ", ".join([logops.repr_of_arg(arg) for arg in inputargs]) debug_print("inputargs: " + args) args = ", ".join([logops.repr_of_arg(arg) for arg in short_inputargs]) debug_print("short inputargs: " + args) self.short_boxes.debug_print(logops) # Force virtuals amoung the jump_args of the preamble to get the # operations needed to setup the proper state of those virtuals # in the peeled loop inputarg_setup_ops = [] preamble_optimizer.newoperations = [] seen = {} for box in inputargs: if box in seen: continue seen[box] = True value = preamble_optimizer.getvalue(box) inputarg_setup_ops.extend(value.make_guards(box)) for box in short_inputargs: if box in seen: continue seen[box] = True value = preamble_optimizer.getvalue(box) value.force_box() preamble_optimizer.flush() inputarg_setup_ops += preamble_optimizer.newoperations # Setup the state of the new optimizer by emiting the # short preamble operations and discarding the result self.optimizer.emitting_dissabled = True for op in inputarg_setup_ops: self.optimizer.send_extra_operation(op) seen = {} for op in self.short_boxes.operations(): self.ensure_short_op_emitted(op, self.optimizer, seen) if op and op.result: # The order of these guards is not important as # self.optimizer.emitting_dissabled is False value = preamble_optimizer.getvalue(op.result) for guard in value.make_guards(op.result): self.optimizer.send_extra_operation(guard) newresult = self.optimizer.getvalue(op.result).get_key_box() if newresult is not op.result: self.short_boxes.alias(newresult, op.result) self.optimizer.flush() self.optimizer.emitting_dissabled = False # XXX Hack to prevent the arraylen/strlen/unicodelen ops generated # by value.make_guards() from ending up in pure_operations for key, op in self.optimizer.pure_operations.items(): if not self.short_boxes.has_producer(op.result): del self.optimizer.pure_operations[key] initial_inputargs_len = len(inputargs) self.inliner = Inliner(loop.inputargs, jump_args) short = self.inline(inputargs, self.cloned_operations, loop.inputargs, short_inputargs, virtual_state) loop.inputargs = inputargs args = [preamble_optimizer.getvalue(self.short_boxes.original(a)).force_box() for a in inputargs] jmp = ResOperation(rop.JUMP, args, None) jmp.setdescr(loop.token) loop.preamble.operations.append(jmp) loop.operations = self.optimizer.newoperations maxguards = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.max_retrace_guards if self.optimizer.emitted_guards > maxguards: loop.preamble.token.retraced_count = sys.maxint if short: assert short[-1].getopnum() == rop.JUMP short[-1].setdescr(loop.token) # Turn guards into conditional jumps to the preamble for i in range(len(short)): op = short[i] if op.is_guard(): op = op.clone() op.setfailargs(None) descr = self.start_resumedescr.clone_if_mutable() op.setdescr(descr) short[i] = op short_loop = TreeLoop("short preamble") short_loop.inputargs = short_inputargs short_loop.operations = short # Clone ops and boxes to get private versions and boxmap = {} newargs = [None] * len(short_loop.inputargs) for i in range(len(short_loop.inputargs)): a = short_loop.inputargs[i] if a in boxmap: newargs[i] = boxmap[a] else: newargs[i] = a.clonebox() boxmap[a] = newargs[i] inliner = Inliner(short_loop.inputargs, newargs) for box, const in self.constant_inputargs.items(): inliner.argmap[box] = const short_loop.inputargs = newargs ops = [inliner.inline_op(op) for op in short_loop.operations] short_loop.operations = ops descr = self.start_resumedescr.clone_if_mutable() inliner.inline_descr_inplace(descr) short_loop.start_resumedescr = descr assert isinstance(loop.preamble.token, LoopToken) if loop.preamble.token.short_preamble: loop.preamble.token.short_preamble.append(short_loop) else: loop.preamble.token.short_preamble = [short_loop] short_loop.virtual_state = virtual_state # Forget the values to allow them to be freed for box in short_loop.inputargs: box.forget_value() for op in short_loop.operations: if op.result: op.result.forget_value()
def create_empty_loop(metainterp): name = metainterp.staticdata.stats.name_for_new_loop() return TreeLoop(name)
def propagate_all_forward(self): loop = self.optimizer.loop jumpop = loop.operations[-1] if jumpop.getopnum() == rop.JUMP: loop.operations = loop.operations[:-1] else: loopop = None self.optimizer.propagate_all_forward() if jumpop: assert jumpop.getdescr() is loop.token jump_args = jumpop.getarglist() jumpop.initarglist([]) #virtual_state = [self.getvalue(a).is_virtual() for a in jump_args] modifier = VirtualStateAdder(self.optimizer) virtual_state = modifier.get_virtual_state(jump_args) loop.preamble.operations = self.optimizer.newoperations loop.preamble.quasi_immutable_deps = ( self.optimizer.quasi_immutable_deps) self.optimizer = self.optimizer.reconstruct_for_next_iteration() inputargs = self.inline(self.cloned_operations, loop.inputargs, jump_args) loop.inputargs = inputargs jmp = ResOperation(rop.JUMP, loop.inputargs[:], None) jmp.setdescr(loop.token) loop.preamble.operations.append(jmp) loop.operations = self.optimizer.newoperations loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps start_resumedescr = loop.preamble.start_resumedescr.clone_if_mutable() assert isinstance(start_resumedescr, ResumeGuardDescr) snapshot = start_resumedescr.rd_snapshot while snapshot is not None: snapshot_args = snapshot.boxes new_snapshot_args = [] for a in snapshot_args: if not isinstance(a, Const): a = loop.preamble.inputargs[jump_args.index(a)] new_snapshot_args.append(a) snapshot.boxes = new_snapshot_args snapshot = snapshot.prev short = self.create_short_preamble(loop.preamble, loop) if short: if False: # FIXME: This should save some memory but requires # a lot of tests to be fixed... loop.preamble.operations = short[:] # Turn guards into conditional jumps to the preamble for i in range(len(short)): op = short[i] if op.is_guard(): op = op.clone() op.setfailargs(None) op.setdescr(start_resumedescr.clone_if_mutable()) short[i] = op short_loop = TreeLoop('short preamble') short_loop.inputargs = loop.preamble.inputargs[:] short_loop.operations = short # Clone ops and boxes to get private versions and newargs = [a.clonebox() for a in short_loop.inputargs] inliner = Inliner(short_loop.inputargs, newargs) short_loop.inputargs = newargs ops = [inliner.inline_op(op) for op in short_loop.operations] short_loop.operations = ops descr = start_resumedescr.clone_if_mutable() inliner.inline_descr_inplace(descr) short_loop.start_resumedescr = descr assert isinstance(loop.preamble.token, LoopToken) if loop.preamble.token.short_preamble: loop.preamble.token.short_preamble.append(short_loop) else: loop.preamble.token.short_preamble = [short_loop] short_loop.virtual_state = virtual_state # Forget the values to allow them to be freed for box in short_loop.inputargs: box.forget_value() for op in short_loop.operations: if op.result: op.result.forget_value()
def optimize_loop(self, ops, expected, expected_shorts=None): loop = self.parse(ops) if expected != "crash!": expected = self.parse(expected) part = TreeLoop('part') part.inputargs = loop.inputargs part.resume_at_jump_descr = FakeDescrWithSnapshot() token = loop.original_jitcell_token optimized = TreeLoop('optimized') optimized.inputargs = loop.inputargs optimized.operations = [] labels = [i for i, op in enumerate(loop.operations) \ if op.getopnum()==rop.LABEL] prv = 0 last_label = [] for nxt in labels + [len(loop.operations)]: assert prv != nxt operations = last_label + loop.operations[prv:nxt] if nxt < len(loop.operations): label = loop.operations[nxt] assert label.getopnum() == rop.LABEL if label.getdescr() is None: label.setdescr(token) operations.append(label) part.operations = operations self._do_optimize_loop(part, None) if part.operations[-1].getopnum() == rop.LABEL: last_label = [part.operations.pop()] else: last_label = [] optimized.operations.extend(part.operations) prv = nxt + 1 # print print "Optimized:" if optimized.operations: print '\n'.join([str(o) for o in optimized.operations]) else: print 'Failed!' print shorts = [op.getdescr().short_preamble for op in optimized.operations if op.getopnum() == rop.LABEL] if expected_shorts: for short in shorts: print print "Short preamble:" print '\n'.join([str(o) for o in short]) assert expected != "crash!", "should have raised an exception" self.assert_equal(optimized, expected) if expected_shorts: assert len(shorts) == len(expected_shorts) for short, expected_short in zip(shorts, expected_shorts): expected_short = self.parse(expected_short) short_preamble = TreeLoop('short preamble') assert short[0].getopnum() == rop.LABEL short_preamble.inputargs = short[0].getarglist() short_preamble.operations = short self.assert_equal(short_preamble, expected_short, text_right='expected short preamble') return optimized
def create_empty_loop(metainterp, name_prefix=""): name = metainterp.staticdata.stats.name_for_new_loop() loop = TreeLoop(name_prefix + name) loop.call_pure_results = metainterp.call_pure_results return loop
def create_empty_loop(metainterp, name_prefix=''): name = metainterp.staticdata.stats.name_for_new_loop() loop = TreeLoop(name_prefix + name) loop.call_pure_results = metainterp.call_pure_results return loop