void TOutputGLSL::writeFunctionParameters(const TIntermSequence& args) { TInfoSinkBase& out = objSink(); for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter) { const TIntermSymbol* arg = (*iter)->getAsSymbolNode(); ASSERT(arg != NULL); const TType& type = arg->getType(); TQualifier qualifier = type.getQualifier(); // TODO(alokp): Validate qualifier for function arguments. if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) out << type.getQualifierString() << " "; out << getTypeName(type); const TString& name = arg->getSymbol(); if (!name.empty()) out << " " << name; if (type.isArray()) out << arrayBrackets(type); // Put a comma if this is not the last argument. if (iter != args.end() - 1) out << ", "; } }
bool isChildofMain(TIntermNode *node, TIntermNode *root) { TIntermNode *main = getFunctionBySignature(MAIN_FUNC_SIGNATURE, root); if (!main) { dbgPrint(DBGLVL_ERROR, "CodeTools - could not find main function\n"); exit(1); } TIntermAggregate *aggregate; if (!(aggregate = main->getAsAggregate())) { dbgPrint(DBGLVL_ERROR, "CodeTools - main is not Aggregate\n"); exit(1); } TIntermSequence sequence = aggregate->getSequence(); TIntermSequence::iterator sit; for(sit = sequence.begin(); sit != sequence.end(); sit++) { if (*sit == node) { return true; } } return false; }
int getFunctionDebugParameter(TIntermAggregate *node) { int result = -1; int i; if (!node) return result; if ( node->getOp() != EOpFunction) { return result; } TIntermSequence funcDeclSeq = node->getSequence(); if (!funcDeclSeq[0] || !funcDeclSeq[0]->getAsAggregate() || !(funcDeclSeq[0]->getAsAggregate()->getOp() == EOpParameters)) { dbgPrint(DBGLVL_ERROR, "CodeTools - function does not comply with assumptions\n"); exit(1); } TIntermSequence funcDeclParamSeq = (funcDeclSeq[0]->getAsAggregate())->getSequence(); TIntermSequence::iterator pD = funcDeclParamSeq.begin(); for (i=0; pD != funcDeclParamSeq.end(); ++pD, ++i) { if ((*pD)->getAsFuncParamNode()->getType().getQualifier() == EvqIn) { result = i; } } return result; }
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(); }
// Traverse an aggregate node. Same comments in binary node apply here. void TIntermTraverser::traverseAggregate(TIntermAggregate *node) { bool visit = true; TIntermSequence *sequence = node->getSequence(); if (preVisit) visit = visitAggregate(PreVisit, node); if (visit) { incrementDepth(node); for (auto *child : *sequence) { child->traverse(this); if (visit && inVisit) { if (child != sequence->back()) visit = visitAggregate(InVisit, node); } } decrementDepth(); } if (visit && postVisit) visitAggregate(PostVisit, node); }
// // 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]); } }
// Traverse a block node. void TIntermTraverser::traverseBlock(TIntermBlock *node) { bool visit = true; TIntermSequence *sequence = node->getSequence(); if (preVisit) visit = visitBlock(PreVisit, node); if (visit) { incrementDepth(node); pushParentBlock(node); for (auto *child : *sequence) { child->traverse(this); if (visit && inVisit) { if (child != sequence->back()) visit = visitBlock(InVisit, node); } incrementParentBlockPos(); } popParentBlock(); decrementDepth(); } if (visit && postVisit) visitBlock(PostVisit, node); }
TIntermAggregate *EmulatePrecision::createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr) { std::stringstream strstr = sh::InitializeStream<std::stringstream>(); if (left->getPrecision() == EbpMedium) strstr << "angle_compound_" << opNameStr << "_frm"; else strstr << "angle_compound_" << opNameStr << "_frl"; ImmutableString functionName = ImmutableString(strstr.str()); TIntermSequence *arguments = new TIntermSequence(); arguments->push_back(left); arguments->push_back(right); TVector<const TVariable *> parameters; TType *leftParamType = new TType(left->getType()); leftParamType->setPrecision(EbpHigh); leftParamType->setQualifier(EvqOut); parameters.push_back(new TVariable(mSymbolTable, kParamXName, static_cast<const TType *>(leftParamType), SymbolType::AngleInternal)); TType *rightParamType = new TType(right->getType()); rightParamType->setPrecision(EbpHigh); rightParamType->setQualifier(EvqIn); parameters.push_back(new TVariable(mSymbolTable, kParamYName, static_cast<const TType *>(rightParamType), SymbolType::AngleInternal)); return TIntermAggregate::CreateRawFunctionCall( *getInternalFunction(functionName, left->getType(), arguments, parameters, false), arguments); }
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(); }
bool TCompiler::pruneUnusedFunctions(TIntermNode *root) { TIntermAggregate *rootNode = root->getAsAggregate(); ASSERT(rootNode != nullptr); UnusedPredicate isUnused(&mCallDag, &functionMetadata); TIntermSequence *sequence = rootNode->getSequence(); sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end()); return true; }
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; }
// // Traverse an aggregate node. Same comments in binary node apply here. // void TIntermTraverser::traverseAggregate(TIntermAggregate *node) { bool visit = true; TIntermSequence *sequence = node->getSequence(); if (preVisit) visit = visitAggregate(PreVisit, node); if (visit) { incrementDepth(node); if (node->getOp() == EOpSequence) pushParentBlock(node); else if (node->getOp() == EOpFunction) mInGlobalScope = false; for (auto *child : *sequence) { child->traverse(this); if (visit && inVisit) { if (child != sequence->back()) visit = visitAggregate(InVisit, node); } if (node->getOp() == EOpSequence) incrementParentBlockPos(); } if (node->getOp() == EOpSequence) popParentBlock(); else if (node->getOp() == EOpFunction) mInGlobalScope = true; decrementDepth(); } if (visit && postVisit) visitAggregate(PostVisit, node); }
TIntermAggregate *EmulatePrecision::createRoundingFunctionCallNode(TIntermTyped *roundedChild) { const ImmutableString *roundFunctionName = &kAngleFrmString; if (roundedChild->getPrecision() == EbpLow) roundFunctionName = &kAngleFrlString; TIntermSequence *arguments = new TIntermSequence(); arguments->push_back(roundedChild); TVector<const TVariable *> parameters; TType *paramType = new TType(roundedChild->getType()); paramType->setPrecision(EbpHigh); paramType->setQualifier(EvqIn); parameters.push_back(new TVariable(mSymbolTable, kParamXName, static_cast<const TType *>(paramType), SymbolType::AngleInternal)); return TIntermAggregate::CreateRawFunctionCall( *getInternalFunction(*roundFunctionName, roundedChild->getType(), arguments, parameters, true), arguments); }
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(); }
TIntermTyped *TIntermediate::addSwizzle( TVectorFields &fields, const TSourceLoc &line) { TIntermAggregate *node = new TIntermAggregate(EOpSequence); node->setLine(line); TIntermConstantUnion *constIntNode; TIntermSequence *sequenceVector = node->getSequence(); ConstantUnion *unionArray; for (int i = 0; i < fields.num; i++) { unionArray = new ConstantUnion[1]; unionArray->setIConst(fields.offsets[i]); constIntNode = addConstantUnion( unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); sequenceVector->push_back(constIntNode); } return node; }
TIntermNode* getFunctionBySignature(const char *sig, TIntermNode* root) // Assumption: 1. roots hold all function definitions. // for single file shaders this should hold. // Todo: Add solution for multiple files compiled in one shader. { TIntermAggregate *aggregate; TIntermSequence sequence; TIntermSequence::iterator sit; // Root must be aggregate if (!(aggregate = root->getAsAggregate())) { return NULL; } if (aggregate->getOp() == EOpFunction) { // do not stop search at function prototypes if (aggregate->getSequence().size() != 0) { if (!strcmp(sig, aggregate->getName().c_str())) { return aggregate; } } } else { sequence = aggregate->getSequence(); for (sit = sequence.begin(); sit != sequence.end(); sit++) { if ((*sit)->getAsAggregate() && (*sit)->getAsAggregate()->getOp() == EOpFunction) { // do not stop search at function prototypes if ((*sit)->getAsAggregate()->getSequence().size() != 0) { if (!strcmp(sig, (*sit)->getAsAggregate()->getName().c_str())) { return *sit; } } } } } return NULL; }
void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args) { TInfoSinkBase& out = objSink(); for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter) { const TIntermSymbol* arg = (*iter)->getAsSymbolNode(); ASSERT(arg != NULL); const TType& type = arg->getType(); writeVariableType(type); const TString& name = arg->getSymbol(); if (!name.empty()) out << " " << name; if (type.isArray()) out << arrayBrackets(type); // Put a comma if this is not the last argument. if (iter != args.end() - 1) out << ", "; } }
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 DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals, TSymbolTable *symbolTable) { TIntermSequence *deferredInitializers = new TIntermSequence(); // Loop over all global statements and process the declarations. This is simpler than using a // traverser. for (TIntermNode *statement : *root->getSequence()) { TIntermDeclaration *declaration = statement->getAsDeclarationNode(); if (declaration) { GetDeferredInitializers(declaration, initializeUninitializedGlobals, deferredInitializers); } } // Add the function with initialization and the call to that. if (!deferredInitializers->empty()) { InsertInitCallToMain(root, deferredInitializers, symbolTable); } }
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); } }
// // 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); }
void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement) { TIntermSequence insertions; insertions.push_back(statement); insertStatementsInParentBlock(insertions); }
void Parser::parseExpr(TIntermSequence& e) { for (auto it = e.begin(); it != e.end(); ++it) { auto aggregate = (*it)->getAsAggregate(); auto binop = (*it)->getAsBinaryNode(); if (aggregate != nullptr) { switch (aggregate->getOp()) { case EOpFunctionCall: { ParsedExpr expr; expr.v = nullptr; ParsedValue value; value.v = nullptr; value.p = aggregate->getLine().first_line; std::vector<TIntermTyped*> args; for (auto it2 = aggregate->getSequence().begin(); it2 != aggregate->getSequence().end(); ++it2) { args.push_back((*it2)->getAsTyped()); } expr.e = new ParsedValue(makeCall(aggregate->getName().c_str(), args, aggregate->getLine().first_line)); expr.p = aggregate->getLine().first_line; cur.exprs.push_back(expr); break; } case EOpDeclaration: { PLocal* local = new PLocal; auto var = dynamic_cast<TIntermBinary*>(aggregate->getSequence()[0]); if (var->getOp() != EOpInitialize) error("Expected initialization.", var->getLine().first_line); local->v = allocVar(var->getLeft()->getAsSymbolNode()->getSymbol().c_str(), var->getLeft()->getTypePointer(), VTmp, var->getLine().first_line); ParsedExpr expr; ParsedValue* value = new ParsedValue; value->v = local; value->p = var->getLine().first_line; expr.v = value; expr.e = new ParsedValue(parseValue(var->getRight())); expr.p = var->getLine().first_line; cur.exprs.push_back(expr); break; } default: break; } } else if (binop != nullptr) { switch (binop->getOp()) { case EOpAssign: addAssign(parseValue(binop->getLeft()), parseValue(binop->getRight()), binop->getLine().first_line); break; case EOpAddAssign: break; case EOpSubAssign: break; case EOpMulAssign: break; case EOpVectorTimesScalarAssign: break; case EOpMatrixTimesScalarAssign: break; case EOpVectorTimesMatrixAssign: break; case EOpMatrixTimesMatrixAssign: //case OpAssignOp(op): // addAssign(parseValue(e1), parseValue( { expr : EBinop(op, e1, e2), pos : e.pos } ), e.pos); break; default: error("Operation should have side-effects", binop->getLine().first_line); } } /*switch (e.expr) { case EBlock(el): auto eold = cur.exprs; auto old = allowReturn; auto last = el[el.length - 1]; cur.exprs = []; for (e in el) { allowReturn = old && (e == last); parseExpr(e); } allowReturn = old; eold.push({ v : null, e : { v : PBlock(cur.exprs), p : e.pos }, p : e.pos }); cur.exprs = eold; case EIf(cond, eif, eelse): var pcond = parseValue(cond); var eold = cur.exprs; cur.exprs = []; parseExpr(eif); var pif = { v : PBlock(cur.exprs), p : eif.pos }; var pelse = null; if( eelse != null ) { cur.exprs = []; parseExpr(eelse); pelse = { v : PBlock(cur.exprs), p : eelse.pos }; } cur.exprs = eold; cur.exprs.push( {v:null, e: { v:PIf(pcond, pif, pelse), p : e.pos }, p : e.pos} ); case EFor(it, expr): var iter = null, vname = null; switch( it.expr ) { case EIn(v,it): switch( v.expr ) { case EConst(c): switch( c ) { case CIdent(i) #if !haxe3 , CType(i) #end: vname = i; default: } default: } iter = parseValue(it); default: } if( vname == null ) error("For should be in the form for( x in it )", it.pos); var old = cur.exprs; cur.exprs = []; parseExpr(expr); var pexpr = { v : PBlock(cur.exprs), p : expr.pos }; cur.exprs = old; cur.exprs.push( {v : null, e:{v:PFor(vname, iter, pexpr), p:e.pos}, p:e.pos } ); case EReturn(r): if( r == null ) error("Return must return a value", e.pos); if( !allowReturn ) error("Return only allowed as final expression in helper methods", e.pos); var v = parseValue(r); cur.exprs.push( { v : null, e : { v : PReturn(v), p : e.pos }, p : e.pos } ); default: error("Unsupported expression", e.pos); }*/ } }
TIntermTyped *CreateZeroNode(const TType &type) { TType constType(type); constType.setQualifier(EvqConst); if (!type.isArray() && type.getBasicType() != EbtStruct) { size_t size = constType.getObjectSize(); TConstantUnion *u = new TConstantUnion[size]; for (size_t i = 0; i < size; ++i) { switch (type.getBasicType()) { case EbtFloat: u[i].setFConst(0.0f); break; case EbtInt: u[i].setIConst(0); break; case EbtUInt: u[i].setUConst(0u); break; case EbtBool: u[i].setBConst(false); break; default: // CreateZeroNode is called by ParseContext that keeps parsing even when an // error occurs, so it is possible for CreateZeroNode to be called with // non-basic types. This happens only on error condition but CreateZeroNode // needs to return a value with the correct type to continue the typecheck. // That's why we handle non-basic type by setting whatever value, we just need // the type to be right. u[i].setIConst(42); break; } } TIntermConstantUnion *node = new TIntermConstantUnion(u, constType); return node; } if (type.getBasicType() == EbtVoid) { // Void array. This happens only on error condition, similarly to the case above. We don't // have a constructor operator for void, so this needs special handling. We'll end up with a // value without the array type, but that should not be a problem. while (constType.isArray()) { constType.toArrayElementType(); } return CreateZeroNode(constType); } TIntermSequence *arguments = new TIntermSequence(); if (type.isArray()) { TType elementType(type); elementType.toArrayElementType(); size_t arraySize = type.getOutermostArraySize(); for (size_t i = 0; i < arraySize; ++i) { arguments->push_back(CreateZeroNode(elementType)); } } else { ASSERT(type.getBasicType() == EbtStruct); TStructure *structure = type.getStruct(); for (const auto &field : structure->fields()) { arguments->push_back(CreateZeroNode(*field->type())); } } return TIntermAggregate::CreateConstructor(constType, arguments); }
void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix) { ASSERT(aggregate); int size = 0; switch (aggregate->getOp()) { case EOpConstructVec2: case EOpConstructBVec2: case EOpConstructIVec2: size = 2; break; case EOpConstructVec3: case EOpConstructBVec3: case EOpConstructIVec3: size = 3; break; case EOpConstructVec4: case EOpConstructBVec4: case EOpConstructIVec4: case EOpConstructMat2: size = 4; break; case EOpConstructMat2x3: case EOpConstructMat3x2: size = 6; break; case EOpConstructMat2x4: case EOpConstructMat4x2: size = 8; break; case EOpConstructMat3: size = 9; break; case EOpConstructMat3x4: case EOpConstructMat4x3: size = 12; break; case EOpConstructMat4: size = 16; break; default: break; } TIntermSequence *sequence = aggregate->getSequence(); TIntermSequence original(*sequence); sequence->clear(); for (size_t ii = 0; ii < original.size(); ++ii) { ASSERT(size > 0); TIntermTyped *node = original[ii]->getAsTyped(); ASSERT(node); TString varName = createTempVariable(node); if (node->isScalar()) { TIntermSymbol *symbolNode = new TIntermSymbol(-1, varName, node->getType()); sequence->push_back(symbolNode); size--; } else if (node->isVector()) { if (scalarizeVector) { int repeat = std::min(size, node->getNominalSize()); size -= repeat; for (int index = 0; index < repeat; ++index) { TIntermSymbol *symbolNode = new TIntermSymbol(-1, varName, node->getType()); TIntermBinary *newNode = ConstructVectorIndexBinaryNode( symbolNode, index); sequence->push_back(newNode); } } else { TIntermSymbol *symbolNode = new TIntermSymbol(-1, varName, node->getType()); sequence->push_back(symbolNode); size -= node->getNominalSize(); } } else { ASSERT(node->isMatrix()); if (scalarizeMatrix) { int colIndex = 0, rowIndex = 0; int repeat = std::min(size, node->getCols() * node->getRows()); size -= repeat; while (repeat > 0) { TIntermSymbol *symbolNode = new TIntermSymbol(-1, varName, node->getType()); TIntermBinary *newNode = ConstructMatrixIndexBinaryNode( symbolNode, colIndex, rowIndex); sequence->push_back(newNode); rowIndex++; if (rowIndex >= node->getRows()) { rowIndex = 0; colIndex++; } repeat--; } } else { TIntermSymbol *symbolNode = new TIntermSymbol(-1, varName, node->getType()); sequence->push_back(symbolNode); size -= node->getCols() * node->getRows(); } } } }
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); }
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; TInfoSinkBase &out = objSink(); switch (node->getOp()) { case EOpInitialize: if (visit == InVisit) { out << " = "; // RHS of initialize is not being declared. mDeclaringVariables = false; } break; case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; case EOpIModAssign: writeTriplet(visit, "(", " %= ", ")"); break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; case EOpBitShiftLeftAssign: writeTriplet(visit, "(", " <<= ", ")"); break; case EOpBitShiftRightAssign: writeTriplet(visit, "(", " >>= ", ")"); break; case EOpBitwiseAndAssign: writeTriplet(visit, "(", " &= ", ")"); break; case EOpBitwiseXorAssign: writeTriplet(visit, "(", " ^= ", ")"); break; case EOpBitwiseOrAssign: writeTriplet(visit, "(", " |= ", ")"); break; case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break; case EOpIndexIndirect: if (node->getAddIndexClamp()) { if (visit == InVisit) { if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) out << "[int(clamp(float("; else out << "[webgl_int_clamp("; } else if (visit == PostVisit) { int maxSize; TIntermTyped *left = node->getLeft(); TType leftType = left->getType(); if (left->isArray()) { // The shader will fail validation if the array length is not > 0. maxSize = leftType.getArraySize() - 1; } else { maxSize = leftType.getNominalSize() - 1; } if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) out << "), 0.0, float(" << maxSize << ")))]"; else out << ", 0, " << maxSize << ")]"; } } else { writeTriplet(visit, NULL, "[", "]"); } break; case EOpIndexDirectStruct: if (visit == InVisit) { // Here we are writing out "foo.bar", where "foo" is struct // and "bar" is field. In AST, it is represented as a binary // node, where left child represents "foo" and right child "bar". // The node itself represents ".". The struct field "bar" is // actually stored as an index into TStructure::fields. out << "."; const TStructure *structure = node->getLeft()->getType().getStruct(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TField *field = structure->fields()[index->getIConst(0)]; TString fieldName = field->name(); if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion)) fieldName = hashName(fieldName); out << fieldName; visitChildren = false; } break; case EOpIndexDirectInterfaceBlock: if (visit == InVisit) { out << "."; const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TField *field = interfaceBlock->fields()[index->getIConst(0)]; TString fieldName = field->name(); ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion)); fieldName = hashName(fieldName); out << fieldName; visitChildren = false; } break; case EOpVectorSwizzle: if (visit == InVisit) { out << "."; TIntermAggregate *rightChild = node->getRight()->getAsAggregate(); TIntermSequence *sequence = rightChild->getSequence(); for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit) { TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); ASSERT(element->getBasicType() == EbtInt); ASSERT(element->getNominalSize() == 1); const TConstantUnion& data = element->getUnionArrayPointer()[0]; ASSERT(data.getType() == EbtInt); switch (data.getIConst()) { case 0: out << "x"; break; case 1: out << "y"; break; case 2: out << "z"; break; case 3: out << "w"; break; default: UNREACHABLE(); } } visitChildren = false; } break; case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; case EOpIMod: writeTriplet(visit, "(", " % ", ")"); break; case EOpBitShiftLeft: writeTriplet(visit, "(", " << ", ")"); break; case EOpBitShiftRight: writeTriplet(visit, "(", " >> ", ")"); break; case EOpBitwiseAnd: writeTriplet(visit, "(", " & ", ")"); break; case EOpBitwiseXor: writeTriplet(visit, "(", " ^ ", ")"); break; case EOpBitwiseOr: writeTriplet(visit, "(", " | ", ")"); break; case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; // Notice the fall-through. case EOpVectorTimesScalar: case EOpVectorTimesMatrix: case EOpMatrixTimesVector: case EOpMatrixTimesScalar: case EOpMatrixTimesMatrix: writeTriplet(visit, "(", " * ", ")"); break; case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; default: UNREACHABLE(); } return visitChildren; }