Author: Richard Plangger <r...@pasra.at> Branch: vecopt Changeset: r77959:fab36fa4cf6d Date: 2015-06-08 15:39 +0200 http://bitbucket.org/pypy/pypy/changeset/fab36fa4cf6d/
Log: finished refactor the structure diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -4,6 +4,13 @@ gathered with IntegralForwardModification """ +from rpython.jit.metainterp.optimizeopt.util import Renamer +from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, + MemoryRef, Node, IndexVar) +from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) +from rpython.jit.metainterp.history import (ConstInt, BoxVector, + BoxFloat, BoxInt, ConstFloat, Box) + class Guard(object): """ An object wrapper around a guard. Helps to determine if one guard implies another 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,3 +1,12 @@ + +from rpython.jit.metainterp.history import (FLOAT,INT,ConstInt,BoxVector, + BoxFloat,BoxInt) +from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) +from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, + MemoryRef, Node, IndexVar) +from rpython.jit.metainterp.optimizeopt.util import Renamer +from rpython.rlib.objectmodel import we_are_translated + class SchedulerData(object): pass @@ -71,6 +80,60 @@ node.clear_dependencies() node.emitted = True +class PackType(object): + UNKNOWN_TYPE = '-' + + def __init__(self, type, size, signed, count=-1): + assert type in (FLOAT, INT, PackType.UNKNOWN_TYPE) + self.type = type + self.size = size + self.signed = signed + self.count = count + + def gettype(self): + return self.type + + def getsize(self): + return self.size + + def getsigned(self): + return self.signed + + def get_byte_size(self): + return self.size + + def getcount(self): + return self.count + + @staticmethod + def by_descr(descr, vec_reg_size): + _t = INT + if descr.is_array_of_floats() or descr.concrete_type == FLOAT: + _t = FLOAT + size = descr.get_item_size_in_bytes() + pt = PackType(_t, size, descr.is_item_signed(), vec_reg_size // size) + return pt + + def is_valid(self): + return self.type != PackType.UNKNOWN_TYPE and self.size > 0 + + def new_vector_box(self, count): + return BoxVector(self.type, count, self.size, self.signed) + + def __repr__(self): + return 'PackType(%s, %d, %d, #%d)' % (self.type, self.size, self.signed, self.count) + + @staticmethod + def of(box, count=-1): + assert isinstance(box, BoxVector) + if count == -1: + count = box.item_count + return PackType(box.item_type, box.item_size, box.item_signed, count) + + def clone(self): + return PackType(self.type, self.size, self.signed, self.count) + + PT_FLOAT_2 = PackType(FLOAT, 4, False, 2) PT_DOUBLE_2 = PackType(FLOAT, 8, False, 2) PT_FLOAT_GENERIC = PackType(INT, -1, True) @@ -82,6 +145,285 @@ INT_RES = PT_INT_GENERIC FLOAT_RES = PT_FLOAT_GENERIC +class OpToVectorOp(object): + 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.preamble_ops = None + self.sched_data = None + self.pack = None + self.input_type = None + self.output_type = None + + def clone_vbox_set_count(self, box, count): + return BoxVector(box.item_type, count, box.item_size, box.item_signed) + + def is_vector_arg(self, i): + if i < 0 or i >= len(self.arg_ptypes): + return False + return self.arg_ptypes[i] is not None + + def getsplitsize(self): + return self.input_type.getsize() + + def determine_input_type(self, op): + arg = op.getarg(0) + _, vbox = self.sched_data.getvector_of_box(op.getarg(0)) + if vbox: + return PackType.of(vbox) + else: + vec_reg_size = self.sched_data.vec_reg_size + if isinstance(arg, ConstInt) or isinstance(arg, BoxInt): + return PackType(INT, 8, True, 2) + elif isinstance(arg, ConstFloat) or isinstance(arg, BoxFloat): + return PackType(FLOAT, 8, True, 2) + else: + raise NotImplementedError("arg %s not supported" % (arg,)) + + def determine_output_type(self, op): + return self.determine_input_type(op) + + def update_input_output(self, pack): + op0 = pack.operations[0].getoperation() + self.input_type = self.determine_input_type(op0) + self.output_type = self.determine_output_type(op0) + + def as_vector_operation(self, pack, sched_data, oplist): + self.sched_data = sched_data + self.preamble_ops = oplist + self.update_input_output(pack) + + + off = 0 + stride = self.split_pack(pack) + left = len(pack.operations) + assert stride > 0 + while off < len(pack.operations): + if left < stride: + self.preamble_ops.append(pack.operations[off].getoperation()) + off += 1 + continue + ops = pack.operations[off:off+stride] + self.pack = Pack(ops) + self.transform_pack(ops, off, stride) + off += stride + left -= stride + + self.pack = None + self.preamble_ops = None + self.sched_data = None + self.input_type = None + self.output_type = None + + def split_pack(self, pack): + pack_count = len(pack.operations) + vec_reg_size = self.sched_data.vec_reg_size + bytes = pack_count * self.getsplitsize() + if bytes > vec_reg_size: + return vec_reg_size // self.getsplitsize() + if bytes < vec_reg_size: + return 1 + return pack_count + + def before_argument_transform(self, args): + pass + + def transform_pack(self, ops, off, stride): + op = self.pack.operations[0].getoperation() + args = op.getarglist() + # + self.before_argument_transform(args) + # + for i,arg in enumerate(args): + if self.is_vector_arg(i): + args[i] = self.transform_argument(args[i], i, off) + # + result = op.result + result = self.transform_result(result, off) + # + vop = ResOperation(op.vector, args, result, op.getdescr()) + self.preamble_ops.append(vop) + + 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(self.pack.operations): + op = node.getoperation() + self.sched_data.setvector_of_box(op.result, i, vbox) + return vbox + + def new_result_vector_box(self): + type = self.output_type.gettype() + size = self.output_type.getsize() + count = min(self.output_type.getcount(), len(self.pack.operations)) + signed = self.output_type.signed + return BoxVector(type, count, size, signed) + + 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.expand(ops, arg, argidx) + box_pos = 0 + + # use the input as an indicator for the pack type + packable = self.sched_data.vec_reg_size // self.input_type.getsize() + packed = vbox.item_count + assert packed >= 0 + assert packable >= 0 + if packed < packable: + # the argument is scattered along different vector boxes + args = [op.getoperation().getarg(argidx) for op in ops] + vbox = self._pack(vbox, packed, args, packable) + self.update_input_output(self.pack) + elif packed > packable: + # the argument has more items than the operation is able to process! + vbox = self.unpack(vbox, off, packable, self.input_type) + self.update_input_output(self.pack) + # + if off != 0 and box_pos != 0: + # The original box is at a position != 0 but it + # is required to be at position 0. Unpack it! + vbox = self.unpack(vbox, off, len(ops), self.input_type) + self.update_input_output(self.pack) + # convert size i64 -> i32, i32 -> i64, ... + if self.input_type.getsize() > 0 and \ + self.input_type.getsize() != vbox.getsize(): + vbox = self.extend(vbox, self.input_type) + # + return vbox + + def extend(self, vbox, newtype): + assert vbox.gettype() == newtype.gettype() + if vbox.gettype() == INT: + return self.extend_int(vbox, newtype) + else: + raise NotImplementedError("cannot yet extend float") + + def extend_int(self, vbox, newtype): + vbox_cloned = newtype.new_vector_box(vbox.item_count) + op = ResOperation(rop.VEC_INT_SIGNEXT, + [vbox, ConstInt(newtype.getsize())], + vbox_cloned) + self.preamble_ops.append(op) + return vbox_cloned + + def unpack(self, vbox, index, count, arg_ptype): + vbox_cloned = self.clone_vbox_set_count(vbox, count) + opnum = rop.VEC_FLOAT_UNPACK + if vbox.item_type == INT: + opnum = rop.VEC_INT_UNPACK + op = ResOperation(opnum, [vbox, ConstInt(index), ConstInt(count)], vbox_cloned) + self.preamble_ops.append(op) + return vbox_cloned + + def _pack(self, tgt_box, index, args, packable): + """ If there are two vector boxes: + v1 = [<empty>,<emtpy>,X,Y] + v2 = [A,B,<empty>,<empty>] + this function creates a box pack instruction to merge them to: + v1/2 = [A,B,X,Y] + """ + opnum = rop.VEC_FLOAT_PACK + if tgt_box.item_type == INT: + opnum = rop.VEC_INT_PACK + arg_count = len(args) + i = index + while i < arg_count and tgt_box.item_count < packable: + arg = args[i] + pos, src_box = self.sched_data.getvector_of_box(arg) + if pos == -1: + i += 1 + continue + count = tgt_box.item_count + src_box.item_count + new_box = self.clone_vbox_set_count(tgt_box, count) + op = ResOperation(opnum, [tgt_box, src_box, ConstInt(i), + ConstInt(src_box.item_count)], new_box) + self.preamble_ops.append(op) + if not we_are_translated(): + self._check_vec_pack(op) + i += src_box.item_count + + # overwrite the new positions, arguments now live in new_box + # at a new position + for j in range(i): + arg = args[j] + self.sched_data.setvector_of_box(arg, j, new_box) + tgt_box = new_box + _, vbox = self.sched_data.getvector_of_box(args[0]) + return vbox + + def _check_vec_pack(self, op): + result = op.result + arg0 = op.getarg(0) + arg1 = op.getarg(1) + index = op.getarg(2) + count = op.getarg(3) + assert isinstance(result, BoxVector) + assert isinstance(arg0, BoxVector) + assert isinstance(index, ConstInt) + assert isinstance(count, ConstInt) + assert arg0.item_size == result.item_size + if isinstance(arg1, BoxVector): + assert arg1.item_size == result.item_size + else: + assert count.value == 1 + assert index.value < result.item_count + assert index.value + count.value <= result.item_count + assert result.item_count > arg0.item_count + + def expand(self, nodes, arg, argidx): + vbox = self.input_type.new_vector_box(len(nodes)) + box_type = arg.type + expanded_map = self.sched_data.expanded_map + invariant_ops = self.sched_data.invariant_oplist + invariant_vars = self.sched_data.invariant_vector_vars + if isinstance(arg, BoxVector): + box_type = arg.item_type + + # note that heterogenous nodes are not yet tracked + already_expanded = expanded_map.get(arg, None) + if already_expanded: + return already_expanded + + for i, node in enumerate(nodes): + op = node.getoperation() + if not arg.same_box(op.getarg(argidx)): + break + i += 1 + else: + expand_opnum = rop.VEC_FLOAT_EXPAND + if box_type == INT: + expand_opnum = rop.VEC_INT_EXPAND + op = ResOperation(expand_opnum, [arg], vbox) + invariant_ops.append(op) + invariant_vars.append(vbox) + expanded_map[arg] = vbox + return vbox + + op = ResOperation(rop.VEC_BOX, [ConstInt(len(nodes))], vbox) + invariant_ops.append(op) + opnum = rop.VEC_FLOAT_PACK + if arg.type == INT: + opnum = rop.VEC_INT_PACK + for i,node in enumerate(nodes): + 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 + invariant_ops.append(op) + + invariant_vars.append(vbox) + return vbox + + class OpToVectorOpConv(OpToVectorOp): def __init__(self, intype, outtype): self.from_size = intype.getsize() @@ -264,3 +606,65 @@ return oplist +class Pack(object): + """ A pack is a set of n statements that are: + * isomorphic + * independent + """ + def __init__(self, ops): + self.operations = ops + for i,node in enumerate(self.operations): + node.pack = self + node.pack_position = i + self.accum_variable = None + self.accum_position = -1 + + def opcount(self): + return len(self.operations) + + def opnum(self): + assert len(self.operations) > 0 + return self.operations[0].getoperation().getopnum() + + def clear(self): + for node in self.operations: + node.pack = None + node.pack_position = -1 + + def rightmost_match_leftmost(self, other): + assert isinstance(other, Pack) + rightmost = self.operations[-1] + leftmost = other.operations[0] + return rightmost == leftmost and \ + self.accum_variable == other.accum_variable and \ + self.accum_position == other.accum_position + + def __repr__(self): + return "Pack(%r)" % self.operations + + def is_accumulating(self): + return self.accum_variable is not None + +class Pair(Pack): + """ A special Pack object with only two statements. """ + def __init__(self, left, right): + assert isinstance(left, Node) + assert isinstance(right, Node) + self.left = left + self.right = right + Pack.__init__(self, [left, right]) + + def __eq__(self, other): + if isinstance(other, Pair): + return self.left is other.left and \ + self.right is other.right + +class AccumPair(Pair): + def __init__(self, left, right, accum_var, accum_pos): + assert isinstance(left, Node) + assert isinstance(right, Node) + Pair.__init__(self, left, right) + self.left = left + self.right = right + self.accum_variable = accum_var + self.accum_position = accum_pos 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 @@ -4,10 +4,11 @@ from rpython.rlib.objectmodel import r_dict, compute_identity_hash, specialize from rpython.rlib.rarithmetic import intmask from rpython.rlib.unroll import unrolling_iterable +from rpython.rlib.debug import make_sure_not_resized +from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp import resoperation -from rpython.rlib.debug import make_sure_not_resized from rpython.jit.metainterp.resoperation import rop -from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.resume import Snapshot # ____________________________________________________________ # Misc. utilities @@ -188,3 +189,53 @@ assert False assert len(oplist1) == len(oplist2) return True + +class Renamer(object): + def __init__(self): + self.rename_map = {} + + def rename_box(self, box): + return self.rename_map.get(box, box) + + def start_renaming(self, var, tovar): + self.rename_map[var] = tovar + + def rename(self, op): + for i, arg in enumerate(op.getarglist()): + arg = self.rename_map.get(arg, arg) + op.setarg(i, arg) + + if op.is_guard(): + assert isinstance(op, resoperation.GuardResOp) + op.rd_snapshot = self.rename_rd_snapshot(op.rd_snapshot) + self.rename_failargs(op) + + return True + + def rename_failargs(self, guard, clone=False): + if guard.getfailargs() is not None: + if clone: + args = guard.getfailargs()[:] + else: + args = guard.getfailargs() + for i,arg in enumerate(args): + value = self.rename_map.get(arg,arg) + args[i] = value + return args + return None + + def rename_rd_snapshot(self, snapshot, clone=False): + # snapshots are nested like the MIFrames + if snapshot is None: + return None + if clone: + boxes = snapshot.boxes[:] + else: + boxes = snapshot.boxes + for i,box in enumerate(boxes): + value = self.rename_map.get(box,box) + boxes[i] = value + # + rec_snap = self.rename_rd_snapshot(snapshot.prev, clone) + return Snapshot(rec_snap, boxes) + 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 @@ -7,10 +7,10 @@ from rpython.jit.metainterp.history import (ConstInt, VECTOR, FLOAT, INT, BoxVector, BoxFloat, BoxInt, ConstFloat, TargetToken, JitCellToken, Box) from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization -from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method -from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, +from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method, Renamer +from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) -from rpython.jit.metainterp.optimizeopt.schedule import VecScheduleData, Scheduler +from rpython.jit.metainterp.optimizeopt.schedule import VecScheduleData, Scheduler, Pack, Pair, AccumPair from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) from rpython.rlib.objectmodel import we_are_translated @@ -462,55 +462,6 @@ guard_node.edge_to(ee_guard_node, label='pullup-last-guard') guard_node.relax_guard_to(ee_guard_node) -class Renamer(object): - def __init__(self): - self.rename_map = {} - - def rename_box(self, box): - return self.rename_map.get(box, box) - - def start_renaming(self, var, tovar): - self.rename_map[var] = tovar - - def rename(self, op): - for i, arg in enumerate(op.getarglist()): - arg = self.rename_map.get(arg, arg) - op.setarg(i, arg) - - if op.is_guard(): - assert isinstance(op, GuardResOp) - op.rd_snapshot = self.rename_rd_snapshot(op.rd_snapshot) - self.rename_failargs(op) - - return True - - def rename_failargs(self, guard, clone=False): - if guard.getfailargs() is not None: - if clone: - args = guard.getfailargs()[:] - else: - args = guard.getfailargs() - for i,arg in enumerate(args): - value = self.rename_map.get(arg,arg) - args[i] = value - return args - return None - - def rename_rd_snapshot(self, snapshot, clone=False): - # snapshots are nested like the MIFrames - if snapshot is None: - return None - if clone: - boxes = snapshot.boxes[:] - else: - boxes = snapshot.boxes - for i,box in enumerate(boxes): - value = self.rename_map.get(box,box) - boxes[i] = value - # - rec_snap = self.rename_rd_snapshot(snapshot.prev, clone) - return Snapshot(rec_snap, boxes) - class CostModel(object): def __init__(self, threshold): self.threshold = threshold @@ -556,336 +507,6 @@ return 1 -class PackType(object): - UNKNOWN_TYPE = '-' - - def __init__(self, type, size, signed, count=-1): - assert type in (FLOAT, INT, PackType.UNKNOWN_TYPE) - self.type = type - self.size = size - self.signed = signed - self.count = count - - def gettype(self): - return self.type - - def getsize(self): - return self.size - - def getsigned(self): - return self.signed - - def get_byte_size(self): - return self.size - - def getcount(self): - return self.count - - @staticmethod - def by_descr(descr, vec_reg_size): - _t = INT - if descr.is_array_of_floats() or descr.concrete_type == FLOAT: - _t = FLOAT - size = descr.get_item_size_in_bytes() - pt = PackType(_t, size, descr.is_item_signed(), vec_reg_size // size) - return pt - - def is_valid(self): - return self.type != PackType.UNKNOWN_TYPE and self.size > 0 - - def new_vector_box(self, count): - return BoxVector(self.type, count, self.size, self.signed) - - def __repr__(self): - return 'PackType(%s, %d, %d, #%d)' % (self.type, self.size, self.signed, self.count) - - @staticmethod - def of(box, count=-1): - assert isinstance(box, BoxVector) - if count == -1: - count = box.item_count - return PackType(box.item_type, box.item_size, box.item_signed, count) - - def clone(self): - return PackType(self.type, self.size, self.signed, self.count) - -class OpToVectorOp(object): - 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.preamble_ops = None - self.sched_data = None - self.pack = None - self.input_type = None - self.output_type = None - - def clone_vbox_set_count(self, box, count): - return BoxVector(box.item_type, count, box.item_size, box.item_signed) - - def is_vector_arg(self, i): - if i < 0 or i >= len(self.arg_ptypes): - return False - return self.arg_ptypes[i] is not None - - def getsplitsize(self): - return self.input_type.getsize() - - def determine_input_type(self, op): - arg = op.getarg(0) - _, vbox = self.sched_data.getvector_of_box(op.getarg(0)) - if vbox: - return PackType.of(vbox) - else: - vec_reg_size = self.sched_data.vec_reg_size - if isinstance(arg, ConstInt) or isinstance(arg, BoxInt): - return PackType(INT, 8, True, 2) - elif isinstance(arg, ConstFloat) or isinstance(arg, BoxFloat): - return PackType(FLOAT, 8, True, 2) - else: - raise NotImplementedError("arg %s not supported" % (arg,)) - - def determine_output_type(self, op): - return self.determine_input_type(op) - - def update_input_output(self, pack): - op0 = pack.operations[0].getoperation() - self.input_type = self.determine_input_type(op0) - self.output_type = self.determine_output_type(op0) - - def as_vector_operation(self, pack, sched_data, oplist): - self.sched_data = sched_data - self.preamble_ops = oplist - self.update_input_output(pack) - - - off = 0 - stride = self.split_pack(pack) - left = len(pack.operations) - assert stride > 0 - while off < len(pack.operations): - if left < stride: - self.preamble_ops.append(pack.operations[off].getoperation()) - off += 1 - continue - ops = pack.operations[off:off+stride] - self.pack = Pack(ops) - self.transform_pack(ops, off, stride) - off += stride - left -= stride - - self.pack = None - self.preamble_ops = None - self.sched_data = None - self.input_type = None - self.output_type = None - - def split_pack(self, pack): - pack_count = len(pack.operations) - vec_reg_size = self.sched_data.vec_reg_size - bytes = pack_count * self.getsplitsize() - if bytes > vec_reg_size: - return vec_reg_size // self.getsplitsize() - if bytes < vec_reg_size: - return 1 - return pack_count - - def before_argument_transform(self, args): - pass - - def transform_pack(self, ops, off, stride): - op = self.pack.operations[0].getoperation() - args = op.getarglist() - # - self.before_argument_transform(args) - # - for i,arg in enumerate(args): - if self.is_vector_arg(i): - args[i] = self.transform_argument(args[i], i, off) - # - result = op.result - result = self.transform_result(result, off) - # - vop = ResOperation(op.vector, args, result, op.getdescr()) - self.preamble_ops.append(vop) - - 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(self.pack.operations): - op = node.getoperation() - self.sched_data.setvector_of_box(op.result, i, vbox) - return vbox - - def new_result_vector_box(self): - type = self.output_type.gettype() - size = self.output_type.getsize() - count = min(self.output_type.getcount(), len(self.pack.operations)) - signed = self.output_type.signed - return BoxVector(type, count, size, signed) - - 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.expand(ops, arg, argidx) - box_pos = 0 - - # use the input as an indicator for the pack type - packable = self.sched_data.vec_reg_size // self.input_type.getsize() - packed = vbox.item_count - assert packed >= 0 - assert packable >= 0 - if packed < packable: - # the argument is scattered along different vector boxes - args = [op.getoperation().getarg(argidx) for op in ops] - vbox = self._pack(vbox, packed, args, packable) - self.update_input_output(self.pack) - elif packed > packable: - # the argument has more items than the operation is able to process! - vbox = self.unpack(vbox, off, packable, self.input_type) - self.update_input_output(self.pack) - # - if off != 0 and box_pos != 0: - # The original box is at a position != 0 but it - # is required to be at position 0. Unpack it! - vbox = self.unpack(vbox, off, len(ops), self.input_type) - self.update_input_output(self.pack) - # convert size i64 -> i32, i32 -> i64, ... - if self.input_type.getsize() > 0 and \ - self.input_type.getsize() != vbox.getsize(): - vbox = self.extend(vbox, self.input_type) - # - return vbox - - def extend(self, vbox, newtype): - assert vbox.gettype() == newtype.gettype() - if vbox.gettype() == INT: - return self.extend_int(vbox, newtype) - else: - raise NotImplementedError("cannot yet extend float") - - def extend_int(self, vbox, newtype): - vbox_cloned = newtype.new_vector_box(vbox.item_count) - op = ResOperation(rop.VEC_INT_SIGNEXT, - [vbox, ConstInt(newtype.getsize())], - vbox_cloned) - self.preamble_ops.append(op) - return vbox_cloned - - def unpack(self, vbox, index, count, arg_ptype): - vbox_cloned = self.clone_vbox_set_count(vbox, count) - opnum = rop.VEC_FLOAT_UNPACK - if vbox.item_type == INT: - opnum = rop.VEC_INT_UNPACK - op = ResOperation(opnum, [vbox, ConstInt(index), ConstInt(count)], vbox_cloned) - self.preamble_ops.append(op) - return vbox_cloned - - def _pack(self, tgt_box, index, args, packable): - """ If there are two vector boxes: - v1 = [<empty>,<emtpy>,X,Y] - v2 = [A,B,<empty>,<empty>] - this function creates a box pack instruction to merge them to: - v1/2 = [A,B,X,Y] - """ - opnum = rop.VEC_FLOAT_PACK - if tgt_box.item_type == INT: - opnum = rop.VEC_INT_PACK - arg_count = len(args) - i = index - while i < arg_count and tgt_box.item_count < packable: - arg = args[i] - pos, src_box = self.sched_data.getvector_of_box(arg) - if pos == -1: - i += 1 - continue - count = tgt_box.item_count + src_box.item_count - new_box = self.clone_vbox_set_count(tgt_box, count) - op = ResOperation(opnum, [tgt_box, src_box, ConstInt(i), - ConstInt(src_box.item_count)], new_box) - self.preamble_ops.append(op) - if not we_are_translated(): - self._check_vec_pack(op) - i += src_box.item_count - - # overwrite the new positions, arguments now live in new_box - # at a new position - for j in range(i): - arg = args[j] - self.sched_data.setvector_of_box(arg, j, new_box) - tgt_box = new_box - _, vbox = self.sched_data.getvector_of_box(args[0]) - return vbox - - def _check_vec_pack(self, op): - result = op.result - arg0 = op.getarg(0) - arg1 = op.getarg(1) - index = op.getarg(2) - count = op.getarg(3) - assert isinstance(result, BoxVector) - assert isinstance(arg0, BoxVector) - assert isinstance(index, ConstInt) - assert isinstance(count, ConstInt) - assert arg0.item_size == result.item_size - if isinstance(arg1, BoxVector): - assert arg1.item_size == result.item_size - else: - assert count.value == 1 - assert index.value < result.item_count - assert index.value + count.value <= result.item_count - assert result.item_count > arg0.item_count - - def expand(self, nodes, arg, argidx): - vbox = self.input_type.new_vector_box(len(nodes)) - box_type = arg.type - expanded_map = self.sched_data.expanded_map - invariant_ops = self.sched_data.invariant_oplist - invariant_vars = self.sched_data.invariant_vector_vars - if isinstance(arg, BoxVector): - box_type = arg.item_type - - # note that heterogenous nodes are not yet tracked - already_expanded = expanded_map.get(arg, None) - if already_expanded: - return already_expanded - - for i, node in enumerate(nodes): - op = node.getoperation() - if not arg.same_box(op.getarg(argidx)): - break - i += 1 - else: - expand_opnum = rop.VEC_FLOAT_EXPAND - if box_type == INT: - expand_opnum = rop.VEC_INT_EXPAND - op = ResOperation(expand_opnum, [arg], vbox) - invariant_ops.append(op) - invariant_vars.append(vbox) - expanded_map[arg] = vbox - return vbox - - op = ResOperation(rop.VEC_BOX, [ConstInt(len(nodes))], vbox) - invariant_ops.append(op) - opnum = rop.VEC_FLOAT_PACK - if arg.type == INT: - opnum = rop.VEC_INT_PACK - for i,node in enumerate(nodes): - 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 - invariant_ops.append(op) - - invariant_vars.append(vbox) - return vbox def isomorphic(l_op, r_op): """ Subject of definition """ @@ -1021,65 +642,3 @@ del self.packs[last_pos] return last_pos -class Pack(object): - """ A pack is a set of n statements that are: - * isomorphic - * independent - """ - def __init__(self, ops): - self.operations = ops - for i,node in enumerate(self.operations): - node.pack = self - node.pack_position = i - self.accum_variable = None - self.accum_position = -1 - - def opcount(self): - return len(self.operations) - - def opnum(self): - assert len(self.operations) > 0 - return self.operations[0].getoperation().getopnum() - - def clear(self): - for node in self.operations: - node.pack = None - node.pack_position = -1 - - def rightmost_match_leftmost(self, other): - assert isinstance(other, Pack) - rightmost = self.operations[-1] - leftmost = other.operations[0] - return rightmost == leftmost and \ - self.accum_variable == other.accum_variable and \ - self.accum_position == other.accum_position - - def __repr__(self): - return "Pack(%r)" % self.operations - - def is_accumulating(self): - return self.accum_variable is not None - -class Pair(Pack): - """ A special Pack object with only two statements. """ - def __init__(self, left, right): - assert isinstance(left, Node) - assert isinstance(right, Node) - self.left = left - self.right = right - Pack.__init__(self, [left, right]) - - def __eq__(self, other): - if isinstance(other, Pair): - return self.left is other.left and \ - self.right is other.right - -class AccumPair(Pair): - def __init__(self, left, right, accum_var, accum_pos): - assert isinstance(left, Node) - assert isinstance(right, Node) - Pair.__init__(self, left, right) - self.left = left - self.right = right - self.accum_variable = accum_var - self.accum_position = accum_pos _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit