class ConsistancyGroups(object): def __init__(self): self.group = UnionFind() def addConstraint(self, x, y): fx, fy = (x[1],x[0]), (y[1],y[0]) assert not self.group[x] == self.group[fy] assert not self.group[fx] == self.group[y] self.group.union(x, y) self.group.union(fx, fy) def getGroups(self): glut = {} lut = {} for p in self.group: g = self.group[p] if not g in glut: glut[g] = set() glut[g].add(p) lut[p] = glut[g] return lut
def __init__(self, compiler, exgraph, ioinfo): self.compiler = compiler self.exgraph = exgraph self.ioinfo = ioinfo self.compatible = UnionFind() self.samplers = UnionFind() self.readFields = set() self.modifiedFields = set() self.liveInputs = set() self.liveOutputs = set() self.ioRefs = {} self.inputFields = set() self.locals = set() self.holdingCount = collections.defaultdict(lambda: 0) self.typeIDs = {} self.typeUID = 0 self.samplerGroups = {}
def __init__(self, compiler, dataflow, exgraph): TypeDispatcher.__init__(self) self.compiler = compiler self.dataflow = dataflow self.compatable = UnionFind() self.loads = [] self.stores = [] self.fields = {} self.exgraph = exgraph
def __init__(self, compiler, prgm, exgraph): TypeDispatcher.__init__(self) self.compiler = compiler self.prgm = prgm self.compatable = UnionFind() self.loads = [] self.stores = [] self.fields = {} self.exgraph = exgraph self.ssaBroken = False
def __init__(self, exgraph, ioinfo): self.exgraph = exgraph self.ioinfo = ioinfo self.poolInfos = {} self.fieldInfos = {} self.typeIDs = {} self.uid = 0 self.dirty = set() self.lut = SubpoolLUT() self.compatable = UnionFind() self.active = True
def partitionGraph(G): u = UnionFind() for node, next in G.iteritems(): u.union(node, *next) mapping = {} for node in G.iterkeys(): mapping[node] = u[node] domain = set(mapping.itervalues()) groups = setgraph(domain) for node, group in mapping.iteritems(): groups[group].add(node) for d in domain: assert d in groups return domain, groups, mapping
class ConsistancyGroups(object): def __init__(self): self.group = UnionFind() def addConstraint(self, x, y): fx, fy = (x[1], x[0]), (y[1], y[0]) assert not self.group[x] == self.group[fy] assert not self.group[fx] == self.group[y] self.group.union(x, y) self.group.union(fx, fy) def getGroups(self): glut = {} lut = {} for p in self.group: g = self.group[p] if not g in glut: glut[g] = set() glut[g].add(p) lut[p] = glut[g] return lut
class GroupUnifier(object): def __init__(self): self.unify = UnionFind() self.unifyGroups = {} self.dirty = set() def init(self, context): self.unify[context] # Make sure context is in the union find self.unifyGroups[context] = set((context, )) self.dirty.add(context) def unifyContexts(self, contexts): for context in contexts: assert self.unify[context] is context, (context, self.unify[context]) # Unify the contexts result = self.unify.union(*contexts) group = self.unifyGroups[result] for context in contexts: if context is result: continue group.update(self.unifyGroups[context]) del self.unifyGroups[context] # The context may be unified, so make sure it doesn't hang around. if context in self.dirty: self.dirty.remove(context) # Mark the context for processing. self.dirty.add(result) return result def iterGroups(self): return self.unifyGroups.iterkeys() def canonical(self, context): return self.unify[context] def group(self, context): return self.unifyGroups[context]
class GroupUnifier(object): def __init__(self): self.unify = UnionFind() self.unifyGroups = {} self.dirty = set() def init(self, context): self.unify[context] # Make sure context is in the union find self.unifyGroups[context] = set((context,)) self.dirty.add(context) def unifyContexts(self, contexts): for context in contexts: assert self.unify[context] is context, (context, self.unify[context]) # Unify the contexts result = self.unify.union(*contexts) group = self.unifyGroups[result] for context in contexts: if context is result: continue group.update(self.unifyGroups[context]) del self.unifyGroups[context] # The context may be unified, so make sure it doesn't hang around. if context in self.dirty: self.dirty.remove(context) # Mark the context for processing. self.dirty.add(result) return result def iterGroups(self): return self.unifyGroups.iterkeys() def canonical(self, context): return self.unify[context] def group(self, context): return self.unifyGroups[context]
def __init__(self): self.group = UnionFind()
class PoolGraphBuilder(TypeDispatcher): def __init__(self, exgraph, ioinfo): self.exgraph = exgraph self.ioinfo = ioinfo self.poolInfos = {} self.fieldInfos = {} self.typeIDs = {} self.uid = 0 self.dirty = set() self.lut = SubpoolLUT() self.compatable = UnionFind() self.active = True def reads(self, args): self.compatable.union(*args) def modifies(self, args): self.compatable.union(*args) def ambiguousTypes(self, types): for t in types: if not t in self.typeIDs: self.typeIDs[t] = self.uid self.uid += 1 def linkContainedFieldGroups(self, fgs): lut = collections.defaultdict(list) for fg in fgs: objs = set([field.object for field in fg.fields]) for obj in objs: lut[obj].append(fg) for info in self.getUniquePools(): infoFGs = set() for ref in info.refs: infoFGs.update(lut[ref]) info.containedFieldGroups = tuple(infoFGs) def fieldGroups(self): groups = {} for obj, group in self.compatable.parents.iteritems(): if group not in groups: groups[group] = [obj] else: groups[group].append(obj) fgs = [] for name, group in groups.iteritems(): fg = FieldGroup(name, group, self.fieldInfo(name)) fgs.append(fg) # TODO compress mutually exclusive field groups? self.linkContainedFieldGroups(fgs) # Create an index for fg in fgs: for field in fg.fields: self.fieldInfos[field] = fg return fgs def markDirty(self, info): assert not info.dirty info.dirty = True self.dirty.add(info) def isAnchor(self, slot): return slot in self.ioinfo.outputs or slot in self.ioinfo.uniforms or slot in self.ioinfo.inputs def localInfo(self, slot): info = self.poolInfo(slot, slot.annotation.references.merged) info.anchor = self.isAnchor(slot) return info def fieldInfo(self, slot): return self.poolInfo(slot, slot) def poolInfoIfExists(self, slot): return self.poolInfos.get(slot) def poolInfo(self, slot, refs, output=False): if slot not in self.poolInfos: assert self.active, slot info = ReferenceInfo(output) info.addSlot(slot) for ref in refs: info.addRef(ref) self.poolInfos[slot] = info self.markDirty(info) else: info = self.poolInfos[slot] forward = info.forward() if info is not forward: self.poolInfos[slot] = forward info = forward return info @dispatch(ast.leafTypes, ast.Code, ast.CodeParameters, ast.Return, ast.Existing, ast.DoNotCare) def visitLeafs(self, node): pass @dispatch(ast.Local) def visitLocal(self, node): return self.localInfo(node) @dispatch(ast.DirectCall, ast.Call, ast.Allocate, ast.Load, ast.Discard) def visitOp(self, node): node.visitChildren(self) @dispatch(ast.Assign) def visitAssign(self, node): self(node.expr) if isinstance(node.expr, ast.Local): expr = self.localInfo(node.expr) target = self.localInfo(node.lcls[0]) expr.transfer(self, target) elif isinstance(node.expr, ast.Load): load = node.expr expr = self.localInfo(load.expr) target = self.localInfo(node.lcls[0]) self.reads(load.annotation.reads.merged) src = None for field in load.annotation.reads.merged: fieldInfo = self.fieldInfo(field) if src is None: src = fieldInfo else: src = src.merge(self, fieldInfo) src.transfer(self, target) @dispatch(ast.InputBlock) def visitInputBlock(self, node): for input in node.inputs: # HACK ionames are not annotated? src = self.poolInfo(input.src, input.lcl.annotation.references.merged) src.anchor = True lcl = self.localInfo(input.lcl) src.transfer(self, lcl) @dispatch(ast.OutputBlock) def visitOutputBlock(self, node): for output in node.outputs: expr = self.localInfo(output.expr) dst = self.poolInfo(output.dst, output.expr.annotation.references.merged, output=True) dst.anchor = True # TODO no merge? expr.transfer(self, dst) @dispatch(ast.Store) def visitStore(self, node): self.modifies(node.annotation.modifies.merged) node.visitAllChildren(self) if isinstance(node.value, ast.Local): value = self.localInfo(node.value) expr = self.localInfo(node.expr) target = None for field in node.annotation.modifies.merged: fieldInfo = self.fieldInfo(field) if target is None: target = fieldInfo else: target = target.merge(self, fieldInfo) value.transfer(self, target) @dispatch(ast.TypeSwitch) def visitTypeSwitch(self, node): cond = self.localInfo(node.conditional) for case in node.cases: expr = self.localInfo(case.expr) cond = cond.transfer(self, expr) self(case.body) @dispatch(ast.Suite, ast.Switch, ast.Condition, ast.While) def visitOK(self, node): node.visitChildren(self) def analyzeCode(self, code): code.visitChildrenForced(self) def process(self): while self.dirty: info = self.dirty.pop() info.dirty = False info.contract(self) for info in self.getUniquePools(): info.postProcess(self.exgraph) if len(info.types) > 1: self.ambiguousTypes(info.types) for sub in self.getUniqueSubpools(): sub.postProcess(self.exgraph) self.fieldGroups() def getUniquePools(self): unique = set() for info in self.poolInfos.itervalues(): unique.add(info.forward()) return unique def getUniqueSubpools(self): unique = set() for info in self.poolInfos.itervalues(): for subpool in info.lut.subpools.itervalues(): unique.add(subpool.forward()) return unique def dump(self): for info in self.getUniqueSubpools(): print "SLOTS" for slot in info.slots: print "\t", slot print "REFS" for ref in info.refs: print "\t", ref, ref.annotation.final print "VOLATILE", info.volatile print "UNIQUE ", info.unique print "U/I/A ", info.uniform, info.input, info.allocated print return for info in self.getUniquePools(): print "SLOTS" for slot in info.slots: print "\t", slot print "TYPES" for t in info.types: print "\t", t print "REFS" for ref in info.refs: print "\t", ref, ref.annotation.final print "GROUPS REFER" for fg in info.fieldGroupsRefer: print "\t", fg print "GROUPS CONTAINED" for fg in info.containedFieldGroups: print "\t", fg print "FINAL ", info.final print "UNIQUE", info.unique for name, sub in info.lut.subpools.iteritems(): print "\t", name, sub.volatile print "\t", sub.refs print print
ordereddata = fuzzyorder.translateData(data, lut) fuzzyorder.printViolations(ordereddata) print "Domains: ", fuzzyorder.mappingResultSize(lut) sys.exit() G = setgraph(domain) B = setgraph(domain) u = UnionFind() for rank, renames in data.iteritems(): for rename in renames: for k, v in rename.iteritems(): G[k].add(v) B[v].add(k) u.union(k, v) # Find the disjoint subgraphs groupmap = {} for d in domain: groupmap[d] = u[d] groupnames = set(groupmap.itervalues())
class PoolGraphBuilder(TypeDispatcher): def __init__(self, exgraph, ioinfo): self.exgraph = exgraph self.ioinfo = ioinfo self.poolInfos = {} self.fieldInfos = {} self.typeIDs = {} self.uid = 0 self.dirty = set() self.lut = SubpoolLUT() self.compatable = UnionFind() self.active = True def reads(self, args): self.compatable.union(*args) def modifies(self, args): self.compatable.union(*args) def ambiguousTypes(self, types): for t in types: if not t in self.typeIDs: self.typeIDs[t] = self.uid self.uid += 1 def linkContainedFieldGroups(self, fgs): lut = collections.defaultdict(list) for fg in fgs: objs = set([field.object for field in fg.fields]) for obj in objs: lut[obj].append(fg) for info in self.getUniquePools(): infoFGs = set() for ref in info.refs: infoFGs.update(lut[ref]) info.containedFieldGroups = tuple(infoFGs) def fieldGroups(self): groups = {} for obj, group in self.compatable.parents.iteritems(): if group not in groups: groups[group] = [obj] else: groups[group].append(obj) fgs = [] for name, group in groups.iteritems(): fg = FieldGroup(name, group, self.fieldInfo(name)) fgs.append(fg) # TODO compress mutually exclusive field groups? self.linkContainedFieldGroups(fgs) # Create an index for fg in fgs: for field in fg.fields: self.fieldInfos[field] = fg return fgs def markDirty(self, info): assert not info.dirty info.dirty = True self.dirty.add(info) def isAnchor(self, slot): return slot in self.ioinfo.outputs or slot in self.ioinfo.uniforms or slot in self.ioinfo.inputs def localInfo(self, slot): info = self.poolInfo(slot, slot.annotation.references.merged) info.anchor = self.isAnchor(slot) return info def fieldInfo(self, slot): return self.poolInfo(slot, slot) def poolInfoIfExists(self, slot): return self.poolInfos.get(slot) def poolInfo(self, slot, refs, output=False): if slot not in self.poolInfos: assert self.active, slot info = ReferenceInfo(output) info.addSlot(slot) for ref in refs: info.addRef(ref) self.poolInfos[slot] = info self.markDirty(info) else: info = self.poolInfos[slot] forward = info.forward() if info is not forward: self.poolInfos[slot] = forward info = forward return info @dispatch(ast.leafTypes, ast.Code, ast.CodeParameters, ast.Return, ast.Existing, ast.DoNotCare) def visitLeafs(self, node): pass @dispatch(ast.Local) def visitLocal(self, node): return self.localInfo(node) @dispatch(ast.DirectCall, ast.Call, ast.Allocate, ast.Load, ast.Discard) def visitOp(self, node): node.visitChildren(self) @dispatch(ast.Assign) def visitAssign(self, node): self(node.expr) if isinstance(node.expr, ast.Local): expr = self.localInfo(node.expr) target = self.localInfo(node.lcls[0]) expr.transfer(self, target) elif isinstance(node.expr, ast.Load): load = node.expr expr = self.localInfo(load.expr) target = self.localInfo(node.lcls[0]) self.reads(load.annotation.reads.merged) src = None for field in load.annotation.reads.merged: fieldInfo = self.fieldInfo(field) if src is None: src = fieldInfo else: src = src.merge(self, fieldInfo) src.transfer(self, target) @dispatch(ast.InputBlock) def visitInputBlock(self, node): for input in node.inputs: # HACK ionames are not annotated? src = self.poolInfo(input.src, input.lcl.annotation.references.merged) src.anchor = True lcl = self.localInfo(input.lcl) src.transfer(self, lcl) @dispatch(ast.OutputBlock) def visitOutputBlock(self, node): for output in node.outputs: expr = self.localInfo(output.expr) dst = self.poolInfo(output.dst, output.expr.annotation.references.merged, output=True) dst.anchor = True # TODO no merge? expr.transfer(self, dst) @dispatch(ast.Store) def visitStore(self, node): self.modifies(node.annotation.modifies.merged) node.visitAllChildren(self) if isinstance(node.value, ast.Local): value = self.localInfo(node.value) expr = self.localInfo(node.expr) target = None for field in node.annotation.modifies.merged: fieldInfo = self.fieldInfo(field) if target is None: target = fieldInfo else: target = target.merge(self, fieldInfo) value.transfer(self, target) @dispatch(ast.TypeSwitch) def visitTypeSwitch(self, node): cond = self.localInfo(node.conditional) for case in node.cases: expr = self.localInfo(case.expr) cond = cond.transfer(self, expr) self(case.body) @dispatch(ast.Suite, ast.Switch, ast.Condition, ast.While) def visitOK(self, node): node.visitChildren(self) def analyzeCode(self, code): code.visitChildrenForced(self) def process(self): while self.dirty: info = self.dirty.pop() info.dirty = False info.contract(self) for info in self.getUniquePools(): info.postProcess(self.exgraph) if len(info.types) > 1: self.ambiguousTypes(info.types) for sub in self.getUniqueSubpools(): sub.postProcess(self.exgraph) self.fieldGroups() def getUniquePools(self): unique = set() for info in self.poolInfos.itervalues(): unique.add(info.forward()) return unique def getUniqueSubpools(self): unique = set() for info in self.poolInfos.itervalues(): for subpool in info.lut.subpools.itervalues(): unique.add(subpool.forward()) return unique def dump(self): for info in self.getUniqueSubpools(): print "SLOTS" for slot in info.slots: print '\t', slot print "REFS" for ref in info.refs: print '\t', ref, ref.annotation.final print "VOLATILE", info.volatile print "UNIQUE ", info.unique print "U/I/A ", info.uniform, info.input, info.allocated print return for info in self.getUniquePools(): print "SLOTS" for slot in info.slots: print '\t', slot print "TYPES" for t in info.types: print '\t', t print "REFS" for ref in info.refs: print '\t', ref, ref.annotation.final print "GROUPS REFER" for fg in info.fieldGroupsRefer: print '\t', fg print "GROUPS CONTAINED" for fg in info.containedFieldGroups: print '\t', fg print "FINAL ", info.final print "UNIQUE", info.unique for name, sub in info.lut.subpools.iteritems(): print '\t', name, sub.volatile print '\t', sub.refs print print
class FieldTransformAnalysis(TypeDispatcher): def __init__(self, compiler, dataflow, exgraph): TypeDispatcher.__init__(self) self.compiler = compiler self.dataflow = dataflow self.compatable = UnionFind() self.loads = [] self.stores = [] self.fields = {} self.exgraph = exgraph def reads(self, args): args = [arg.name for arg in args] self.compatable.union(*args) def modifies(self, args): args = [arg.name for arg in args] self.compatable.union(*args) @dispatch(ast.DirectCall, ast.Allocate, ast.TypeSwitch) def visitOpJunk(self, node, g): pass @dispatch(ast.Load) def visitLoad(self, node, g): if not intrinsics.isIntrinsicMemoryOp(node): reads = g.annotation.read.flat self.reads(reads) self.loads.append(g) @dispatch(ast.Store) def visitStore(self, node, g): if not intrinsics.isIntrinsicMemoryOp(node): modifies = g.annotation.modify.flat self.modifies(modifies) self.stores.append(g) @dispatch(graph.Entry, graph.Exit, graph.PredicateNode, graph.Gate, graph.NullNode, graph.Split, graph.Merge,) def visitJunk(self, node): pass @dispatch(graph.FieldNode,) def visitField(self, node): name = node.name if name not in self.fields: self.fields[name] = set() self.fields[name].add(node.canonical()) @dispatch(graph.LocalNode, graph.ExistingNode,) def visitSlot(self, node): pass @dispatch(graph.GenericOp) def visitOp(self, node): self(node.op, node) def dumpSlotInfo(self, slot): print id(slot) print slot print "object:", id(slot.object) print "region:", id(slot.region) print "group: ", slot.region.group print self.exgraph.exInfo.get(slot) print def processGroup(self, group): final = True preexisting = True unique = True for objfield in group: object = objfield.object field = objfield.slotName preexisting &= object.annotation.preexisting unique &= object.annotation.unique final &= object.annotation.final exclusive = self.exgraph.mutuallyExclusive(*group) # TODO non-interfering objects? if unique and exclusive: #print "+", group self.transform(group) else: pass #print "-", group if len(group) > 1 and False: print "ex?", exclusive print print for objfield in group: self.dumpSlotInfo(objfield) print print "="*20 print for k, v in self.exgraph.exInfo.iteritems(): if k.isSlot(): self.dumpSlotInfo(k) print def makeLocalForGroup(self, group): # Make up a name, based on an arbitrary field field = group[0].slotName name = field.name.pyobj if field.type == 'Attribute': descriptor = self.compiler.slots.reverse[name] originalName = descriptor.__name__ elif field.type == 'Array': originalName = 'array_%d' % name elif field.type == 'LowLevel': originalName = name else: assert False, field return ast.Local(originalName) def getRemap(self, node): node = node.canonical() if node not in self.remap: # TODO chase through merges and gates assert False, node.defn return self.remap[node] def transformEntry(self, group): lcl = self.makeLocalForGroup(group) hyperblock = self.dataflow.entry.hyperblock g = graph.LocalNode(hyperblock, [lcl]) entry = self.dataflow.entry inEntry = False for slot in group: node = entry.modifies.get(slot) if node is not None: entry.removeEntry(slot, node) self.remap[node] = g inEntry = True if inEntry: self.dataflow.entry.addEntry(lcl, g) return lcl def transformStores(self, group): for store in self.stores: sample = tuple(store.annotation.modify.flat)[0].name if sample in group: value = store.localReads[store.op.value] sg = value.canonical() for mod in store.heapModifies.itervalues(): self.remap[mod.canonical()] = sg store.destroy() def transformLoads(self, group): for load in self.loads: sample = tuple(load.annotation.read.flat)[0].name if sample in group: originalSlot = load.heapReads[sample] remapped = self.getRemap(originalSlot) load.localModifies[0].redirect(remapped) load.destroy() def transformExit(self, group, lcl): exit = self.dataflow.exit inExit = False g = None for slot in group: node = exit.reads.get(slot) if node is not None: exit.removeExit(slot, node) g = self.getRemap(node) inExit = True if inExit: self.dataflow.exit.addExit(lcl, g) def transform(self, group): self.remap = {} # Transform definitions lcl = self.transformEntry(group) self.transformStores(group) # Transform uses self.transformLoads(group) self.transformExit(group, lcl) # TODO transfer annotations? def postProcess(self): groups = {} for obj, group in self.compatable.parents.iteritems(): if group not in groups: groups[group] = [obj] else: groups[group].append(obj) print print "GROUPS" for group in groups.itervalues(): self.processGroup(group) def process(self): # Analyze analysis.dataflowIR.traverse.dfs(self.dataflow, self) self.postProcess()
class PoolAnalysisInfoCollector(TypeDispatcher): def __init__(self, compiler, exgraph, ioinfo): self.compiler = compiler self.exgraph = exgraph self.ioinfo = ioinfo self.compatible = UnionFind() self.samplers = UnionFind() self.readFields = set() self.modifiedFields = set() self.liveInputs = set() self.liveOutputs = set() self.ioRefs = {} self.inputFields = set() self.locals = set() self.holdingCount = collections.defaultdict(lambda: 0) self.typeIDs = {} self.typeUID = 0 self.samplerGroups = {} def samplerGroup(self, sampler): return self.samplerGroups[self.samplers[sampler]] def handleTypes(self, types): if len(types) > 1: for t in types: self.typeIDs[t] = self.typeUID self.typeUID += 1 def reads(self, args): for field in args: if field not in self.readFields: if field in self.ioinfo.uniforms: self.inputFields.add(field) # Increase the holding count for objects contained in read fields. for ref in field: self.holdingCount[ref] += 1 # TODO translate shader names? self.compatible.union(*args) self.readFields.update(args) def modifies(self, args): # TODO translate shader names? self.compatible.union(*args) self.modifiedFields.update(args) @dispatch(ast.Local) def visitLocal(self, node): if node not in self.locals: self.locals.add(node) pools = collections.defaultdict(list) for ref in node.annotation.references.merged: self.holdingCount[ ref] += 1 # NOTE this overestimates shared objects, as they are held by multiple shaders. pt = ref.xtype.obj.pythonType() pools[pt].append(ref) for pt, group in pools.iteritems(): if pt in intrinsics.samplerTypes: self.samplers.union(*group) self.handleTypes(pools.keys()) @dispatch(ast.leafTypes, ast.Code, ast.CodeParameters, ast.Existing, ast.DoNotCare) def visitLeafs(self, node): pass @dispatch(ast.DirectCall, ast.Call, ast.Allocate, ast.Discard, ast.Assign, ast.Return) def visitOp(self, node): node.visitChildren(self) @dispatch(ast.Load) def visitLoad(self, node): self.reads(node.annotation.reads.merged) node.visitChildren(self) @dispatch(ast.Store) def visitStore(self, node): self.modifies(node.annotation.modifies.merged) node.visitChildren(self) @dispatch(ast.InputBlock) def visitInputBlock(self, node): for input in node.inputs: self.liveInputs.add(input.src) self.ioRefs[input.src] = input.lcl.annotation.references.merged @dispatch(ast.OutputBlock) def visitOutputBlock(self, node): for output in node.outputs: self.liveOutputs.add(output.dst) self.ioRefs[output.dst] = output.expr.annotation.references.merged @dispatch(ast.Suite, ast.Switch, ast.Condition, ast.While, ast.TypeSwitch, ast.TypeSwitchCase) def visitOK(self, node): node.visitChildren(self) def analyzeCode(self, code): code.visitChildrenForced(self) def postProcess(self): # Reconstruct field transform info from ioinfo structure. groups = collections.defaultdict(list) for field, ioname in self.ioinfo.fieldTrans.iteritems(): otherio = self.ioinfo.same[ioname] if ioname in self.liveInputs or otherio in self.liveInputs: groups[ioname].append(field) self.inputFields.add(field) #print field, ioname, otherio self.merged = UnionFind() for group in groups.itervalues(): self.merged.union(*group) # TODO only live fields are "compatible"? self.compatible.union(*group) if False: print "Compatible fields" for name, group in model.reindexUnionFind( self.compatible).iteritems(): print name for field in group: print '\t', field print print "Merged fields" for name, group in model.reindexUnionFind(self.merged).iteritems(): if len(group) > 1: print name for field in group: print '\t', field print print "Holding" for name, count in self.holdingCount.iteritems(): print name, count print # Build sampler groups uid = 0 for name, group in model.reindexUnionFind(self.samplers).iteritems(): sg = model.SamplerGroup(name, group, uid) self.samplerGroups[name] = sg uid += 1 self.volatileFields = set() self.volatileIntrinsics = set() #print "Volatile" for field in self.modifiedFields: obj = field.object if self.holdingCount[obj] > 1: if intrinsics.isIntrinsicSlot(field): #print "obj", obj self.volatileIntrinsics.add(obj) else: #print "field", field self.volatileFields.add(self.compatible[field]) #print singleCopy = 0 multiCopy = 0 singleton = 0 pool = 0 for name, count in self.holdingCount.iteritems(): if name in self.volatileIntrinsics or name in self.samplers: if count > 1: pool += 1 else: singleton += 1 else: if count > 1: multiCopy += 1 else: singleCopy += 1 print print singleCopy print multiCopy print singleton print pool print uib = UniformInterfaceBuilder(self.compiler, self) self.ioRefInfo = uib.process() return self
lut = {} for i, d in enumerate(order): lut[d] = i #lut = fuzzyorder.composeMappings(mapping, lut) ordereddata = fuzzyorder.translateData(data, lut) fuzzyorder.printViolations(ordereddata) print "Domains: ", fuzzyorder.mappingResultSize(lut) sys.exit() G = setgraph(domain) B = setgraph(domain) u = UnionFind() for rank, renames in data.iteritems(): for rename in renames: for k, v in rename.iteritems(): G[k].add(v) B[v].add(k) u.union(k, v) # Find the disjoint subgraphs groupmap = {} for d in domain: groupmap[d] = u[d] groupnames = set(groupmap.itervalues()) groups = setgraph(groupnames)
def postProcess(self): # Reconstruct field transform info from ioinfo structure. groups = collections.defaultdict(list) for field, ioname in self.ioinfo.fieldTrans.iteritems(): otherio = self.ioinfo.same[ioname] if ioname in self.liveInputs or otherio in self.liveInputs: groups[ioname].append(field) self.inputFields.add(field) #print field, ioname, otherio self.merged = UnionFind() for group in groups.itervalues(): self.merged.union(*group) # TODO only live fields are "compatible"? self.compatible.union(*group) if False: print "Compatible fields" for name, group in model.reindexUnionFind(self.compatible).iteritems(): print name for field in group: print '\t', field print print "Merged fields" for name, group in model.reindexUnionFind(self.merged).iteritems(): if len(group) > 1: print name for field in group: print '\t', field print print "Holding" for name, count in self.holdingCount.iteritems(): print name, count print # Build sampler groups uid = 0 for name, group in model.reindexUnionFind(self.samplers).iteritems(): sg = model.SamplerGroup(name, group, uid) self.samplerGroups[name] = sg uid += 1 self.volatileFields = set() self.volatileIntrinsics = set() #print "Volatile" for field in self.modifiedFields: obj = field.object if self.holdingCount[obj] > 1: if intrinsics.isIntrinsicSlot(field): #print "obj", obj self.volatileIntrinsics.add(obj) else: #print "field", field self.volatileFields.add(self.compatible[field]) #print singleCopy = 0 multiCopy = 0 singleton = 0 pool = 0 for name, count in self.holdingCount.iteritems(): if name in self.volatileIntrinsics or name in self.samplers: if count > 1: pool += 1 else: singleton += 1 else: if count > 1: multiCopy += 1 else: singleCopy += 1 print print singleCopy print multiCopy print singleton print pool print uib = UniformInterfaceBuilder(self.compiler, self) self.ioRefInfo = uib.process() return self
def __init__(self): self.unify = UnionFind() self.unifyGroups = {} self.dirty = set()
def postProcess(self): # Reconstruct field transform info from ioinfo structure. groups = collections.defaultdict(list) for field, ioname in self.ioinfo.fieldTrans.iteritems(): otherio = self.ioinfo.same[ioname] if ioname in self.liveInputs or otherio in self.liveInputs: groups[ioname].append(field) self.inputFields.add(field) #print field, ioname, otherio self.merged = UnionFind() for group in groups.itervalues(): self.merged.union(*group) # TODO only live fields are "compatible"? self.compatible.union(*group) if False: print "Compatible fields" for name, group in model.reindexUnionFind( self.compatible).iteritems(): print name for field in group: print '\t', field print print "Merged fields" for name, group in model.reindexUnionFind(self.merged).iteritems(): if len(group) > 1: print name for field in group: print '\t', field print print "Holding" for name, count in self.holdingCount.iteritems(): print name, count print # Build sampler groups uid = 0 for name, group in model.reindexUnionFind(self.samplers).iteritems(): sg = model.SamplerGroup(name, group, uid) self.samplerGroups[name] = sg uid += 1 self.volatileFields = set() self.volatileIntrinsics = set() #print "Volatile" for field in self.modifiedFields: obj = field.object if self.holdingCount[obj] > 1: if intrinsics.isIntrinsicSlot(field): #print "obj", obj self.volatileIntrinsics.add(obj) else: #print "field", field self.volatileFields.add(self.compatible[field]) #print singleCopy = 0 multiCopy = 0 singleton = 0 pool = 0 for name, count in self.holdingCount.iteritems(): if name in self.volatileIntrinsics or name in self.samplers: if count > 1: pool += 1 else: singleton += 1 else: if count > 1: multiCopy += 1 else: singleCopy += 1 print print singleCopy print multiCopy print singleton print pool print uib = UniformInterfaceBuilder(self.compiler, self) self.ioRefInfo = uib.process() return self
class FieldTransformAnalysis(TypeDispatcher): def __init__(self, compiler, prgm, exgraph): TypeDispatcher.__init__(self) self.compiler = compiler self.prgm = prgm self.compatable = UnionFind() self.loads = [] self.stores = [] self.fields = {} self.exgraph = exgraph self.ssaBroken = False def reads(self, args): self.compatable.union(*args) def modifies(self, args): self.compatable.union(*args) @dispatch(ast.leafTypes, ast.Local, ast.Existing, ast.DoNotCare, ast.CodeParameters, ast.OutputBlock) def visitLeaf(self, node, stmt=None): pass @dispatch(ast.Suite, ast.Switch, ast.Condition, ast.TypeSwitch, ast.TypeSwitchCase, ast.While) def visitOK(self, node): node.visitChildren(self) @dispatch(ast.Assign, ast.Discard) def visitAssign(self, node): self(node.expr, node) @dispatch(ast.Return) def visitStatement(self, node): pass @dispatch(ast.Allocate) def visitAllocate(self, node, stmt): pass @dispatch(ast.DirectCall) def visitOp(self, node, stmt): pass @dispatch(ast.Load) def visitLoad(self, node, stmt): if not intrinsics.isIntrinsicMemoryOp(node): reads = node.annotation.reads.merged self.reads(reads) self.loads.append((self.code, node)) @dispatch(ast.Store) def visitStore(self, node): if not intrinsics.isIntrinsicMemoryOp(node): modifies = node.annotation.modifies.merged self.modifies(modifies) self.stores.append((self.code, node)) ### Post processing ### def transform(self, code, name, group): lcl = common.localForFieldSlot(self.compiler, code, name, group) ioname = ast.IOName(None) self.header.append(ast.Input(ioname, lcl)) for field in group: self.remap[field] = lcl, ioname def generateRewrites(self, code, name, group): lcl, ioname = self.remap[name] for field in group: self.fields[field] = ioname isLoaded = False for load in self.loadLUT.get((code, name), ()): self.rewrites[load] = lcl isLoaded = True storeCount = 0 for store in self.storeLUT.get((code, name), ()): self.rewrites[store] = ast.Assign(store.value, [lcl]) storeCount += 1 if storeCount > 1 or storeCount == 1 and isLoaded: self.ssaBroken = True def processGroup(self, code, name, group): self.transform(code, name, group) self.generateRewrites(code, name, group) def filterGroups(self, groups): filtered = {} #print #print "GROUPS" for name, group in groups.iteritems(): unique = True for objfield in group: # The field is only unique if the object containing it is unique and # the field is not a "slop" field (e.g. list[-1]) unique &= objfield.annotation.unique exclusive = self.exgraph.mutuallyExclusive(*group) if unique and exclusive: #print "+", group filtered[name] = group else: pass #print "-", group #print unique, exclusive #print [objfield.object.annotation.unique for objfield in group] #print return filtered def fieldGroups(self): groups = {} for obj, group in self.compatable.parents.iteritems(): if group not in groups: groups[group] = [obj] else: groups[group].append(obj) return self.filterGroups(groups) def loadGroups(self): loads = {} for code, load in self.loads: example = load.annotation.reads.merged[0] group = self.compatable[example] key = (code, group) if key not in loads: loads[key] = [load] else: loads[key].append(load) return loads def storeGroups(self): stores = {} for code, store in self.stores: example = store.annotation.modifies.merged[0] group = self.compatable[example] key = (code, group) if key not in stores: stores[key] = [store] else: stores[key].append(store) return stores def postProcess(self): self.groups = self.fieldGroups() self.loadLUT = self.loadGroups() self.storeLUT = self.storeGroups() def processParameters(self, code): params = code.codeparameters for param in params.params[2:]: if isinstance(param, ast.Local): ioname = ast.IOName(None) self.header.append(ast.Input(ioname, param)) self.fields[param] = ioname code.codeparameters = ast.CodeParameters(params.selfparam, params.params[:2], params.paramnames[:2], [], params.vparam, params.kparam, params.returnparams) def postProcessCode(self, code): self.rewrites = {} self.remap = {} self.fields = {} self.header = [] self.processParameters(code) for name, group in self.groups.iteritems(): self.processGroup(code, name, group) rewrite.rewrite(self.compiler, code, self.rewrites) code.ast = ast.Suite([ast.InputBlock(self.header), code.ast]) if self.ssaBroken: ssatransform.evaluateCode(self.compiler, code) simplify.evaluateCode(self.compiler, self.prgm, code) def process(self, code): self.code = code code.visitChildrenForced(self)
class PoolAnalysisInfoCollector(TypeDispatcher): def __init__(self, compiler, exgraph, ioinfo): self.compiler = compiler self.exgraph = exgraph self.ioinfo = ioinfo self.compatible = UnionFind() self.samplers = UnionFind() self.readFields = set() self.modifiedFields = set() self.liveInputs = set() self.liveOutputs = set() self.ioRefs = {} self.inputFields = set() self.locals = set() self.holdingCount = collections.defaultdict(lambda: 0) self.typeIDs = {} self.typeUID = 0 self.samplerGroups = {} def samplerGroup(self, sampler): return self.samplerGroups[self.samplers[sampler]] def handleTypes(self, types): if len(types) > 1: for t in types: self.typeIDs[t] = self.typeUID self.typeUID += 1 def reads(self, args): for field in args: if field not in self.readFields: if field in self.ioinfo.uniforms: self.inputFields.add(field) # Increase the holding count for objects contained in read fields. for ref in field: self.holdingCount[ref] += 1 # TODO translate shader names? self.compatible.union(*args) self.readFields.update(args) def modifies(self, args): # TODO translate shader names? self.compatible.union(*args) self.modifiedFields.update(args) @dispatch(ast.Local) def visitLocal(self, node): if node not in self.locals: self.locals.add(node) pools = collections.defaultdict(list) for ref in node.annotation.references.merged: self.holdingCount[ref] += 1 # NOTE this overestimates shared objects, as they are held by multiple shaders. pt = ref.xtype.obj.pythonType() pools[pt].append(ref) for pt, group in pools.iteritems(): if pt in intrinsics.samplerTypes: self.samplers.union(*group) self.handleTypes(pools.keys()) @dispatch(ast.leafTypes, ast.Code, ast.CodeParameters, ast.Existing, ast.DoNotCare) def visitLeafs(self, node): pass @dispatch(ast.DirectCall, ast.Call, ast.Allocate, ast.Discard, ast.Assign, ast.Return) def visitOp(self, node): node.visitChildren(self) @dispatch(ast.Load) def visitLoad(self, node): self.reads(node.annotation.reads.merged) node.visitChildren(self) @dispatch(ast.Store) def visitStore(self, node): self.modifies(node.annotation.modifies.merged) node.visitChildren(self) @dispatch(ast.InputBlock) def visitInputBlock(self, node): for input in node.inputs: self.liveInputs.add(input.src) self.ioRefs[input.src] = input.lcl.annotation.references.merged @dispatch(ast.OutputBlock) def visitOutputBlock(self, node): for output in node.outputs: self.liveOutputs.add(output.dst) self.ioRefs[output.dst] = output.expr.annotation.references.merged @dispatch(ast.Suite, ast.Switch, ast.Condition, ast.While, ast.TypeSwitch, ast.TypeSwitchCase) def visitOK(self, node): node.visitChildren(self) def analyzeCode(self, code): code.visitChildrenForced(self) def postProcess(self): # Reconstruct field transform info from ioinfo structure. groups = collections.defaultdict(list) for field, ioname in self.ioinfo.fieldTrans.iteritems(): otherio = self.ioinfo.same[ioname] if ioname in self.liveInputs or otherio in self.liveInputs: groups[ioname].append(field) self.inputFields.add(field) #print field, ioname, otherio self.merged = UnionFind() for group in groups.itervalues(): self.merged.union(*group) # TODO only live fields are "compatible"? self.compatible.union(*group) if False: print "Compatible fields" for name, group in model.reindexUnionFind(self.compatible).iteritems(): print name for field in group: print '\t', field print print "Merged fields" for name, group in model.reindexUnionFind(self.merged).iteritems(): if len(group) > 1: print name for field in group: print '\t', field print print "Holding" for name, count in self.holdingCount.iteritems(): print name, count print # Build sampler groups uid = 0 for name, group in model.reindexUnionFind(self.samplers).iteritems(): sg = model.SamplerGroup(name, group, uid) self.samplerGroups[name] = sg uid += 1 self.volatileFields = set() self.volatileIntrinsics = set() #print "Volatile" for field in self.modifiedFields: obj = field.object if self.holdingCount[obj] > 1: if intrinsics.isIntrinsicSlot(field): #print "obj", obj self.volatileIntrinsics.add(obj) else: #print "field", field self.volatileFields.add(self.compatible[field]) #print singleCopy = 0 multiCopy = 0 singleton = 0 pool = 0 for name, count in self.holdingCount.iteritems(): if name in self.volatileIntrinsics or name in self.samplers: if count > 1: pool += 1 else: singleton += 1 else: if count > 1: multiCopy += 1 else: singleCopy += 1 print print singleCopy print multiCopy print singleton print pool print uib = UniformInterfaceBuilder(self.compiler, self) self.ioRefInfo = uib.process() return self