diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp | 319 |
1 files changed, 178 insertions, 141 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp index 74814f22a7..7766c1abc6 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp @@ -9,14 +9,20 @@ #include "compiler/translator/RemoveDynamicIndexing.h" +#include "compiler/translator/Diagnostics.h" #include "compiler/translator/InfoSink.h" -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/SymbolTable.h" +namespace sh +{ + namespace { -TName GetIndexFunctionName(const TType &type, bool write) +std::string GetIndexFunctionName(const TType &type, bool write) { TInfoSinkBase nameSink; nameSink << "dyn_index_"; @@ -49,31 +55,29 @@ TName GetIndexFunctionName(const TType &type, bool write) } nameSink << type.getNominalSize(); } - TString nameString = TFunction::mangleName(nameSink.c_str()); - TName name(nameString); - name.setInternal(true); - return name; + return nameSink.str(); } -TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier) +TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier, TSymbolTable *symbolTable) { - TIntermSymbol *symbol = new TIntermSymbol(0, "base", type); + TIntermSymbol *symbol = new TIntermSymbol(symbolTable->nextUniqueId(), "base", type); symbol->setInternal(true); symbol->getTypePointer()->setQualifier(qualifier); return symbol; } -TIntermSymbol *CreateIndexSymbol() +TIntermSymbol *CreateIndexSymbol(TSymbolTable *symbolTable) { - TIntermSymbol *symbol = new TIntermSymbol(0, "index", TType(EbtInt, EbpHigh)); + TIntermSymbol *symbol = + new TIntermSymbol(symbolTable->nextUniqueId(), "index", TType(EbtInt, EbpHigh)); symbol->setInternal(true); symbol->getTypePointer()->setQualifier(EvqIn); return symbol; } -TIntermSymbol *CreateValueSymbol(const TType &type) +TIntermSymbol *CreateValueSymbol(const TType &type, TSymbolTable *symbolTable) { - TIntermSymbol *symbol = new TIntermSymbol(0, "value", type); + TIntermSymbol *symbol = new TIntermSymbol(symbolTable->nextUniqueId(), "value", type); symbol->setInternal(true); symbol->getTypePointer()->setQualifier(EvqIn); return symbol; @@ -86,38 +90,14 @@ TIntermConstantUnion *CreateIntConstantNode(int i) return new TIntermConstantUnion(constant, TType(EbtInt, EbpHigh)); } -TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType, - const TType &fieldType, - const int index, - TQualifier baseQualifier) -{ - TIntermBinary *indexNode = new TIntermBinary(EOpIndexDirect); - indexNode->setType(fieldType); - TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier); - indexNode->setLeft(baseSymbol); - indexNode->setRight(CreateIntConstantNode(index)); - return indexNode; -} - -TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType) -{ - TIntermBinary *assignNode = new TIntermBinary(EOpAssign); - assignNode->setType(assignedValueType); - assignNode->setLeft(targetNode); - assignNode->setRight(CreateValueSymbol(assignedValueType)); - return assignNode; -} - TIntermTyped *EnsureSignedInt(TIntermTyped *node) { if (node->getBasicType() == EbtInt) return node; - TIntermAggregate *convertedNode = new TIntermAggregate(EOpConstructInt); - convertedNode->setType(TType(EbtInt)); - convertedNode->getSequence()->push_back(node); - convertedNode->setPrecisionFromChildren(); - return convertedNode; + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(node); + return TIntermAggregate::CreateConstructor(TType(EbtInt), arguments); } TType GetFieldType(const TType &indexedType) @@ -177,7 +157,10 @@ TType GetFieldType(const TType &indexedType) // base[1] = value; // } // Note that else is not used in above functions to avoid the RewriteElseBlocks transformation. -TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) +TIntermFunctionDefinition *GetIndexFunctionDefinition(TType type, + bool write, + const TSymbolUniqueId &functionId, + TSymbolTable *symbolTable) { ASSERT(!type.isArray()); // Conservatively use highp here, even if the indexed type is not highp. That way the code can't @@ -185,11 +168,9 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) // highp values are being indexed in the shader. For HLSL precision doesn't matter, but in // principle this code could be used with multiple backends. type.setPrecision(EbpHigh); - TIntermAggregate *indexingFunction = new TIntermAggregate(EOpFunction); - indexingFunction->setNameObj(GetIndexFunctionName(type, write)); TType fieldType = GetFieldType(type); - int numCases = 0; + int numCases = 0; if (type.isMatrix()) { numCases = type.getCols(); @@ -198,41 +179,43 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) { numCases = type.getNominalSize(); } - if (write) - { - indexingFunction->setType(TType(EbtVoid)); - } - else + + TType returnType(EbtVoid); + if (!write) { - indexingFunction->setType(fieldType); + returnType = fieldType; } - TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters); - TQualifier baseQualifier = EvqInOut; + std::string functionName = GetIndexFunctionName(type, write); + TIntermFunctionPrototype *prototypeNode = + CreateInternalFunctionPrototypeNode(returnType, functionName.c_str(), functionId); + + TQualifier baseQualifier = EvqInOut; if (!write) baseQualifier = EvqIn; - TIntermSymbol *baseParam = CreateBaseSymbol(type, baseQualifier); - paramsNode->getSequence()->push_back(baseParam); - TIntermSymbol *indexParam = CreateIndexSymbol(); - paramsNode->getSequence()->push_back(indexParam); + TIntermSymbol *baseParam = CreateBaseSymbol(type, baseQualifier, symbolTable); + prototypeNode->getSequence()->push_back(baseParam); + TIntermSymbol *indexParam = CreateIndexSymbol(symbolTable); + prototypeNode->getSequence()->push_back(indexParam); + TIntermSymbol *valueParam = nullptr; if (write) { - TIntermSymbol *valueParam = CreateValueSymbol(fieldType); - paramsNode->getSequence()->push_back(valueParam); + valueParam = CreateValueSymbol(fieldType, symbolTable); + prototypeNode->getSequence()->push_back(valueParam); } - indexingFunction->getSequence()->push_back(paramsNode); - TIntermAggregate *statementList = new TIntermAggregate(EOpSequence); + TIntermBlock *statementList = new TIntermBlock(); for (int i = 0; i < numCases; ++i) { TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i)); statementList->getSequence()->push_back(caseNode); TIntermBinary *indexNode = - CreateIndexDirectBaseSymbolNode(type, fieldType, i, baseQualifier); + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(i)); if (write) { - TIntermBinary *assignNode = CreateAssignValueSymbolNode(indexNode, fieldType); + TIntermBinary *assignNode = + new TIntermBinary(EOpAssign, indexNode, valueParam->deepCopy()); statementList->getSequence()->push_back(assignNode); TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr); statementList->getSequence()->push_back(returnNode); @@ -250,32 +233,33 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) TIntermBranch *breakNode = new TIntermBranch(EOpBreak, nullptr); statementList->getSequence()->push_back(breakNode); - TIntermSwitch *switchNode = new TIntermSwitch(CreateIndexSymbol(), statementList); + TIntermSwitch *switchNode = new TIntermSwitch(indexParam->deepCopy(), statementList); - TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence); + TIntermBlock *bodyNode = new TIntermBlock(); bodyNode->getSequence()->push_back(switchNode); - TIntermBinary *cond = new TIntermBinary(EOpLessThan); + TIntermBinary *cond = + new TIntermBinary(EOpLessThan, indexParam->deepCopy(), CreateIntConstantNode(0)); cond->setType(TType(EbtBool, EbpUndefined)); - cond->setLeft(CreateIndexSymbol()); - cond->setRight(CreateIntConstantNode(0)); // Two blocks: one accesses (either reads or writes) the first element and returns, // the other accesses the last element. - TIntermAggregate *useFirstBlock = new TIntermAggregate(EOpSequence); - TIntermAggregate *useLastBlock = new TIntermAggregate(EOpSequence); + TIntermBlock *useFirstBlock = new TIntermBlock(); + TIntermBlock *useLastBlock = new TIntermBlock(); TIntermBinary *indexFirstNode = - CreateIndexDirectBaseSymbolNode(type, fieldType, 0, baseQualifier); + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(0)); TIntermBinary *indexLastNode = - CreateIndexDirectBaseSymbolNode(type, fieldType, numCases - 1, baseQualifier); + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(numCases - 1)); if (write) { - TIntermBinary *assignFirstNode = CreateAssignValueSymbolNode(indexFirstNode, fieldType); + TIntermBinary *assignFirstNode = + new TIntermBinary(EOpAssign, indexFirstNode, valueParam->deepCopy()); useFirstBlock->getSequence()->push_back(assignFirstNode); TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr); useFirstBlock->getSequence()->push_back(returnNode); - TIntermBinary *assignLastNode = CreateAssignValueSymbolNode(indexLastNode, fieldType); + TIntermBinary *assignLastNode = + new TIntermBinary(EOpAssign, indexLastNode, valueParam->deepCopy()); useLastBlock->getSequence()->push_back(assignLastNode); } else @@ -286,19 +270,21 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) TIntermBranch *returnLastNode = new TIntermBranch(EOpReturn, indexLastNode); useLastBlock->getSequence()->push_back(returnLastNode); } - TIntermSelection *ifNode = new TIntermSelection(cond, useFirstBlock, nullptr); + TIntermIfElse *ifNode = new TIntermIfElse(cond, useFirstBlock, nullptr); bodyNode->getSequence()->push_back(ifNode); bodyNode->getSequence()->push_back(useLastBlock); - indexingFunction->getSequence()->push_back(bodyNode); - + TIntermFunctionDefinition *indexingFunction = + new TIntermFunctionDefinition(prototypeNode, bodyNode); return indexingFunction; } class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser { public: - RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable, int shaderVersion); + RemoveDynamicIndexingTraverser(TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics); bool visitBinary(Visit visit, TIntermBinary *node) override; @@ -309,10 +295,11 @@ class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser bool usedTreeInsertion() const { return mUsedTreeInsertion; } protected: - // Sets of types that are indexed. Note that these can not store multiple variants - // of the same type with different precisions - only one precision gets stored. - std::set<TType> mIndexedVecAndMatrixTypes; - std::set<TType> mWrittenVecAndMatrixTypes; + // Maps of types that are indexed to the indexing function ids used for them. Note that these + // can not store multiple variants of the same type with different precisions - only one + // precision gets stored. + std::map<TType, TSymbolUniqueId *> mIndexedVecAndMatrixTypes; + std::map<TType, TSymbolUniqueId *> mWrittenVecAndMatrixTypes; bool mUsedTreeInsertion; @@ -321,62 +308,74 @@ class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser // V[j++][i]++. // where V is an array of vectors, j++ will only be evaluated once. bool mRemoveIndexSideEffectsInSubtree; + + PerformanceDiagnostics *mPerfDiagnostics; }; -RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable, - int shaderVersion) +RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser( + TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics) : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion), mUsedTreeInsertion(false), - mRemoveIndexSideEffectsInSubtree(false) + mRemoveIndexSideEffectsInSubtree(false), + mPerfDiagnostics(perfDiagnostics) { } void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root) { - TIntermAggregate *rootAgg = root->getAsAggregate(); - ASSERT(rootAgg != nullptr && rootAgg->getOp() == EOpSequence); + TIntermBlock *rootBlock = root->getAsBlock(); + ASSERT(rootBlock != nullptr); TIntermSequence insertions; - for (TType type : mIndexedVecAndMatrixTypes) + for (auto &type : mIndexedVecAndMatrixTypes) { - insertions.push_back(GetIndexFunctionDefinition(type, false)); + insertions.push_back( + GetIndexFunctionDefinition(type.first, false, *type.second, mSymbolTable)); } - for (TType type : mWrittenVecAndMatrixTypes) + for (auto &type : mWrittenVecAndMatrixTypes) { - insertions.push_back(GetIndexFunctionDefinition(type, true)); + insertions.push_back( + GetIndexFunctionDefinition(type.first, true, *type.second, mSymbolTable)); } - mInsertions.push_back(NodeInsertMultipleEntry(rootAgg, 0, insertions, TIntermSequence())); + rootBlock->insertChildNodes(0, insertions); } // Create a call to dyn_index_*() based on an indirect indexing op node TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node, - TIntermTyped *indexedNode, - TIntermTyped *index) + TIntermTyped *index, + const TSymbolUniqueId &functionId) { ASSERT(node->getOp() == EOpIndexIndirect); - TIntermAggregate *indexingCall = new TIntermAggregate(EOpFunctionCall); + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(node->getLeft()); + arguments->push_back(index); + + TType fieldType = GetFieldType(node->getLeft()->getType()); + std::string functionName = GetIndexFunctionName(node->getLeft()->getType(), false); + TIntermAggregate *indexingCall = + CreateInternalFunctionCallNode(fieldType, functionName.c_str(), functionId, arguments); indexingCall->setLine(node->getLine()); - indexingCall->setUserDefined(); - indexingCall->setNameObj(GetIndexFunctionName(indexedNode->getType(), false)); - indexingCall->getSequence()->push_back(indexedNode); - indexingCall->getSequence()->push_back(index); - - TType fieldType = GetFieldType(indexedNode->getType()); - indexingCall->setType(fieldType); + indexingCall->getFunctionSymbolInfo()->setKnownToNotHaveSideEffects(true); return indexingCall; } TIntermAggregate *CreateIndexedWriteFunctionCall(TIntermBinary *node, TIntermTyped *index, - TIntermTyped *writtenValue) + TIntermTyped *writtenValue, + const TSymbolUniqueId &functionId) { - // Deep copy the left node so that two pointers to the same node don't end up in the tree. - TIntermNode *leftCopy = node->getLeft()->deepCopy(); - ASSERT(leftCopy != nullptr && leftCopy->getAsTyped() != nullptr); + ASSERT(node->getOp() == EOpIndexIndirect); + TIntermSequence *arguments = new TIntermSequence(); + // Deep copy the child nodes so that two pointers to the same node don't end up in the tree. + arguments->push_back(node->getLeft()->deepCopy()); + arguments->push_back(index->deepCopy()); + arguments->push_back(writtenValue); + + std::string functionName = GetIndexFunctionName(node->getLeft()->getType(), true); TIntermAggregate *indexedWriteCall = - CreateIndexFunctionCall(node, leftCopy->getAsTyped(), index); - indexedWriteCall->setNameObj(GetIndexFunctionName(node->getLeft()->getType(), true)); - indexedWriteCall->setType(TType(EbtVoid)); - indexedWriteCall->getSequence()->push_back(writtenValue); + CreateInternalFunctionCallNode(TType(EbtVoid), functionName.c_str(), functionId, arguments); + indexedWriteCall->setLine(node->getLine()); return indexedWriteCall; } @@ -397,23 +396,40 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // Now v_expr[s0] can be safely executed several times without unintended side effects. // Init the temp variable holding the index - TIntermAggregate *initIndex = createTempInitDeclaration(node->getRight()); - TIntermSequence insertions; - insertions.push_back(initIndex); - insertStatementsInParentBlock(insertions); + TIntermDeclaration *initIndex = createTempInitDeclaration(node->getRight()); + insertStatementInParentBlock(initIndex); mUsedTreeInsertion = true; // Replace the index with the temp variable TIntermSymbol *tempIndex = createTempSymbol(node->getRight()->getType()); - NodeUpdateEntry replaceIndex(node, node->getRight(), tempIndex, false); - mReplacements.push_back(replaceIndex); + queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED); } - else if (!node->getLeft()->isArray() && node->getLeft()->getBasicType() != EbtStruct) + else if (IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(node)) { + mPerfDiagnostics->warning(node->getLine(), + "Performance: dynamic indexing of vectors and " + "matrices is emulated and can be slow.", + "[]"); bool write = isLValueRequiredHere(); - TType type = node->getLeft()->getType(); - mIndexedVecAndMatrixTypes.insert(type); +#if defined(ANGLE_ENABLE_ASSERTS) + // Make sure that IntermNodePatternMatcher is consistent with the slightly differently + // implemented checks in this traverser. + IntermNodePatternMatcher matcher( + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue); + ASSERT(matcher.match(node, getParentNode(), isLValueRequiredHere()) == write); +#endif + + const TType &type = node->getLeft()->getType(); + TSymbolUniqueId *indexingFunctionId = new TSymbolUniqueId(mSymbolTable); + if (mIndexedVecAndMatrixTypes.find(type) == mIndexedVecAndMatrixTypes.end()) + { + mIndexedVecAndMatrixTypes[type] = indexingFunctionId; + } + else + { + indexingFunctionId = mIndexedVecAndMatrixTypes[type]; + } if (write) { @@ -432,10 +448,30 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod mRemoveIndexSideEffectsInSubtree = true; return true; } + + TIntermBinary *leftBinary = node->getLeft()->getAsBinaryNode(); + if (leftBinary != nullptr && + IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(leftBinary)) + { + // This is a case like: + // mat2 m; + // m[a][b]++; + // Process the child node m[a] first. + return true; + } + // TODO(oetuaho@nvidia.com): This is not optimal if the expression using the value // only writes it and doesn't need the previous value. http://anglebug.com/1116 - mWrittenVecAndMatrixTypes.insert(type); + TSymbolUniqueId *indexedWriteFunctionId = new TSymbolUniqueId(mSymbolTable); + if (mWrittenVecAndMatrixTypes.find(type) == mWrittenVecAndMatrixTypes.end()) + { + mWrittenVecAndMatrixTypes[type] = indexedWriteFunctionId; + } + else + { + indexedWriteFunctionId = mWrittenVecAndMatrixTypes[type]; + } TType fieldType = GetFieldType(type); TIntermSequence insertionsBefore; @@ -443,28 +479,26 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // Store the index in a temporary signed int variable. TIntermTyped *indexInitializer = EnsureSignedInt(node->getRight()); - TIntermAggregate *initIndex = createTempInitDeclaration(indexInitializer); + TIntermDeclaration *initIndex = createTempInitDeclaration(indexInitializer); initIndex->setLine(node->getLine()); insertionsBefore.push_back(initIndex); - TIntermAggregate *indexingCall = CreateIndexFunctionCall( - node, node->getLeft(), createTempSymbol(indexInitializer->getType())); - - // Create a node for referring to the index after the nextTemporaryIndex() call + // Create a node for referring to the index after the nextTemporaryId() call // below. TIntermSymbol *tempIndex = createTempSymbol(indexInitializer->getType()); - nextTemporaryIndex(); // From now on, creating temporary symbols that refer to the - // field value. + TIntermAggregate *indexingCall = + CreateIndexFunctionCall(node, tempIndex, *indexingFunctionId); + + nextTemporaryId(); // From now on, creating temporary symbols that refer to the + // field value. insertionsBefore.push_back(createTempInitDeclaration(indexingCall)); - TIntermAggregate *indexedWriteCall = - CreateIndexedWriteFunctionCall(node, tempIndex, createTempSymbol(fieldType)); + TIntermAggregate *indexedWriteCall = CreateIndexedWriteFunctionCall( + node, tempIndex, createTempSymbol(fieldType), *indexedWriteFunctionId); insertionsAfter.push_back(indexedWriteCall); insertStatementsInParentBlock(insertionsBefore, insertionsAfter); - NodeUpdateEntry replaceIndex(getParentNode(), node, createTempSymbol(fieldType), - false); - mReplacements.push_back(replaceIndex); + queueReplacement(createTempSymbol(fieldType), OriginalNode::IS_DROPPED); mUsedTreeInsertion = true; } else @@ -476,9 +510,8 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // If the index_expr is unsigned, we'll convert it to signed. ASSERT(!mRemoveIndexSideEffectsInSubtree); TIntermAggregate *indexingCall = CreateIndexFunctionCall( - node, node->getLeft(), EnsureSignedInt(node->getRight())); - NodeUpdateEntry replaceIndex(getParentNode(), node, indexingCall, false); - mReplacements.push_back(replaceIndex); + node, EnsureSignedInt(node->getRight()), *indexingFunctionId); + queueReplacement(indexingCall, OriginalNode::IS_DROPPED); } } } @@ -489,25 +522,29 @@ void RemoveDynamicIndexingTraverser::nextIteration() { mUsedTreeInsertion = false; mRemoveIndexSideEffectsInSubtree = false; - nextTemporaryIndex(); + nextTemporaryId(); } } // namespace void RemoveDynamicIndexing(TIntermNode *root, - unsigned int *temporaryIndex, - const TSymbolTable &symbolTable, - int shaderVersion) + TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics) { - RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion); - ASSERT(temporaryIndex != nullptr); - traverser.useTemporaryIndex(temporaryIndex); + RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion, perfDiagnostics); do { traverser.nextIteration(); root->traverse(&traverser); traverser.updateTree(); } while (traverser.usedTreeInsertion()); + // TODO(oetuaho@nvidia.com): It might be nicer to add the helper definitions also in the middle + // of traversal. Now the tree ends up in an inconsistent state in the middle, since there are + // function call nodes with no corresponding definition nodes. This needs special handling in + // TIntermLValueTrackingTraverser, and creates intricacies that are not easily apparent from a + // superficial reading of the code. traverser.insertHelperDefinitions(root); - traverser.updateTree(); } + +} // namespace sh |