[pypy-commit] pypy default: (fijal, agaynor, tons of other people) merge numpy-exp.
fijal
noreply at buildbot.pypy.org
Tue May 17 13:28:04 CEST 2011
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch:
Changeset: r44237:335d1f0d4d8f
Date: 2011-05-17 13:37 +0200
http://bitbucket.org/pypy/pypy/changeset/335d1f0d4d8f/
Log: (fijal, agaynor, tons of other people) merge numpy-exp.
This brings a start to numpy module being developed on trunk (and
enabled by default) with JIT support.
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -33,7 +33,7 @@
"struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO",
"thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
"_bisect", "binascii", "_multiprocessing", '_warnings',
- "_collections", "_multibytecodec"]
+ "_collections", "_multibytecodec", 'micronumpy']
))
translation_modules = default_modules.copy()
diff --git a/pypy/conftest.py b/pypy/conftest.py
--- a/pypy/conftest.py
+++ b/pypy/conftest.py
@@ -46,6 +46,10 @@
group.addoption('-P', '--platform', action="callback", type="string",
default="host", callback=_set_platform,
help="set up tests to use specified platform as compile/run target")
+ group = parser.getgroup("JIT options")
+ group.addoption('--viewloops', action="store_true",
+ default=False, dest="viewloops",
+ help="show only the compiled loops")
def pytest_sessionstart():
# have python subprocesses avoid startup customizations by default
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -209,7 +209,7 @@
llimpl.compile_add_fail_arg(c, var2index[box])
else:
llimpl.compile_add_fail_arg(c, -1)
-
+
x = op.result
if x is not None:
if isinstance(x, history.BoxInt):
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
@@ -330,7 +330,7 @@
if not we_are_translated():
self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
self.assembler.regalloc_perform_llong(op, arglocs, result_loc)
-
+
def PerformMath(self, op, arglocs, result_loc):
if not we_are_translated():
self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
@@ -676,7 +676,7 @@
loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(0))
self.Perform(op, [loc0], loc0)
self.xrm.possibly_free_var(op.getarg(0))
-
+
consider_float_neg = _consider_float_unary_op
consider_float_abs = _consider_float_unary_op
@@ -764,7 +764,7 @@
loc1 = self.rm.make_sure_var_in_reg(op.getarg(1))
self.PerformLLong(op, [loc1], loc0)
self.rm.possibly_free_vars_for_op(op)
-
+
def _consider_math_sqrt(self, op):
loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(1))
self.PerformMath(op, [loc0], loc0)
@@ -1271,12 +1271,12 @@
xmmtmploc = self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp)
# Part about non-floats
# XXX we don't need a copy, we only just the original list
- src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs())
+ src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs())
if op.getarg(i).type != FLOAT]
assert tmploc not in nonfloatlocs
dst_locations1 = [loc for loc in nonfloatlocs if loc is not None]
# Part about floats
- src_locations2 = [self.loc(op.getarg(i)) for i in range(op.numargs())
+ src_locations2 = [self.loc(op.getarg(i)) for i in range(op.numargs())
if op.getarg(i).type == FLOAT]
dst_locations2 = [loc for loc in floatlocs if loc is not None]
remap_frame_layout_mixed(assembler,
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -508,7 +508,9 @@
LEA = _binaryop('LEA')
MOVSD = _binaryop('MOVSD')
+ MOVAPD = _binaryop('MOVAPD')
ADDSD = _binaryop('ADDSD')
+ ADDPD = _binaryop('ADDPD')
SUBSD = _binaryop('SUBSD')
MULSD = _binaryop('MULSD')
DIVSD = _binaryop('DIVSD')
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -690,12 +690,17 @@
define_modrm_modes('MOVSD_x*', ['\xF2', rex_nw, '\x0F\x10', register(1,8)], regtype='XMM')
define_modrm_modes('MOVSD_*x', ['\xF2', rex_nw, '\x0F\x11', register(2,8)], regtype='XMM')
+define_modrm_modes('MOVAPD_x*', ['\x66', rex_nw, '\x0F\x28', register(1,8)],
+ regtype='XMM')
+define_modrm_modes('MOVAPD_*x', ['\x66', rex_nw, '\x0F\x29', register(2,8)],
+ regtype='XMM')
define_modrm_modes('SQRTSD_x*', ['\xF2', rex_nw, '\x0F\x51', register(1,8)], regtype='XMM')
#define_modrm_modes('XCHG_r*', [rex_w, '\x87', register(1, 8)])
define_modrm_modes('ADDSD_x*', ['\xF2', rex_nw, '\x0F\x58', register(1, 8)], regtype='XMM')
+define_modrm_modes('ADDPD_x*', ['\x66', rex_nw, '\x0F\x58', register(1, 8)], regtype='XMM')
define_modrm_modes('SUBSD_x*', ['\xF2', rex_nw, '\x0F\x5C', register(1, 8)], regtype='XMM')
define_modrm_modes('MULSD_x*', ['\xF2', rex_nw, '\x0F\x59', register(1, 8)], regtype='XMM')
define_modrm_modes('DIVSD_x*', ['\xF2', rex_nw, '\x0F\x5E', register(1, 8)], regtype='XMM')
diff --git a/pypy/jit/conftest.py b/pypy/jit/conftest.py
--- a/pypy/jit/conftest.py
+++ b/pypy/jit/conftest.py
@@ -5,7 +5,4 @@
group.addoption('--slow', action="store_true",
default=False, dest="run_slow_tests",
help="run all the compiled tests (instead of just a few)")
- group.addoption('--viewloops', action="store_true",
- default=False, dest="viewloops",
- help="show only the compiled loops")
diff --git a/pypy/jit/metainterp/test/test_ztranslation.py b/pypy/jit/metainterp/test/test_ztranslation.py
--- a/pypy/jit/metainterp/test/test_ztranslation.py
+++ b/pypy/jit/metainterp/test/test_ztranslation.py
@@ -2,7 +2,7 @@
from pypy.jit.metainterp.warmspot import rpython_ll_meta_interp, ll_meta_interp
from pypy.jit.backend.llgraph import runner
from pypy.rlib.jit import JitDriver, unroll_parameters
-from pypy.rlib.jit import PARAMETERS, dont_look_inside
+from pypy.rlib.jit import PARAMETERS, dont_look_inside, hint
from pypy.jit.metainterp.jitprof import Profiler
from pypy.rpython.lltypesystem import lltype, llmemory
@@ -24,10 +24,21 @@
# - string concatenation, slicing and comparison
class Frame(object):
- _virtualizable2_ = ['i']
+ _virtualizable2_ = ['l[*]']
def __init__(self, i):
+ self = hint(self, fresh_virtualizable=True,
+ access_directly=True)
+ self.l = [i]
+
+ class OtherFrame(object):
+ _virtualizable2_ = ['i', 'l[*]']
+
+ def __init__(self, i):
+ self = hint(self, fresh_virtualizable=True,
+ access_directly=True)
self.i = i
+ self.l = [float(i)]
class OtherFrame(object):
_virtualizable2_ = ['i']
@@ -57,13 +68,13 @@
jitdriver.set_param("trace_eagerness", 2)
total = 0
frame = Frame(i)
- while frame.i > 3:
+ while frame.l[0] > 3:
jitdriver.can_enter_jit(frame=frame, total=total)
jitdriver.jit_merge_point(frame=frame, total=total)
- total += frame.i
- if frame.i >= 20:
- frame.i -= 2
- frame.i -= 1
+ total += frame.l[0]
+ if frame.l[0] >= 20:
+ frame.l[0] -= 2
+ frame.l[0] -= 1
return total * 10
#
myjitdriver2 = JitDriver(greens = ['g'], reds = ['m', 's', 'f'],
@@ -71,25 +82,30 @@
def f2(g, m, x):
s = ""
f = OtherFrame(x)
+ float_s = 0.0
while m > 0:
- myjitdriver2.can_enter_jit(g=g, m=m, f=f, s=s)
- myjitdriver2.jit_merge_point(g=g, m=m, f=f, s=s)
+ myjitdriver2.can_enter_jit(g=g, m=m, f=f, s=s, float_s=float_s)
+ myjitdriver2.jit_merge_point(g=g, m=m, f=f, s=s,
+ float_s=float_s)
s += 'xy'
if s[:2] == 'yz':
return -666
m -= 1
f.i += 3
+ float_s += f.l[0]
return f.i
#
def main(i, j):
return f(i) - f2(i+j, i, j)
res = ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass,
- type_system=self.type_system)
+ type_system=self.type_system,
+ listops=True)
assert res == main(40, 5)
res = rpython_ll_meta_interp(main, [40, 5],
CPUClass=self.CPUClass,
type_system=self.type_system,
- ProfilerClass=Profiler)
+ ProfilerClass=Profiler,
+ listops=True)
assert res == main(40, 5)
def test_external_exception_handling_translates(self):
diff --git a/pypy/jit/metainterp/typesystem.py b/pypy/jit/metainterp/typesystem.py
--- a/pypy/jit/metainterp/typesystem.py
+++ b/pypy/jit/metainterp/typesystem.py
@@ -5,7 +5,7 @@
from pypy.rpython.annlowlevel import cast_instance_to_base_obj
from pypy.jit.metainterp import history
from pypy.jit.codewriter import heaptracker
-from pypy.rlib.objectmodel import r_dict
+from pypy.rlib.objectmodel import r_dict, specialize
def deref(T):
if isinstance(T, lltype.Ptr):
@@ -97,12 +97,15 @@
def cast_to_baseclass(self, value):
return lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), value)
+ @specialize.ll()
def getlength(self, array):
return len(array)
+ @specialize.ll()
def getarrayitem(self, array, i):
return array[i]
+ @specialize.ll()
def setarrayitem(self, array, i, newvalue):
array[i] = newvalue
@@ -201,12 +204,15 @@
def cast_to_baseclass(self, value):
return ootype.cast_from_object(ootype.ROOT, value)
+ @specialize.ll()
def getlength(self, array):
return array.ll_length()
+ @specialize.ll()
def getarrayitem(self, array, i):
return array.ll_getitem_fast(i)
+ @specialize.ll()
def setarrayitem(self, array, i, newvalue):
array.ll_setitem_fast(i, newvalue)
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -42,6 +42,7 @@
config.objspace.usemodules._lsprof = True
#
config.objspace.usemodules._ffi = True
+config.objspace.usemodules.micronumpy = True
#
set_pypy_opt_level(config, level='jit')
diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py
--- a/pypy/jit/tl/pypyjit_demo.py
+++ b/pypy/jit/tl/pypyjit_demo.py
@@ -1,11 +1,10 @@
try:
- def f(x):
- i = 0
- while i < x:
- range(i)
- i += 1
- f(10000)
+ import numpy
+ a = numpy.array(range(10))
+ b = a + a + a
+ print b[3]
+
except Exception, e:
print "Exception: ", type(e)
print e
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -1,13 +1,23 @@
-from pypy.interpreter.mixedmodule import MixedModule
+from pypy.interpreter.mixedmodule import MixedModule
class Module(MixedModule):
applevel_name = 'numpy'
-
+
interpleveldefs = {
- 'zeros' : 'numarray.zeros',
- 'minimum' : 'ufunc.minimum',
- }
+ 'array': 'interp_numarray.SingleDimArray',
+ 'zeros': 'interp_numarray.zeros',
+
+ # ufuncs
+ 'absolute': 'interp_ufuncs.absolute',
+ 'copysign': 'interp_ufuncs.copysign',
+ 'exp': 'interp_ufuncs.exp',
+ 'maximum': 'interp_ufuncs.maximum',
+ 'minimum': 'interp_ufuncs.minimum',
+ 'negative': 'interp_ufuncs.negative',
+ 'reciprocal': 'interp_ufuncs.reciprocal',
+ 'sign': 'interp_ufuncs.sign',
+ }
appleveldefs = {}
diff --git a/pypy/module/micronumpy/bench/add.py b/pypy/module/micronumpy/bench/add.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/bench/add.py
@@ -0,0 +1,10 @@
+
+import numpy
+
+def f():
+ a = numpy.zeros(10000000)
+ a = a + a + a + a + a
+ # To ensure that the computation isn't totally optimized away.
+ a[0] = 3.0
+
+f()
diff --git a/pypy/module/micronumpy/bench/iterate.py b/pypy/module/micronumpy/bench/iterate.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/bench/iterate.py
@@ -0,0 +1,11 @@
+
+import numpy
+
+def f():
+ sum = 0
+ a = numpy.zeros(10000000)
+ for i in range(10000000):
+ sum += a[i]
+ return sum
+
+f()
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -0,0 +1,257 @@
+from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
+from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rlib import jit
+from pypy.rpython.lltypesystem import lltype
+from pypy.tool.sourcetools import func_with_new_name
+
+
+def dummy1(v):
+ assert isinstance(v, float)
+ return v
+
+def dummy2(v):
+ assert isinstance(v, float)
+ return v
+
+TP = lltype.Array(lltype.Float, hints={'nolength': True})
+
+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 = []
+
+ def invalidated(self):
+ for arr in self.invalidates:
+ arr.force_if_needed()
+ self.invalidates = []
+
+ def _binop_impl(function):
+ signature = Signature()
+ def impl(self, space, w_other):
+ new_sig = self.signature.transition(signature)
+ if isinstance(w_other, BaseArray):
+ res = Call2(
+ function,
+ self,
+ w_other,
+ new_sig.transition(w_other.signature)
+ )
+ w_other.invalidates.append(res)
+ else:
+ w_other = FloatWrapper(space.float_w(w_other))
+ res = Call2(
+ function,
+ self,
+ w_other,
+ new_sig.transition(w_other.signature)
+ )
+ self.invalidates.append(res)
+ return space.wrap(res)
+ return func_with_new_name(impl, "binop_%s_impl" % function.__name__)
+
+ 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
+
+ def descr_len(self, space):
+ return self.get_concrete().descr_len(space)
+
+ @unwrap_spec(item=int)
+ def descr_getitem(self, space, item):
+ return self.get_concrete().descr_getitem(space, item)
+
+ @unwrap_spec(item=int, value=float)
+ def descr_setitem(self, space, item, value):
+ self.invalidated()
+ return self.get_concrete().descr_setitem(space, item, value)
+
+
+class FloatWrapper(BaseArray):
+ """
+ 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 find_size(self):
+ raise ValueError
+
+ def eval(self, i):
+ return self.float_value
+
+class VirtualArray(BaseArray):
+ """
+ Class for representing virtual arrays, such as binary ops or ufuncs
+ """
+ def __init__(self, signature):
+ BaseArray.__init__(self)
+ self.forced_result = None
+ self.signature = signature
+
+ def compute(self):
+ i = 0
+ signature = self.signature
+ result_size = self.find_size()
+ result = SingleDimArray(result_size)
+ while i < result_size:
+ numpy_driver.jit_merge_point(signature=signature,
+ result_size=result_size, i=i,
+ self=self, result=result)
+ result.storage[i] = self.eval(i)
+ i += 1
+ return result
+
+ def force_if_needed(self):
+ if self.forced_result is None:
+ self.forced_result = self.compute()
+
+ def get_concrete(self):
+ self.force_if_needed()
+ return self.forced_result
+
+ def eval(self, i):
+ if self.forced_result is not None:
+ return self.forced_result.eval(i)
+ return self._eval(i)
+
+class Call1(VirtualArray):
+ _immutable_fields_ = ["function", "values"]
+
+ 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_ = ["function", "left", "right"]
+ def __init__(self, function, left, right, signature):
+ VirtualArray.__init__(self, signature)
+ self.function = function
+ self.left = left
+ self.right = right
+
+ def find_size(self):
+ try:
+ return self.left.find_size()
+ except ValueError:
+ pass
+ return self.right.find_size()
+
+ def _eval(self, i):
+ lhs, rhs = self.left.eval(i), self.right.eval(i)
+ return self.function(lhs, rhs)
+
+
+class SingleDimArray(BaseArray):
+ signature = Signature()
+
+ def __init__(self, size):
+ BaseArray.__init__(self)
+ self.size = size
+ self.storage = lltype.malloc(TP, size, zero=True,
+ flavor='raw', track_allocation=False)
+ # XXX find out why test_zjit explodes with trackign of allocations
+
+ def get_concrete(self):
+ return self
+
+ def find_size(self):
+ return self.size
+
+ def eval(self, i):
+ return self.storage[i]
+
+ def getindex(self, space, item):
+ if item >= self.size:
+ raise operationerrfmt(space.w_IndexError,
+ '%d above array size', item)
+ if item < 0:
+ item += self.size
+ if item < 0:
+ raise operationerrfmt(space.w_IndexError,
+ '%d below zero', item)
+ return item
+
+ def descr_len(self, space):
+ return space.wrap(self.size)
+
+ @unwrap_spec(item=int)
+ def descr_getitem(self, space, item):
+ item = self.getindex(space, item)
+ return space.wrap(self.storage[item])
+
+ @unwrap_spec(item=int, value=float)
+ def descr_setitem(self, space, item, value):
+ item = self.getindex(space, item)
+ self.invalidated()
+ self.storage[item] = value
+
+ def __del__(self):
+ lltype.free(self.storage, flavor='raw')
+
+def descr_new_numarray(space, w_type, w_size_or_iterable):
+ l = space.listview(w_size_or_iterable)
+ arr = SingleDimArray(len(l))
+ i = 0
+ for w_elem in l:
+ arr.storage[i] = space.float_w(space.float(w_elem))
+ i += 1
+ return space.wrap(arr)
+
+ at unwrap_spec(ObjSpace, int)
+def zeros(space, size):
+ return space.wrap(SingleDimArray(size))
+
+
+BaseArray.typedef = TypeDef(
+ 'numarray',
+ __new__ = interp2app(descr_new_numarray),
+ __len__ = interp2app(BaseArray.descr_len),
+ __getitem__ = interp2app(BaseArray.descr_getitem),
+ __setitem__ = interp2app(BaseArray.descr_setitem),
+
+ __add__ = interp2app(BaseArray.descr_add),
+ __sub__ = interp2app(BaseArray.descr_sub),
+ __mul__ = interp2app(BaseArray.descr_mul),
+ __div__ = interp2app(BaseArray.descr_div),
+)
\ No newline at end of file
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -0,0 +1,63 @@
+import math
+
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature
+from pypy.rlib import rfloat
+from pypy.tool.sourcetools import func_with_new_name
+
+
+def ufunc(func):
+ signature = Signature()
+ @unwrap_spec(array=BaseArray)
+ def impl(space, 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__)
+
+def ufunc2(func):
+ signature = Signature()
+ @unwrap_spec(larray=BaseArray, rarray=BaseArray)
+ def impl(space, larray, rarray):
+ new_sig = larray.signature.transition(signature).transition(rarray.signature)
+ w_res = Call2(func, larray, rarray, new_sig)
+ larray.invalidates.append(w_res)
+ rarray.invalidates.append(w_res)
+ return w_res
+ return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
+
+ at ufunc
+def absolute(value):
+ return abs(value)
+
+ at ufunc2
+def copysign(lvalue, rvalue):
+ return rfloat.copysign(lvalue, rvalue)
+
+ at ufunc
+def exp(value):
+ return math.exp(value)
+
+ at ufunc2
+def maximum(lvalue, rvalue):
+ return max(lvalue, rvalue)
+
+ at ufunc2
+def minimum(lvalue, rvalue):
+ return min(lvalue, rvalue)
+
+ at ufunc
+def negative(value):
+ return -value
+
+ at ufunc
+def reciprocal(value):
+ if value == 0.0:
+ return rfloat.copysign(rfloat.INFINITY, value)
+ return 1.0 / value
+
+ at ufunc
+def sign(value):
+ if value == 0.0:
+ return 0.0
+ return rfloat.copysign(1.0, value)
\ No newline at end of file
diff --git a/pypy/module/micronumpy/numarray.py b/pypy/module/micronumpy/numarray.py
deleted file mode 100644
--- a/pypy/module/micronumpy/numarray.py
+++ /dev/null
@@ -1,123 +0,0 @@
-
-from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
-from pypy.rlib.debug import make_sure_not_resized
-
-class BaseNumArray(Wrappable):
- pass
-
-class NumArray(BaseNumArray):
- def __init__(self, space, dim, dtype):
- self.dim = dim
- self.space = space
- # ignore dtype for now
- self.storage = [0] * dim
- make_sure_not_resized(self.storage)
-
- @unwrap_spec(index=int)
- def descr_getitem(self, index):
- space = self.space
- try:
- return space.wrap(self.storage[index])
- except IndexError:
- raise OperationError(space.w_IndexError,
- space.wrap("list index out of range"))
-
- @unwrap_spec(index=int, value=int)
- def descr_setitem(self, index, value):
- space = self.space
- try:
- self.storage[index] = value
- except IndexError:
- raise OperationError(space.w_IndexError,
- space.wrap("list index out of range"))
- return space.w_None
-
- def descr_len(self):
- return self.space.wrap(len(self.storage))
-
-NumArray.typedef = TypeDef(
- 'NumArray',
- __getitem__ = interp2app(NumArray.descr_getitem),
- __setitem__ = interp2app(NumArray.descr_setitem),
- __len__ = interp2app(NumArray.descr_len),
-)
-
-def compute_pos(space, indexes, dim):
- current = 1
- pos = 0
- for i in range(len(indexes)):
- index = indexes[i]
- d = dim[i]
- if index >= d or index <= -d - 1:
- raise OperationError(space.w_IndexError,
- space.wrap("invalid index"))
- if index < 0:
- index = d + index
- pos += index * current
- current *= d
- return pos
-
-class MultiDimArray(BaseNumArray):
- def __init__(self, space, dim, dtype):
- self.dim = dim
- self.space = space
- # ignore dtype for now
- size = 1
- for el in dim:
- size *= el
- self.storage = [0] * size
- make_sure_not_resized(self.storage)
-
- def _unpack_indexes(self, space, w_index):
- indexes = [space.int_w(w_i) for w_i in space.fixedview(w_index)]
- if len(indexes) != len(self.dim):
- raise OperationError(space.w_IndexError, space.wrap(
- 'Wrong index'))
- return indexes
-
- def descr_getitem(self, w_index):
- space = self.space
- indexes = self._unpack_indexes(space, w_index)
- pos = compute_pos(space, indexes, self.dim)
- return space.wrap(self.storage[pos])
-
- @unwrap_spec(value=int)
- def descr_setitem(self, w_index, value):
- space = self.space
- indexes = self._unpack_indexes(space, w_index)
- pos = compute_pos(space, indexes, self.dim)
- self.storage[pos] = value
- return space.w_None
-
- def descr_len(self):
- return self.space.wrap(self.dim[0])
-
-MultiDimArray.typedef = TypeDef(
- 'NumArray',
- __getitem__ = interp2app(MultiDimArray.descr_getitem),
- __setitem__ = interp2app(MultiDimArray.descr_setitem),
- __len__ = interp2app(MultiDimArray.descr_len),
-)
-
-def unpack_dim(space, w_dim):
- if space.is_true(space.isinstance(w_dim, space.w_int)):
- return [space.int_w(w_dim)]
- dim_w = space.fixedview(w_dim)
- return [space.int_w(w_i) for w_i in dim_w]
-
-def unpack_dtype(space, w_dtype):
- if space.is_w(w_dtype, space.w_int):
- return 'i'
- else:
- raise NotImplementedError
-
-def zeros(space, w_dim, w_dtype):
- dim = unpack_dim(space, w_dim)
- dtype = unpack_dtype(space, w_dtype)
- if len(dim) == 1:
- return space.wrap(NumArray(space, dim[0], dtype))
- else:
- return space.wrap(MultiDimArray(space, dim, dtype))
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -0,0 +1,19 @@
+from pypy.conftest import gettestobjspace
+from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper
+
+
+class BaseNumpyAppTest(object):
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=('micronumpy',))
+
+
+class TestSignature(object):
+ def test_binop_signature(self, space):
+ ar = SingleDimArray(10)
+ v1 = ar.descr_add(space, ar)
+ v2 = ar.descr_add(space, FloatWrapper(2.0))
+ assert v1.signature is not v2.signature
+ v3 = ar.descr_add(space, FloatWrapper(1.0))
+ assert v2.signature is v3.signature
+ v4 = ar.descr_add(space, ar)
+ assert v1.signature is v4.signature
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -0,0 +1,141 @@
+import py
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestNumArray(BaseNumpyAppTest):
+ def test_type(self):
+ from numpy import array
+ ar = array(range(5))
+ assert type(ar) is type(ar + ar)
+
+ def test_init(self):
+ from numpy import zeros
+ a = zeros(15)
+ # Check that storage was actually zero'd.
+ assert a[10] == 0.0
+ # And check that changes stick.
+ a[13] = 5.3
+ assert a[13] == 5.3
+
+ def test_iterator_init(self):
+ from numpy import array
+ a = array(range(5))
+ assert a[3] == 3
+
+ def test_getitem(self):
+ from numpy import array
+ a = array(range(5))
+ raises(IndexError, "a[5]")
+ a = a + a
+ raises(IndexError, "a[5]")
+ assert a[-1] == 8
+ raises(IndexError, "a[-6]")
+
+ def test_setitem(self):
+ from numpy import array
+ a = array(range(5))
+ a[-1] = 5.0
+ assert a[4] == 5.0
+ raises(IndexError, "a[5] = 0.0")
+ raises(IndexError, "a[-6] = 3.0")
+
+ def test_len(self):
+ from numpy import array
+ a = array(range(5))
+ assert len(a) == 5
+ assert len(a + a) == 5
+
+ def test_add(self):
+ from numpy import array
+ a = array(range(5))
+ b = a + a
+ for i in range(5):
+ assert b[i] == i + i
+
+ def test_add_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array(reversed(range(5)))
+ c = a + b
+ for i in range(5):
+ assert c[i] == 4
+
+ def test_add_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a + 5
+ for i in range(5):
+ assert b[i] == i + 5
+
+ def test_subtract(self):
+ from numpy import array
+ a = array(range(5))
+ b = a - a
+ for i in range(5):
+ assert b[i] == 0
+
+ def test_subtract_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array([1, 1, 1, 1, 1])
+ c = a - b
+ for i in range(5):
+ assert c[i] == i - 1
+
+ def test_subtract_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a - 5
+ for i in range(5):
+ assert b[i] == i - 5
+
+ def test_mul(self):
+ from numpy import array
+ a = array(range(5))
+ b = a * a
+ for i in range(5):
+ assert b[i] == i * i
+
+ def test_mul_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a * 5
+ for i in range(5):
+ assert b[i] == i * 5
+
+ def test_div(self):
+ from numpy import array
+ a = array(range(1, 6))
+ b = a / a
+ for i in range(5):
+ assert b[i] == 1
+
+ def test_div_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array([2, 2, 2, 2, 2])
+ c = a / b
+ for i in range(5):
+ assert c[i] == i / 2.0
+
+ def test_div_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a / 5.0
+ for i in range(5):
+ assert b[i] == i / 5.0
+
+ def test_auto_force(self):
+ from numpy import array
+ a = array(range(5))
+ b = a - 1
+ a[2] = 3
+ for i in range(5):
+ assert b[i] == i - 1
+
+ a = array(range(5))
+ b = a + a
+ c = b + b
+ b[1] = 5
+ assert c[1] == 4
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_numpy.py b/pypy/module/micronumpy/test/test_numpy.py
deleted file mode 100644
--- a/pypy/module/micronumpy/test/test_numpy.py
+++ /dev/null
@@ -1,65 +0,0 @@
-
-from pypy.conftest import gettestobjspace
-
-class AppTestNumpy(object):
- def setup_class(cls):
- cls.space = gettestobjspace(usemodules=('micronumpy',))
-
- def test_zeroes(self):
- from numpy import zeros
- ar = zeros(3, dtype=int)
- assert ar[0] == 0
-
- def test_setitem_getitem(self):
- from numpy import zeros
- ar = zeros(8, dtype=int)
- assert ar[0] == 0
- ar[1] = 3
- assert ar[1] == 3
- raises((TypeError, ValueError), ar.__getitem__, 'xyz')
- raises(IndexError, ar.__getitem__, 38)
- assert ar[-2] == 0
- assert ar[-7] == 3
- assert len(ar) == 8
-
- def test_minimum(self):
- from numpy import zeros, minimum
- ar = zeros(5, dtype=int)
- ar2 = zeros(5, dtype=int)
- ar[0] = 3
- ar[1] = -3
- ar[2] = 8
- ar2[3] = -1
- ar2[4] = 8
- x = minimum(ar, ar2)
- assert x[0] == 0
- assert x[1] == -3
- assert x[2] == 0
- assert x[3] == -1
- assert x[4] == 0
- assert len(x) == 5
- raises(ValueError, minimum, ar, zeros(3, dtype=int))
-
-class AppTestMultiDim(object):
- def setup_class(cls):
- cls.space = gettestobjspace(usemodules=('micronumpy',))
-
- def test_multidim(self):
- from numpy import zeros
- ar = zeros((3, 3), dtype=int)
- assert ar[0, 2] == 0
- raises(IndexError, ar.__getitem__, (3, 0))
- assert ar[-2, 1] == 0
-
- def test_multidim_getset(self):
- from numpy import zeros
- ar = zeros((3, 3, 3), dtype=int)
- ar[1, 2, 1] = 3
- assert ar[1, 2, 1] == 3
- assert ar[-2, 2, 1] == 3
- assert ar[2, 2, 1] == 0
- assert ar[-2, 2, -2] == 3
-
- def test_len(self):
- from numpy import zeros
- assert len(zeros((3, 2, 1), dtype=int)) == 3
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -0,0 +1,79 @@
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestUfuncs(BaseNumpyAppTest):
+ def test_negative(self):
+ from numpy import array, negative
+
+ a = array([-5.0, 0.0, 1.0])
+ b = negative(a)
+ for i in range(3):
+ assert b[i] == -a[i]
+
+ a = array([-5.0, 1.0])
+ b = negative(a)
+ a[0] = 5.0
+ assert b[0] == 5.0
+
+ def test_abs(self):
+ from numpy import array, absolute
+
+ a = array([-5.0, -0.0, 1.0])
+ b = absolute(a)
+ for i in range(3):
+ assert b[i] == abs(a[i])
+
+ def test_minimum(self):
+ from numpy import array, minimum
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = minimum(a, b)
+ for i in range(3):
+ assert c[i] == min(a[i], b[i])
+
+ def test_maximum(self):
+ from numpy import array, maximum
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = maximum(a, b)
+ for i in range(3):
+ assert c[i] == max(a[i], b[i])
+
+ def test_sign(self):
+ from numpy import array, sign
+
+ reference = [-1.0, 0.0, 0.0, 1.0]
+ a = array([-5.0, -0.0, 0.0, 6.0])
+ b = sign(a)
+ for i in range(4):
+ assert b[i] == reference[i]
+
+ def test_reciporocal(self):
+ from numpy import array, reciprocal
+
+ reference = [-0.2, float("inf"), float("-inf"), 2.0]
+ a = array([-5.0, 0.0, -0.0, 0.5])
+ b = reciprocal(a)
+ for i in range(4):
+ assert b[i] == reference[i]
+
+ def test_copysign(self):
+ from numpy import array, copysign
+
+ reference = [5.0, -0.0, 0.0, -6.0]
+ a = array([-5.0, 0.0, 0.0, 6.0])
+ b = array([5.0, -0.0, 3.0, -6.0])
+ c = copysign(a, b)
+ for i in range(4):
+ assert c[i] == reference[i]
+
+ def test_exp(self):
+ import math
+ from numpy import array, exp
+
+ a = array([-5.0, -0.0, 0.0, float("inf")])
+ b = exp(a)
+ for i in range(4):
+ assert b[i] == math.exp(a[i])
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -0,0 +1,94 @@
+from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature,
+ FloatWrapper, Call1, Call2, add, mul)
+from pypy.module.micronumpy.interp_ufuncs import negative
+
+
+class FakeSpace(object):
+ pass
+
+class TestNumpyJIt(LLJitMixin):
+ def setup_class(cls):
+ cls.space = FakeSpace()
+
+ def test_add(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ v = Call2(add, ar, ar, Signature())
+ return v.get_concrete().storage[3]
+
+ 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)
+ v = Call2(add, ar, FloatWrapper(4.5), Signature())
+ return v.get_concrete().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
+ "setarrayitem_raw": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1})
+ assert result == f(5)
+
+ def test_already_forecd(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ 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]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ # This is the sum of the ops for both loops, however if you remove the
+ # optimization then you end up with 2 float_adds, so we can still be
+ # sure it was optimized correctly.
+ self.check_loops({"getarrayitem_raw": 2, "float_mul": 1, "float_add": 1,
+ "setarrayitem_raw": 2, "int_add": 2,
+ "int_lt": 2, "guard_true": 2, "jump": 2})
+ assert result == f(5)
+
+ def test_ufunc(self):
+ space = self.space
+ def f(i):
+ ar = SingleDimArray(i)
+ v1 = Call2(add, ar, ar, Signature())
+ v2 = negative(space, v1)
+ return v2.get_concrete().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1,
+ "setarrayitem_raw": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1,
+ })
+ 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
diff --git a/pypy/module/micronumpy/ufunc.py b/pypy/module/micronumpy/ufunc.py
deleted file mode 100644
--- a/pypy/module/micronumpy/ufunc.py
+++ /dev/null
@@ -1,21 +0,0 @@
-
-from numarray import NumArray
-from pypy.interpreter.baseobjspace import ObjSpace, W_Root
-from pypy.interpreter.error import OperationError
-
-def minimum(space, w_a, w_b):
- if not isinstance(w_a, NumArray) or not isinstance(w_b, NumArray):
- raise OperationError(space.w_TypeError,
- space.wrap("expecting NumArrat object"))
- if w_a.dim != w_b.dim:
- raise OperationError(space.w_ValueError,
- space.wrap("minimum of arrays of different length"))
- res = NumArray(space, w_a.dim, 'i')
- for i in range(len(w_a.storage)):
- one = w_a.storage[i]
- two = w_b.storage[i]
- if one < two:
- res.storage[i] = one
- else:
- res.storage[i] = two
- return space.wrap(res)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -113,7 +113,7 @@
flags['fresh_virtualizable'] = True
s_x = annmodel.SomeInstance(s_x.classdef,
s_x.can_be_None,
- flags)
+ flags)
return s_x
def specialize_call(self, hop, **kwds_i):
@@ -201,7 +201,7 @@
# VRefs
def virtual_ref(x):
-
+
"""Creates a 'vref' object that contains a reference to 'x'. Calls
to virtual_ref/virtual_ref_finish must be properly nested. The idea
is that the object 'x' is supposed to be JITted as a virtual between
@@ -275,7 +275,7 @@
# ____________________________________________________________
-class JitDriver(object):
+class JitDriver(object):
"""Base class to declare fine-grained user control on the JIT. So
far, there must be a singleton instance of JitDriver. This style
will allow us (later) to support a single RPython program with
@@ -557,7 +557,7 @@
def specialize_call(self, hop):
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.lltypesystem.rstr import string_repr
-
+
hop.exception_cannot_occur()
driver = self.instance.im_self
name = hop.args_s[0].const
diff --git a/pypy/rlib/nonconst.py b/pypy/rlib/nonconst.py
--- a/pypy/rlib/nonconst.py
+++ b/pypy/rlib/nonconst.py
@@ -18,6 +18,12 @@
def __nonzero__(self):
return bool(self.__dict__['constant'])
+ def __eq__(self, other):
+ return self.__dict__['constant'] == other
+
+ def __add__(self, other):
+ return self.__dict__['constant'] + other
+
class EntryNonConstant(ExtRegistryEntry):
_about_ = NonConstant
diff --git a/pypy/translator/c/src/float.h b/pypy/translator/c/src/float.h
--- a/pypy/translator/c/src/float.h
+++ b/pypy/translator/c/src/float.h
@@ -43,3 +43,4 @@
#define OP_CAST_FLOAT_TO_LONGLONG(x,r) r = (long long)(x)
#define OP_CAST_FLOAT_TO_ULONGLONG(x,r) r = (unsigned long long)(x)
#endif
+
diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/goal/targetnumpystandalone.py
@@ -0,0 +1,57 @@
+
+""" Usage:
+
+./targetnumpystandalone-c <bytecode> array_size
+
+Will execute a give numpy bytecode. Arrays will be ranges (in float) modulo 10,
+constants would be consecutive starting from one.
+
+Bytecode should contain letters 'a' 'l' and 'f' so far and be correct
+"""
+
+import time
+from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute
+from pypy.jit.codewriter.policy import JitPolicy
+
+def create_array(size):
+ a = SingleDimArray(size)
+ for i in range(size):
+ a.storage[i] = float(i % 10)
+ return a
+
+def entry_point(argv):
+ if len(argv) != 3:
+ print __doc__
+ return 1
+ bytecode = argv[1]
+ for b in bytecode:
+ if b not in 'alf':
+ print "WRONG BYTECODE"
+ print __doc__
+ return 2
+ try:
+ size = int(argv[2])
+ except ValueError:
+ print "INVALID LITERAL FOR INT:", argv[2]
+ print __doc__
+ return 3
+ no_arrays = bytecode.count('l')
+ no_floats = bytecode.count('f')
+ arrays = []
+ floats = []
+ for i in range(no_arrays):
+ arrays.append(create_array(size))
+ for i in range(no_floats):
+ floats.append(float(i + 1))
+ code = Code(bytecode, arrays, floats)
+ t0 = time.time()
+ compute(code)
+ print "bytecode:", bytecode, "size:", size
+ print "took:", time.time() - t0
+ return 0
+
+def target(*args):
+ return entry_point, None
+
+def jitpolicy(driver):
+ return JitPolicy()
More information about the pypy-commit
mailing list