Author: Richard Plangger <planri...@gmail.com> Branch: vecopt-merge Changeset: r79622:289407699445 Date: 2015-09-14 13:31 +0200 http://bitbucket.org/pypy/pypy/changeset/289407699445/
Log: slowly approaching the first passing scheduling test, code is smaller and more compact diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -355,7 +355,7 @@ def __repr__(self): pack = '' if self.pack: - pack = "p: %d" % self.pack.opcount() + pack = "p: %d" % self.pack.numops() return "Node(%s,%s i: %d)" % (self.op.getopname(), pack, self.opidx) def __ne__(self, other): 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 @@ -18,7 +18,7 @@ def post_schedule(self): loop = self.graph.loop - self.renamer.rename(loop.label.getoperation()) + self.renamer.rename(loop.jump) def profitable(self): return self.costmodel.profitable() @@ -66,7 +66,7 @@ Keeps worklist sorted (see priority) """ op = node.getoperation() state.renamer.rename(op) - state.unpack_from_vector(op, self) + state.unpack_from_vector(op) node.position = len(state.oplist) worklist = state.worklist for dep in node.provides()[:]: # COPY @@ -97,6 +97,7 @@ """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) + import pdb; pdb.set_trace() while state.has_more(): node = self.next(state) if node: @@ -177,40 +178,43 @@ rop.UINT_LT, rop.UINT_LE, rop.UINT_GT, rop.UINT_GE) -class Type(object): - """ The type of one operation. Saves type, size and sign. """ - @staticmethod - def of(op): - descr = op.getdescr() - if descr: - type = INT - if descr.is_array_of_floats() or descr.concrete_type == FLOAT: - type = FLOAT - size = descr.get_item_size_in_bytes() - sign = descr.is_item_signed() - return Type(type, size, sign) - else: - size = 8 - sign = True - if op.type == 'f' or op.getopnum() in UNSIGNED_OPS: - sign = False - return Type(op.type, size, sign) - - def __init__(self, type, size, signed): - assert type in (FLOAT, INT) - self.type = type - self.size = size - self.signed = signed - - def clone(self): - return Type(self.type, self.size, self.signed) - - def __repr__(self): - sign = '-' - if not self.signed: - sign = '+' - return 'Type(%s%s, %d)' % (sign, self.type, self.size) - +#class Type(object): +# """ The type of one operation. Saves type, size and sign. """ +# @staticmethod +# def of(op): +# descr = op.getdescr() +# if descr: +# type = INT +# if descr.is_array_of_floats() or descr.concrete_type == FLOAT: +# type = FLOAT +# size = descr.get_item_size_in_bytes() +# sign = descr.is_item_signed() +# return Type(type, size, sign) +# else: +# size = 8 +# sign = True +# if op.type == 'f' or op.getopnum() in UNSIGNED_OPS: +# sign = False +# return Type(op.type, size, sign) +# +# def __init__(self, type, size, signed): +# assert type in (FLOAT, INT) +# self.type = type +# self.size = size +# self.signed = signed +# +# def bytecount(self): +# return self.size +# +# def clone(self): +# return Type(self.type, self.size, self.signed) +# +# def __repr__(self): +# sign = '-' +# if not self.signed: +# sign = '+' +# return 'Type(%s%s, %d)' % (sign, self.type, self.size) +# #UNKNOWN_TYPE = '-' #@staticmethod @@ -268,10 +272,6 @@ #def getcount(self): # return self.count - #def pack_byte_size(self, pack): - # if len(pack.operations) == 0: - # return 0 - # return self.getsize() * pack.opcount() class TypeRestrict(object): ANY_TYPE = -1 @@ -301,6 +301,20 @@ self.type = type self.count = count + + def bytecount(self): + return self.count * self.type.bytecount() + +class DataTyper(object): + + def infer_type(self, op): + # default action, pass through: find the first arg + # the output is the same as the first argument! + if op.returns_void() or op.argcount() == 0: + return + arg0 = op.getarg(0) + op.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + class PassFirstArg(TypeOutput): def __init__(self): pass @@ -316,17 +330,14 @@ op = pack.leftmost() args = op.getarglist() self.prepare_arguments(state, op.getarglist()) - # - vop = VecOperation(op.vector, args, otype. op.getdescr()) - #result = self.transform_result(op) + vop = VecOperation(op.vector, args, op, pack.numops(), op.getdescr()) # if op.is_guard(): assert isinstance(op, GuardResOp) assert isinstance(vop, GuardResOp) vop.setfailargs(op.getfailargs()) vop.rd_snapshot = op.rd_snapshot - self.vecops.append(vop) - self.costmodel.record_pack_savings(self.pack, self.pack.opcount()) + state.costmodel.record_pack_savings(pack, pack.numops()) # if pack.is_accumulating(): box = oplist[position].result @@ -335,8 +346,10 @@ op = node.getoperation() assert not op.returns_void() scheduler.renamer.start_renaming(op, box) + # + state.oplist.append(vop) - def transform_arguments(self, state, args): + def prepare_arguments(self, state, args): self.before_argument_transform(args) # Transforming one argument to a vector box argument # The following cases can occur: @@ -732,12 +745,12 @@ def __init__(self): OpToVectorOp.__init__(self, (), TypeRestrict()) - def before_argument_transform(self, args): - count = min(self.output_type.getcount(), len(self.getoperations())) - args.append(ConstInt(count)) + # OLD def before_argument_transform(self, args): + #count = min(self.output_type.getcount(), len(self.getoperations())) + #args.append(ConstInt(count)) def get_output_type_given(self, input_type, op): - return Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) + return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) def get_input_type_given(self, output_type, op): return None @@ -760,7 +773,7 @@ return None def get_input_type_given(self, output_type, op): - return Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) + return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) class PassThroughOp(OpToVectorOp): """ This pass through is only applicable if the target @@ -778,7 +791,7 @@ class trans(object): - PASS = PassFirstArg() + DT_PASS = DataTyper() TR_ANY_FLOAT = TypeRestrict(FLOAT) TR_ANY_INTEGER = TypeRestrict(INT) @@ -787,9 +800,9 @@ TR_LONG = TypeRestrict(INT, 8, 2) TR_INT_2 = TypeRestrict(INT, 4, 2) - INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), PASS) - FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), PASS) - FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), PASS) + INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), DT_PASS) + FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), DT_PASS) + FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), DT_PASS) LOAD = LoadToVectorLoad() STORE = StoreToVectorStore() GUARD = PassThroughOp((TR_ANY_INTEGER,)) @@ -839,6 +852,11 @@ rop.VEC_INT_IS_TRUE: OpToVectorOp((TR_ANY_INTEGER,TR_ANY_INTEGER), None), # TR_ANY_INTEGER), } + # TODO? + UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, + rop.UINT_LT, rop.UINT_LE, + rop.UINT_GT, rop.UINT_GE) + def determine_input_output_types(pack, node, forward): """ This function is two fold. If moving forward, it gets an input type from the packs output type and returns @@ -888,9 +906,11 @@ def post_schedule(self): loop = self.graph.loop - self.sched_data.unpack_from_vector(loop.jump.getoperation(), self) + self.unpack_from_vector(loop.jump) SchedulerState.post_schedule(self) + self.graph.loop.operations = self.oplist + # add accumulation info to the descriptor #for version in self.loop.versions: # # this needs to be done for renamed (accum arguments) @@ -928,11 +948,11 @@ to emit the actual operation into the oplist of the scheduler. """ if node.pack: + assert node.pack.numops() > 1 for node in node.pack.operations: scheduler.mark_emitted(node, self) - assert node.pack.opcount() > 1 - op2vecop = determine_trans(node.pack.leftmost()) - op2vecop.as_vector_operation(self, node.pack) + op2vecop = determine_trans(node.pack.leftmost()) + op2vecop.as_vector_operation(self, node.pack) return True return False @@ -950,7 +970,7 @@ return True return False - def unpack_from_vector(self, op, scheduler): + def unpack_from_vector(self, op): """ If a box is needed that is currently stored within a vector box, this utility creates a unpacking instruction. """ @@ -959,7 +979,7 @@ # unpack for an immediate use for i, arg in enumerate(op.getarglist()): if not arg.is_constant(): - argument = self._unpack_from_vector(i, arg, scheduler) + argument = self._unpack_from_vector(i, arg) if arg is not argument: op.setarg(i, argument) if not op.returns_void(): @@ -969,11 +989,11 @@ fail_args = op.getfailargs() for i, arg in enumerate(fail_args): if arg and not arg.is_constant(): - argument = self._unpack_from_vector(i, arg, scheduler) + argument = self._unpack_from_vector(i, arg) if arg is not argument: fail_args[i] = argument - def _unpack_from_vector(self, i, arg, scheduler): + def _unpack_from_vector(self, i, arg): if arg in self.seen or arg.type == 'V': return arg (j, vbox) = self.getvector_of_box(arg) @@ -982,14 +1002,14 @@ return arg arg_cloned = arg.clonebox() self.seen[arg_cloned] = None - scheduler.renamer.start_renaming(arg, arg_cloned) + self.renamer.start_renaming(arg, arg_cloned) self.setvector_of_box(arg_cloned, j, vbox) cj = ConstInt(j) ci = ConstInt(1) opnum = getunpackopnum(vbox.gettype()) unpack_op = ResOperation(opnum, [vbox, cj, ci], arg_cloned) self.costmodel.record_vector_unpack(vbox, j, 1) - scheduler.oplist.append(unpack_op) + self.oplist.append(unpack_op) return arg_cloned return arg @@ -1042,15 +1062,19 @@ """ FULL = 0 - def __init__(self, ops, input_type, output_type): + def __init__(self, ops): self.operations = ops self.accum = None - self.input_type = input_type - self.output_type = output_type - assert self.input_type is not None or self.output_type is not None self.update_pack_of_nodes() + # initializes the type + # TODO + #input_type, output_type = \ + # determine_input_output_types(origin_pack, lnode, forward) + #self.input_type = input_type + #self.output_type = output_type + #assert self.input_type is not None or self.output_type is not None - def opcount(self): + def numops(self): return len(self.operations) def leftmost(self): @@ -1078,22 +1102,25 @@ return self._byte_size(self.output_type) def pack_load(self, vec_reg_size): - """ Returns the load of the pack. A value - smaller than 0 indicates that it is empty - or nearly empty, zero indicates that all slots - are used and > 0 indicates that too many operations - are in this pack instance. + """ Returns the load of the pack a vector register would hold + just after executing the operation. + returns: < 0 - empty, nearly empty + = 0 - full + > 0 - overloaded """ - if len(self.operations) == 0: + left = self.leftmost() + if left.returns_void(): + return 0 + if self.numops() == 0: return -1 size = maximum_byte_size(self, vec_reg_size) - if self.input_type is None: + return left.bytesize * self.numops() - size + #if self.input_type is None: # e.g. load operations - return self.output_type.pack_byte_size(self) - size + # return self.output_type.bytecount(self) - size # default only consider the input type # e.g. store operations, int_add, ... - return self.input_type.pack_byte_size(self) - size - + #return self.input_type.bytecount(self) - size def is_full(self, vec_reg_size): """ If one input element times the opcount is equal @@ -1131,12 +1158,14 @@ newpack = pack.clone(newoplist) load = newpack.pack_load(vec_reg_size) if load >= Pack.FULL: + pack.update_pack_of_nodes() pack = newpack packlist.append(newpack) else: newpack.clear() newpack.operations = [] break + pack.update_pack_of_nodes() def slice_operations(self, vec_reg_size): count = opcount_filling_vector_register(self, vec_reg_size) @@ -1163,31 +1192,26 @@ def __repr__(self): if len(self.operations) == 0: - return "Pack(-, [])" - opname = self.operations[0].getoperation().getopname() - return "Pack(%s,%r)" % (opname, self.operations) + return "Pack(empty)" + return "Pack(%dx %s)" % (self.numops(), self.operations[0]) def is_accumulating(self): return self.accum is not None def clone(self, oplist): - cloned = Pack(oplist, self.input_type, self.output_type) + cloned = Pack(oplist) cloned.accum = self.accum return cloned class Pair(Pack): """ A special Pack object with only two statements. """ - def __init__(self, left, right, input_type, output_type): + def __init__(self, left, right): assert isinstance(left, Node) assert isinstance(right, Node) self.left = left self.right = right - if input_type: - input_type = input_type.clone() - if output_type: - output_type = output_type.clone() - Pack.__init__(self, [left, right], input_type, output_type) + Pack.__init__(self, [left, right]) def __eq__(self, other): if isinstance(other, Pair): 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 @@ -7,7 +7,7 @@ Pack, Pair, NotAProfitableLoop, VectorizingOptimizer, X86_CostModel, PackSet) from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph -from rpython.jit.metainterp.optimizeopt.schedule import Type, Scheduler +from rpython.jit.metainterp.optimizeopt.schedule import Scheduler from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_dependency import (DependencyBaseTest, FakeDependencyGraph) @@ -17,13 +17,13 @@ from rpython.jit.tool.oparser import parse as opparse from rpython.jit.tool.oparser_model import get_model -F64 = Type('f',8,False) -F32 = Type('f',4,False) -F32_2 = Type('f',4,False) -I64 = Type('i',8,True) -I32 = Type('i',4,True) -I32_2 = Type('i',4,True) -I16 = Type('i',2,True) +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): @@ -68,7 +68,7 @@ return loop def pack(self, loop, l, r, input_type, output_type): - return Pack(loop.graph.nodes[1+l:1+r], input_type, output_type) + return Pack(loop.graph.nodes[1+l:1+r]) def schedule(self, loop, packs, vec_reg_size=16, prepend_invariant=False, overwrite_funcs=None): @@ -79,7 +79,7 @@ for i in range(len(pack.operations)-1): o1 = pack.operations[i] o2 = pack.operations[i+1] - pair = Pair(o1,o2,pack.input_type,pack.output_type) + pair = Pair(o1,o2) pairs.append(pair) packset = FakePackSet(pairs) state = VecScheduleState(loop.graph, packset, self.cpu, cm) @@ -94,6 +94,9 @@ state.prepend_invariant_operations = lambda list, _: list opt.combine_packset() opt.schedule(state) + # works for now. might be the wrong class? + # wrap label + operations + jump it in tree loop otherwise + return state.graph.loop class Test(SchedulerBaseTest, LLtypeMixin): @@ -124,7 +127,7 @@ pack1 = self.pack(loop1, 0, 6, None, F32) loop2 = self.schedule(loop1, [pack1]) loop3 = self.parse_trace(""" - v10[i32|4] = vec_raw_load_i(p0, i0, 4, descr=float) + v10[4xi32] = vec_raw_load_i(p0, i0, descr=float) f10 = raw_load_f(p0, i4, descr=float) f11 = raw_load_f(p0, i5, descr=float) """, False) @@ -144,7 +147,7 @@ pack3 = self.pack(loop1, 4, 6, I32_2, F32_2) loop2 = self.schedule(loop1, [pack1, pack2, pack3]) loop3 = self.parse_trace(""" - v10[i64|2] = vec_raw_load_i(p0, i0, 2, descr=long) + v10[i64|2] = vec_raw_load_i(p0, i0, descr=long) v20[i32|2] = vec_int_signext(v10[i64|2], 4) v30[f64|2] = vec_cast_int_to_float(v20[i32|2]) """, False) @@ -268,7 +271,7 @@ """) pack1 = self.pack(loop1, 0, 8, None, F64) pack2 = self.pack(loop1, 8, 16, F64, I32_2) - I16_2 = Type('i',2,True) + 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) def void(b,c): @@ -278,10 +281,10 @@ '_prevent_signext': void }) loop3 = self.parse_trace(""" - v10[f64|2] = vec_raw_load_f(p0, i1, 2, descr=double) - v11[f64|2] = vec_raw_load_f(p0, i3, 2, descr=double) - v12[f64|2] = vec_raw_load_f(p0, i5, 2, descr=double) - v13[f64|2] = vec_raw_load_f(p0, i7, 2, descr=double) + v10[f64|2] = vec_raw_load_f(p0, i1, descr=double) + v11[f64|2] = vec_raw_load_f(p0, i3, descr=double) + v12[f64|2] = vec_raw_load_f(p0, i5, descr=double) + v13[f64|2] = vec_raw_load_f(p0, i7, descr=double) v14[i32|2] = vec_cast_float_to_int(v10[f64|2]) v15[i32|2] = vec_cast_float_to_int(v11[f64|2]) v16[i32|2] = vec_cast_float_to_int(v12[f64|2]) @@ -319,8 +322,8 @@ pack3 = self.pack(loop1, 8, 12, I32, None) loop2 = self.schedule(loop1, [pack1,pack2,pack3]) loop3 = self.parse_trace(""" - v44[f64|2] = vec_raw_load_f(p0, i1, 2, descr=double) - v45[f64|2] = vec_raw_load_f(p0, i3, 2, descr=double) + v44[f64|2] = vec_raw_load_f(p0, i1, descr=double) + v45[f64|2] = vec_raw_load_f(p0, i3, descr=double) v46[i32|2] = vec_cast_float_to_singlefloat(v44[f64|2]) v47[i32|2] = vec_cast_float_to_singlefloat(v45[f64|2]) v41[i32|4] = vec_int_pack(v46[i32|2], v47[i32|2], 2, 2) @@ -345,7 +348,7 @@ loop2 = self.schedule(loop1, [pack1,pack2,pack3], prepend_invariant=True) loop3 = self.parse_trace(""" v9[i64|2] = vec_int_expand(255,2) - v10[i64|2] = vec_raw_load_i(p0, i1, 2, descr=long) + v10[i64|2] = vec_raw_load_i(p0, i1, descr=long) v11[i64|2] = vec_int_and(v10[i64|2], v9[i64|2]) guard_true(v11[i64|2]) [] """, False) @@ -365,7 +368,7 @@ pack2 = self.pack(loop1, 4, 6, I32_2, None) loop2 = self.schedule(loop1, [pack1,pack2], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[i32|4] = vec_raw_load_i(p0, i1, 4, descr=float) + v1[i32|4] = vec_raw_load_i(p0, i1, descr=float) i10 = vec_int_unpack(v1[i32|4], 0, 1) raw_store(p0, i3, i10, descr=float) i11 = vec_int_unpack(v1[i32|4], 1, 1) 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 @@ -22,7 +22,7 @@ from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum, - getunpackopnum, Type, determine_input_output_types) + getunpackopnum) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, Accum) from rpython.rlib import listsort @@ -453,7 +453,7 @@ state.prepare() scheduler = Scheduler() scheduler.walk_and_emit(state) - if state.profitable(): + if not state.profitable(): return state.post_schedule() @@ -674,15 +674,11 @@ if origin_pack is None: op = lnode.getoperation() if op.is_primitive_load(): - # load outputs value, no input - return Pair(lnode, rnode, None, Type.of(op)) + return Pair(lnode, rnode) else: - # store only has an input - return Pair(lnode, rnode, Type.of(op), None) + return Pair(lnode, rnode) if self.profitable_pack(lnode, rnode, origin_pack, forward): - input_type, output_type = \ - determine_input_output_types(origin_pack, lnode, forward) - return Pair(lnode, rnode, input_type, output_type) + return Pair(lnode, rnode) else: if self.contains_pair(lnode, rnode): return None @@ -734,17 +730,9 @@ operations = pack_i.operations for op in pack_j.operations[1:]: operations.append(op) - input_type = pack_i.input_type - output_type = pack_i.output_type - if input_type: - input_type.combine(pack_j.input_type) - if output_type: - output_type.combine(pack_j.output_type) - pack = Pack(operations, input_type, output_type) + pack = Pack(operations) self.packs[i] = pack - # preserve the accum variable (if present) of the - # left most pack, that is the pack with the earliest - # operation at index 0 in the trace + # preserve the accum variable (if present) pack.accum = pack_i.accum pack_i.accum = pack_j.accum = None @@ -851,6 +839,5 @@ pack.clear() self.packs[i] = None continue - pack.update_pack_of_nodes() self.packs = [pack for pack in self.packs + newpacks if pack] 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 @@ -80,21 +80,70 @@ elif op.is_guard(): assert not descr.final_descr op.setdescr(descr) + op.inittype() return op -def VecOperation(opnum, args, type, count, descr=None): +def VecOperation(opnum, args, baseop, count, descr=None): + return VecOperationNew(opnum, args, baseop.datatype, baseop.bytesize, baseop.signed, count, descr) + +def VecOperationNew(opnum, args, datateyp, bytesize, signed, count, descr=None): op = ResOperation(opnum, args, descr) - op.item_type = type - op.item_count = count + op.datatype = datateyp + op.bytesize = bytesize + op.signed = signed + op.count = count return op -class AbstractResOpOrInputArg(AbstractValue): +class Typed(object): + _mixin_ = True + _attrs_ = ('datatype', 'bytesize', 'signed') + + datatype = '\x00' + bytesize = -1 + signed = True + + def inittype(self): + if self.returns_void(): + self.bytesize = 0 + self.datatype = 'v' + return + + if self.is_primitive_array_access(): + descr = self.getdescr() + type = self.type + if descr.is_array_of_floats() or descr.concrete_type == 'f': + type = FLOAT + self.bytesize = descr.get_item_size_in_bytes() + self.sign = descr.is_item_signed() + self.datatype = type + else: + # pass through the type of the first input argument + if self.numargs() == 0: + return + arg0 = self.getarg(0) + self.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + assert self.datatype != '\x00' + assert self.bytesize > 0 + + def setdatatype(self, data_type, bytesize, signed): + self.datatype = data_type + self.bytesize = bytesize + self.signed = signed + + def typestr(self): + sign = '-' + if not self.signed: + sign = '+' + return 'Type(%s%s, %d)' % (sign, self.type, self.size) + +class AbstractResOpOrInputArg(AbstractValue, Typed): _attrs_ = ('_forwarded',) _forwarded = None # either another resop or OptInfo def get_forwarded(self): return self._forwarded + class AbstractResOp(AbstractResOpOrInputArg): """The central ResOperation class, representing one operation.""" @@ -109,6 +158,7 @@ boolreflex = -1 boolinverse = -1 vector = -1 # -1 means, no vector equivalent, -2 it is a vector statement + casts = ('\x00', -1, '\x00', -1) def getopnum(self): return self.opnum @@ -192,7 +242,11 @@ except KeyError: num = len(memo) memo[self] = num - sres = self.type + str(num) + ' = ' + if self.is_vector(): + assert isinstance(self, VectorOp) + sres = 'v%d[%dx%s%d] = ' % (num, self.count, self.datatype, self.bytesize * 8) + else: + sres = self.type + str(num) + ' = ' #if self.result is not None: # sres = '%s = ' % (self.result,) else: @@ -219,6 +273,10 @@ except KeyError: num = len(memo) memo[self] = num + if self.is_vector(): + assert isinstance(self, VectorOp) + return 'v%d[%dx%s%d]' % (num, self.count, self.datatype, + self.bytesize * 8) return self.type + str(num) def __repr__(self): @@ -363,6 +421,9 @@ def is_label(self): return self.getopnum() == rop.LABEL + def is_vector(self): + return self.vector == -2 + def returns_void(self): return self.type == 'v' @@ -376,28 +437,6 @@ class PlainResOp(AbstractResOp): pass -class CastResOp(AbstractResOp): - _attrs_ = ('casts') - casts = ('\x00', -1, '\x00', -1) - - def casts_box(self): - return True - - def cast_to(self): - _, _, to_type, size = self.casts - if self.casts[3] == 0: - if self.getopnum() == rop.INT_SIGNEXT: - from rpython.jit.metainterp.history import ConstInt - arg = self.getarg(1) - assert isinstance(arg, ConstInt) - return (to_type,arg.value) - else: - raise NotImplementedError - return (to_type,size) - - def cast_from(self): - return ('\x00',-1) - class ResOpWithDescr(AbstractResOp): _descr = None @@ -556,68 +595,56 @@ def accumulates_value(self): return True +class CastOp(object): + _mixin_ = True + + def casts_box(self): + return True + + def cast_to(self): + _, _, to_type, size = self.casts + if self.casts[3] == 0: + if self.getopnum() == rop.INT_SIGNEXT: + from rpython.jit.metainterp.history import ConstInt + arg = self.getarg(1) + assert isinstance(arg, ConstInt) + return (to_type,arg.value) + else: + raise NotImplementedError + return (to_type,size) + + def cast_from(self): + return ('\x00',-1) + class VectorOp(object): _mixin_ = True - #_attrs_ = ('item_type','item_count','item_size','item_signed','accum') - _attrs_ = ('item_type', 'item_count') - - #def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False, accum=None): - # assert item_type in (FLOAT, INT) - # self.item_type = item_type - # self.item_count = item_count - # self.item_size = item_size - # self.item_signed = item_signed - # self.accum = None - - def gettype(self): - return self.type - - def getbytes(self): - return self.slot_bytes - - def getcount(self): - return self.item_count - - def fully_packed(self, vec_reg_size): - return self.item_size * self.item_count == vec_reg_size - - def forget_value(self): - raise NotImplementedError("cannot forget value of vector") - - def clonebox(self): - 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") - - def nonnull(self): - raise NotImplementedError("no value known, nonnull is unkown") + _attrs_ = ('count',) def repr_rpython(self): return repr_rpython(self, 'bv') def same_shape(self, other): - if not isinstance(other, BoxVector): + """ NOT_RPYTHON """ + if not other.is_vector(): return False # - if other.item_size == -1 or self.item_size == -1: + # TODO ? if other.item_size == -1 or self.item_size == -1: # fallback for tests that do not specify the size - return True + # return True # - if self.item_type != other.item_type: + if self.datatype != other.datatype: return False - if self.item_size != other.item_size: + if self.bytesize != other.bytesize: return False - if self.item_count != other.item_count: + if self.signed!= other.signed: return False - if self.item_signed != other.item_signed: + if self.count != other.count: return False return True def getaccum(self): return self.accum - class AbstractInputArg(AbstractResOpOrInputArg): def set_forwarded(self, forwarded_to): self._forwarded = forwarded_to @@ -642,6 +669,9 @@ def is_inputarg(self): return True + def initinputtype(self, cpu): + pass + class InputArgInt(IntOp, AbstractInputArg): def __init__(self, intval=0): self.setint(intval) @@ -974,11 +1004,11 @@ '_RAW_LOAD_FIRST', 'GETARRAYITEM_GC/2d/rfi', - 'VEC_GETARRAYITEM_GC/3d/fi', + 'VEC_GETARRAYITEM_GC/2d/fi', 'GETARRAYITEM_RAW/2d/fi', - 'VEC_GETARRAYITEM_RAW/3d/fi', + 'VEC_GETARRAYITEM_RAW/2d/fi', 'RAW_LOAD/2d/fi', - 'VEC_RAW_LOAD/3d/fi', + 'VEC_RAW_LOAD/2d/fi', '_RAW_LOAD_LAST', 'GETINTERIORFIELD_GC/2d/rfi', @@ -1059,19 +1089,15 @@ '_LAST', # for the backend to add more internal operations ] -FLOAT = 'f' -INT = 'i' _cast_ops = { - 'INT_SIGNEXT': (INT, 0, INT, 0), - 'CAST_FLOAT_TO_INT': (FLOAT, 8, INT, 4), - 'CAST_INT_TO_FLOAT': (INT, 4, FLOAT, 8), - 'CAST_FLOAT_TO_SINGLEFLOAT': (FLOAT, 8, FLOAT, 4), - 'CAST_SINGLEFLOAT_TO_FLOAT': (FLOAT, 4, FLOAT, 8), - 'CAST_PTR_TO_INT': (INT, 0, INT, 4), - 'CAST_INT_TO_PTR': (INT, 4, INT, 0), + 'INT_SIGNEXT': ('i', 0, 'i', 0), + 'CAST_FLOAT_TO_INT': ('f', 8, 'i', 4), + 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8), + 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4), + 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8), + 'CAST_PTR_TO_INT': ('r', 0, 'i', 4), + 'CAST_INT_TO_PTR': ('i', 4, 'r', 0), } -del FLOAT -del INT # ____________________________________________________________ @@ -1156,8 +1182,6 @@ if is_guard: assert withdescr baseclass = GuardResOp - elif name in _cast_ops: - baseclass = CastResOp elif withdescr: baseclass = ResOpWithDescr else: @@ -1171,6 +1195,8 @@ mixins.append(RefOp) else: assert result_type == 'n' + if name in _cast_ops: + mixins.append(CastOp) if name.startswith('VEC'): mixins.insert(1,VectorOp) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit