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