[pypy-commit] pypy numpy-exp: (alex, arigato, michaelh) Replace hacky bytecode with less-hacky signature objects.
alex_gaynor
noreply at buildbot.pypy.org
Mon May 16 22:42:07 CEST 2011
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: numpy-exp
Changeset: r44218:3944edac9c2d
Date: 2011-05-16 15:51 -0500
http://bitbucket.org/pypy/pypy/changeset/3944edac9c2d/
Log: (alex, arigato, michaelh) Replace hacky bytecode with less-hacky
signature objects.
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -17,9 +17,28 @@
TP = lltype.Array(lltype.Float, hints={'nolength': True})
-numpy_driver = jit.JitDriver(greens = ['bytecode'],
+numpy_driver = jit.JitDriver(greens = ['signature'],
reds = ['result_size', 'i', 'self', 'result'])
+class Signature(object):
+ def __init__(self):
+ self.transitions = {}
+
+ def transition(self, target):
+ if target in self.transitions:
+ return self.transitions[target]
+ self.transitions[target] = new = Signature()
+ return new
+
+def add(v1, v2):
+ return v1 + v2
+def sub(v1, v2):
+ return v1 - v2
+def mul(v1, v2):
+ return v1 * v2
+def div(v1, v2):
+ return v1 / v2
+
class BaseArray(Wrappable):
def __init__(self):
self.invalidates = []
@@ -29,25 +48,34 @@
arr.force_if_needed()
self.invalidates = []
- def _binop_impl(bytecode):
+ def _binop_impl(function):
+ signature = Signature()
def impl(self, space, w_other):
+ new_sig = self.signature.transition(signature)
if isinstance(w_other, BaseArray):
- res = space.wrap(BinOp(bytecode, self, w_other))
+ res = space.wrap(Call2(
+ function,
+ self,
+ w_other,
+ new_sig.transition(w_other.signature)
+ ))
w_other.invalidates.append(res)
else:
- res = space.wrap(BinOp(
- bytecode,
+ w_other = FloatWrapper(space.float_w(w_other))
+ res = space.wrap(Call2(
+ function,
self,
- FloatWrapper(space.float_w(w_other))
+ w_other,
+ new_sig.transition(w_other.signature)
))
self.invalidates.append(res)
return res
- return func_with_new_name(impl, "binop_%s_impl" % bytecode)
+ return func_with_new_name(impl, "binop_%s_impl" % function.__name__)
- descr_add = _binop_impl("a")
- descr_sub = _binop_impl("s")
- descr_mul = _binop_impl("m")
- descr_div = _binop_impl("d")
+ descr_add = _binop_impl(add)
+ descr_sub = _binop_impl(sub)
+ descr_mul = _binop_impl(mul)
+ descr_div = _binop_impl(div)
def get_concrete(self):
raise NotImplementedError
@@ -70,14 +98,12 @@
Intermediate class representing a float literal.
"""
_immutable_fields_ = ["float_value"]
+ signature = Signature()
def __init__(self, float_value):
BaseArray.__init__(self)
self.float_value = float_value
- def bytecode(self):
- return "f"
-
def find_size(self):
raise ValueError
@@ -88,17 +114,18 @@
"""
Class for representing virtual arrays, such as binary ops or ufuncs
"""
- def __init__(self):
+ def __init__(self, signature):
BaseArray.__init__(self)
self.forced_result = None
+ self.signature = signature
def compute(self):
i = 0
- bytecode = self.bytecode()
+ signature = self.signature
result_size = self.find_size()
result = SingleDimArray(result_size)
while i < result_size:
- numpy_driver.jit_merge_point(bytecode=bytecode,
+ numpy_driver.jit_merge_point(signature=signature,
result_size=result_size, i=i,
self=self, result=result)
result.storage[i] = self.eval(i)
@@ -118,24 +145,31 @@
return self.forced_result.eval(i)
return self._eval(i)
+class Call1(VirtualArray):
+ _immutable_fields_ = ["function", "values"]
-class BinOp(VirtualArray):
+ def __init__(self, function, values, signature):
+ VirtualArray.__init__(self, signature)
+ self.function = function
+ self.values = values
+
+ def find_size(self):
+ return self.values.find_size()
+
+ def _eval(self, i):
+ return self.function(self.values.eval(i))
+
+class Call2(VirtualArray):
"""
Intermediate class for performing binary operations.
"""
- _immutable_fields_ = ["opcode", "left", "right"]
- # Hack for test_zjit so the annotator doesn't see the bytecode as constant
- opcode = "?"
-
- def __init__(self, opcode, left, right):
- VirtualArray.__init__(self)
- self.opcode = opcode
+ _immutable_fields_ = ["function", "left", "right"]
+ def __init__(self, function, left, right, signature):
+ VirtualArray.__init__(self, signature)
+ self.function = function
self.left = left
self.right = right
- def bytecode(self):
- return self.opcode + self.left.bytecode() + self.right.bytecode()
-
def find_size(self):
try:
return self.left.find_size()
@@ -145,36 +179,12 @@
def _eval(self, i):
lhs, rhs = self.left.eval(i), self.right.eval(i)
- if self.opcode == "a":
- return lhs + rhs
- elif self.opcode == "s":
- return lhs - rhs
- elif self.opcode == "m":
- return lhs * rhs
- elif self.opcode == "d":
- return lhs / rhs
- else:
- raise NotImplementedError("Don't know opcode %s" % self.opcode)
-
-class Call(VirtualArray):
- _immutable_fields_ = ["function", "values"]
-
- def __init__(self, function, values):
- VirtualArray.__init__(self)
- self.function = function
- self.values = values
-
- def bytecode(self):
- return "c" + self.values.bytecode()
-
- def find_size(self):
- return self.values.find_size()
-
- def _eval(self, i):
- return self.function(self.values.eval(i))
+ return self.function(lhs, rhs)
class SingleDimArray(BaseArray):
+ signature = Signature()
+
def __init__(self, size):
BaseArray.__init__(self)
self.size = size
@@ -185,9 +195,6 @@
def get_concrete(self):
return self
- def bytecode(self):
- return "l"
-
def find_size(self):
return self.size
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -1,12 +1,13 @@
from pypy.interpreter.gateway import unwrap_spec
-from pypy.module.micronumpy.interp_numarray import BaseArray, Call
+from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Signature
from pypy.tool.sourcetools import func_with_new_name
def ufunc(func):
+ signature = Signature()
@unwrap_spec(array=BaseArray)
def impl(space, array):
- w_res = Call(func, array)
+ w_res = Call1(func, array, array.signature.transition(signature))
array.invalidates.append(w_res)
return w_res
return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -1,6 +1,6 @@
from pypy.jit.metainterp.test.support import LLJitMixin
-from pypy.module.micronumpy.interp_numarray import (SingleDimArray, BinOp,
- FloatWrapper, Call)
+from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature,
+ FloatWrapper, Call1, Call2, add, mul)
from pypy.module.micronumpy.interp_ufuncs import negative
@@ -16,10 +16,7 @@
def f(i):
ar = SingleDimArray(i)
- if i:
- v = BinOp('a', ar, ar)
- else:
- v = ar
+ v = Call2(add, ar, ar, Signature())
return v.get_concrete().storage[3]
result = self.meta_interp(f, [5], listops=True, backendopt=True)
@@ -33,10 +30,7 @@
def f(i):
ar = SingleDimArray(i)
- if i:
- v = BinOp('a', ar, FloatWrapper(4.5))
- else:
- v = ar
+ v = Call2(add, ar, FloatWrapper(4.5), Signature())
return v.get_concrete().storage[3]
result = self.meta_interp(f, [5], listops=True, backendopt=True)
@@ -50,8 +44,8 @@
def f(i):
ar = SingleDimArray(i)
- v1 = BinOp('a', ar, FloatWrapper(4.5))
- v2 = BinOp('m', v1, FloatWrapper(4.5))
+ v1 = Call2(add, ar, FloatWrapper(4.5), Signature())
+ v2 = Call2(mul, v1, FloatWrapper(4.5), Signature())
v1.force_if_needed()
return v2.get_concrete().storage[3]
@@ -68,7 +62,7 @@
space = self.space
def f(i):
ar = SingleDimArray(i)
- v1 = BinOp('a', ar, ar)
+ v1 = Call2(add, ar, ar, Signature())
v2 = negative(space, v1)
return v2.get_concrete().storage[3]
@@ -77,4 +71,24 @@
"setarrayitem_raw": 1, "int_add": 1,
"int_lt": 1, "guard_true": 1, "jump": 1,
})
- assert result == f(5)
\ No newline at end of file
+ assert result == f(5)
+
+ def test_appropriate_specialization(self):
+ space = self.space
+ def f(i):
+ add_sig = Signature()
+ mul_sig = Signature()
+ ar = SingleDimArray(i)
+
+ v1 = Call2(add, ar, ar, ar.signature.transition(add_sig))
+ v2 = negative(space, v1)
+ v2.get_concrete()
+
+ for i in xrange(5):
+ v1 = Call2(mul, ar, ar, ar.signature.transition(mul_sig))
+ v2 = negative(space, v1)
+ v2.get_concrete()
+
+ self.meta_interp(f, [5], listops=True, backendopt=True)
+ # This is 3, not 2 because there is a bridge for the exit.
+ self.check_loop_count(3)
\ No newline at end of file
More information about the pypy-commit
mailing list