Author: Benjamin Peterson <benja...@python.org> Branch: Changeset: r48594:b9fb5a2b414e Date: 2011-10-28 19:30 -0400 http://bitbucket.org/pypy/pypy/changeset/b9fb5a2b414e/
Log: merge heads 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 @@ -929,6 +929,9 @@ def view(self, **kwds): pass + def clear(self): + pass + class Stats(object): """For tests.""" @@ -943,6 +946,15 @@ self.aborted_keys = [] self.invalidated_token_numbers = set() + def clear(self): + del self.loops[:] + del self.locations[:] + del self.aborted_keys[:] + self.invalidated_token_numbers.clear() + self.compiled_count = 0 + self.enter_count = 0 + self.aborted_count = 0 + def set_history(self, history): self.operations = history.operations diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -976,6 +976,29 @@ """ self.optimize_loop(ops, expected) + def test_virtual_array_of_struct_forced(self): + ops = """ + [f0, f1] + p0 = new_array(1, descr=complexarraydescr) + setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr) + setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr) + f2 = getinteriorfield_gc(p0, 0, descr=complexrealdescr) + f3 = getinteriorfield_gc(p0, 0, descr=compleximagdescr) + f4 = float_mul(f2, f3) + i0 = escape(f4, p0) + finish(i0) + """ + expected = """ + [f0, f1] + f2 = float_mul(f0, f1) + p0 = new_array(1, descr=complexarraydescr) + setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr) + setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr) + i0 = escape(f2, p0) + finish(i0) + """ + self.optimize_loop(ops, expected) + def test_nonvirtual_1(self): ops = """ [i] diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py --- a/pypy/jit/metainterp/warmspot.py +++ b/pypy/jit/metainterp/warmspot.py @@ -62,7 +62,7 @@ clear_tcache() return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) -def jittify_and_run(interp, graph, args, repeat=1, +def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, function_threshold=4, @@ -93,6 +93,8 @@ jd.warmstate.set_param_max_retrace_guards(max_retrace_guards) jd.warmstate.set_param_enable_opts(enable_opts) warmrunnerdesc.finish() + if graph_and_interp_only: + return interp, graph res = interp.eval_graph(graph, args) if not kwds.get('translate_support_code', False): warmrunnerdesc.metainterp_sd.profiler.finish() @@ -157,6 +159,9 @@ def get_stats(): return pyjitpl._warmrunnerdesc.stats +def reset_stats(): + pyjitpl._warmrunnerdesc.stats.clear() + def get_translator(): return pyjitpl._warmrunnerdesc.translator 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 @@ -13,6 +13,9 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', 'fromstring': 'interp_support.fromstring', + + 'True_': 'space.w_True', + 'False_': 'space.w_False', } # ufuncs diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -4,30 +4,52 @@ """ from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root -from pypy.module.micronumpy.interp_dtype import W_Float64Dtype -from pypy.module.micronumpy.interp_numarray import Scalar, SingleDimArray, BaseArray +from pypy.module.micronumpy.interp_dtype import W_Float64Dtype, W_BoolDtype +from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray, + descr_new_array, scalar_w, SingleDimArray) +from pypy.module.micronumpy import interp_ufuncs from pypy.rlib.objectmodel import specialize class BogusBytecode(Exception): pass -def create_array(dtype, size): - a = SingleDimArray(size, dtype=dtype) - for i in range(size): - dtype.setitem(a.storage, i, dtype.box(float(i % 10))) - return a +class ArgumentMismatch(Exception): + pass + +class ArgumentNotAnArray(Exception): + pass + +class WrongFunctionName(Exception): + pass + +SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "unegative"] class FakeSpace(object): w_ValueError = None w_TypeError = None + w_None = None + + w_bool = "bool" + w_int = "int" + w_float = "float" + w_list = "list" + w_long = "long" + w_tuple = 'tuple' def __init__(self): """NOT_RPYTHON""" self.fromcache = InternalSpaceCache(self).getorbuild + self.w_float64dtype = W_Float64Dtype(self) def issequence_w(self, w_obj): - return True + return isinstance(w_obj, ListObject) or isinstance(w_obj, SingleDimArray) + + def isinstance_w(self, w_obj, w_tp): + return False + + def decode_index4(self, w_idx, size): + return (self.int_w(w_idx), 0, 0, 1) @specialize.argtype(1) def wrap(self, obj): @@ -39,72 +61,382 @@ return IntObject(obj) raise Exception + def newlist(self, items): + return ListObject(items) + + def listview(self, obj): + assert isinstance(obj, ListObject) + return obj.items + def float(self, w_obj): assert isinstance(w_obj, FloatObject) return w_obj def float_w(self, w_obj): + assert isinstance(w_obj, FloatObject) return w_obj.floatval + def int_w(self, w_obj): + if isinstance(w_obj, IntObject): + return w_obj.intval + elif isinstance(w_obj, FloatObject): + return int(w_obj.floatval) + raise NotImplementedError + + def int(self, w_obj): + return w_obj + + def is_true(self, w_obj): + assert isinstance(w_obj, BoolObject) + return w_obj.boolval + + def is_w(self, w_obj, w_what): + return w_obj is w_what + + def type(self, w_obj): + return w_obj.tp + + def gettypefor(self, w_obj): + return None + + def call_function(self, tp, w_dtype): + return w_dtype + + @specialize.arg(1) + def interp_w(self, tp, what): + assert isinstance(what, tp) + return what class FloatObject(W_Root): + tp = FakeSpace.w_float def __init__(self, floatval): self.floatval = floatval class BoolObject(W_Root): + tp = FakeSpace.w_bool def __init__(self, boolval): self.boolval = boolval class IntObject(W_Root): + tp = FakeSpace.w_int def __init__(self, intval): self.intval = intval +class ListObject(W_Root): + tp = FakeSpace.w_list + def __init__(self, items): + self.items = items -space = FakeSpace() +class InterpreterState(object): + def __init__(self, code): + self.code = code + self.variables = {} + self.results = [] -def numpy_compile(bytecode, array_size): - stack = [] - i = 0 - dtype = space.fromcache(W_Float64Dtype) - for b in bytecode: - if b == 'a': - stack.append(create_array(dtype, array_size)) - i += 1 - elif b == 'f': - stack.append(Scalar(dtype, dtype.box(1.2))) - elif b == '+': - right = stack.pop() - res = stack.pop().descr_add(space, right) - assert isinstance(res, BaseArray) - stack.append(res) - elif b == '-': - right = stack.pop() - res = stack.pop().descr_sub(space, right) - assert isinstance(res, BaseArray) - stack.append(res) - elif b == '*': - right = stack.pop() - res = stack.pop().descr_mul(space, right) - assert isinstance(res, BaseArray) - stack.append(res) - elif b == '/': - right = stack.pop() - res = stack.pop().descr_div(space, right) - assert isinstance(res, BaseArray) - stack.append(res) - elif b == '%': - right = stack.pop() - res = stack.pop().descr_mod(space, right) - assert isinstance(res, BaseArray) - stack.append(res) - elif b == '|': - res = stack.pop().descr_abs(space) - assert isinstance(res, BaseArray) - stack.append(res) + def run(self, space): + self.space = space + for stmt in self.code.statements: + stmt.execute(self) + +class Node(object): + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self.__dict__ == other.__dict__) + + def __ne__(self, other): + return not self == other + + def wrap(self, space): + raise NotImplementedError + + def execute(self, interp): + raise NotImplementedError + +class Assignment(Node): + def __init__(self, name, expr): + self.name = name + self.expr = expr + + def execute(self, interp): + interp.variables[self.name] = self.expr.execute(interp) + + def __repr__(self): + return "%% = %r" % (self.name, self.expr) + +class ArrayAssignment(Node): + def __init__(self, name, index, expr): + self.name = name + self.index = index + self.expr = expr + + def execute(self, interp): + arr = interp.variables[self.name] + w_index = self.index.execute(interp).eval(0).wrap(interp.space) + w_val = self.expr.execute(interp).eval(0).wrap(interp.space) + arr.descr_setitem(interp.space, w_index, w_val) + + def __repr__(self): + return "%s[%r] = %r" % (self.name, self.index, self.expr) + +class Variable(Node): + def __init__(self, name): + self.name = name + + def execute(self, interp): + return interp.variables[self.name] + + def __repr__(self): + return 'v(%s)' % self.name + +class Operator(Node): + def __init__(self, lhs, name, rhs): + self.name = name + self.lhs = lhs + self.rhs = rhs + + def execute(self, interp): + w_lhs = self.lhs.execute(interp) + assert isinstance(w_lhs, BaseArray) + if isinstance(self.rhs, SliceConstant): + # XXX interface has changed on multidim branch + raise NotImplementedError + w_rhs = self.rhs.execute(interp) + if self.name == '+': + w_res = w_lhs.descr_add(interp.space, w_rhs) + elif self.name == '*': + w_res = w_lhs.descr_mul(interp.space, w_rhs) + elif self.name == '-': + w_res = w_lhs.descr_sub(interp.space, w_rhs) + elif self.name == '->': + if isinstance(w_rhs, Scalar): + index = int(interp.space.float_w( + w_rhs.value.wrap(interp.space))) + dtype = interp.space.fromcache(W_Float64Dtype) + return Scalar(dtype, w_lhs.get_concrete().eval(index)) + else: + raise NotImplementedError else: - print "Unknown opcode: %s" % b - raise BogusBytecode() - if len(stack) != 1: - print "Bogus bytecode, uneven stack length" - raise BogusBytecode() - return stack[0] + raise NotImplementedError + if not isinstance(w_res, BaseArray): + dtype = interp.space.fromcache(W_Float64Dtype) + w_res = scalar_w(interp.space, dtype, w_res) + return w_res + + def __repr__(self): + return '(%r %s %r)' % (self.lhs, self.name, self.rhs) + +class FloatConstant(Node): + def __init__(self, v): + self.v = float(v) + + def __repr__(self): + return "Const(%s)" % self.v + + def wrap(self, space): + return space.wrap(self.v) + + def execute(self, interp): + dtype = interp.space.fromcache(W_Float64Dtype) + assert isinstance(dtype, W_Float64Dtype) + return Scalar(dtype, dtype.box(self.v)) + +class RangeConstant(Node): + def __init__(self, v): + self.v = int(v) + + def execute(self, interp): + w_list = interp.space.newlist( + [interp.space.wrap(float(i)) for i in range(self.v)]) + dtype = interp.space.fromcache(W_Float64Dtype) + return descr_new_array(interp.space, None, w_list, w_dtype=dtype) + + def __repr__(self): + return 'Range(%s)' % self.v + +class Code(Node): + def __init__(self, statements): + self.statements = statements + + def __repr__(self): + return "\n".join([repr(i) for i in self.statements]) + +class ArrayConstant(Node): + def __init__(self, items): + self.items = items + + def wrap(self, space): + return space.newlist([item.wrap(space) for item in self.items]) + + def execute(self, interp): + w_list = self.wrap(interp.space) + dtype = interp.space.fromcache(W_Float64Dtype) + return descr_new_array(interp.space, None, w_list, w_dtype=dtype) + + def __repr__(self): + return "[" + ", ".join([repr(item) for item in self.items]) + "]" + +class SliceConstant(Node): + def __init__(self): + pass + + def __repr__(self): + return 'slice()' + +class Execute(Node): + def __init__(self, expr): + self.expr = expr + + def __repr__(self): + return repr(self.expr) + + def execute(self, interp): + interp.results.append(self.expr.execute(interp)) + +class FunctionCall(Node): + def __init__(self, name, args): + self.name = name + self.args = args + + def __repr__(self): + return "%s(%s)" % (self.name, ", ".join([repr(arg) + for arg in self.args])) + + def execute(self, interp): + if self.name in SINGLE_ARG_FUNCTIONS: + if len(self.args) != 1: + raise ArgumentMismatch + arr = self.args[0].execute(interp) + if not isinstance(arr, BaseArray): + raise ArgumentNotAnArray + if self.name == "sum": + w_res = arr.descr_sum(interp.space) + elif self.name == "prod": + w_res = arr.descr_prod(interp.space) + elif self.name == "max": + w_res = arr.descr_max(interp.space) + elif self.name == "min": + w_res = arr.descr_min(interp.space) + elif self.name == "any": + w_res = arr.descr_any(interp.space) + elif self.name == "all": + w_res = arr.descr_all(interp.space) + elif self.name == "unegative": + neg = interp_ufuncs.get(interp.space).negative + w_res = neg.call(interp.space, [arr]) + else: + assert False # unreachable code + if isinstance(w_res, BaseArray): + return w_res + if isinstance(w_res, FloatObject): + dtype = interp.space.fromcache(W_Float64Dtype) + elif isinstance(w_res, BoolObject): + dtype = interp.space.fromcache(W_BoolDtype) + else: + dtype = None + return scalar_w(interp.space, dtype, w_res) + else: + raise WrongFunctionName + +class Parser(object): + def parse_identifier(self, id): + id = id.strip(" ") + #assert id.isalpha() + return Variable(id) + + def parse_expression(self, expr): + tokens = [i for i in expr.split(" ") if i] + if len(tokens) == 1: + return self.parse_constant_or_identifier(tokens[0]) + stack = [] + tokens.reverse() + while tokens: + token = tokens.pop() + if token == ')': + raise NotImplementedError + elif self.is_identifier_or_const(token): + if stack: + name = stack.pop().name + lhs = stack.pop() + rhs = self.parse_constant_or_identifier(token) + stack.append(Operator(lhs, name, rhs)) + else: + stack.append(self.parse_constant_or_identifier(token)) + else: + stack.append(Variable(token)) + assert len(stack) == 1 + return stack[-1] + + def parse_constant(self, v): + lgt = len(v)-1 + assert lgt >= 0 + if ':' in v: + # a slice + assert v == ':' + return SliceConstant() + if v[0] == '[': + return ArrayConstant([self.parse_constant(elem) + for elem in v[1:lgt].split(",")]) + if v[0] == '|': + return RangeConstant(v[1:lgt]) + return FloatConstant(v) + + def is_identifier_or_const(self, v): + c = v[0] + if ((c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or + (c >= '0' and c <= '9') or c in '-.[|:'): + if v == '-' or v == "->": + return False + return True + return False + + def parse_function_call(self, v): + l = v.split('(') + assert len(l) == 2 + name = l[0] + cut = len(l[1]) - 1 + assert cut >= 0 + args = [self.parse_constant_or_identifier(id) + for id in l[1][:cut].split(",")] + return FunctionCall(name, args) + + def parse_constant_or_identifier(self, v): + c = v[0] + if (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z'): + if '(' in v: + return self.parse_function_call(v) + return self.parse_identifier(v) + return self.parse_constant(v) + + def parse_array_subscript(self, v): + v = v.strip(" ") + l = v.split("[") + lgt = len(l[1]) - 1 + assert lgt >= 0 + rhs = self.parse_constant_or_identifier(l[1][:lgt]) + return l[0], rhs + + def parse_statement(self, line): + if '=' in line: + lhs, rhs = line.split("=") + lhs = lhs.strip(" ") + if '[' in lhs: + name, index = self.parse_array_subscript(lhs) + return ArrayAssignment(name, index, self.parse_expression(rhs)) + else: + return Assignment(lhs, self.parse_expression(rhs)) + else: + return Execute(self.parse_expression(line)) + + def parse(self, code): + statements = [] + for line in code.split("\n"): + if '#' in line: + line = line.split('#', 1)[0] + line = line.strip(" ") + if line: + statements.append(self.parse_statement(line)) + return Code(statements) + +def numpy_compile(code): + parser = Parser() + return InterpreterState(parser.parse(code)) 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 @@ -14,6 +14,27 @@ any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype']) slice_driver = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest']) +def descr_new_array(space, w_subtype, w_size_or_iterable, w_dtype=None): + l = space.listview(w_size_or_iterable) + if space.is_w(w_dtype, space.w_None): + w_dtype = None + for w_item in l: + w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype) + if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype): + break + if w_dtype is None: + w_dtype = space.w_None + + dtype = space.interp_w(interp_dtype.W_Dtype, + space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) + ) + arr = SingleDimArray(len(l), dtype=dtype) + i = 0 + for w_elem in l: + dtype.setitem_w(space, arr.storage, i, w_elem) + i += 1 + return arr + class BaseArray(Wrappable): _attrs_ = ["invalidates", "signature"] @@ -32,27 +53,6 @@ def add_invalidates(self, other): self.invalidates.append(other) - def descr__new__(space, w_subtype, w_size_or_iterable, w_dtype=None): - l = space.listview(w_size_or_iterable) - if space.is_w(w_dtype, space.w_None): - w_dtype = None - for w_item in l: - w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype) - if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype): - break - if w_dtype is None: - w_dtype = space.w_None - - dtype = space.interp_w(interp_dtype.W_Dtype, - space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) - ) - arr = SingleDimArray(len(l), dtype=dtype) - i = 0 - for w_elem in l: - dtype.setitem_w(space, arr.storage, i, w_elem) - i += 1 - return arr - def _unaryop_impl(ufunc_name): def impl(self, space): return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self]) @@ -570,7 +570,7 @@ BaseArray.typedef = TypeDef( 'numarray', - __new__ = interp2app(BaseArray.descr__new__.im_func), + __new__ = interp2app(descr_new_array), __len__ = interp2app(BaseArray.descr_len), 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 @@ -32,11 +32,17 @@ return self.identity.wrap(space) def descr_call(self, space, __args__): - try: - args_w = __args__.fixedunpack(self.argcount) - except ValueError, e: - raise OperationError(space.w_TypeError, space.wrap(str(e))) - return self.call(space, args_w) + if __args__.keywords or len(__args__.arguments_w) < self.argcount: + raise OperationError(space.w_ValueError, + space.wrap("invalid number of arguments") + ) + elif len(__args__.arguments_w) > self.argcount: + # The extra arguments should actually be the output array, but we + # don't support that yet. + raise OperationError(space.w_TypeError, + space.wrap("invalid number of arguments") + ) + return self.call(space, __args__.arguments_w) def descr_reduce(self, space, w_obj): from pypy.module.micronumpy.interp_numarray import convert_to_array, Scalar @@ -236,22 +242,20 @@ return dt def find_dtype_for_scalar(space, w_obj, current_guess=None): - w_type = space.type(w_obj) - bool_dtype = space.fromcache(interp_dtype.W_BoolDtype) long_dtype = space.fromcache(interp_dtype.W_LongDtype) int64_dtype = space.fromcache(interp_dtype.W_Int64Dtype) - if space.is_w(w_type, space.w_bool): + if space.isinstance_w(w_obj, space.w_bool): if current_guess is None or current_guess is bool_dtype: return bool_dtype return current_guess - elif space.is_w(w_type, space.w_int): + elif space.isinstance_w(w_obj, space.w_int): if (current_guess is None or current_guess is bool_dtype or current_guess is long_dtype): return long_dtype return current_guess - elif space.is_w(w_type, space.w_long): + elif space.isinstance_w(w_obj, space.w_long): if (current_guess is None or current_guess is bool_dtype or current_guess is long_dtype or current_guess is int64_dtype): return int64_dtype diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_compile.py @@ -0,0 +1,170 @@ + +import py +from pypy.module.micronumpy.compile import * + +class TestCompiler(object): + def compile(self, code): + return numpy_compile(code) + + def test_vars(self): + code = """ + a = 2 + b = 3 + """ + interp = self.compile(code) + assert isinstance(interp.code.statements[0], Assignment) + assert interp.code.statements[0].name == 'a' + assert interp.code.statements[0].expr.v == 2 + assert interp.code.statements[1].name == 'b' + assert interp.code.statements[1].expr.v == 3 + + def test_array_literal(self): + code = "a = [1,2,3]" + interp = self.compile(code) + assert isinstance(interp.code.statements[0].expr, ArrayConstant) + st = interp.code.statements[0] + assert st.expr.items == [FloatConstant(1), FloatConstant(2), + FloatConstant(3)] + + def test_array_literal2(self): + code = "a = [[1],[2],[3]]" + interp = self.compile(code) + assert isinstance(interp.code.statements[0].expr, ArrayConstant) + st = interp.code.statements[0] + assert st.expr.items == [ArrayConstant([FloatConstant(1)]), + ArrayConstant([FloatConstant(2)]), + ArrayConstant([FloatConstant(3)])] + + def test_expr_1(self): + code = "b = a + 1" + interp = self.compile(code) + assert (interp.code.statements[0].expr == + Operator(Variable("a"), "+", FloatConstant(1))) + + def test_expr_2(self): + code = "b = a + b - 3" + interp = self.compile(code) + assert (interp.code.statements[0].expr == + Operator(Operator(Variable("a"), "+", Variable("b")), "-", + FloatConstant(3))) + + def test_expr_3(self): + # an equivalent of range + code = "a = |20|" + interp = self.compile(code) + assert interp.code.statements[0].expr == RangeConstant(20) + + def test_expr_only(self): + code = "3 + a" + interp = self.compile(code) + assert interp.code.statements[0] == Execute( + Operator(FloatConstant(3), "+", Variable("a"))) + + def test_array_access(self): + code = "a -> 3" + interp = self.compile(code) + assert interp.code.statements[0] == Execute( + Operator(Variable("a"), "->", FloatConstant(3))) + + def test_function_call(self): + code = "sum(a)" + interp = self.compile(code) + assert interp.code.statements[0] == Execute( + FunctionCall("sum", [Variable("a")])) + + def test_comment(self): + code = """ + # some comment + a = b + 3 # another comment + """ + interp = self.compile(code) + assert interp.code.statements[0] == Assignment( + 'a', Operator(Variable('b'), "+", FloatConstant(3))) + +class TestRunner(object): + def run(self, code): + interp = numpy_compile(code) + space = FakeSpace() + interp.run(space) + return interp + + def test_one(self): + code = """ + a = 3 + b = 4 + a + b + """ + interp = self.run(code) + assert sorted(interp.variables.keys()) == ['a', 'b'] + assert interp.results[0] + + def test_array_add(self): + code = """ + a = [1,2,3,4] + b = [4,5,6,5] + a + b + """ + interp = self.run(code) + assert interp.results[0]._getnums(False) == ["5.0", "7.0", "9.0", "9.0"] + + def test_array_getitem(self): + code = """ + a = [1,2,3,4] + b = [4,5,6,5] + a + b -> 3 + """ + interp = self.run(code) + assert interp.results[0].value.val == 3 + 6 + + def test_range_getitem(self): + code = """ + r = |20| + 3 + r -> 3 + """ + interp = self.run(code) + assert interp.results[0].value.val == 6 + + def test_sum(self): + code = """ + a = [1,2,3,4,5] + r = sum(a) + r + """ + interp = self.run(code) + assert interp.results[0].value.val == 15 + + def test_array_write(self): + code = """ + a = [1,2,3,4,5] + a[3] = 15 + a -> 3 + """ + interp = self.run(code) + assert interp.results[0].value.val == 15 + + def test_min(self): + interp = self.run(""" + a = |30| + a[15] = -12 + b = a + a + min(b) + """) + assert interp.results[0].value.val == -24 + + def test_max(self): + interp = self.run(""" + a = |30| + a[13] = 128 + b = a + a + max(b) + """) + assert interp.results[0].value.val == 256 + + def test_slice(self): + py.test.skip("in progress") + interp = self.run(""" + a = [1,2,3,4] + b = a -> : + b -> 3 + """) + assert interp.results[0].value.val == 3 diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -36,37 +36,40 @@ assert str(d) == "bool" def test_bool_array(self): - from numpy import array + import numpy - a = array([0, 1, 2, 2.5], dtype='?') - assert a[0] is False + a = numpy.array([0, 1, 2, 2.5], dtype='?') + assert a[0] is numpy.False_ for i in xrange(1, 4): - assert a[i] is True + assert a[i] is numpy.True_ def test_copy_array_with_dtype(self): - from numpy import array - a = array([0, 1, 2, 3], dtype=long) + import numpy + + a = numpy.array([0, 1, 2, 3], dtype=long) # int on 64-bit, long in 32-bit assert isinstance(a[0], (int, long)) b = a.copy() assert isinstance(b[0], (int, long)) - a = array([0, 1, 2, 3], dtype=bool) - assert isinstance(a[0], bool) + a = numpy.array([0, 1, 2, 3], dtype=bool) + assert a[0] is numpy.False_ b = a.copy() - assert isinstance(b[0], bool) + assert b[0] is numpy.False_ def test_zeros_bool(self): - from numpy import zeros - a = zeros(10, dtype=bool) + import numpy + + a = numpy.zeros(10, dtype=bool) for i in range(10): - assert a[i] is False + assert a[i] is numpy.False_ def test_ones_bool(self): - from numpy import ones - a = ones(10, dtype=bool) + import numpy + + a = numpy.ones(10, dtype=bool) for i in range(10): - assert a[i] is True + assert a[i] is numpy.True_ def test_zeros_long(self): from numpy import zeros @@ -77,7 +80,7 @@ def test_ones_long(self): from numpy import ones - a = ones(10, dtype=bool) + a = ones(10, dtype=long) for i in range(10): assert isinstance(a[i], (int, long)) assert a[1] == 1 @@ -96,8 +99,9 @@ def test_bool_binop_types(self): from numpy import array, dtype - types = ('?','b','B','h','H','i','I','l','L','q','Q','f','d') - N = len(types) + types = [ + '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd' + ] a = array([True], '?') for t in types: assert (a + array([0], t)).dtype is dtype(t) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -214,7 +214,7 @@ def test_add_other(self): from numpy import array a = array(range(5)) - b = array(reversed(range(5))) + b = array(range(4, -1, -1)) c = a + b for i in range(5): assert c[i] == 4 @@ -264,18 +264,19 @@ assert b[i] == i - 5 def test_mul(self): - from numpy import array, dtype - a = array(range(5)) + import numpy + + a = numpy.array(range(5)) b = a * a for i in range(5): assert b[i] == i * i - a = array(range(5), dtype=bool) + a = numpy.array(range(5), dtype=bool) b = a * a - assert b.dtype is dtype(bool) - assert b[0] is False + assert b.dtype is numpy.dtype(bool) + assert b[0] is numpy.False_ for i in range(1, 5): - assert b[i] is True + assert b[i] is numpy.True_ def test_mul_constant(self): from numpy import array diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -24,10 +24,10 @@ def test_wrong_arguments(self): from numpy import add, sin - raises(TypeError, add, 1) + raises(ValueError, add, 1) raises(TypeError, add, 1, 2, 3) raises(TypeError, sin, 1, 2) - raises(TypeError, sin) + raises(ValueError, sin) def test_single_item(self): from numpy import negative, sign, minimum @@ -82,6 +82,8 @@ b = negative(a) a[0] = 5.0 assert b[0] == 5.0 + a = array(range(30)) + assert negative(a + a)[3] == -6 def test_abs(self): from numpy import array, absolute @@ -355,4 +357,4 @@ (3.5, 3), (3, 3.5), ]: - assert ufunc(a, b) is func(a, b) + assert ufunc(a, b) == func(a, b) 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,253 +1,195 @@ from pypy.jit.metainterp.test.support import LLJitMixin from pypy.module.micronumpy import interp_ufuncs, signature -from pypy.module.micronumpy.compile import (numpy_compile, FakeSpace, - FloatObject, IntObject) -from pypy.module.micronumpy.interp_dtype import W_Int32Dtype, W_Float64Dtype, W_Int64Dtype, W_UInt64Dtype -from pypy.module.micronumpy.interp_numarray import (BaseArray, SingleDimArray, - SingleDimSlice, scalar_w) +from pypy.module.micronumpy.compile import (FakeSpace, + FloatObject, IntObject, numpy_compile, BoolObject) +from pypy.module.micronumpy.interp_numarray import (SingleDimArray, + SingleDimSlice) from pypy.rlib.nonconst import NonConstant -from pypy.rpython.annlowlevel import llstr -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.annlowlevel import llstr, hlstr +from pypy.jit.metainterp.warmspot import reset_stats +from pypy.jit.metainterp import pyjitpl import py class TestNumpyJIt(LLJitMixin): - def setup_class(cls): - cls.space = FakeSpace() - cls.float64_dtype = cls.space.fromcache(W_Float64Dtype) - cls.int64_dtype = cls.space.fromcache(W_Int64Dtype) - cls.uint64_dtype = cls.space.fromcache(W_UInt64Dtype) - cls.int32_dtype = cls.space.fromcache(W_Int32Dtype) + graph = None + interp = None + + def run(self, code): + space = FakeSpace() + + def f(code): + interp = numpy_compile(hlstr(code)) + interp.run(space) + res = interp.results[-1] + w_res = res.eval(0).wrap(interp.space) + if isinstance(w_res, BoolObject): + return float(w_res.boolval) + elif isinstance(w_res, FloatObject): + return w_res.floatval + elif isinstance(w_res, IntObject): + return w_res.intval + else: + return -42. + + if self.graph is None: + interp, graph = self.meta_interp(f, [llstr(code)], + listops=True, + backendopt=True, + graph_and_interp_only=True) + self.__class__.interp = interp + self.__class__.graph = graph + + reset_stats() + pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear() + return self.interp.eval_graph(self.graph, [llstr(code)]) def test_add(self): - def f(i): - ar = SingleDimArray(i, dtype=self.float64_dtype) - v = interp_ufuncs.get(self.space).add.call(self.space, [ar, ar]) - return v.get_concrete().eval(3).val - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = |30| + b = a + a + b -> 3 + """) 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) + assert result == 3 + 3 def test_floatadd(self): - def f(i): - ar = SingleDimArray(i, dtype=self.float64_dtype) - v = interp_ufuncs.get(self.space).add.call(self.space, [ - ar, - scalar_w(self.space, self.float64_dtype, self.space.wrap(4.5)) - ], - ) - assert isinstance(v, BaseArray) - return v.get_concrete().eval(3).val - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = |30| + 3 + a -> 3 + """) + assert result == 3 + 3 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_sum(self): - space = self.space - float64_dtype = self.float64_dtype - int64_dtype = self.int64_dtype - - def f(i): - if NonConstant(False): - dtype = int64_dtype - else: - dtype = float64_dtype - ar = SingleDimArray(i, dtype=dtype) - v = ar.descr_add(space, ar).descr_sum(space) - assert isinstance(v, FloatObject) - return v.floatval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = |30| + b = a + a + sum(b) + """) + assert result == 2 * sum(range(30)) self.check_loops({"getarrayitem_raw": 2, "float_add": 2, "int_add": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) - assert result == f(5) def test_prod(self): - space = self.space - float64_dtype = self.float64_dtype - int64_dtype = self.int64_dtype - - def f(i): - if NonConstant(False): - dtype = int64_dtype - else: - dtype = float64_dtype - ar = SingleDimArray(i, dtype=dtype) - v = ar.descr_add(space, ar).descr_prod(space) - assert isinstance(v, FloatObject) - return v.floatval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = |30| + b = a + a + prod(b) + """) + expected = 1 + for i in range(30): + expected *= i * 2 + assert result == expected self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_mul": 1, "int_add": 1, "int_lt": 1, "guard_true": 1, "jump": 1}) - assert result == f(5) def test_max(self): - space = self.space - float64_dtype = self.float64_dtype - int64_dtype = self.int64_dtype - - def f(i): - if NonConstant(False): - dtype = int64_dtype - else: - dtype = float64_dtype - ar = SingleDimArray(i, dtype=dtype) - j = 0 - while j < i: - ar.get_concrete().setitem(j, float64_dtype.box(float(j))) - j += 1 - v = ar.descr_add(space, ar).descr_max(space) - assert isinstance(v, FloatObject) - return v.floatval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + py.test.skip("broken, investigate") + result = self.run(""" + a = |30| + a[13] = 128 + b = a + a + max(b) + """) + assert result == 256 self.check_loops({"getarrayitem_raw": 2, "float_add": 1, - "float_gt": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, - "guard_false": 1, "jump": 1}) - assert result == f(5) + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) def test_min(self): - space = self.space - float64_dtype = self.float64_dtype - int64_dtype = self.int64_dtype - - def f(i): - if NonConstant(False): - dtype = int64_dtype - else: - dtype = float64_dtype - ar = SingleDimArray(i, dtype=dtype) - j = 0 - while j < i: - ar.get_concrete().setitem(j, float64_dtype.box(float(j))) - j += 1 - v = ar.descr_add(space, ar).descr_min(space) - assert isinstance(v, FloatObject) - return v.floatval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + py.test.skip("broken, investigate") + result = self.run(""" + a = |30| + a[15] = -12 + b = a + a + min(b) + """) + assert result == -24 self.check_loops({"getarrayitem_raw": 2, "float_add": 1, - "float_lt": 1, "int_add": 1, - "int_lt": 1, "guard_true": 2, - "jump": 1}) - assert result == f(5) - - def test_argmin(self): - space = self.space - float64_dtype = self.float64_dtype - - def f(i): - ar = SingleDimArray(i, dtype=NonConstant(float64_dtype)) - j = 0 - while j < i: - ar.get_concrete().setitem(j, float64_dtype.box(float(j))) - j += 1 - return ar.descr_add(space, ar).descr_argmin(space).intval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 2, "float_add": 1, - "float_lt": 1, "int_add": 1, - "int_lt": 1, "guard_true": 2, - "jump": 1}) - assert result == f(5) - - def test_all(self): - space = self.space - float64_dtype = self.float64_dtype - - def f(i): - ar = SingleDimArray(i, dtype=NonConstant(float64_dtype)) - j = 0 - while j < i: - ar.get_concrete().setitem(j, float64_dtype.box(1.0)) - j += 1 - return ar.descr_add(space, ar).descr_all(space).boolval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) - self.check_loops({"getarrayitem_raw": 2, "float_add": 1, - "int_add": 1, "float_ne": 1, - "int_lt": 1, "guard_true": 2, "jump": 1}) - assert result == f(5) + "float_mul": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1}) def test_any(self): - space = self.space - float64_dtype = self.float64_dtype - - def f(i): - ar = SingleDimArray(i, dtype=NonConstant(float64_dtype)) - return ar.descr_add(space, ar).descr_any(space).boolval - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = [0,0,0,0,0,0,0,0,0,0,0] + a[8] = -12 + b = a + a + any(b) + """) + assert result == 1 self.check_loops({"getarrayitem_raw": 2, "float_add": 1, - "int_add": 1, "float_ne": 1, "guard_false": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) - assert result == f(5) + "float_ne": 1, "int_add": 1, + "int_lt": 1, "guard_true": 1, "jump": 1, + "guard_false": 1}) def test_already_forced(self): - space = self.space - - def f(i): - ar = SingleDimArray(i, dtype=self.float64_dtype) - v1 = interp_ufuncs.get(self.space).add.call(space, [ar, scalar_w(space, self.float64_dtype, space.wrap(4.5))]) - assert isinstance(v1, BaseArray) - v2 = interp_ufuncs.get(self.space).multiply.call(space, [v1, scalar_w(space, self.float64_dtype, space.wrap(4.5))]) - v1.force_if_needed() - assert isinstance(v2, BaseArray) - return v2.get_concrete().eval(3).val - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = |30| + b = a + 4.5 + b -> 5 # forces + c = b * 8 + c -> 5 + """) + assert result == (5 + 4.5) * 8 # 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, dtype=self.float64_dtype) - v1 = interp_ufuncs.get(self.space).add.call(space, [ar, ar]) - v2 = interp_ufuncs.get(self.space).negative.call(space, [v1]) - return v2.get_concrete().eval(3).val - - result = self.meta_interp(f, [5], listops=True, backendopt=True) + result = self.run(""" + a = |30| + b = a + a + c = unegative(b) + c -> 3 + """) + assert result == -6 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): - ar = SingleDimArray(i, dtype=self.float64_dtype) - - v1 = interp_ufuncs.get(self.space).add.call(space, [ar, ar]) - v2 = interp_ufuncs.get(self.space).negative.call(space, [v1]) - v2.get_concrete() - - for i in xrange(5): - v1 = interp_ufuncs.get(self.space).multiply.call(space, [ar, ar]) - v2 = interp_ufuncs.get(self.space).negative.call(space, [v1]) - v2.get_concrete() - - self.meta_interp(f, [5], listops=True, backendopt=True) + def test_specialization(self): + self.run(""" + a = |30| + b = a + a + c = unegative(b) + c -> 3 + d = a * a + unegative(d) + d -> 3 + d = a * a + unegative(d) + d -> 3 + d = a * a + unegative(d) + d -> 3 + d = a * a + unegative(d) + d -> 3 + """) # This is 3, not 2 because there is a bridge for the exit. self.check_loop_count(3) + +class TestNumpyOld(LLJitMixin): + def setup_class(cls): + from pypy.module.micronumpy.compile import FakeSpace + from pypy.module.micronumpy.interp_dtype import W_Float64Dtype + + cls.space = FakeSpace() + cls.float64_dtype = cls.space.fromcache(W_Float64Dtype) + def test_slice(self): def f(i): step = 3 @@ -332,17 +274,3 @@ result = self.meta_interp(f, [5], listops=True, backendopt=True) assert result == f(5) -class TestTranslation(object): - def test_compile(self): - x = numpy_compile('aa+f*f/a-', 10) - x = x.compute() - assert isinstance(x, SingleDimArray) - assert x.size == 10 - assert x.eval(0).val == 0 - assert x.eval(1).val == ((1 + 1) * 1.2) / 1.2 - 1 - - def test_translation(self): - # we import main to check if the target compiles - from pypy.translator.goal.targetnumpystandalone import main - - interpret(main, [llstr('af+'), 100]) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -69,4 +69,51 @@ i9 = int_add(i5, 1) --TICK-- jump(..., descr=...) + """) + + def test_non_virtual_dict(self): + def main(n): + i = 0 + while i < n: + d = {str(i): i} + i += d[str(i)] - i + 1 + return i + + log = self.run(main, [1000]) + assert log.result == main(1000) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i8 = int_lt(i5, i7) + guard_true(i8, descr=...) + guard_not_invalidated(descr=...) + p10 = call(ConstClass(ll_int_str), i5, descr=<GcPtrCallDescr>) + guard_no_exception(descr=...) + i12 = call(ConstClass(ll_strhash), p10, descr=<SignedCallDescr>) + p13 = new(descr=...) + p15 = new_array(8, descr=<dictentryArrayDescr>) + setfield_gc(p13, p15, descr=<GcPtrFieldDescr dicttable.entries .*>) + i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>) + setfield_gc(p13, 16, descr=<SignedFieldDescr dicttable.resize_counter 16>) + guard_no_exception(descr=...) + p20 = new_with_vtable(ConstClass(W_IntObject)) + call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<VoidCallDescr>) + setfield_gc(p20, i5, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>) + guard_no_exception(descr=...) + i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>) + guard_no_exception(descr=...) + i26 = int_and(i23, .*) + i27 = int_is_true(i26) + guard_false(i27, descr=...) + p28 = getfield_gc(p13, descr=<GcPtrFieldDescr dicttable.entries .*>) + p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>) + guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...) + i31 = getfield_gc_pure(p29, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>) + i32 = int_sub_ovf(i31, i5) + guard_no_overflow(descr=...) + i34 = int_add_ovf(i32, 1) + guard_no_overflow(descr=...) + i35 = int_add_ovf(i5, i34) + guard_no_overflow(descr=...) + --TICK-- + jump(p0, p1, p2, p3, p4, i35, p13, i7, descr=<Loop0>) """) \ No newline at end of file diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -20,6 +20,7 @@ from pypy.rpython.rmodel import Repr from pypy.rpython.lltypesystem import llmemory from pypy.tool.sourcetools import func_with_new_name +from pypy.rpython.lltypesystem.lloperation import llop # ____________________________________________________________ # @@ -364,8 +365,10 @@ while lpos < rpos and s.chars[lpos] == ch: lpos += 1 if right: - while lpos < rpos and s.chars[rpos] == ch: + while lpos < rpos + 1 and s.chars[rpos] == ch: rpos -= 1 + if rpos < lpos: + return s.empty() r_len = rpos - lpos + 1 result = s.malloc(r_len) s.copy_contents(s, result, lpos, 0, r_len) diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py --- a/pypy/rpython/test/test_rstr.py +++ b/pypy/rpython/test/test_rstr.py @@ -372,12 +372,20 @@ return const('!ab!').lstrip(const('!')) def right(): return const('!ab!').rstrip(const('!')) + def empty(): + return const(' ').strip(' ') + def left2(): + return const('a ').strip(' ') res = self.interpret(both, []) assert self.ll_to_string(res) == const('ab') res = self.interpret(left, []) assert self.ll_to_string(res) == const('ab!') res = self.interpret(right, []) assert self.ll_to_string(res) == const('!ab') + res = self.interpret(empty, []) + assert self.ll_to_string(res) == const('') + res = self.interpret(left2, []) + assert self.ll_to_string(res) == const('a') def test_upper(self): const = self.const _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit