void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node) { bool visit = true; if (preVisit) visit = visitUnary(PreVisit, node); if (visit) { incrementDepth(node); ASSERT(!operatorRequiresLValue()); switch (node->getOp()) { case EOpPostIncrement: case EOpPostDecrement: case EOpPreIncrement: case EOpPreDecrement: setOperatorRequiresLValue(true); break; default: break; } node->getOperand()->traverse(this); setOperatorRequiresLValue(false); decrementDepth(); } if (visit && postVisit) visitUnary(PostVisit, node); }
// // Traverse a loop node. Same comments in binary node apply here. // void TIntermTraverser::traverseLoop(TIntermLoop *node) { bool visit = true; if (preVisit) visit = visitLoop(PreVisit, node); if (visit) { incrementDepth(node); if (node->getInit()) node->getInit()->traverse(this); if (node->getCondition()) node->getCondition()->traverse(this); if (node->getBody()) node->getBody()->traverse(this); if (node->getExpression()) node->getExpression()->traverse(this); decrementDepth(); } if (visit && postVisit) visitLoop(PostVisit, node); }
// 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); }
// 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); }
void TOutputTraverser::visitSymbol(TIntermSymbol* node) { OutputTreeText(infoSink, node, depth); infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n"; if (! node->getConstArray().empty()) OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1); else if (node->getConstSubtree()) { incrementDepth(node); node->getConstSubtree()->traverse(this); decrementDepth(); } }
// // Traverse a case node. Same comments in binary node apply here. // void TIntermTraverser::traverseCase(TIntermCase *node) { bool visit = true; if (preVisit) visit = visitCase(PreVisit, node); if (visit && node->getCondition()) { incrementDepth(node); node->getCondition()->traverse(this); decrementDepth(); } if (visit && postVisit) visitCase(PostVisit, node); }
// // Traverse a branch node. Same comments in binary node apply here. // void TIntermTraverser::traverseBranch(TIntermBranch *node) { bool visit = true; if (preVisit) visit = visitBranch(PreVisit, node); if (visit && node->getExpression()) { incrementDepth(node); node->getExpression()->traverse(this); decrementDepth(); } if (visit && postVisit) visitBranch(PostVisit, node); }
// // Traverse a unary node. Same comments in binary node apply here. // void TIntermTraverser::traverseUnary(TIntermUnary *node) { bool visit = true; if (preVisit) visit = visitUnary(PreVisit, node); if (visit) { incrementDepth(node); node->getOperand()->traverse(this); decrementDepth(); } if (visit && postVisit) visitUnary(PostVisit, node); }
bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node) { TInfoSinkBase& out = objSink(); incrementDepth(); // Loop header. if (node->testFirst()) // for loop { out << "for ("; if (node->getInit()) node->getInit()->traverse(this); out << "; "; ASSERT(node->getTest() != NULL); node->getTest()->traverse(this); out << "; "; if (node->getTerminal()) node->getTerminal()->traverse(this); out << ")\n"; } else // do-while loop { out << "do\n"; } // Loop body. visitCodeBlock(node->getBody()); // Loop footer. if (!node->testFirst()) // while loop { out << "while ("; ASSERT(node->getTest() != NULL); node->getTest()->traverse(this); out << ");\n"; } decrementDepth(); // No need to visit children. They have been already processed in // this function. return false; }
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) { TInfoSinkBase &out = objSink(); out << "if ("; node->getCondition()->traverse(this); out << ")\n"; incrementDepth(node); visitCodeBlock(node->getTrueBlock()); if (node->getFalseBlock()) { out << "else\n"; visitCodeBlock(node->getFalseBlock()); } decrementDepth(); return false; }
// // 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); }
// // Traverse a switch node. Same comments in binary node apply here. // void TIntermTraverser::traverseSwitch(TIntermSwitch *node) { bool visit = true; if (preVisit) visit = visitSwitch(PreVisit, node); if (visit) { incrementDepth(node); node->getInit()->traverse(this); if (inVisit) visit = visitSwitch(InVisit, node); if (visit && node->getStatementList()) node->getStatementList()->traverse(this); decrementDepth(); } if (visit && postVisit) visitSwitch(PostVisit, node); }
// Traverse an if-else node. Same comments in binary node apply here. void TIntermTraverser::traverseIfElse(TIntermIfElse *node) { bool visit = true; if (preVisit) visit = visitIfElse(PreVisit, node); if (visit) { incrementDepth(node); node->getCondition()->traverse(this); if (node->getTrueBlock()) node->getTrueBlock()->traverse(this); if (node->getFalseBlock()) node->getFalseBlock()->traverse(this); decrementDepth(); } if (visit && postVisit) visitIfElse(PostVisit, node); }
// // Traverse a ternary node. Same comments in binary node apply here. // void TIntermTraverser::traverseTernary(TIntermTernary *node) { bool visit = true; if (preVisit) visit = visitTernary(PreVisit, node); if (visit) { incrementDepth(node); node->getCondition()->traverse(this); if (node->getTrueExpression()) node->getTrueExpression()->traverse(this); if (node->getFalseExpression()) node->getFalseExpression()->traverse(this); decrementDepth(); } if (visit && postVisit) visitTernary(PostVisit, node); }
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node) { TInfoSinkBase& out = objSink(); if (node->usesTernaryOperator()) { // Notice two brackets at the beginning and end. The outer ones // encapsulate the whole ternary expression. This preserves the // order of precedence when ternary expressions are used in a // compound expression, i.e., c = 2 * (a < b ? 1 : 2). out << "(("; node->getCondition()->traverse(this); out << ") ? ("; node->getTrueBlock()->traverse(this); out << ") : ("; node->getFalseBlock()->traverse(this); out << "))"; } else { out << "if ("; node->getCondition()->traverse(this); out << ")\n"; incrementDepth(); visitCodeBlock(node->getTrueBlock()); if (node->getFalseBlock()) { out << "else\n"; visitCodeBlock(node->getFalseBlock()); } decrementDepth(); } return false; }
// // Traverse a binary node. // void TIntermTraverser::traverseBinary(TIntermBinary *node) { bool visit = true; // // visit the node before children if pre-visiting. // if (preVisit) visit = visitBinary(PreVisit, node); // // Visit the children, in the right order. // if (visit) { incrementDepth(node); if (node->getLeft()) node->getLeft()->traverse(this); if (inVisit) visit = visitBinary(InVisit, node); if (visit && node->getRight()) node->getRight()->traverse(this); decrementDepth(); } // // Visit the node after the children, if requested and the traversal // hasn't been cancelled yet. // if (visit && postVisit) visitBinary(PostVisit, node); }
// Traverse a function definition node. void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node) { bool visit = true; if (preVisit) visit = visitFunctionDefinition(PreVisit, node); if (visit) { incrementDepth(node); mInGlobalScope = false; node->getFunctionParameters()->traverse(this); if (inVisit) visit = visitFunctionDefinition(InVisit, node); node->getBody()->traverse(this); mInGlobalScope = true; decrementDepth(); } if (visit && postVisit) visitFunctionDefinition(PostVisit, node); }
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = true; TInfoSinkBase &out = objSink(); bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction()); switch (node->getOp()) { case EOpSequence: // Scope the sequences except when at the global scope. if (mDepth > 0) { out << "{\n"; } incrementDepth(node); for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); iter != node->getSequence()->end(); ++iter) { TIntermNode *curNode = *iter; ASSERT(curNode != NULL); curNode->traverse(this); if (isSingleStatement(curNode)) out << ";\n"; } decrementDepth(); // Scope the sequences except when at the global scope. if (mDepth > 0) { out << "}\n"; } visitChildren = false; break; case EOpPrototype: // Function declaration. ASSERT(visit == PreVisit); { const TType &type = node->getType(); writeVariableType(type); if (type.isArray()) out << arrayBrackets(type); } out << " " << hashFunctionNameIfNeeded(node->getNameObj()); out << "("; writeFunctionParameters(*(node->getSequence())); out << ")"; visitChildren = false; break; case EOpFunction: { // Function definition. ASSERT(visit == PreVisit); { const TType &type = node->getType(); writeVariableType(type); if (type.isArray()) out << arrayBrackets(type); } out << " " << hashFunctionNameIfNeeded(node->getNameObj()); incrementDepth(node); // Function definition node contains one or two children nodes // representing function parameters and function body. The latter // is not present in case of empty function bodies. const TIntermSequence &sequence = *(node->getSequence()); ASSERT((sequence.size() == 1) || (sequence.size() == 2)); TIntermSequence::const_iterator seqIter = sequence.begin(); // Traverse function parameters. TIntermAggregate *params = (*seqIter)->getAsAggregate(); ASSERT(params != NULL); ASSERT(params->getOp() == EOpParameters); params->traverse(this); // Traverse function body. TIntermAggregate *body = ++seqIter != sequence.end() ? (*seqIter)->getAsAggregate() : NULL; visitCodeBlock(body); decrementDepth(); // Fully processed; no need to visit children. visitChildren = false; break; } case EOpFunctionCall: // Function call. if (visit == PreVisit) out << hashFunctionNameIfNeeded(node->getNameObj()) << "("; else if (visit == InVisit) out << ", "; else out << ")"; break; case EOpParameters: // Function parameters. ASSERT(visit == PreVisit); out << "("; writeFunctionParameters(*(node->getSequence())); out << ")"; visitChildren = false; break; case EOpDeclaration: // Variable declaration. if (visit == PreVisit) { const TIntermSequence &sequence = *(node->getSequence()); const TIntermTyped *variable = sequence.front()->getAsTyped(); writeVariableType(variable->getType()); out << " "; mDeclaringVariables = true; } else if (visit == InVisit) { out << ", "; mDeclaringVariables = true; } else { mDeclaringVariables = false; } break; case EOpInvariantDeclaration: // Invariant declaration. ASSERT(visit == PreVisit); { const TIntermSequence *sequence = node->getSequence(); ASSERT(sequence && sequence->size() == 1); const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode(); ASSERT(symbol); out << "invariant " << hashVariableName(symbol->getSymbol()); } visitChildren = false; break; case EOpConstructFloat: writeConstructorTriplet(visit, node->getType(), "float"); break; case EOpConstructVec2: writeConstructorTriplet(visit, node->getType(), "vec2"); break; case EOpConstructVec3: writeConstructorTriplet(visit, node->getType(), "vec3"); break; case EOpConstructVec4: writeConstructorTriplet(visit, node->getType(), "vec4"); break; case EOpConstructBool: writeConstructorTriplet(visit, node->getType(), "bool"); break; case EOpConstructBVec2: writeConstructorTriplet(visit, node->getType(), "bvec2"); break; case EOpConstructBVec3: writeConstructorTriplet(visit, node->getType(), "bvec3"); break; case EOpConstructBVec4: writeConstructorTriplet(visit, node->getType(), "bvec4"); break; case EOpConstructInt: writeConstructorTriplet(visit, node->getType(), "int"); break; case EOpConstructIVec2: writeConstructorTriplet(visit, node->getType(), "ivec2"); break; case EOpConstructIVec3: writeConstructorTriplet(visit, node->getType(), "ivec3"); break; case EOpConstructIVec4: writeConstructorTriplet(visit, node->getType(), "ivec4"); break; case EOpConstructUInt: writeConstructorTriplet(visit, node->getType(), "uint"); break; case EOpConstructUVec2: writeConstructorTriplet(visit, node->getType(), "uvec2"); break; case EOpConstructUVec3: writeConstructorTriplet(visit, node->getType(), "uvec3"); break; case EOpConstructUVec4: writeConstructorTriplet(visit, node->getType(), "uvec4"); break; case EOpConstructMat2: writeConstructorTriplet(visit, node->getType(), "mat2"); break; case EOpConstructMat2x3: writeConstructorTriplet(visit, node->getType(), "mat2x3"); break; case EOpConstructMat2x4: writeConstructorTriplet(visit, node->getType(), "mat2x4"); break; case EOpConstructMat3x2: writeConstructorTriplet(visit, node->getType(), "mat3x2"); break; case EOpConstructMat3: writeConstructorTriplet(visit, node->getType(), "mat3"); break; case EOpConstructMat3x4: writeConstructorTriplet(visit, node->getType(), "mat3x4"); break; case EOpConstructMat4x2: writeConstructorTriplet(visit, node->getType(), "mat4x2"); break; case EOpConstructMat4x3: writeConstructorTriplet(visit, node->getType(), "mat4x3"); break; case EOpConstructMat4: writeConstructorTriplet(visit, node->getType(), "mat4"); break; case EOpConstructStruct: { const TType &type = node->getType(); ASSERT(type.getBasicType() == EbtStruct); TString constructorName = hashName(type.getStruct()->name()); writeConstructorTriplet(visit, node->getType(), constructorName.c_str()); break; } case EOpOuterProduct: writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction); break; case EOpLessThan: writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction); break; case EOpGreaterThan: writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction); break; case EOpLessThanEqual: writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction); break; case EOpGreaterThanEqual: writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction); break; case EOpVectorEqual: writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction); break; case EOpVectorNotEqual: writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction); break; case EOpComma: writeTriplet(visit, "(", ", ", ")"); break; case EOpMod: writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction); break; case EOpModf: writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction); break; case EOpPow: writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction); break; case EOpAtan: writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction); break; case EOpMin: writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction); break; case EOpMax: writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction); break; case EOpClamp: writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction); break; case EOpMix: writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction); break; case EOpStep: writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction); break; case EOpSmoothStep: writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction); break; case EOpDistance: writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction); break; case EOpDot: writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction); break; case EOpCross: writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction); break; case EOpFaceForward: writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction); break; case EOpReflect: writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction); break; case EOpRefract: writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction); break; case EOpMul: writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction); break; default: UNREACHABLE(); } return visitChildren; }
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) { TInfoSinkBase &out = objSink(); incrementDepth(node); // Loop header. TLoopType loopType = node->getType(); if (loopType == ELoopFor) // for loop { if (!node->getUnrollFlag()) { out << "for ("; if (node->getInit()) node->getInit()->traverse(this); out << "; "; if (node->getCondition()) node->getCondition()->traverse(this); out << "; "; if (node->getExpression()) node->getExpression()->traverse(this); out << ")\n"; } else { // Need to put a one-iteration loop here to handle break. TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence(); TIntermSymbol *indexSymbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); TString name = hashVariableName(indexSymbol->getSymbol()); out << "for (int " << name << " = 0; " << name << " < 1; " << "++" << name << ")\n"; } } else if (loopType == ELoopWhile) // while loop { out << "while ("; ASSERT(node->getCondition() != NULL); node->getCondition()->traverse(this); out << ")\n"; } else // do-while loop { ASSERT(loopType == ELoopDoWhile); out << "do\n"; } // Loop body. if (node->getUnrollFlag()) { out << "{\n"; mLoopUnrollStack.push(node); while (mLoopUnrollStack.satisfiesLoopCondition()) { visitCodeBlock(node->getBody()); mLoopUnrollStack.step(); } mLoopUnrollStack.pop(); out << "}\n"; } else { visitCodeBlock(node->getBody()); } // Loop footer. if (loopType == ELoopDoWhile) // do-while loop { out << "while ("; ASSERT(node->getCondition() != NULL); node->getCondition()->traverse(this); out << ");\n"; } decrementDepth(); // No need to visit children. They have been already processed in // this function. return false; }
void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) { bool visit = true; // // visit the node before children if pre-visiting. // if (preVisit) visit = visitBinary(PreVisit, node); // // Visit the children, in the right order. // if (visit) { incrementDepth(node); // Some binary operations like indexing can be inside an expression which must be an // l-value. bool parentOperatorRequiresLValue = operatorRequiresLValue(); bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter(); if (node->isAssignment()) { ASSERT(!isLValueRequiredHere()); setOperatorRequiresLValue(true); } if (node->getLeft()) node->getLeft()->traverse(this); if (inVisit) visit = visitBinary(InVisit, node); if (node->isAssignment()) setOperatorRequiresLValue(false); // Index is not required to be an l-value even when the surrounding expression is required // to be an l-value. TOperator op = node->getOp(); if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock || op == EOpIndexDirectStruct || op == EOpIndexIndirect) { setOperatorRequiresLValue(false); setInFunctionCallOutParameter(false); } if (visit && node->getRight()) node->getRight()->traverse(this); setOperatorRequiresLValue(parentOperatorRequiresLValue); setInFunctionCallOutParameter(parentInFunctionCallOutParameter); decrementDepth(); } // // Visit the node after the children, if requested and the traversal // hasn't been cancelled yet. // if (visit && postVisit) visitBinary(PostVisit, node); }
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node) { bool visitChildren = true; TInfoSinkBase& out = objSink(); TString preString; bool delayedWrite = false; switch (node->getOp()) { case EOpSequence: { // Scope the sequences except when at the global scope. if (depth > 0) out << "{\n"; incrementDepth(); const TIntermSequence& sequence = node->getSequence(); for (TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter) { TIntermNode* node = *iter; ASSERT(node != NULL); node->traverse(this); if (isSingleStatement(node)) out << ";\n"; } decrementDepth(); // Scope the sequences except when at the global scope. if (depth > 0) out << "}\n"; visitChildren = false; break; } case EOpPrototype: { // Function declaration. ASSERT(visit == PreVisit); writeVariableType(node->getType()); out << " " << node->getName(); out << "("; writeFunctionParameters(node->getSequence()); out << ")"; visitChildren = false; break; } case EOpFunction: { // Function definition. ASSERT(visit == PreVisit); writeVariableType(node->getType()); out << " " << TFunction::unmangleName(node->getName()); incrementDepth(); // Function definition node contains one or two children nodes // representing function parameters and function body. The latter // is not present in case of empty function bodies. const TIntermSequence& sequence = node->getSequence(); ASSERT((sequence.size() == 1) || (sequence.size() == 2)); TIntermSequence::const_iterator seqIter = sequence.begin(); // Traverse function parameters. TIntermAggregate* params = (*seqIter)->getAsAggregate(); ASSERT(params != NULL); ASSERT(params->getOp() == EOpParameters); params->traverse(this); // Traverse function body. TIntermAggregate* body = ++seqIter != sequence.end() ? (*seqIter)->getAsAggregate() : NULL; visitCodeBlock(body); decrementDepth(); // Fully processed; no need to visit children. visitChildren = false; break; } case EOpFunctionCall: // Function call. if (visit == PreVisit) { TString functionName = TFunction::unmangleName(node->getName()); out << functionName << "("; } else if (visit == InVisit) { out << ", "; } else { out << ")"; } break; case EOpParameters: { // Function parameters. ASSERT(visit == PreVisit); out << "("; writeFunctionParameters(node->getSequence()); out << ")"; visitChildren = false; break; } case EOpDeclaration: { // Variable declaration. if (visit == PreVisit) { const TIntermSequence& sequence = node->getSequence(); const TIntermTyped* variable = sequence.front()->getAsTyped(); writeVariableType(variable->getType()); out << " "; mDeclaringVariables = true; } else if (visit == InVisit) { out << ", "; mDeclaringVariables = true; } else { mDeclaringVariables = false; } break; } case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break; case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break; case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break; case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break; case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break; case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break; case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break; case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break; case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break; case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break; case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break; case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break; case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break; case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break; case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break; case EOpConstructStruct: if (visit == PreVisit) { const TType& type = node->getType(); ASSERT(type.getBasicType() == EbtStruct); out << type.getTypeName() << "("; } else if (visit == InVisit) { out << ", "; } else { out << ")"; } break; case EOpLessThan: preString = "lessThan("; delayedWrite = true; break; case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break; case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break; case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break; case EOpVectorEqual: preString = "equal("; delayedWrite = true; break; case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break; case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break; case EOpMod: preString = "mod("; delayedWrite = true; break; case EOpPow: preString = "pow("; delayedWrite = true; break; case EOpAtan: preString = "atan("; delayedWrite = true; break; case EOpMin: preString = "min("; delayedWrite = true; break; case EOpMax: preString = "max("; delayedWrite = true; break; case EOpClamp: preString = "clamp("; delayedWrite = true; break; case EOpMix: preString = "mix("; delayedWrite = true; break; case EOpStep: preString = "step("; delayedWrite = true; break; case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break; case EOpDistance: preString = "distance("; delayedWrite = true; break; case EOpDot: preString = "dot("; delayedWrite = true; break; case EOpCross: preString = "cross("; delayedWrite = true; break; case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break; case EOpReflect: preString = "reflect("; delayedWrite = true; break; case EOpRefract: preString = "refract("; delayedWrite = true; break; case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break; default: UNREACHABLE(); break; } if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction()) preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); if (delayedWrite) writeTriplet(visit, preString.c_str(), ", ", ")"); return visitChildren; }
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node) { TInfoSinkBase& out = objSink(); incrementDepth(); // Loop header. TLoopType loopType = node->getType(); if (loopType == ELoopFor) // for loop { if (!node->getUnrollFlag()) { out << "for ("; if (node->getInit()) node->getInit()->traverse(this); out << "; "; if (node->getCondition()) node->getCondition()->traverse(this); out << "; "; if (node->getExpression()) node->getExpression()->traverse(this); out << ")\n"; } } else if (loopType == ELoopWhile) // while loop { out << "while ("; ASSERT(node->getCondition() != NULL); node->getCondition()->traverse(this); out << ")\n"; } else // do-while loop { ASSERT(loopType == ELoopDoWhile); out << "do\n"; } // Loop body. if (node->getUnrollFlag()) { TLoopIndexInfo indexInfo; mLoopUnroll.FillLoopIndexInfo(node, indexInfo); mLoopUnroll.Push(indexInfo); while (mLoopUnroll.SatisfiesLoopCondition()) { visitCodeBlock(node->getBody()); mLoopUnroll.Step(); } mLoopUnroll.Pop(); } else { visitCodeBlock(node->getBody()); } // Loop footer. if (loopType == ELoopDoWhile) // do-while loop { out << "while ("; ASSERT(node->getCondition() != NULL); node->getCondition()->traverse(this); out << ");\n"; } decrementDepth(); // No need to visit children. They have been already processed in // this function. return false; }
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); }