Author: Richard Plangger <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit