Author: Carl Friedrich Bolz <[email protected]>
Branch: applevel-unroll-safe
Changeset: r84976:b2124aa81410
Date: 2016-06-06 17:17 +0200
http://bitbucket.org/pypy/pypy/changeset/b2124aa81410/
Log: experimental hack: implement @unroll_safe at app-level
diff --git a/lib-python/2.7/opcode.py b/lib-python/2.7/opcode.py
--- a/lib-python/2.7/opcode.py
+++ b/lib-python/2.7/opcode.py
@@ -194,5 +194,6 @@
def_op('CALL_METHOD', 202) # #args not including 'self'
def_op('BUILD_LIST_FROM_ARG', 203)
jrel_op('JUMP_IF_NOT_DEBUG', 204) # jump over assert statements
+jabs_op('JUMP_ABSOLUTE_UNROLL', 205) # ""
del def_op, name_op, jrel_op, jabs_op
diff --git a/pypy/interpreter/astcompiler/assemble.py
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -657,6 +657,7 @@
ops.JUMP_FORWARD: 0,
ops.JUMP_ABSOLUTE: 0,
+ ops.JUMP_ABSOLUTE_UNROLL: 0,
ops.JUMP_IF_TRUE_OR_POP: 0,
ops.JUMP_IF_FALSE_OR_POP: 0,
ops.POP_JUMP_IF_TRUE: -1,
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -198,6 +198,8 @@
return next_instr
elif opcode == opcodedesc.JUMP_ABSOLUTE.index:
return self.jump_absolute(oparg, ec)
+ elif opcode == opcodedesc.JUMP_ABSOLUTE_UNROLL.index:
+ return self.jump_absolute_unroll(oparg, ec)
elif opcode == opcodedesc.BREAK_LOOP.index:
next_instr = self.BREAK_LOOP(oparg, next_instr)
elif opcode == opcodedesc.CONTINUE_LOOP.index:
@@ -1055,6 +1057,10 @@
check_nonneg(jumpto)
return jumpto
+ def jump_absolute_unroll(self, jumpto, ec):
+ check_nonneg(jumpto)
+ return jumpto
+
def JUMP_FORWARD(self, jumpby, next_instr):
next_instr += jumpby
return next_instr
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -59,6 +59,7 @@
class Module(MixedModule):
appleveldefs = {
+ '_unroll_safe' : 'app_magic._unroll_safe',
}
interpleveldefs = {
@@ -90,7 +91,7 @@
'save_module_content_for_future_reload':
'interp_magic.save_module_content_for_future_reload',
'decode_long' : 'interp_magic.decode_long',
- '_promote' : 'interp_magic._promote',
+ '_promote' : 'interp_magic._promote',
}
if sys.platform == 'win32':
interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/app_magic.py
b/pypy/module/__pypy__/app_magic.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/app_magic.py
@@ -0,0 +1,42 @@
+
+
+def _unroll_safe(func):
+ """ Decorator to mark a function as unroll-safe, meaning the JIT will not
+ trace any of the loops in the function. Instead, the loops will be unrolled
+ fully into the caller.
+
+ This function is experimental.
+ """
+ # bit of a hack: replace JUMP_ABSOLUTE bytecode with JUMP_ABSOLUTE_UNROLL,
+ # which will not trigger jitting
+ from opcode import opname, HAVE_ARGUMENT, EXTENDED_ARG, opmap
+ from types import CodeType, FunctionType
+ code = list(func.func_code.co_code)
+ n = len(code)
+ i = 0
+ replaced = False
+ while i < n:
+ orig_i = i
+ c = code[i]
+ op = ord(c)
+ i = i+1
+ if op >= HAVE_ARGUMENT:
+ i = i+2
+ if op == opmap['JUMP_ABSOLUTE']:
+ replaced = True
+ code[orig_i] = chr(opmap['JUMP_ABSOLUTE_UNROLL'])
+ if not replaced:
+ raise TypeError("function %s does not contain a loop" % func)
+ new_codestring = "".join(code)
+ code = func.func_code
+ new_code = CodeType(code.co_argcount, code.co_nlocals, code.co_stacksize,
+ code.co_flags, new_codestring, code.co_consts, code.co_names,
+ code.co_varnames, code.co_filename, code.co_name,
code.co_firstlineno,
+ code.co_lnotab, code.co_freevars, code.co_cellvars)
+ f = FunctionType(new_code, func.func_globals, func.func_name,
+ func.func_defaults, func.func_closure)
+ if func.func_dict:
+ f.func_dict = {}
+ f.func_dict.update(func.func_dict)
+ f.func_doc = func.func_doc
+ return f
diff --git a/pypy/module/__pypy__/test/test_magic.py
b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -60,3 +60,22 @@
pass
a = A()
assert _promote(a) is a
+
+ def test_unroll_safe(self):
+ from __pypy__ import _unroll_safe
+ import opcode
+ def f(x):
+ r = 0
+ for i in range(x):
+ r += i
+ return r
+ assert chr(opcode.opmap['JUMP_ABSOLUTE_UNROLL']) not in
f.func_code.co_code
+ f1 = _unroll_safe(f)
+ assert chr(opcode.opmap['JUMP_ABSOLUTE_UNROLL']) in
f1.func_code.co_code
+ assert f(10) == f1(10)
+
+ def decorate_no_loop():
+ @_unroll_safe
+ def f(x):
+ pass
+ raises(TypeError, decorate_no_loop)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit