Author: Antonio Cuni <[email protected]>
Branch: 
Changeset: r44145:318b15a08614
Date: 2011-05-13 15:45 +0000
http://bitbucket.org/pypy/pypy/changeset/318b15a08614/

Log:    merge the x86-dump-labels branch: new the jit-log-opt section
        contain an offset at the side of each op, which represent where the
        code for that op starts in the assembler

diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -35,7 +35,7 @@
     def do_write_barrier(self, gcref_struct, gcref_newptr):
         pass
     def rewrite_assembler(self, cpu, operations):
-        pass
+        return operations
     def can_inline_malloc(self, descr):
         return False
     def can_inline_malloc_varsize(self, descr, num_elem):
@@ -831,8 +831,7 @@
                         op = op.copy_and_change(rop.SETARRAYITEM_RAW)
             # ----------
             newops.append(op)
-        del operations[:]
-        operations.extend(newops)
+        return newops
 
     def _gen_write_barrier(self, newops, v_base, v_value):
         args = [v_base, v_value]
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py 
b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -413,7 +413,7 @@
             ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None),
             ]
         gc_ll_descr = self.gc_ll_descr
-        gc_ll_descr.rewrite_assembler(None, operations)
+        operations = gc_ll_descr.rewrite_assembler(None, operations)
         assert len(operations) == 0
 
     def test_rewrite_assembler_1(self):
@@ -437,7 +437,7 @@
             ]
         gc_ll_descr = self.gc_ll_descr
         gc_ll_descr.gcrefs = MyFakeGCRefList()
-        gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
+        operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
         assert len(operations) == 2
         assert operations[0].getopnum() == rop.GETFIELD_RAW
         assert operations[0].getarg(0) == ConstInt(43)
@@ -474,7 +474,7 @@
         old_can_move = rgc.can_move
         try:
             rgc.can_move = lambda s: False
-            gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
+            operations = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations)
         finally:
             rgc.can_move = old_can_move
         assert len(operations) == 1
@@ -496,7 +496,7 @@
                          descr=field_descr),
             ]
         gc_ll_descr = self.gc_ll_descr
-        gc_ll_descr.rewrite_assembler(self.fake_cpu, operations)
+        operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations)
         assert len(operations) == 2
         #
         assert operations[0].getopnum() == rop.COND_CALL_GC_WB
@@ -520,7 +520,7 @@
                          descr=array_descr),
             ]
         gc_ll_descr = self.gc_ll_descr
-        gc_ll_descr.rewrite_assembler(self.fake_cpu, operations)
+        operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations)
         assert len(operations) == 2
         #
         assert operations[0].getopnum() == rop.COND_CALL_GC_WB
@@ -552,8 +552,8 @@
         setfield_gc(p0, p1, descr=xdescr)
         jump()
         """, namespace=locals())
-        self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
-        equaloplists(ops.operations, expected.operations)
+        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, 
ops.operations)
+        equaloplists(operations, expected.operations)
 
     def test_rewrite_assembler_initialization_store_2(self):
         S = lltype.GcStruct('S', ('parent', OBJECT),
@@ -576,8 +576,8 @@
         setfield_raw(p0, p1, descr=xdescr)
         jump()
         """, namespace=locals())
-        self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
-        equaloplists(ops.operations, expected.operations)
+        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, 
ops.operations)
+        equaloplists(operations, expected.operations)
 
     def test_rewrite_assembler_initialization_store_3(self):
         A = lltype.GcArray(lltype.Ptr(lltype.GcStruct('S')))
@@ -594,8 +594,8 @@
         setarrayitem_gc(p0, 0, p1, descr=arraydescr)
         jump()
         """, namespace=locals())
-        self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
-        equaloplists(ops.operations, expected.operations)
+        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu, 
ops.operations)
+        equaloplists(operations, expected.operations)
 
 class TestFrameworkMiniMark(TestFramework):
     gc = 'minimark'
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -53,12 +53,19 @@
         """Called once by the front-end when the program stops."""
         pass
 
-
     def compile_loop(self, inputargs, operations, looptoken, log=True):
         """Assemble the given loop.
         Should create and attach a fresh CompiledLoopToken to
         looptoken.compiled_loop_token and stick extra attributes
         on it to point to the compiled loop in assembler.
+
+        Optionally, return a ``ops_offset`` dictionary, which maps each 
operation
+        to its offset in the compiled code.  The ``ops_offset`` dictionary is 
then
+        used by the operation logger to print the offsets in the log.  The
+        offset representing the end of the last operation is stored in
+        ``ops_offset[None]``: note that this might not coincide with the end of
+        the loop, because usually in the loop footer there is code which does
+        not belong to any particular operation.
         """
         raise NotImplementedError
 
@@ -66,9 +73,16 @@
                        original_loop_token, log=True):
         """Assemble the bridge.
         The FailDescr is the descr of the original guard that failed.
+
+        Optionally, return a ``ops_offset`` dictionary.  See the docstring of
+        ``compiled_loop`` for more informations about it.
         """
         raise NotImplementedError    
 
+    def dump_loop_token(self, looptoken):
+        """Print a disassembled version of looptoken to stdout"""
+        raise NotImplementedError
+
     def execute_token(self, looptoken):
         """Execute the generated code referenced by the looptoken.
         Returns the descr of the last executed operation: either the one
diff --git a/pypy/jit/backend/test/runner_test.py 
b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -173,6 +173,8 @@
         wr_i1 = weakref.ref(i1)
         wr_guard = weakref.ref(operations[2])
         self.cpu.compile_loop(inputargs, operations, looptoken)
+        if hasattr(looptoken, '_x86_ops_offset'):
+            del looptoken._x86_ops_offset # else it's kept alive
         del i0, i1, i2
         del inputargs
         del operations
diff --git a/pypy/jit/backend/x86/assembler.py 
b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -334,7 +334,7 @@
             operations = self._inject_debugging_code(looptoken, operations)
 
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
-        arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
+        arglocs, operations = regalloc.prepare_loop(inputargs, operations, 
looptoken)
         looptoken._x86_arglocs = arglocs
 
         bootstrappos = self.mc.get_relative_pos()
@@ -361,6 +361,13 @@
                                 frame_depth + param_depth)
         self.patch_pending_failure_recoveries(rawstart)
         #
+        ops_offset = self.mc.ops_offset
+        if not we_are_translated():
+            # used only by looptoken.dump() -- useful in tests
+            looptoken._x86_rawstart = rawstart
+            looptoken._x86_fullsize = fullsize
+            looptoken._x86_ops_offset = ops_offset
+
         looptoken._x86_bootstrap_code = rawstart + bootstrappos
         looptoken._x86_loop_code = rawstart + self.looppos
         looptoken._x86_direct_bootstrap_code = rawstart + directbootstrappos
@@ -370,6 +377,7 @@
             name = "Loop # %s: %s" % (looptoken.number, funcname)
             self.cpu.profile_agent.native_code_written(name,
                                                        rawstart, fullsize)
+        return ops_offset
 
     def assemble_bridge(self, faildescr, inputargs, operations,
                         original_loop_token, log):
@@ -397,8 +405,8 @@
                     [loc.assembler() for loc in faildescr._x86_debug_faillocs])
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
         fail_depths = faildescr._x86_current_depths
-        regalloc.prepare_bridge(fail_depths, inputargs, arglocs,
-                                operations)
+        operations = regalloc.prepare_bridge(fail_depths, inputargs, arglocs,
+                                             operations)
 
         stackadjustpos = self._patchable_stackadjust()
         frame_depth, param_depth = self._assemble(regalloc, operations)
@@ -419,12 +427,14 @@
             faildescr._x86_bridge_param_depth = param_depth
         # patch the jump from original guard
         self.patch_jump_for_descr(faildescr, rawstart)
+        ops_offset = self.mc.ops_offset
         self.teardown()
         # oprofile support
         if self.cpu.profile_agent is not None:
             name = "Bridge # %s: %s" % (descr_number, funcname)
             self.cpu.profile_agent.native_code_written(name,
                                                        rawstart, fullsize)
+        return ops_offset
 
     def write_pending_failure_recoveries(self):
         # for each pending guard, generate the code of the recovery stub
diff --git a/pypy/jit/backend/x86/codebuf.py b/pypy/jit/backend/x86/codebuf.py
--- a/pypy/jit/backend/x86/codebuf.py
+++ b/pypy/jit/backend/x86/codebuf.py
@@ -1,5 +1,7 @@
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.debug import debug_start, debug_print, debug_stop
+from pypy.rlib.debug import have_debug_prints
 from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
 from pypy.jit.backend.x86.rx86 import X86_32_CodeBuilder, X86_64_CodeBuilder
 from pypy.jit.backend.x86.regloc import LocationCodeBuilder
@@ -25,10 +27,19 @@
         # at [p-4:p] encode an absolute address that will need to be
         # made relative.
         self.relocations = []
+        #
+        # ResOperation --> offset in the assembly.
+        # ops_offset[None] represents the beginning of the code after the last 
op
+        # (i.e., the tail of the loop)
+        self.ops_offset = {}
 
     def add_pending_relocation(self):
         self.relocations.append(self.get_relative_pos())
 
+    def mark_op(self, op):
+        pos = self.get_relative_pos()
+        self.ops_offset[op] = pos
+
     def copy_to_raw_memory(self, addr):
         self._copy_to_raw_memory(addr)
         for reloc in self.relocations:
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -161,7 +161,7 @@
         self.fm = X86FrameManager()
         self.param_depth = 0
         cpu = self.assembler.cpu
-        cpu.gc_ll_descr.rewrite_assembler(cpu, operations)
+        operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations)
         # compute longevity of variables
         longevity = self._compute_vars_longevity(inputargs, operations)
         self.longevity = longevity
@@ -170,20 +170,22 @@
                                   assembler = self.assembler)
         self.xrm = xmm_reg_mgr_cls(longevity, frame_manager = self.fm,
                                    assembler = self.assembler)
+        return operations
 
     def prepare_loop(self, inputargs, operations, looptoken):
-        self._prepare(inputargs, operations)
+        operations = self._prepare(inputargs, operations)
         jump = operations[-1]
         loop_consts = self._compute_loop_consts(inputargs, jump, looptoken)
         self.loop_consts = loop_consts
-        return self._process_inputargs(inputargs)
+        return self._process_inputargs(inputargs), operations
 
     def prepare_bridge(self, prev_depths, inputargs, arglocs, operations):
-        self._prepare(inputargs, operations)
+        operations = self._prepare(inputargs, operations)
         self.loop_consts = {}
         self._update_bindings(arglocs, inputargs)
         self.fm.frame_depth = prev_depths[0]
         self.param_depth = prev_depths[1]
+        return operations
 
     def reserve_param(self, n):
         self.param_depth = max(self.param_depth, n)
@@ -406,6 +408,7 @@
         #self.operations = operations
         while i < len(operations):
             op = operations[i]
+            self.assembler.mc.mark_op(op)
             self.rm.position = i
             self.xrm.position = i
             if op.has_no_side_effect() and op.result not in self.longevity:
@@ -424,6 +427,7 @@
             i += 1
         assert not self.rm.reg_bindings
         assert not self.xrm.reg_bindings
+        self.assembler.mc.mark_op(None) # end of the loop
 
     def _compute_vars_longevity(self, inputargs, operations):
         # compute a dictionary that maps variables to index in
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -60,16 +60,33 @@
         self.assembler.finish_once()
         self.profile_agent.shutdown()
 
+    def dump_loop_token(self, looptoken):
+        """
+        NOT_RPYTHON
+        """
+        from pypy.jit.backend.x86.tool.viewcode import machine_code_dump
+        data = []
+        label_list = [(offset, name) for name, offset in
+                      looptoken._x86_ops_offset.iteritems()]
+        label_list.sort()
+        addr = looptoken._x86_rawstart
+        src = rffi.cast(rffi.CCHARP, addr)
+        for p in range(looptoken._x86_fullsize):
+            data.append(src[p])
+        data = ''.join(data)
+        lines = machine_code_dump(data, addr, self.backend_name, label_list)
+        print ''.join(lines)
+
     def compile_loop(self, inputargs, operations, looptoken, log=True):
-        self.assembler.assemble_loop(inputargs, operations, looptoken,
-                                     log=log)
+        return self.assembler.assemble_loop(inputargs, operations, looptoken,
+                                            log=log)
 
     def compile_bridge(self, faildescr, inputargs, operations,
                        original_loop_token, log=True):
         clt = original_loop_token.compiled_loop_token
         clt.compiling_a_bridge()
-        self.assembler.assemble_bridge(faildescr, inputargs, operations,
-                                       original_loop_token, log=log)
+        return self.assembler.assemble_bridge(faildescr, inputargs, operations,
+                                              original_loop_token, log=log)
 
     def set_future_value_int(self, index, intvalue):
         self.assembler.fail_boxes_int.setitem(index, intvalue)
@@ -164,7 +181,9 @@
         # positions invalidated
         looptoken.compiled_loop_token.invalidate_positions = []
 
+
 class CPU386(AbstractX86CPU):
+    backend_name = 'x86'
     WORD = 4
     NUM_REGS = 8
     CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.esi, regloc.edi]
@@ -180,6 +199,7 @@
     supports_longlong = False
 
 class CPU_X86_64(AbstractX86CPU):
+    backend_name = 'x86_64'
     WORD = 8
     NUM_REGS = 16
     CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14, 
regloc.r15]
diff --git a/pypy/jit/backend/x86/test/test_runner.py 
b/pypy/jit/backend/x86/test/test_runner.py
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -390,6 +390,29 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
+    def test_ops_offset(self):
+        from pypy.rlib import debug
+        i0 = BoxInt()
+        i1 = BoxInt()
+        i2 = BoxInt()
+        looptoken = LoopToken()
+        operations = [
+            ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
+            ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
+            ResOperation(rop.JUMP, [i1], None, descr=looptoken),
+            ]
+        inputargs = [i0]
+        debug._log = dlog = debug.DebugLog()
+        ops_offset = self.cpu.compile_loop(inputargs, operations, looptoken)
+        debug._log = None
+        #
+        assert ops_offset is looptoken._x86_ops_offset
+        # getfield_raw/int_add/setfield_raw + ops + None
+        assert len(ops_offset) == 3 + len(operations) + 1
+        assert (ops_offset[operations[0]] <=
+                ops_offset[operations[1]] <=
+                ops_offset[operations[2]] <=
+                ops_offset[None])
 
 class TestDebuggingAssembler(object):
     def setup_method(self, meth):
diff --git a/pypy/jit/backend/x86/tool/__init__.py 
b/pypy/jit/backend/x86/tool/__init__.py
new file mode 100644
diff --git a/pypy/jit/backend/x86/tool/test/test_viewcode.py 
b/pypy/jit/backend/x86/tool/test/test_viewcode.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/x86/tool/test/test_viewcode.py
@@ -0,0 +1,55 @@
+from cStringIO import StringIO
+from pypy.jit.backend.x86.tool.viewcode import format_code_dump_with_labels
+
+def test_format_code_dump_with_labels():
+    lines = StringIO("""
+aa00 <.data>:
+aa00: one
+aa01: two
+aa03: three
+aa04: for
+aa05: five
+aa06: six
+aa0c: seven
+aa12: eight
+""".strip()).readlines()
+    #
+    label_list = [(0x00, 'AAA'), (0x03, 'BBB'), (0x0c, 'CCC')]
+    lines = format_code_dump_with_labels(0xAA00, lines, label_list)
+    out = ''.join(lines)
+    assert out == """
+aa00 <.data>:
+
+AAA
+aa00: one
+aa01: two
+
+BBB
+aa03: three
+aa04: for
+aa05: five
+aa06: six
+
+CCC
+aa0c: seven
+aa12: eight
+""".strip()
+
+
+def test_format_code_dump_with_labels_no_labels():
+    input = """
+aa00 <.data>:
+aa00: one
+aa01: two
+aa03: three
+aa04: for
+aa05: five
+aa06: six
+aa0c: seven
+aa12: eight
+""".strip()
+    lines = StringIO(input).readlines()
+    #
+    lines = format_code_dump_with_labels(0xAA00, lines, label_list=None)
+    out = ''.join(lines)
+    assert out.strip() == input
diff --git a/pypy/jit/backend/x86/tool/viewcode.py 
b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -31,7 +31,7 @@
 if sys.platform == "win32":
     XXX   # lots more in Psyco
 
-def machine_code_dump(data, originaddr, backend_name):
+def machine_code_dump(data, originaddr, backend_name, label_list=None):
     objdump_backend_option = {
         'x86': 'i386',
         'x86_64': 'x86-64',
@@ -51,7 +51,32 @@
     }, 'r')
     result = g.readlines()
     g.close()
-    return result[6:]   # drop some objdump cruft
+    lines = result[6:]   # drop some objdump cruft
+    return format_code_dump_with_labels(originaddr, lines, label_list)
+
+def format_code_dump_with_labels(originaddr, lines, label_list):
+    from pypy.rlib.rarithmetic import r_uint
+    if not label_list:
+        label_list = []
+    originaddr = r_uint(originaddr)
+    itlines = iter(lines)
+    yield itlines.next() # don't process the first line
+    for lbl_start, lbl_name in label_list:
+        for line in itlines:
+            addr, _ = line.split(':', 1)
+            addr = int(addr, 16)
+            if addr >= originaddr+lbl_start:
+                yield '\n'
+                if lbl_name is None:
+                    yield '--end of the loop--\n'
+                else:
+                    yield str(lbl_name) + '\n'
+                yield line
+                break
+            yield line
+    # yield all the remaining lines
+    for line in itlines:
+        yield line
 
 def load_symbols(filename):
     # the program that lists symbols, and the output it gives
@@ -135,6 +160,7 @@
     def disassemble(self):
         if not hasattr(self, 'text'):
             lines = machine_code_dump(self.data, self.addr, 
self.world.backend_name)
+            lines = list(lines)
             # instead of adding symbol names in the dumps we could
             # also make the 0xNNNNNNNN addresses be red and show the
             # symbol name when the mouse is over them
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -156,20 +156,14 @@
     loop_token.number = n = globaldata.loopnumbering
     globaldata.loopnumbering += 1
 
-    metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type)
-    short = loop.token.short_preamble
-    if short:
-        metainterp_sd.logger_ops.log_short_preamble(short[-1].inputargs,
-                                                    short[-1].operations)
-
     if not we_are_translated():
         show_loop(metainterp_sd, loop)
         loop.check_consistency()
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
     try:
-        metainterp_sd.cpu.compile_loop(loop.inputargs, loop.operations,
-                                       loop.token)
+        ops_offset = metainterp_sd.cpu.compile_loop(loop.inputargs, 
loop.operations,
+                                                    loop.token)
     finally:
         debug_stop("jit-backend")
     metainterp_sd.profiler.end_backend()
@@ -180,27 +174,36 @@
         else:
             loop._ignore_during_counting = True
     metainterp_sd.log("compiled new " + type)
+    #
+    metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, 
type, ops_offset)
+    short = loop.token.short_preamble
+    if short:
+        metainterp_sd.logger_ops.log_short_preamble(short[-1].inputargs,
+                                                    short[-1].operations)
+    #
     if metainterp_sd.warmrunnerdesc is not None:    # for tests
         metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token)
 
 def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations,
                            original_loop_token):
-    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)
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
     try:
-        metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
-                                         original_loop_token)
+        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")
+    #
+    n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
+    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)
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -785,6 +785,8 @@
     def repr_of_descr(self):
         return '<Loop%d>' % self.number
 
+    def dump(self):
+        self.compiled_loop_token.cpu.dump_loop_token(self)
 
 class TreeLoop(object):
     inputargs = None
diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py
--- a/pypy/jit/metainterp/logger.py
+++ b/pypy/jit/metainterp/logger.py
@@ -14,33 +14,33 @@
         self.ts = metainterp_sd.cpu.ts
         self.guard_number = guard_number
 
-    def log_loop(self, inputargs, operations, number=0, type=None):
+    def log_loop(self, inputargs, operations, number=0, type=None, 
ops_offset=None):
         if type is None:
             debug_start("jit-log-noopt-loop")
-            self._log_operations(inputargs, operations)
+            self._log_operations(inputargs, operations, ops_offset)
             debug_stop("jit-log-noopt-loop")
         else:
             debug_start("jit-log-opt-loop")
             debug_print("# Loop", number, ":", type,
                         "with", len(operations), "ops")
-            self._log_operations(inputargs, operations)
+            self._log_operations(inputargs, operations, ops_offset)
             debug_stop("jit-log-opt-loop")
 
-    def log_bridge(self, inputargs, operations, number=-1):
+    def log_bridge(self, inputargs, operations, number=-1, ops_offset=None):
         if number == -1:
             debug_start("jit-log-noopt-bridge")
-            self._log_operations(inputargs, operations)
+            self._log_operations(inputargs, operations, ops_offset)
             debug_stop("jit-log-noopt-bridge")
         else:
             debug_start("jit-log-opt-bridge")
             debug_print("# bridge out of Guard", number,
                         "with", len(operations), "ops")
-            self._log_operations(inputargs, operations)
+            self._log_operations(inputargs, operations, ops_offset)
             debug_stop("jit-log-opt-bridge")
 
     def log_short_preamble(self, inputargs, operations):
         debug_start("jit-log-short-preamble")
-        self._log_operations(inputargs, operations)
+        self._log_operations(inputargs, operations, ops_offset=None)
         debug_stop("jit-log-short-preamble")            
 
     def repr_of_descr(self, descr):
@@ -75,9 +75,11 @@
         else:
             return '?'
 
-    def _log_operations(self, inputargs, operations):
+    def _log_operations(self, inputargs, operations, ops_offset):
         if not have_debug_prints():
             return
+        if ops_offset is None:
+            ops_offset = {}
         memo = {}
         if inputargs is not None:
             args = ", ".join([self.repr_of_arg(memo, arg) for arg in 
inputargs])
@@ -89,6 +91,11 @@
                 reclev = op.getarg(1).getint()
                 debug_print("debug_merge_point('%s', %s)" % (loc, reclev))
                 continue
+            offset = ops_offset.get(op, -1)
+            if offset == -1:
+                s_offset = ""
+            else:
+                s_offset = "+%d: " % offset
             args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in 
range(op.numargs())])
             if op.result is not None:
                 res = self.repr_of_arg(memo, op.result) + " = "
@@ -108,8 +115,11 @@
                                               for arg in op.getfailargs()]) + 
']'
             else:
                 fail_args = ''
-            debug_print(res + op.getopname() +
+            debug_print(s_offset + res + op.getopname() +
                         '(' + args + ')' + fail_args)
+        if ops_offset and None in ops_offset:
+            offset = ops_offset[None]
+            debug_print("+%d: --end of the loop--" % offset)
 
 
 def int_could_be_an_address(x):
diff --git a/pypy/jit/metainterp/test/test_compile.py 
b/pypy/jit/metainterp/test/test_compile.py
--- a/pypy/jit/metainterp/test/test_compile.py
+++ b/pypy/jit/metainterp/test/test_compile.py
@@ -34,7 +34,7 @@
         self.seen.append((inputargs, operations, token))
 
 class FakeLogger(object):
-    def log_loop(self, inputargs, operations, number=0, type=None):
+    def log_loop(self, inputargs, operations, number=0, type=None, 
ops_offset=None):
         pass
 
 class FakeState(object):
diff --git a/pypy/jit/metainterp/test/test_logger.py 
b/pypy/jit/metainterp/test/test_logger.py
--- a/pypy/jit/metainterp/test/test_logger.py
+++ b/pypy/jit/metainterp/test/test_logger.py
@@ -31,10 +31,10 @@
     return log_stream.getvalue()
 
 class Logger(logger.Logger):
-    def log_loop(self, loop, namespace={}):
+    def log_loop(self, loop, namespace={}, ops_offset=None):
         self.namespace = namespace
         return capturing(logger.Logger.log_loop, self,
-                         loop.inputargs, loop.operations)
+                         loop.inputargs, loop.operations, 
ops_offset=ops_offset)
 
     def repr_of_descr(self, descr):
         for k, v in self.namespace.items():
@@ -178,3 +178,27 @@
         output = capturing(bare_logger.log_bridge, [], [], 3)
         assert output.splitlines()[0] == "# bridge out of Guard 3 with 0 ops"
         pure_parse(output)
+
+    def test_ops_offset(self):
+        inp = '''
+        [i0]
+        i1 = int_add(i0, 1)
+        i2 = int_mul(i1, 2)
+        jump(i2)
+        '''
+        loop = pure_parse(inp)
+        ops = loop.operations
+        ops_offset = {
+            ops[0]: 10,
+            ops[2]: 30,
+            None: 40
+            }
+        logger = Logger(self.make_metainterp_sd())
+        output = logger.log_loop(loop, ops_offset=ops_offset)
+        assert output.strip() == """
+[i0]
++10: i2 = int_add(i0, 1)
+i4 = int_mul(i2, 2)
++30: jump(i4)
++40: --end of the loop--
+""".strip()
diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py
--- a/pypy/jit/tool/oparser.py
+++ b/pypy/jit/tool/oparser.py
@@ -312,7 +312,7 @@
                 continue  # a comment or empty line
             newlines.append(line)
         base_indent, inpargs, newlines = self.parse_inpargs(newlines)
-        num, ops = self.parse_ops(base_indent, newlines, 0)
+        num, ops, last_offset = self.parse_ops(base_indent, newlines, 0)
         if num < len(newlines):
             raise ParseError("unexpected dedent at line: %s" % newlines[num])
         loop = ExtendedTreeLoop("loop")
@@ -320,11 +320,13 @@
         loop.token = self.looptoken
         loop.operations = ops
         loop.inputargs = inpargs
+        loop.last_offset = last_offset
         return loop
 
     def parse_ops(self, indent, lines, start):
         num = start
         ops = []
+        last_offset = None
         while num < len(lines):
             line = lines[num]
             if not line.startswith(" " * indent):
@@ -333,9 +335,25 @@
             elif line.startswith(" "*(indent + 1)):
                 raise ParseError("indentation not valid any more")
             else:
-                ops.append(self.parse_next_op(lines[num].strip()))
+                line = line.strip()
+                offset, line = self.parse_offset(line)
+                if line == '--end of the loop--':
+                    last_offset = offset
+                else:
+                    op = self.parse_next_op(line)
+                    if offset:
+                        op.offset = offset
+                    ops.append(op)
                 num += 1
-        return num, ops
+        return num, ops, last_offset
+
+    def parse_offset(self, line):
+        if line.startswith('+'):
+            # it begins with an offset, like: "+10: i1 = int_add(...)"
+            offset, _, line = line.partition(':')
+            offset = int(offset)
+            return offset, line.strip()
+        return None, line
 
     def parse_inpargs(self, lines):
         line = lines[0]
diff --git a/pypy/jit/tool/test/test_oparser.py 
b/pypy/jit/tool/test/test_oparser.py
--- a/pypy/jit/tool/test/test_oparser.py
+++ b/pypy/jit/tool/test/test_oparser.py
@@ -1,7 +1,7 @@
-
+import py
 from pypy.rpython.lltypesystem import lltype, llmemory
 
-from pypy.jit.tool.oparser import parse
+from pypy.jit.tool.oparser import parse, ParseError
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\
      BoxFloat
@@ -203,3 +203,25 @@
     loop = parse(x, nonstrict=True)
     assert loop.inputargs == []
     assert loop.operations[0].getopname() == 'int_add'
+
+def test_offsets():
+    x = """
+    [i0, i1]
+    +10: i2 = int_add(i0, i1)
+    i3 = int_add(i2, 3)
+    """
+    #    +30: --end of the loop--
+    loop = parse(x)
+    assert loop.operations[0].offset == 10
+    assert not hasattr(loop.operations[1], 'offset')
+
+def test_last_offset():
+    x = """
+    [i0, i1]
+    +10: i2 = int_add(i0, i1)
+    i3 = int_add(i2, 3)
+    +30: --end of the loop--
+    """
+    loop = parse(x)
+    assert len(loop.operations) == 2
+    assert loop.last_offset == 30
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to