[pypy-svn] pypy numpy-exp: micronumpy: Bring in hodgestar's float support.
MostAwesomeDude
commits-noreply at bitbucket.org
Wed May 4 18:42:45 CEST 2011
Author: Corbin Simpson <MostAwesomeDude at gmail.com>
Branch: numpy-exp
Changeset: r43889:af8ad6737b5d
Date: 2011-03-25 21:11 -0700
http://bitbucket.org/pypy/pypy/changeset/af8ad6737b5d/
Log: micronumpy: Bring in hodgestar's float support.
Had to be fairly heftily rewritten. Also, enable the tests, fix up
slightly, and make things more readable.
I have a tendency to comment and doc things. Hope this isn't a Bad
Thing.
diff --git a/pypy/module/micronumpy/numarray.py b/pypy/module/micronumpy/numarray.py
--- a/pypy/module/micronumpy/numarray.py
+++ b/pypy/module/micronumpy/numarray.py
@@ -1,7 +1,7 @@
from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
-from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import operationerrfmt
from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec
+from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.rpython.lltypesystem import lltype
from pypy.rlib import jit
@@ -13,21 +13,37 @@
virtualizables = ['frame'])
class ComputationFrame(object):
- _virtualizable2_ = ['valuestackdepth', 'valuestack[*]', 'local_pos',
- 'locals[*]']
+ _virtualizable2_ = ['valuestackdepth', 'valuestack[*]',
+ 'array_pos', 'arrays[*]',
+ 'float_pos', 'floats[*]',
+ ]
- def __init__(self, input):
+ def __init__(self, arrays, floats):
self = jit.hint(self, access_directly=True, fresh_virtualizable=True)
self.valuestackdepth = 0
- self.valuestack = [0.0] * len(input)
- self.locals = input[:]
- self.local_pos = len(input)
+ self.arrays = arrays
+ self.array_pos = len(arrays)
+ self.floats = floats
+ self.float_pos = len(floats)
+ self.valuestack = [0.0] * (len(arrays) + len(floats))
- def getlocal(self):
- p = self.local_pos - 1
+ def reset(self):
+ self.valuestackdepth = 0
+ self.array_pos = len(self.arrays)
+ self.float_pos = len(self.floats)
+
+ def getarray(self):
+ p = self.array_pos - 1
assert p >= 0
- res = self.locals[p]
- self.local_pos = p
+ res = self.arrays[p]
+ self.array_pos = p
+ return res
+
+ def getfloat(self):
+ p = self.float_pos - 1
+ assert p >= 0
+ res = self.floats[p]
+ self.float_pos = p
return res
def popvalue(self):
@@ -41,12 +57,37 @@
self.valuestack[self.valuestackdepth] = v
self.valuestackdepth += 1
-def compute(bytecode, input):
- result_size = input[0].size
+class Code(object):
+ """
+ A chunk of bytecode.
+ """
+
+ def __init__(self, bytecode, arrays, floats):
+ self.bytecode = bytecode
+ self.arrays = arrays
+ self.floats = floats
+
+ def merge(self, code, other):
+ """
+ Merge this bytecode with the other bytecode, using ``code`` as the
+ bytecode instruction for performing the merge.
+ """
+
+ return Code(code + self.bytecode + other.bytecode,
+ self.arrays + other.arrays,
+ self.floats + other.floats)
+
+def compute(code):
+ """
+ Crunch a ``Code`` full of bytecode.
+ """
+
+ bytecode = code.bytecode
+ result_size = code.arrays[0].size
result = SingleDimArray(result_size)
bytecode_pos = len(bytecode) - 1
i = 0
- frame = ComputationFrame(input)
+ frame = ComputationFrame(code.arrays, code.floats)
while i < result_size:
numpy_driver.jit_merge_point(bytecode=bytecode, result=result,
result_size=result_size,
@@ -54,9 +95,8 @@
bytecode_pos=bytecode_pos)
if bytecode_pos == -1:
bytecode_pos = len(bytecode) - 1
- frame.local_pos = len(frame.locals)
+ frame.reset()
result.storage[i] = frame.valuestack[0]
- frame.valuestackdepth = 0
i += 1
numpy_driver.can_enter_jit(bytecode=bytecode, result=result,
result_size=result_size,
@@ -65,15 +105,21 @@
else:
opcode = bytecode[bytecode_pos]
if opcode == 'l':
- val = frame.getlocal().storage[i]
- frame.valuestack[frame.valuestackdepth] = val
- frame.valuestackdepth += 1
+ # Load array.
+ val = frame.getarray().storage[i]
+ frame.pushvalue(val)
+ elif opcode == 'f':
+ # Load float.
+ val = frame.getfloat()
+ frame.pushvalue(val)
elif opcode == 'a':
+ # Add.
b = frame.popvalue()
a = frame.popvalue()
frame.pushvalue(a + b)
else:
- raise NotImplementedError
+ raise NotImplementedError(
+ "Can't handle bytecode instruction %s" % opcode)
bytecode_pos -= 1
return result
@@ -81,37 +127,56 @@
class BaseArray(Wrappable):
def force(self):
- bytecode, stack = self.compile()
+ code = self.compile()
try:
- bytecode = JITCODES[bytecode]
+ code.bytecode = JITCODES[code.bytecode]
except KeyError:
- JITCODES[bytecode] = bytecode
+ JITCODES[code.bytecode] = code.bytecode
# the point of above hacks is to intern the bytecode string
# otherwise we have to compile new assembler each time, which sucks
# (we still have to compile new bytecode, but too bad)
- return compute(bytecode, stack)
+ return compute(code)
def descr_add(self, space, w_other):
- return space.wrap(Add(self, w_other))
+ if isinstance(w_other, BaseArray):
+ return space.wrap(Add(self, w_other))
+ else:
+ return space.wrap(FloatAdd(self, space.float_w(w_other)))
def compile(self):
raise NotImplementedError("abstract base class")
class Add(BaseArray):
+ """
+ Intermediate class for adding arrays.
+ """
+
def __init__(self, left, right):
- assert isinstance(left, BaseArray)
- assert isinstance(right, BaseArray)
self.left = left
self.right = right
def compile(self):
- left_bc, left_stack = self.left.compile()
- right_bc, right_stack = self.right.compile()
- return 'a' + left_bc + right_bc, left_stack + right_stack
+ left_code = self.left.compile()
+ right_code = self.right.compile()
+ return left_code.merge('a', right_code)
+
+class FloatAdd(BaseArray):
+ """
+ Intermediate class for adding an array and a float.
+ """
+
+ def __init__(self, left, right):
+ self.left = left
+ self.right = right
+
+ def compile(self):
+ left_code = self.left.compile()
+ right_code = Code('f', [], [self.right])
+ return left_code.merge('a', right_code)
BaseArray.typedef = TypeDef(
'Operation',
- force=interp2app(BaseArray.force),
+ force = interp2app(BaseArray.force),
__add__ = interp2app(BaseArray.descr_add),
)
@@ -123,7 +188,7 @@
# XXX find out why test_jit explodes with trackign of allocations
def compile(self):
- return "l", [self]
+ return Code('l', [self], [])
@unwrap_spec(item=int)
def descr_getitem(self, space, item):
@@ -173,4 +238,3 @@
__add__ = interp2app(BaseArray.descr_add),
force = interp2app(SingleDimArray.force),
)
-
diff --git a/pypy/module/micronumpy/test/test_jit.py b/pypy/module/micronumpy/test/test_jit.py
--- a/pypy/module/micronumpy/test/test_jit.py
+++ b/pypy/module/micronumpy/test/test_jit.py
@@ -1,6 +1,4 @@
-
-from pypy.module.micronumpy.numarray import SingleDimArray, Add
-from pypy.conftest import gettestobjspace
+from pypy.module.micronumpy.numarray import SingleDimArray, Add, FloatAdd
from pypy.jit.metainterp.test.test_basic import LLJitMixin
class FakeSpace(object):
@@ -21,8 +19,25 @@
v = ar
return v.force().storage[3]
- self.meta_interp(f, [5], listops=True, backendopt=True)
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
self.check_loops({'getarrayitem_raw': 2, 'float_add': 1,
'setarrayitem_raw': 1, 'int_add': 1,
'int_lt': 1, 'guard_true': 1, 'jump': 1})
-
+ assert result == f(5)
+
+ def test_floatadd(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ if i:
+ v = FloatAdd(ar, 4.5)
+ else:
+ v = ar
+ return v.force().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_gc": 2, "float_add": 2,
+ "setarrayitem_gc": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1})
+ assert result == f(5)
diff --git a/pypy/module/micronumpy/test/test_numpy.py b/pypy/module/micronumpy/test/test_numpy.py
--- a/pypy/module/micronumpy/test/test_numpy.py
+++ b/pypy/module/micronumpy/test/test_numpy.py
@@ -25,9 +25,17 @@
b = b.force()
assert b[2] == 2 + 2
+ def test_floatadd(self):
+ from numpy import array
+ a = array(range(5))
+ b = a + 5
+ b = b.force()
+ for i in range(5):
+ assert b[i] == i + 5
+
+
class AppTestNumpy(object):
def setup_class(cls):
- py.test.skip("skip")
cls.space = gettestobjspace(usemodules=('micronumpy',))
def test_zeroes(self):
@@ -67,7 +75,6 @@
class AppTestMultiDim(object):
def setup_class(cls):
- py.test.skip("skip")
cls.space = gettestobjspace(usemodules=('micronumpy',))
def test_multidim(self):
More information about the Pypy-commit
mailing list