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; }
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 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; }
// // 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); }
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 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); }
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; }
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); }
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); }*/ } }