Author: Richard Plangger <[email protected]>
Branch: vecopt-merge
Changeset: r79643:d1e29e8b7db7
Date: 2015-09-15 12:13 +0200
http://bitbucket.org/pypy/pypy/changeset/d1e29e8b7db7/
Log: revived broken as_vector_operation, partly working now, still need
to adapt it further to work in the current setup
diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py
b/rpython/jit/metainterp/optimizeopt/schedule.py
--- a/rpython/jit/metainterp/optimizeopt/schedule.py
+++ b/rpython/jit/metainterp/optimizeopt/schedule.py
@@ -1,7 +1,7 @@
from rpython.jit.metainterp.history import (VECTOR, FLOAT, INT,
ConstInt, ConstFloat, TargetToken)
from rpython.jit.metainterp.resoperation import (rop, ResOperation,
- GuardResOp, VecOperation)
+ GuardResOp, VecOperation, OpHelpers)
from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph,
MemoryRef, Node, IndexVar)
from rpython.jit.metainterp.optimizeopt.renamer import Renamer
@@ -437,10 +437,7 @@
pos, vecop = state.getvector_of_box(arg)
if not vecop:
# 2) constant/variable expand this box
- # TODO just as one function call
- vecop = expand(state, pack, args, arg, i)
- state.setvector_of_box(arg, 0, vecop)
- pos = 0
+ expand(state, pack, args, arg, i)
continue
args[i] = vecop
assemble_scattered_values(state, pack, args, i)
@@ -688,18 +685,13 @@
assert index.value + count.value <= result.getcount()
assert result.getcount() > arg0.getcount()
-def expand(state, pack, op, arg, argidx):
+def expand(state, pack, args, arg, index):
""" Expand a value into a vector box. useful for arith metic
of one vector with a scalar (either constant/varialbe)
"""
- vecop = OpHelpers.create_vec(OpHelpers.vector_for_type(arg.type), None,
- arg.type, op.bytesize, op.signed, op.count)
+ left = pack.leftmost()
box_type = arg.type
- #expanded_map = state.expanded_map
- ## note that heterogenous nodes are not yet tracked
- #already_expanded = expanded_map.get(arg, None)
- #if already_expanded:
- # return already_expanded
+ expanded_map = state.expanded_map
ops = state.invariant_oplist
variables = state.invariant_vector_vars
@@ -707,36 +699,40 @@
ops = self.vecops
variables = None
- for i, node in enumerate(self.getoperations()):
+ for i, node in enumerate(pack.operations):
op = node.getoperation()
- if not arg.same_box(op.getarg(argidx)):
+ if not arg.same_box(op.getarg(index)):
break
i += 1
else:
- vecop = OpHelpers.create_expand(arg.type, arg, op.count)
- ops.append(vecop)
- ops.append(op)
+ # note that heterogenous nodes are not yet tracked
+ already_expanded = expanded_map.get(arg, None)
+ if already_expanded:
+ return already_expanded
+ vecop = OpHelpers.create_vec_expand(arg, op.bytesize, op.signed,
pack.numops())
+ state.oplist.append(vecop)
if variables is not None:
variables.append(vecop)
expanded_map[arg] = vecop
- return vbox
+ for i in range(vecop.count):
+ state.setvector_of_box(arg, i, vecop)
+ args[index] = vecop
+ return vecop
- op = ResOperation(rop.VEC_BOX, [ConstInt(elem_count)], vbox)
- ops.append(op)
- opnum = getpackopnum(arg.type)
- for i,node in enumerate(self.getoperations()):
+ vecop = OpHelpers.create_vec(arg.type, left.bytesize, left.signed)
+ state.oplist.append(vecop)
+ for i,node in enumerate(pack.operations):
op = node.getoperation()
- arg = op.getarg(argidx)
- new_box = vbox.clonebox()
- ci = ConstInt(i)
- c1 = ConstInt(1)
- op = ResOperation(opnum, [vbox,arg,ci,c1], new_box)
- vbox = new_box
- ops.append(op)
+ arg = op.getarg(index)
+ arguments = [vecop, arg, ConstInt(i), ConstInt(1)]
+ vecop = OpHelpers.create_vec_pack(arg.type, arguments, left.bytesize,
+ left.signed, vecop.count+1)
+ state.setvector_of_box(arg, i, vecop)
+ state.oplist.append(vecop)
if variables is not None:
- variables.append(vbox)
- return vbox
+ variables.append(vecop)
+ args[index] = vecop
class OpToVectorOp(object):
def __init__(self): #, restrictargs, typeoutput):
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
@@ -17,14 +17,6 @@
from rpython.jit.tool.oparser import parse as opparse
from rpython.jit.tool.oparser_model import get_model
-F64 = None #('f',8,False)
-F32 = None #('f',4,False)
-F32_2 = None #('f',4,False)
-I64 = None #('i',8,True)
-I32 = None #('i',4,True)
-I32_2 = None #('i',4,True)
-I16 = None #('i',2,True)
-
class FakePackSet(PackSet):
def __init__(self, packs):
self.packs = packs
@@ -176,10 +168,10 @@
pack1 = self.pack(loop1, 0, 2)
loop2 = self.schedule(loop1, [pack1], prepend_invariant=True)
loop3 = self.parse_trace("""
- v10[2xi64] = vec_box_i()
- v20[2xi64] = vec_int_pack(v10[2xi64], i0, 0, 1)
- v30[2xi64] = vec_int_pack(v20[2xi64], i1, 1, 1)
- v40[2xi64] = vec_int_expand(73,2)
+ v10[0xi64] = vec_i()
+ v20[1xi64] = vec_pack_i(v10[2xi64], i0, 0, 1)
+ v30[2xi64] = vec_pack_i(v20[2xi64], i1, 1, 1)
+ v40[2xi64] = vec_expand_i(73)
#
v50[2xi64] = vec_int_add(v30[2xi64], v40[2xi64])
""", False)
@@ -189,13 +181,13 @@
f10 = float_add(f0, 73.0)
f11 = float_add(f1, 73.0)
""")
- pack1 = self.pack(loop1, 0, 2, F64, F64)
+ pack1 = self.pack(loop1, 0, 2)
loop2 = self.schedule(loop1, [pack1], prepend_invariant=True)
loop3 = self.parse_trace("""
- v10[2xf64] = vec_box_f()
- v20[2xf64] = vec_float_pack(v10[2xf64], f0, 0, 1)
- v30[2xf64] = vec_float_pack(v20[2xf64], f1, 1, 1)
- v40[2xf64] = vec_float_expand(73.0,2)
+ v10[0xf64] = vec_f()
+ v20[1xf64] = vec_pack_f(v10[2xf64], f0, 0, 1)
+ v30[2xf64] = vec_pack_f(v20[2xf64], f1, 1, 1)
+ v40[2xf64] = vec_expand_f(73.0)
#
v50[2xf64] = vec_float_add(v30[2xf64], v40[2xf64])
""", False)
@@ -208,14 +200,14 @@
f12 = float_add(f10, f5)
f13 = float_add(f11, f5)
""")
- pack1 = self.pack(loop1, 0, 2, F64, F64)
- pack2 = self.pack(loop1, 2, 4, F64, F64)
+ pack1 = self.pack(loop1, 0, 2)
+ pack2 = self.pack(loop1, 2, 4)
loop2 = self.schedule(loop1, [pack1, pack2], prepend_invariant=True)
loop3 = self.parse_trace("""
- v10[2xf64] = vec_box_f()
- v20[2xf64] = vec_float_pack(v10[2xf64], f0, 0, 1)
- v30[2xf64] = vec_float_pack(v20[2xf64], f1, 1, 1)
- v40[2xf64] = vec_float_expand(f5,2) # only expaned once
+ v10[0xf64] = vec_f()
+ v20[1xf64] = vec_pack_f(v10[2xf64], f0, 0, 1)
+ v30[2xf64] = vec_pack_f(v20[2xf64], f1, 1, 1)
+ v40[2xf64] = vec_expand_f(f5) # only expaned once
#
v50[2xf64] = vec_float_add(v30[2xf64], v40[2xf64])
v60[2xf64] = vec_float_add(v50[2xf64], v40[2xf64])
@@ -233,7 +225,7 @@
i10 = int_signext(i1, 4)
i11 = int_signext(i1, 4)
""", additional_args=['v10[2xi64]'])
- pack1 = self.pack(loop1, 0, 2, I64, I32_2)
+ pack1 = self.pack(loop1, 0, 2)
var = self.find_input_arg('v10', loop1)
def i1inv103204(v):
return 0, var
@@ -284,11 +276,10 @@
raw_store(p1, i7, i24, descr=short)
raw_store(p1, i8, i25, descr=short)
""")
- pack1 = self.pack(loop1, 0, 8, None, F64)
- pack2 = self.pack(loop1, 8, 16, F64, I32_2)
- I16_2 = None #Type('i',2,True)
- pack3 = self.pack(loop1, 16, 24, I32_2, I16_2)
- pack4 = self.pack(loop1, 24, 32, I16, None)
+ pack1 = self.pack(loop1, 0, 8)
+ pack2 = self.pack(loop1, 8, 16)
+ pack3 = self.pack(loop1, 16, 24)
+ pack4 = self.pack(loop1, 24, 32)
def void(b,c):
pass
loop2 = self.schedule(loop1, [pack1,pack2,pack3,pack4],
@@ -308,9 +299,9 @@
v19[2xi16] = vec_int_signext(v15[2xi32],2)
v20[2xi16] = vec_int_signext(v16[2xi32],2)
v21[2xi16] = vec_int_signext(v17[2xi32],2)
- v22[4xi16] = vec_int_pack(v18[2xi16], v19[2xi16], 2, 2)
- v23[6xi16] = vec_int_pack(v22[4xi16], v20[2xi16], 4, 2)
- v24[8xi16] = vec_int_pack(v23[6xi16], v21[2xi16], 6, 2)
+ v22[4xi16] = vec_pack_i(v18[2xi16], v19[2xi16], 2, 2)
+ v23[6xi16] = vec_pack_i(v22[4xi16], v20[2xi16], 4, 2)
+ v24[8xi16] = vec_pack_i(v23[6xi16], v21[2xi16], 6, 2)
vec_raw_store(p1, i1, v24[8xi16], descr=short)
""", False)
self.assert_equal(loop2, loop3)
@@ -332,16 +323,16 @@
raw_store(p1, i3, i12, descr=float)
raw_store(p1, i4, i13, descr=float)
""")
- pack1 = self.pack(loop1, 0, 4, None, F64)
- pack2 = self.pack(loop1, 4, 8, F64, I32_2)
- pack3 = self.pack(loop1, 8, 12, I32, None)
+ pack1 = self.pack(loop1, 0, 4)
+ pack2 = self.pack(loop1, 4, 8)
+ pack3 = self.pack(loop1, 8, 12)
loop2 = self.schedule(loop1, [pack1,pack2,pack3])
loop3 = self.parse_trace("""
v44[2xf64] = vec_raw_load_f(p0, i1, descr=double)
v45[2xf64] = vec_raw_load_f(p0, i3, descr=double)
v46[2xi32] = vec_cast_float_to_singlefloat(v44[2xf64])
v47[2xi32] = vec_cast_float_to_singlefloat(v45[2xf64])
- v41[4xi32] = vec_int_pack(v46[2xi32], v47[2xi32], 2, 2)
+ v41[4xi32] = vec_pack_i(v46[2xi32], v47[2xi32], 2, 2)
vec_raw_store(p1, i1, v41[4xi32], descr=float)
""", False)
self.assert_equal(loop2, loop3)
@@ -357,12 +348,12 @@
guard_true(i12) []
guard_true(i13) []
""")
- pack1 = self.pack(loop1, 0, 2, None, I64)
- pack2 = self.pack(loop1, 2, 4, I64, I64)
- pack3 = self.pack(loop1, 4, 6, I64, None)
+ pack1 = self.pack(loop1, 0, 2)
+ pack2 = self.pack(loop1, 2, 4)
+ pack3 = self.pack(loop1, 4, 6)
loop2 = self.schedule(loop1, [pack1,pack2,pack3],
prepend_invariant=True)
loop3 = self.parse_trace("""
- v9[2xi64] = vec_int_expand(255,2)
+ v9[2xi64] = vec_expand_i(255)
v10[2xi64] = vec_raw_load_i(p0, i1, descr=long)
v11[2xi64] = vec_int_and(v10[2xi64], v9[2xi64])
guard_true(v11[2xi64]) []
@@ -379,14 +370,14 @@
raw_store(p0, i3, i10, descr=float)
raw_store(p0, i4, i11, descr=float)
""")
- pack1 = self.pack(loop1, 0, 4, None, I32)
- pack2 = self.pack(loop1, 4, 6, I32_2, None)
+ pack1 = self.pack(loop1, 0, 4)
+ pack2 = self.pack(loop1, 4, 6)
loop2 = self.schedule(loop1, [pack1,pack2], prepend_invariant=True)
loop3 = self.parse_trace("""
v1[4xi32] = vec_raw_load_i(p0, i1, descr=float)
- i10 = vec_int_unpack(v1[4xi32], 0, 1)
+ i10 = vec_unpack_i(v1[4xi32], 0, 1)
raw_store(p0, i3, i10, descr=float)
- i11 = vec_int_unpack(v1[4xi32], 1, 1)
+ i11 = vec_unpack_i(v1[4xi32], 1, 1)
raw_store(p0, i4, i11, descr=float)
""", False)
# unfortunate ui32 is the type for float32... the unsigned u is for
@@ -398,11 +389,11 @@
i10 = int_and(255, i1)
i11 = int_and(255, i1)
""")
- pack1 = self.pack(loop1, 0, 2, I64, I64)
+ pack1 = self.pack(loop1, 0, 2)
loop2 = self.schedule(loop1, [pack1], prepend_invariant=True)
loop3 = self.parse_trace("""
- v1[2xi64] = vec_int_expand(255,2)
- v2[2xi64] = vec_int_expand(i1,2)
+ v1[2xi64] = vec_expand_i(255)
+ v2[2xi64] = vec_expand_i(i1)
v3[2xi64] = vec_int_and(v1[2xi64], v2[2xi64])
""", False)
self.assert_equal(loop2, loop3)
@@ -412,11 +403,11 @@
i10 = int_and(255, i1)
i11 = int_and(255, i1)
""")
- pack1 = self.pack(loop1, 0, 2, I64, I64)
+ pack1 = self.pack(loop1, 0, 2)
loop2 = self.schedule(loop1, [pack1], prepend_invariant=True)
loop3 = self.parse_trace("""
- v1[2xi64] = vec_int_expand(255, 2)
- v2[2xi64] = vec_int_expand(i1, 2)
+ v1[2xi64] = vec_expand_i(255)
+ v2[2xi64] = vec_expand_i(i1)
v3[2xi64] = vec_int_and(v1[2xi64], v2[2xi64])
""", False)
self.assert_equal(loop2, loop3)
@@ -430,22 +421,22 @@
i14 = int_and(i1, i12)
i15 = int_and(i2, i13)
""")
- pack1 = self.pack(loop1, 0, 2, I64, I64)
- pack4 = self.pack(loop1, 4, 6, I64, I64)
+ pack1 = self.pack(loop1, 0, 2)
+ pack4 = self.pack(loop1, 4, 6)
loop2 = self.schedule(loop1, [pack1,pack4], prepend_invariant=True)
loop3 = self.parse_trace("""
- v1[2xi64] = vec_int_expand(255,2)
- v2[2xi64] = vec_box_i()
- v3[2xi64] = vec_int_pack(v2[2xi64], i1, 0, 1)
- v4[2xi64] = vec_int_pack(v3[2xi64], i2, 1, 1)
+ v1[2xi64] = vec_expand_i(255)
+ v2[0xi64] = vec_i()
+ v3[1xi64] = vec_pack_i(v2[2xi64], i1, 0, 1)
+ v4[2xi64] = vec_pack_i(v3[2xi64], i2, 1, 1)
v5[2xi64] = vec_int_and(v1[2xi64], v4[2xi64])
- i10 = vec_int_unpack(v5[2xi64], 0, 1)
+ i10 = vec_unpack_i(v5[2xi64], 0, 1)
i12 = uint_floordiv(i10,1)
- i11 = vec_int_unpack(v5[2xi64], 1, 1)
+ i11 = vec_unpack_i(v5[2xi64], 1, 1)
i13 = uint_floordiv(i11,1)
- v6[2xi64] = vec_box_i()
- v7[2xi64] = vec_int_pack(v6[2xi64], i12, 0, 1)
- v8[2xi64] = vec_int_pack(v7[2xi64], i13, 1, 1)
+ v6[0xi64] = vec_i()
+ v7[1xi64] = vec_pack_i(v6[2xi64], i12, 0, 1)
+ v8[2xi64] = vec_pack_i(v7[2xi64], i13, 1, 1)
v9[2xi64] = vec_int_and(v4[2xi64], v8[i64])
""", False)
self.assert_equal(loop2, loop3)
@@ -457,7 +448,7 @@
f12 = cast_int_to_float(i3)
f13 = cast_int_to_float(i4)
""")
- pack = self.pack(trace, 0, 4, I64, F32)
+ pack = self.pack(trace, 0, 4)
packs = []
pack.split(packs, 16)
packs.append(pack)
@@ -468,7 +459,7 @@
i10 = int_add(i1, i3)
i11 = int_add(i2, i3)
""")
- pack = self.pack(trace, 0, 2, I16, I16)
+ pack = self.pack(trace, 0, 2)
packset = FakePackSet([pack])
packset.split_overloaded_packs()
assert len(packset.packs) == 0
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
@@ -163,6 +163,7 @@
assert remap.get(y, y) is None
else:
assert x.same_box(remap.get(y, y))
+ assert x.same_shape(remap.get(y, y))
else:
fail_args1 = set(op1.getfailargs())
fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()])
diff --git a/rpython/jit/metainterp/optimizeopt/vector.py
b/rpython/jit/metainterp/optimizeopt/vector.py
--- a/rpython/jit/metainterp/optimizeopt/vector.py
+++ b/rpython/jit/metainterp/optimizeopt/vector.py
@@ -825,7 +825,6 @@
state.renamer.start_renaming(accum.getoriginalbox(), result)
def split_overloaded_packs(self):
- import pdb; pdb. set_trace()
newpacks = []
for i,pack in enumerate(self.packs):
load = pack.pack_load(self.vec_reg_size)
diff --git a/rpython/jit/metainterp/resoperation.py
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -36,6 +36,9 @@
def same_box(self, other):
return self is other
+ def same_shape(self, other):
+ return self is other
+
def repr_short(self, memo):
return self.repr(memo)
@@ -71,6 +74,9 @@
def returns_vector(self):
return False
+ def is_vector(self):
+ return False
+
def ResOperation(opnum, args, descr=None):
cls = opclasses[opnum]
op = cls()
@@ -684,16 +690,11 @@
""" NOT_RPYTHON """
if not other.is_vector():
return False
- #
- # TODO ? if other.item_size == -1 or self.item_size == -1:
- # fallback for tests that do not specify the size
- # return True
- #
if self.datatype != other.datatype:
return False
if self.bytesize != other.bytesize:
return False
- if self.signed!= other.signed:
+ if self.signed != other.signed:
return False
if self.count != other.count:
return False
@@ -752,8 +753,8 @@
self.setref_base(lltype.nullptr(llmemory.GCREF.TO))
class InputArgVector(VectorOp, AbstractInputArg):
- def __init__(self, datatype):
- self.datatype = datatype
+ def __init__(self):
+ self.type = 'v'
def returns_vector(self):
return True
@@ -1008,9 +1009,9 @@
'_VEC_CAST_LAST',
'VEC/0/if',
- 'VEC_UNPACK/3/if', # iX|fX = VEC_INT_UNPACK(vX, index, item_count)
- 'VEC_PACK/4/if', # VEC_INT_PACK(vX, var/const, index,
item_count)
- 'VEC_EXPAND/2/if', # vX = VEC_INT_EXPAND(var/const, item_count)
+ 'VEC_UNPACK/3/if', # iX|fX = VEC_INT_UNPACK(vX, index, count)
+ 'VEC_PACK/4/if', # VEC_INT_PACK(vX, var/const, index, count)
+ 'VEC_EXPAND/1/if', # vX = VEC_INT_EXPAND(var/const)
'_VEC_PURE_LAST',
#
'INT_LT/2b/i',
@@ -1566,20 +1567,29 @@
return InputArgFloat()
@staticmethod
- def create_expand(datatype, arg, bytesize, signed, count):
- if datatype == 'i':
+ def create_vec_expand(arg, bytesize, signed, count):
+ if arg.type == 'i':
opnum = rop.VEC_EXPAND_I
else:
- assert datatype == 'f'
+ assert arg.type == 'f'
opnum = rop.VEC_EXPAND_F
- return VecOperationNew(opnum, [arg], datatype, bytesize, signed, count)
+ return VecOperationNew(opnum, [arg], arg.type, bytesize, signed, count)
@staticmethod
- def create_vec(datatype, arg, bytesize, signed, count):
- if type == 'i':
+ def create_vec(datatype, bytesize, signed):
+ if datatype == 'i':
opnum = rop.VEC_I
else:
- assert type == 'f'
+ assert datatype == 'f'
opnum = rop.VEC_F
- return VecOperationNew(opnum, [arg], datatype, bytesize, signed, count)
+ return VecOperationNew(opnum, [], datatype, bytesize, signed, 0)
+ @staticmethod
+ def create_vec_pack(datatype, args, bytesize, signed, count):
+ if datatype == 'i':
+ opnum = rop.VEC_PACK_I
+ else:
+ assert datatype == 'f'
+ opnum = rop.VEC_PACK_F
+ return VecOperationNew(opnum, args, datatype, bytesize, signed, count)
+
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
@@ -8,8 +8,8 @@
from rpython.jit.tool.oparser_model import get_model
from rpython.jit.metainterp.resoperation import rop, ResOperation, \
- InputArgInt, InputArgRef, InputArgFloat, ResOpWithDescr, N_aryOp, \
- UnaryOp, PlainResOp, optypes
+ InputArgInt, InputArgRef, InputArgFloat, InputArgVector, \
+ ResOpWithDescr, N_aryOp, UnaryOp, PlainResOp, optypes
class ParseError(Exception):
pass
@@ -191,6 +191,9 @@
v = InputArgInt(0)
elif elem.startswith('f'):
v = InputArgFloat(0.0)
+ elif elem.startswith('v'):
+ v = InputArgVector()
+ elem = self.update_vector(v, elem)
else:
from rpython.rtyper.lltypesystem import lltype, llmemory
assert elem.startswith('p')
@@ -231,6 +234,11 @@
elif arg.startswith('ConstInt('):
name = arg[len('ConstInt('):-1]
return self.get_const(name, 'int')
+ elif arg.startswith('v') and '[' in arg:
+ i = 1
+ while i < len(arg) and arg[i] != '[':
+ i += 1
+ return self.getvar(arg[:i])
elif arg == 'None':
return None
elif arg == 'NULL':
@@ -344,11 +352,11 @@
if res in self.vars:
raise ParseError("Double assign to var %s in line: %s" % (res,
line))
resop = self.create_op(opnum, args, res, descr, fail_args)
- self.update_vector_count(resop, res)
+ res = self.update_vector(resop, res)
self.vars[res] = resop
return resop
- def update_vector_count(self, resop, var):
+ def update_vector(self, resop, var):
pattern = re.compile('.*\[(\d+)x(u?)(i|f)(\d+)\]')
match = pattern.match(var)
if match:
@@ -356,6 +364,8 @@
resop.signed = not (match.group(2) == 'u')
resop.datatype = match.group(3)
resop.bytesize = int(match.group(4)) // 8
+ return var[:var.find('[')]
+ return var
def parse_op_no_result(self, line):
opnum, args, descr, fail_args = self.parse_op(line)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit