[pypy-commit] pypy vecopt: enhanced test env to check schedule operation

plan_rich noreply at buildbot.pypy.org
Tue May 26 16:56:41 CEST 2015


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt
Changeset: r77583:9eec1d3c661e
Date: 2015-05-26 14:17 +0200
http://bitbucket.org/pypy/pypy/changeset/9eec1d3c661e/

Log:	enhanced test env to check schedule operation added same_shape to
	AbstractValue (needed for comparison of two BoxVector and their
	shape) found an error where returned box had an invalid shape

diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -127,6 +127,10 @@
     def same_box(self, other):
         return self is other
 
+    def same_shape(self, other):
+        # only structured containers can compare their shape (vector box)
+        return True
+
 
 class AbstractDescr(AbstractValue):
     __slots__ = ()
@@ -391,8 +395,8 @@
                 t = 'b'
             self._str = '%s%d' % (t, Box._counter)
             if self.type == VECTOR:
-                self._str += '[%s%d#%d]' % (self.item_type, self.item_size * 8,
-                                            self.item_count)
+                self._str = '%s%d[%s%d#%d]' % (t, Box._counter, self.item_type,
+                                               self.item_size * 8, self.item_count)
             Box._counter += 1
         return self._str
 
@@ -551,19 +555,19 @@
     _attrs_ = ('item_type','item_count','item_size','signed')
     _extended_display = False
 
-    def __init__(self, item_type=FLOAT, item_count=2, item_size=8, signed=True):
+    def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False):
         assert item_type in (FLOAT, INT)
         self.item_type = item_type
         self.item_count = item_count
         self.item_size = item_size
-        self.signed = signed
+        self.item_signed = item_signed
 
     def gettype(self):
         return self.item_type
     def getsize(self):
         return self.item_size
     def getsigned(self):
-        return self.signed
+        return self.item_signed
     def getcount(self):
         return self.item_count
 
@@ -571,7 +575,7 @@
         raise NotImplementedError("cannot forget value of vector")
 
     def clonebox(self):
-        return BoxVector(self.item_type, self.item_count, self.item_size, self.signed)
+        return BoxVector(self.item_type, self.item_count, self.item_size, self.item_signed)
 
     def constbox(self):
         raise NotImplementedError("not possible to have a constant vector box")
@@ -582,6 +586,24 @@
     def repr_rpython(self):
         return repr_rpython(self, 'bv')
 
+    def same_shape(self, other):
+        if not isinstance(other, BoxVector):
+            return False
+        #
+        if other.item_size == -1 or self.item_size == -1:
+            # fallback for tests that do not specify the size
+            return True
+        #
+        if self.item_type != other.item_type:
+            return False
+        if self.item_size != other.item_size:
+            return False
+        if self.item_count != other.item_count:
+            return False
+        if self.item_signed != other.item_signed:
+            return False
+        return True
+
 # ____________________________________________________________
 
 
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
@@ -1,13 +1,66 @@
 import py
 
+from rpython.jit.metainterp.optimizeopt.util import equaloplists
+from rpython.jit.metainterp.optimizeopt.vectorize import (VecScheduleData,
+        Pack)
+from rpython.jit.metainterp.optimizeopt.dependency import Node
 from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
 from rpython.jit.metainterp.optimizeopt.test.test_dependency import DependencyBaseTest
+from rpython.jit.tool.oparser import parse as opparse
+from rpython.jit.tool.oparser_model import get_model
 
 class SchedulerBaseTest(DependencyBaseTest):
 
-    def test_schedule_split_arith(self):
-        pass
+    def parse(self, source):
+        ns = {
+            'double': self.floatarraydescr,
+            'float': self.singlefloatarraydescr,
+        }
+        loop = opparse("        [p0,p1,p2,p3,p4,p5,i0,i1,i2,i3,i4,i5,f0,f1,f2,f3,f4,f5]\n" + source + \
+                       "\n        jump(p0,p1,p2,p3,p4,p5,i0,i1,i2,i3,i4,i5,f0,f1,f2,f3,f4,f5)",
+                       cpu=self.cpu,
+                       namespace=ns)
+        del loop.operations[-1]
+        return loop
 
+    def pack(self, loop, l, r):
+        return [Node(op,i) for i,op in enumerate(loop.operations[l:r])]
+
+    def schedule(self, loop_orig, packs, vec_reg_size=16):
+        loop = get_model(False).ExtendedTreeLoop("loop")
+        loop.original_jitcell_token = loop_orig.original_jitcell_token
+        loop.inputargs = loop_orig.inputargs
+
+        ops = []
+        vsd = VecScheduleData(vec_reg_size)
+        for pack in packs:
+            if len(pack) == 1:
+                ops.append(pack[0])
+            else:
+                for op in vsd.as_vector_operation(Pack(pack)):
+                    ops.append(op)
+        loop.operations = ops
+        return loop
+
+    def assert_operations_match(self, loop_a, loop_b):
+        assert equaloplists(loop_a.operations, loop_b.operations)
+
+    def test_schedule_split_load(self):
+        loop1 = self.parse("""
+        i10 = raw_load(p0, i0, descr=float)
+        i11 = raw_load(p0, i1, descr=float)
+        i12 = raw_load(p0, i2, descr=float)
+        i13 = raw_load(p0, i3, descr=float)
+        i14 = raw_load(p0, i4, descr=float)
+        i15 = raw_load(p0, i5, descr=float)
+        """)
+        pack1 = self.pack(loop1, 0, 6)
+        loop2 = self.schedule(loop1, [pack1])
+        loop3 = self.parse("""
+        v1[i32#4] = vec_raw_load(p0, i0, 4, descr=float)
+        v1[i32#2] = vec_raw_load(p0, i4, 2, descr=float)
+        """)
+        self.assert_equal(loop2, loop3)
 
 class TestLLType(SchedulerBaseTest, LLtypeMixin):
     pass
diff --git a/rpython/jit/metainterp/optimizeopt/util.py b/rpython/jit/metainterp/optimizeopt/util.py
--- a/rpython/jit/metainterp/optimizeopt/util.py
+++ b/rpython/jit/metainterp/optimizeopt/util.py
@@ -156,14 +156,17 @@
         for i in range(op1.numargs()):
             x = op1.getarg(i)
             y = op2.getarg(i)
+            assert x.same_shape(y)
             assert x.same_box(remap.get(y, y))
         if op2.result in remap:
             if op2.result is None:
                 assert op1.result == remap[op2.result]
             else:
+                assert op1.result.same_shape(op2.result)
                 assert op1.result.same_box(remap[op2.result])
         else:
             remap[op2.result] = op1.result
+            assert op2.result.same_shape(op1.result)
         if op1.getopnum() not in [rop.JUMP, rop.LABEL] and not op1.is_guard():
             assert op1.getdescr() == op2.getdescr()
         if op1.getfailargs() or op2.getfailargs():
diff --git a/rpython/jit/metainterp/optimizeopt/vectorize.py b/rpython/jit/metainterp/optimizeopt/vectorize.py
--- a/rpython/jit/metainterp/optimizeopt/vectorize.py
+++ b/rpython/jit/metainterp/optimizeopt/vectorize.py
@@ -743,16 +743,12 @@
 
 
 class OpToVectorOp(object):
-    def __init__(self, arg_ptypes, result_ptype, has_descr=False,
-                 arg_clone_ptype=0, 
-                 needs_count_in_params=False):
+    def __init__(self, arg_ptypes, result_ptype):
         self.arg_ptypes = [a for a in arg_ptypes] # do not use a tuple. rpython cannot union
         self.result_ptype = result_ptype
-        self.has_descr = has_descr
-        self.arg_clone_ptype = arg_clone_ptype
-        self.needs_count_in_params = needs_count_in_params
         self.preamble_ops = None
         self.sched_data = None
+        self.pack = None
 
     def is_vector_arg(self, i):
         if i < 0 or i >= len(self.arg_ptypes):
@@ -760,17 +756,11 @@
         return self.arg_ptypes[i] is not None
 
     def pack_ptype(self, op):
-        opnum = op.vector
-        args = op.getarglist()
-        result = op.result
-        if self.has_descr:
-            descr = op.getdescr()
-            return PackType.by_descr(descr, self.sched_data.vec_reg_size)
-        if self.arg_clone_ptype >= 0:
-            arg = args[self.arg_clone_ptype]
-            _, vbox = self.sched_data.box_to_vbox.get(arg, (-1, None))
-            if vbox:
-                return PackType.of(vbox)
+        _, vbox = self.getvector_of_box(op.getarg(0))
+        if vbox:
+            return PackType.of(vbox)
+        else:
+            raise RuntimeError("fatal: box %s is not in a vector box" % (arg,))
 
     def as_vector_operation(self, pack, sched_data, oplist):
         self.sched_data = sched_data
@@ -783,9 +773,11 @@
         assert stride > 0
         while off < len(pack.operations):
             ops = pack.operations[off:off+stride]
+            self.pack = Pack(ops)
             self.transform_pack(ops, off, stride)
             off += stride
 
+        self.pack = None
         self.preamble_ops = None
         self.sched_data = None
         self.ptype = None
@@ -797,43 +789,47 @@
             return vec_reg_size // self.ptype.getsize()
         return pack_count
 
+    def before_argument_transform(self, args):
+        pass
+
     def transform_pack(self, ops, off, stride):
-        op = ops[0].getoperation()
+        op = self.pack.operations[0].getoperation()
         args = op.getarglist()
-        if self.needs_count_in_params:
-            args.append(ConstInt(len(ops)))
+        #
+        self.before_argument_transform(args)
+        #
         result = op.result
-        descr = op.getdescr()
         for i,arg in enumerate(args):
             if self.is_vector_arg(i):
-                args[i] = self.transform_argument(ops, args[i], i, off, stride)
+                args[i] = self.transform_argument(args[i], i, off)
         #
-        result = self.transform_result(ops, result, off)
+        result = self.transform_result(result, off)
         #
-        vop = ResOperation(op.vector, args, result, descr)
+        vop = ResOperation(op.vector, args, result, op.getdescr())
         self.preamble_ops.append(vop)
 
-    def transform_result(self, ops, result, off):
+    def transform_result(self, result, off):
         if result is None:
             return None
         vbox = self.new_result_vector_box()
         #
         # mark the position and the vbox in the hash
-        for i, node in enumerate(ops):
+        for i, node in enumerate(self.pack.operations):
             op = node.getoperation()
             self.sched_data.setvector_of_box(op.result, i, vbox)
         return vbox
 
     def new_result_vector_box(self):
         size = self.ptype.getsize()
-        count = self.ptype.getcount()
+        count = min(self.ptype.getcount(), len(self.pack.operations))
         return BoxVector(self.ptype.gettype(), count, size, self.ptype.signed)
 
-    def transform_argument(self, ops, arg, argidx, off, count):
+    def transform_argument(self, arg, argidx, off):
+        ops = self.pack.operations
         box_pos, vbox = self.sched_data.getvector_of_box(arg)
         if not vbox:
             # constant/variable expand this box
-            vbox = self.ptype.new_vector_box(count)
+            vbox = self.ptype.new_vector_box(len(ops))
             vbox = self.expand_box_to_vector_box(vbox, ops, arg, argidx)
             box_pos = 0
 
@@ -1017,6 +1013,25 @@
             count = vec_reg_size // self.size
         return BoxVector(self.result_ptype.gettype(), count, self.size, self.ptype.signed)
 
+PT_GENERIC = PackType(PackType.UNKNOWN_TYPE, -1, False)
+
+class LoadToVectorLoad(OpToVectorOp):
+    def __init__(self):
+        OpToVectorOp.__init__(self, (), PT_GENERIC)
+
+    def pack_ptype(self, op):
+        return PackType.by_descr(op.getdescr(), self.sched_data.vec_reg_size)
+
+    def before_argument_transform(self, args):
+        args.append(ConstInt(len(self.pack.operations)))
+
+class StoreToVectorStore(OpToVectorOp):
+    def __init__(self):
+        OpToVectorOp.__init__(self, (None, None, PT_GENERIC), None)
+        self.has_descr = True
+
+    def pack_ptype(self, op):
+        return PackType.by_descr(op.getdescr(), self.sched_data.vec_reg_size)
 
 PT_FLOAT = PackType(FLOAT, 4, False)
 PT_DOUBLE = PackType(FLOAT, 8, False)
@@ -1024,15 +1039,16 @@
 PT_INT64 = PackType(INT, 8, True)
 PT_INT32 = PackType(INT, 4, True)
 PT_INT_GENERIC = PackType(INT, -1, True)
-PT_GENERIC = PackType(PackType.UNKNOWN_TYPE, -1, True)
+PT_GENERIC = PackType(PackType.UNKNOWN_TYPE, -1, False)
 
 INT_RES = PT_INT_GENERIC
 FLOAT_RES = PT_FLOAT_GENERIC
-LOAD_RES = PT_GENERIC
 
 INT_OP_TO_VOP = OpToVectorOp((PT_INT_GENERIC, PT_INT_GENERIC), INT_RES)
 FLOAT_OP_TO_VOP = OpToVectorOp((PT_FLOAT_GENERIC, PT_FLOAT_GENERIC), FLOAT_RES)
 FLOAT_SINGLE_ARG_OP_TO_VOP = OpToVectorOp((PT_FLOAT_GENERIC,), FLOAT_RES)
+LOAD_TRANS = LoadToVectorLoad()
+STORE_TRANS = StoreToVectorStore()
 
 ROP_ARG_RES_VECTOR = {
     rop.VEC_INT_ADD:     INT_OP_TO_VOP,
@@ -1052,17 +1068,10 @@
     rop.VEC_FLOAT_NEG:   FLOAT_SINGLE_ARG_OP_TO_VOP,
     rop.VEC_FLOAT_EQ:    OpToVectorOp((PT_FLOAT_GENERIC,PT_FLOAT_GENERIC), INT_RES),
 
-    rop.VEC_RAW_LOAD:         OpToVectorOp((), LOAD_RES, has_descr=True,
-                                           arg_clone_ptype=-2,
-                                           needs_count_in_params=True
-                                          ),
-    rop.VEC_GETARRAYITEM_RAW: OpToVectorOp((), LOAD_RES,
-                                           has_descr=True,
-                                           arg_clone_ptype=-2,
-                                           needs_count_in_params=True
-                                          ),
-    rop.VEC_RAW_STORE:        OpToVectorOp((None,None,PT_GENERIC,), None, has_descr=True, arg_clone_ptype=2),
-    rop.VEC_SETARRAYITEM_RAW: OpToVectorOp((None,None,PT_GENERIC,), None, has_descr=True, arg_clone_ptype=2),
+    rop.VEC_RAW_LOAD:         LOAD_TRANS,
+    rop.VEC_GETARRAYITEM_RAW: LOAD_TRANS,
+    rop.VEC_RAW_STORE:        STORE_TRANS,
+    rop.VEC_SETARRAYITEM_RAW: STORE_TRANS,
 
     rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: OpToVectorOpConv(PT_DOUBLE, PT_FLOAT),
     rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: OpToVectorOpConv(PT_FLOAT, PT_DOUBLE),
diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py
--- a/rpython/jit/tool/oparser.py
+++ b/rpython/jit/tool/oparser.py
@@ -3,6 +3,8 @@
 in a nicer fashion
 """
 
+import re
+
 from rpython.jit.tool.oparser_model import get_model
 
 from rpython.jit.metainterp.resoperation import rop, ResOperation, \
@@ -121,8 +123,20 @@
             box = ts.BoxRef()
             _box_counter_more_than(self.model, elem[1:])
         elif elem.startswith('v'):
-            box = self.model.BoxVector()
-            _box_counter_more_than(self.model, elem[1:])
+            pattern = re.compile('.*\[(-?)(i|f)(\d+)#(\d+)\]')
+            match = pattern.match(elem)
+            if match:
+                item_type = match.group(2)[0]
+                item_size = int(match.group(3)) // 8
+                item_count = int(match.group(4))
+                item_signed = match.group(1) == 's'
+                box = self.model.BoxVector(item_type, item_count, item_size, item_signed)
+                lbracket = elem.find('[')
+                number = elem[1:lbracket]
+            else:
+                box = self.model.BoxVector()
+                number = elem[1:]
+            _box_counter_more_than(self.model, number)
         else:
             for prefix, boxclass in self.boxkinds.iteritems():
                 if elem.startswith(prefix):


More information about the pypy-commit mailing list