// // Merge the linker objects from unitLinkerObjects into linkerObjects. // Duplication is expected and filtered out, but contradictions are an error. // void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects) { // Error check and merge the linker objects (duplicates should not be created) std::size_t initialNumLinkerObjects = linkerObjects.size(); for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) { bool merge = true; for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) { TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode(); TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); assert(symbol && unitSymbol); if (symbol->getName() == unitSymbol->getName()) { // filter out copy merge = false; // but if one has an initializer and the other does not, update // the initializer if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty()) symbol->setConstArray(unitSymbol->getConstArray()); // Similarly for binding if (! symbol->getQualifier().hasBinding() && unitSymbol->getQualifier().hasBinding()) symbol->getQualifier().layoutBinding = unitSymbol->getQualifier().layoutBinding; // Update implicit array sizes mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType()); // Check for consistent types/qualification/initializers etc. mergeErrorCheck(infoSink, *symbol, *unitSymbol, false); } } if (merge) linkerObjects.push_back(unitLinkerObjects[unitLinkObj]); } }
TType* getTypeDebugParameter(TIntermAggregate *node, int pnum) { TType *result = NULL; if (!node) return result; if (node->getOp() != EOpFunctionCall) return result; TIntermSequence funcCallSeq = node->getSequence(); if ((int) funcCallSeq.size() < pnum) { dbgPrint(DBGLVL_ERROR, "CodeTools - function does not have this much parameter\n"); exit(1); } if (!funcCallSeq[pnum]->getAsTyped()) { dbgPrint(DBGLVL_ERROR, "CodeTools - in parameter is not of type TIntermTyped\n"); exit(1); } return funcCallSeq[pnum]->getAsTyped()->getTypePointer(); }
int ValidateLimitations::validateForLoopInit(TIntermLoop *node) { TIntermNode *init = node->getInit(); if (init == NULL) { error(node->getLine(), "Missing init declaration", "for"); return -1; } // // init-declaration has the form: // type-specifier identifier = constant-expression // TIntermAggregate *decl = init->getAsAggregate(); if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) { error(init->getLine(), "Invalid init declaration", "for"); return -1; } // To keep things simple do not allow declaration list. TIntermSequence *declSeq = decl->getSequence(); if (declSeq->size() != 1) { error(decl->getLine(), "Invalid init declaration", "for"); return -1; } TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) { error(decl->getLine(), "Invalid init declaration", "for"); return -1; } TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); if (symbol == NULL) { error(declInit->getLine(), "Invalid init declaration", "for"); return -1; } // The loop index has type int or float. TBasicType type = symbol->getBasicType(); if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) { error(symbol->getLine(), "Invalid type for loop index", getBasicString(type)); return -1; } // The loop index is initialized with constant expression. if (!isConstExpr(declInit->getRight())) { error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression", symbol->getSymbol().c_str()); return -1; } return symbol->getId(); }
// // Merge the function bodies and global-level initializers from unitGlobals into globals. // Will error check duplication of function bodies for the same signature. // void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals) { // TODO: link-time performance: Processing in alphabetical order will be faster // Error check the global objects, not including the linker objects for (unsigned int child = 0; child < globals.size() - 1; ++child) { for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) { TIntermAggregate* body = globals[child]->getAsAggregate(); TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate(); if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) { error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:"); infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n"; } } } // Merge the global objects, just in front of the linker objects globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1); }
bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = !mCodeInserted; switch (node->getOp()) { case EOpSequence: break; case EOpFunction: { // Function definition. ASSERT(visit == PreVisit); if (node->getName() == "main(") { TIntermSequence *sequence = node->getSequence(); ASSERT((sequence->size() == 1) || (sequence->size() == 2)); TIntermAggregate *body = NULL; if (sequence->size() == 1) { body = new TIntermAggregate(EOpSequence); sequence->push_back(body); } else { body = (*sequence)[1]->getAsAggregate(); } ASSERT(body); insertInitCode(body->getSequence()); mCodeInserted = true; } break; } default: visitChildren = false; break; } return visitChildren; }
void CollectVariables::visitInfoList(const TIntermSequence &sequence, std::vector<VarT> *infoList) const { for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++) { const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode(); // The only case in which the sequence will not contain a // TIntermSymbol node is initialization. It will contain a // TInterBinary node in that case. Since attributes, uniforms, // and varyings cannot be initialized in a shader, we must have // only TIntermSymbol nodes in the sequence. ASSERT(variable != NULL); visitVariable(variable, infoList); } }
bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node) { ASSERT(node->getOp() == EOpFunctionCall); // If not within loop body, there is nothing to check. if (!withinLoopBody()) return true; // List of param indices for which loop indices are used as argument. typedef std::vector<size_t> ParamIndex; ParamIndex pIndex; TIntermSequence *params = node->getSequence(); for (TIntermSequence::size_type i = 0; i < params->size(); ++i) { TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode(); if (symbol && isLoopIndex(symbol)) pIndex.push_back(i); } // If none of the loop indices are used as arguments, // there is nothing to check. if (pIndex.empty()) return true; bool valid = true; TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable; TSymbol *symbol = symbolTable.find(node->getFunctionSymbolInfo()->getName(), GetGlobalParseContext()->getShaderVersion()); ASSERT(symbol && symbol->isFunction()); TFunction *function = static_cast<TFunction *>(symbol); for (ParamIndex::const_iterator i = pIndex.begin(); i != pIndex.end(); ++i) { const TConstParameter ¶m = function->getParam(*i); TQualifier qual = param.type->getQualifier(); if ((qual == EvqOut) || (qual == EvqInOut)) { error((*params)[*i]->getLine(), "Loop index cannot be used as argument to a function out or inout parameter", (*params)[*i]->getAsSymbolNode()->getSymbol().c_str()); valid = false; } } return valid; }
bool getHasSideEffectsDebugParameter(TIntermAggregate *node, int pnum) { if (!node) return false; if ( node->getOp() != EOpFunctionCall) return false; TIntermSequence funcCallSeq = node->getSequence(); if ((int) funcCallSeq.size() < pnum) { dbgPrint(DBGLVL_ERROR, "CodeTools - function does not have this much parameter\n"); exit(1); } if (!funcCallSeq[pnum]->getAsTyped()) { dbgPrint(DBGLVL_ERROR, "CodeTools - in parameter is not of type TIntermTyped\n"); exit(1); } return funcCallSeq[pnum]->getAsTyped()->hasSideEffects(); }
bool TSamplerTraverser::traverseAggregate( bool preVisit, TIntermAggregate *node, TIntermTraverser *it) { TSamplerTraverser* sit = static_cast<TSamplerTraverser*>(it); TInfoSink &infoSink = sit->infoSink; if (sit->abort) return false; if (! (sit->typing) ) { switch (node->getOp()) { case EOpFunction: // Store the current function name to use to setup the parameters sit->currentFunction = node->getName().c_str(); break; case EOpParameters: // Store the parameters to the function in the map sit->functionMap[sit->currentFunction.c_str()] = &(node->getSequence()); break; case EOpFunctionCall: { // This is a bit tricky. Find the function in the map. Loop over the parameters // and see if the parameters have been marked as a typed sampler. If so, propagate // the sampler type to the caller if ( sit->functionMap.find ( node->getName().c_str() ) != sit->functionMap.end() ) { // Get the sequence of function parameters TIntermSequence *funcSequence = sit->functionMap[node->getName().c_str()]; // Get the sequence of parameters being passed to function TIntermSequence &sequence = node->getSequence(); // Grab iterators to both sequences TIntermSequence::iterator it = sequence.begin(); TIntermSequence::iterator funcIt = funcSequence->begin(); assert ( sequence.size() == funcSequence->size() ); if ( sequence.size() == funcSequence->size() ) { while ( it != sequence.end() ) { TIntermSymbol *sym = (*it)->getAsSymbolNode(); TIntermSymbol *funcSym = (*funcIt)->getAsSymbolNode(); if ( sym != NULL && funcSym != NULL) { // If the parameter is generic, and the sampler to which // it is being passed has been marked, propogate its sampler // type to the caller. if ( sym->getBasicType() == EbtSamplerGeneric && funcSym->getBasicType() != EbtSamplerGeneric ) { sit->typeSampler ( sym, funcSym->getBasicType() ); } } it++; funcIt++; } } } } break; //HLSL texture functions case EOpTex1D: case EOpTex1DProj: case EOpTex1DLod: case EOpTex1DBias: case EOpTex1DGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSampler1D); } else if (sampArg->getBasicType() != EbtSampler1D) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTex2D: case EOpTex2DProj: case EOpTex2DLod: case EOpTex2DBias: case EOpTex2DGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSampler2D); } else if (sampArg->getBasicType() != EbtSampler2D) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTexRect: case EOpTexRectProj: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSamplerRect); } else if (sampArg->getBasicType() != EbtSamplerRect) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTex3D: case EOpTex3DProj: case EOpTex3DLod: case EOpTex3DBias: case EOpTex3DGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSampler3D); } else if (sampArg->getBasicType() != EbtSampler3D) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTexCube: case EOpTexCubeProj: case EOpTexCubeLod: case EOpTexCubeBias: case EOpTexCubeGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSamplerCube); } else if (sampArg->getBasicType() != EbtSamplerCube) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; default: break; } } return !(sit->abort); }
void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) { bool visit = true; TIntermSequence *sequence = node->getSequence(); if (node->getOp() == EOpPrototype) { addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence); } if (preVisit) visit = visitAggregate(PreVisit, node); if (visit) { bool inFunctionMap = false; if (node->getOp() == EOpFunctionCall) { inFunctionMap = isInFunctionMap(node); if (!inFunctionMap) { // The function is not user-defined - it is likely built-in texture function. // Assume that those do not have out parameters. setInFunctionCallOutParameter(false); } } incrementDepth(node); if (inFunctionMap) { TIntermSequence *params = getFunctionParameters(node); TIntermSequence::iterator paramIter = params->begin(); for (auto *child : *sequence) { ASSERT(paramIter != params->end()); TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier(); setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut); child->traverse(this); if (visit && inVisit) { if (child != sequence->back()) visit = visitAggregate(InVisit, node); } ++paramIter; } setInFunctionCallOutParameter(false); } else { // Find the built-in function corresponding to this op so that we can determine the // in/out qualifiers of its parameters. TFunction *builtInFunc = nullptr; TString opString = GetOperatorString(node->getOp()); if (!node->isConstructor() && !opString.empty()) { // The return type doesn't affect the mangled name of the function, which is used // to look it up from the symbol table. TType dummyReturnType; TFunction call(&opString, &dummyReturnType, node->getOp()); for (auto *child : *sequence) { TType *paramType = child->getAsTyped()->getTypePointer(); TConstParameter p(paramType); call.addParameter(p); } TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion); if (sym != nullptr && sym->isFunction()) { builtInFunc = static_cast<TFunction *>(sym); ASSERT(builtInFunc->getParamCount() == sequence->size()); } } size_t paramIndex = 0; for (auto *child : *sequence) { TQualifier qualifier = EvqIn; if (builtInFunc != nullptr) qualifier = builtInFunc->getParam(paramIndex).type->getQualifier(); setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut); child->traverse(this); if (visit && inVisit) { if (child != sequence->back()) visit = visitAggregate(InVisit, node); } ++paramIndex; } setInFunctionCallOutParameter(false); } decrementDepth(); } if (visit && postVisit) visitAggregate(PostVisit, node); }