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
Example #2
0
	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 = {}
Example #3
0
    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 = {}
Example #4
0
	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
Example #5
0
    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
Example #6
0
    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
Example #8
0
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
Example #9
0
    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 __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
Example #11
0
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
Example #12
0
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]
Example #13
0
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()
Example #15
0
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())
Example #17
0
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
Example #18
0
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()
Example #19
0
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
Example #20
0
 def __init__(self):
     self.group = UnionFind()
Example #21
0
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)
Example #22
0
	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
Example #23
0
 def __init__(self):
     self.unify = UnionFind()
     self.unifyGroups = {}
     self.dirty = set()
Example #24
0
    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
Example #25
0
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)
Example #26
0
	def __init__(self):
		self.unify         = UnionFind()
		self.unifyGroups   = {}
		self.dirty         = set()
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)
Example #28
0
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