def bindStreams(compiler, translator, context): code = symbols.SymbolRewriter(compiler.extractor, streamCodeTemplate) bind = symbols.SymbolRewriter(compiler.extractor, streamBindTemplate) originalParams = context.originalParams currentParams = context.code.codeparameters self = ast.Local('self') streams = [] statements = [] for original in originalParams.params[2:]: root = ast.Local(original.name) streams.append(root) ioname = context.shaderdesc.fields[original] if ioname in translator.liveInputs: refs = original.annotation.references.merged assert len(refs) == 1 obj = refs[0] assert intrinsics.isIntrinsicObject(obj) t = obj.xtype.obj.pythonType() attr = "bind_stream_" + t.__name__ structInfo = translator.ioRefInfo.get(ioname) shaderName = structInfo.lut.subpools[t].name statements.append(bind.rewrite(self=self, attr=attr, shaderName=shaderName, name=root)) # for original, current in zip(originalParams.params, currentParams.params)[2:]: # root = ast.Local(original.name) # streams.append(root) # # if current.isDoNotCare(): continue # # refs = current.annotation.references.merged # assert len(refs) == 1 # obj = refs[0] # assert intrinsics.isIntrinsicObject(obj) # t = obj.xtype.obj.pythonType() # attr = "bind_stream_" + t.__name__ # # structInfo = translator.serializationInfo(current) # assert structInfo is not None # # shaderName = structInfo.intrinsics[t].decl.name # # statements.append(bind.rewrite(self=self, attr=attr, shaderName=shaderName, name=root)) body = ast.Suite(statements) args = [self] args.extend(streams) names = [arg.name for arg in args] return code.rewrite(args=args, argnames=names, body=body)
def bindUniforms(compiler, translator, uniformSlot): code = symbols.SymbolRewriter(compiler.extractor, uniformCodeTemplate) self = ast.Local('self') shader = ast.Local('shader') if uniformSlot.annotation.references: uniformRefs = uniformSlot.annotation.references.merged body = ast.Suite(serializeUniformNode(compiler, translator, self, uniformSlot, uniformRefs, shader)) else: # No uniforms are used. body = ast.Suite([]) return code.rewrite(args=[self, shader], body=body)
def makeExternalSlot(self, name): code = self.externalFunction context = self.externalFunctionContext dummyLocal = ast.Local(name) dummyName = self.canonical.localName(code, dummyLocal, context) dummySlot = self.storeGraph.root(dummyName) return dummySlot
def createLocalNode(hyperblock, name, values): lcl = ast.Local(name) node = graph.LocalNode(hyperblock, (lcl, )) annotation = annotations.DataflowSlotAnnotation(values, True) node.annotation = annotation return node
def upwardSlots(self, slot): if slot not in self.slotReverse: self.slotReverse[slot].append( self.src.local(ast.Local('summaryTemp'))) result = self.slotReverse[slot] assert result return result
def process(self, node, vparamLen): # TODO rewrite local references. p = node.codeparameters self.code = node self.vparam = p.vparam self.newParams = [ast.Local(None) for i in range(vparamLen)] self.newNames = [None for i in range(vparamLen)] if vparamLen > 0: # Defaults are never used defaults = () else: # Number of arguments unchanged, defaults may be used, do nothing defaults = p.defaults for i, lcl in enumerate(self.newParams): field = self.storeGraph.canonical.fieldName('Array', self.storeGraph.extractor.getObject(i)) self.transferReferences(self.vparam, field, lcl) selfparam = p.selfparam parameters = self.extend(p.params, self.newParams) parameternames = self.extend(p.paramnames, self.newNames) vparam = None kparam = p.kparam returnparams = p.returnparams node.codeparameters = ast.CodeParameters(selfparam, parameters, parameternames, defaults, vparam, kparam, returnparams) node.ast = self(node.ast)
def __init__(self, compiler, graph, opPathLength, clone): self.decompileTime = 0 self.console = compiler.console self.extractor = compiler.extractor self.clone = clone # Should we copy the code before annotating it? # Has the context been constructed? self.liveContexts = set() self.liveCode = set() # Constraint information, for debugging self.constraints = [] # The worklist self.dirty = collections.deque() self.canonical = graph.canonical self._canonicalContext = util.canonical.CanonicalCache( base.AnalysisContext) # Controls how many previous ops are remembered by a context. # TODO remember prior CPA signatures? self.opPathLength = opPathLength self.cache = {} # Information for contextual operations. self.opAllocates = collections.defaultdict(set) self.opReads = collections.defaultdict(set) self.opModifies = collections.defaultdict(set) self.opInvokes = collections.defaultdict(set) self.codeContexts = collections.defaultdict(set) self.storeGraph = graph # Setup the "external" context, used for creaing bogus slots. self.externalOp = util.canonical.Sentinel('<externalOp>') self.externalFunction = ast.Code( 'external', ast.CodeParameters(None, [], [], [], None, None, [ast.Local('internal_return')]), ast.Suite([])) externalSignature = self._signature(self.externalFunction, None, ()) opPath = self.initialOpPath() self.externalFunctionContext = self._canonicalContext( externalSignature, opPath, self.storeGraph) self.codeContexts[self.externalFunction].add( self.externalFunctionContext) # For vargs self.tupleClass = self.extractor.getObject(tuple) self.ensureLoaded(self.tupleClass) # For kargs self.dictionaryClass = self.extractor.getObject(dict) self.ensureLoaded(self.dictionaryClass) self.entryPointOp = {}
def buildTempLocal(analysis, objs): if objs is None: return None else: lcl = analysis.root.local(ast.Local('entry_point_arg')) objs = frozenset([analysis.objectName(xtype) for xtype in objs]) lcl.updateValues(objs) return lcl
def translateLocal(self, node): if not node in self.localMap: lcl = ast.Local(node.name) self.localMap[node] = lcl self.transferLocal(node, lcl) else: lcl = self.localMap[node] return lcl
def setNumReturns(self, num): if self.numReturns is None: self.numReturns = num p = self.code.codeparameters if num != len(p.returnparams): returnparams = [ast.Local('internal_return_%d' % i) for i in range(num)] self.code.codeparameters = ast.CodeParameters(p.selfparam, p.params, p.paramnames, p.defaults, p.vparam, p.kparam, returnparams) else: assert num == self.numReturns
def methodCallToTypeSwitch(self, node, arg, pos, targets): # TODO if mutable types are allowed, we should be looking at the LowLevel type slot? # TODO localy rebuild read/modify/allocate information using filtered invokes. # TODO should the return value be SSAed? This might interfere with nessled type switches. # If so, retarget the return value and fix up return types groups = self.groupTypes(node, arg, pos) if groups is None or len(groups) <= 1: return None # Don't create trivial type switches cases = [] for group in groups: # Create a filtered version of the argument. name = arg.name if isinstance(arg, ast.Local) else None expr = ast.Local(name) expr.annotation = self.filterReferenceAnnotationByType( arg.annotation, group) # Create the new op opannotation = node.annotation # Kill contexts where the filtered expression has no references. # (In these contexts, the new op will never be evaluated.) mask = self.makeRemapMask(expr.annotation) if -1 in mask: opannotation = opannotation.contextSubset(mask) # Filter out invocations that don't have the right type for the given parameter. opannotation = self.filterOpAnnotationByType( opannotation, group, pos) # Rewrite the op to use expr instead of the original arg. newop = rewrite.rewriteTerm(node, {arg: expr}) assert newop is not node newop.annotation = opannotation # Try to reduce it to a direct call newop = self(newop) # Create the suite for this case stmts = [] if targets is None: stmts.append(ast.Discard(newop)) else: # HACK should SSA it? stmts.append(ast.Assign(newop, list(targets))) suite = ast.Suite(stmts) case = ast.TypeSwitchCase([self.existingFromObj(t) for t in group], expr, suite) cases.append(case) ts = ast.TypeSwitch(arg, cases) return ts
def handleUniformType(compiler, translator, self, holdingSlot, ref, root, t): statements = [] # Find the group name holdingSlot = translator.compatible[holdingSlot] structInfo = translator.ioRefInfo.get(holdingSlot) if structInfo: if structInfo.multipleTypes(): sub = structInfo.lut.subpools['type'] name = sub.name uid = translator.typeIDs[t] uidO = compiler.extractor.getObject(uid) statements.append(bindUniform(compiler, self, name, int, ast.Existing(uidO))) if intrinsics.isIntrinsicType(t): if t in intrinsics.samplerTypes: sg = translator.samplerGroup(ref) assert sg.unique name = sg.name else: sub = structInfo.lut.subpools[t] name = sub.name statements.append(bindUniform(compiler, self, name, t, root)) # TODO fields? get = symbols.SymbolRewriter(compiler.extractor, uniformGetTemplate) # TODO mutually exclusive? for field in ref.slots.itervalues(): if not intrinsics.isIntrinsicSlot(field): if field.slotName.type != 'Attribute': continue cls, attr = classAttrFromField(compiler, field.slotName) assert issubclass(t, cls), (ref, field) target = ast.Local('bogus') # Load the field assign = get.rewrite(cls=cls, attr=attr, root=root, target=target) statements.append(assign) # Recurse statements.extend(serializeUniformNode(compiler, translator, self, field, field, target)) return statements
def generateTypeLoad(self, expr, fieldName, refs): pt = refs[0].xtype.obj.pythonType() for ref in refs[1:]: assert ref.xtype.obj.pythonType is pt, "Temporary Limitation" ex = self.generateExisting(self.compiler.extractor.getObject(pt)) name = common.nameForField(self.compiler, fieldName) lcl = ast.Local(name) lcl.annotation = ex.annotation self.statements.append(ast.Assign(ex, [lcl])) return lcl
def visitAssign(self, node): if isinstance(node.expr, ast.BinaryOp) and node.expr.op in opnames.inplaceOps: assert len(node.lcls) == 1 target = node.lcls[0] #assert not node.lcl in self.collapsable # Workarround for synthesizing inplace BinaryOps that don't put their result into the left argument. # If the operation actually is inplace, don't hack it. temp = node.expr.right if target != node.expr.left: if target == node.expr.right: # Take care of the case Assign(a, BinaryOp(b, inplace, a)) # Otherwise the subsequent statement cobbers the right value. temp = ast.Local(None) stmt = "%s = %s" % (self.seg.process(temp), self.seg.process(node.expr.right)) self.emitStatement(stmt) stmt = "%s = %s" % (self.seg.process(target), self.seg.process(node.expr.left)) self.emitStatement(stmt) stmt = "%s %s %s" % (self.seg.process(target), node.expr.op, self.seg.process(temp)) self.emitStatement(stmt) elif isinstance(node.expr, ast.MakeFunction): assert len(node.lcls) == 1 # HACK to rename the function self(node.expr) name = node.expr.code.name lcl = self.seg.process(node.lcls[0]) if name != lcl: self.emitStatement("%s = %s" % (lcl, name)) elif isinstance(node.expr, ast.Existing) and node.expr.object.isConstant() and isinstance(node.expr.object.pyobj, types.CodeType): # HACK pass ## elif isinstance(node.expr, (ast.ShortCircutAnd, ast.ShortCircutOr)): ## expr, p = self(node.expr) ## ## stmt = "%s = %s" % (self.seg.process(node.lcl), expr) ## self.emitStatement(stmt) else: if len(node.lcls) == 1 and node.lcls[0] in self.collapsable and self.supressStatements: #if node.lcl in self.collapsable: self.seg.processCollapsed(node.lcls[0], node.expr) else: stmt = "%s = %s" % (', '.join([self.seg.process(lcl) for lcl in node.lcls]), self.seg.process(node.expr)) self.emitStatement(stmt)
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 getReplacementSource(self, dominator): if dominator not in self.newName: if isinstance(dominator, ast.Store): old = dominator.value else: assert len(dominator.lcls) == 1 old = dominator.lcls[0] if isinstance(old, ast.Existing): src = ast.Existing(old.object) else: src = ast.Local(old.name) self.replace[dominator] = [dominator, ast.Assign(old, [src])] src.annotation = old.annotation self.newName[dominator] = src else: src = self.newName[dominator] return src
def existingTemp(self, obj): lcl = self.context.local(ast.Local('existing_temp')) lcl.updateSingleValue(obj) return lcl
def makeTarget(self, context): lcl = context.local(ast.Local(self.localName())) lcl.addPrev(self) self.dst.append(lcl) return lcl
def makeLocalObjs(self, name): lcl = ast.Local(name) slot = self.sys.canonical.localSlot(lcl) expr = self.sys.canonical.localExpr(slot) return lcl, slot, expr
body = ast.Suite(statements) args = [self] args.extend(streams) names = [arg.name for arg in args] return code.rewrite(args=args, argnames=names, body=body) classTemplate = ast.ClassDef( symbols.Symbol('className'), [ast.GetAttr( ast.GetGlobal(existingConstant('pystreamruntime')), existingConstant('BaseCompiledShader') )], ast.Suite([ ast.Assign(existingSymbol('original'), [ast.Local('original')]), ast.Assign(existingSymbol('vsCode'), [ast.Local('vs')]), ast.Assign(existingSymbol('fsCode'), [ast.Local('fs')]), ast.FunctionDef('_bindUniforms', symbols.Symbol('bindUniforms'), []), ast.FunctionDef('bindStreams', symbols.Symbol('bindStreams'), []) ]), [] ) callback = ast.Local('callback') # Not a FunctionDef, as the symbol rewriter would not be able to reach through the (shared) code registerTemplate = ast.Code( 'register', ast.CodeParameters( None,