diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp')
-rwxr-xr-x | gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp new file mode 100755 index 000000000..766f700ee --- /dev/null +++ b/gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp @@ -0,0 +1,217 @@ +// +// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The ArrayReturnValueToOutParameter function changes return values of an array type to out parameters in +// function definitions, prototypes, and call sites. + +#include "compiler/translator/ArrayReturnValueToOutParameter.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +namespace +{ + +void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to) +{ + const TIntermSequence *fromSequence = from->getSequence(); + for (size_t ii = 0; ii < fromSequence->size(); ++ii) + { + to->getSequence()->push_back(fromSequence->at(ii)); + } +} + +TIntermSymbol *CreateReturnValueSymbol(const TType &type) +{ + TIntermSymbol *node = new TIntermSymbol(0, "angle_return", type); + node->setInternal(true); + return node; +} + +TIntermSymbol *CreateReturnValueOutSymbol(const TType &type) +{ + TType outType(type); + outType.setQualifier(EvqOut); + return CreateReturnValueSymbol(outType); +} + +TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, TIntermTyped *returnValueTarget) +{ + TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall); + replacementCall->setType(TType(EbtVoid)); + replacementCall->setUserDefined(); + *replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo(); + replacementCall->setLine(originalCall->getLine()); + TIntermSequence *replacementParameters = replacementCall->getSequence(); + TIntermSequence *originalParameters = originalCall->getSequence(); + for (auto ¶m : *originalParameters) + { + replacementParameters->push_back(param); + } + replacementParameters->push_back(returnValueTarget); + return replacementCall; +} + +class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermNode *root, unsigned int *temporaryIndex); + private: + ArrayReturnValueToOutParameterTraverser(); + + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBranch(Visit visit, TIntermBranch *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + + bool mInFunctionWithArrayReturnValue; +}; + +void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex) +{ + ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam; + arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex); + root->traverse(&arrayReturnValueToOutParam); + arrayReturnValueToOutParam.updateTree(); +} + +ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser() + : TIntermTraverser(true, false, true), + mInFunctionWithArrayReturnValue(false) +{ +} + +bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition( + Visit visit, + TIntermFunctionDefinition *node) +{ + if (node->isArray() && visit == PreVisit) + { + // Replace the parameters child node of the function definition with another node + // that has the out parameter added. + // Also set the function to return void. + + TIntermAggregate *params = node->getFunctionParameters(); + ASSERT(params != nullptr && params->getOp() == EOpParameters); + + TIntermAggregate *replacementParams = new TIntermAggregate; + replacementParams->setOp(EOpParameters); + CopyAggregateChildren(params, replacementParams); + replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType())); + replacementParams->setLine(params->getLine()); + + queueReplacementWithParent(node, params, replacementParams, OriginalNode::IS_DROPPED); + + node->setType(TType(EbtVoid)); + + mInFunctionWithArrayReturnValue = true; + } + if (visit == PostVisit) + { + // This isn't conditional on node->isArray() since the type has already been changed on + // PreVisit. + mInFunctionWithArrayReturnValue = false; + } + return true; +} + +bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (visit == PreVisit) + { + if (node->isArray()) + { + if (node->getOp() == EOpPrototype) + { + // Replace the whole prototype node with another node that has the out parameter added. + TIntermAggregate *replacement = new TIntermAggregate; + replacement->setOp(EOpPrototype); + CopyAggregateChildren(node, replacement); + replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType())); + replacement->setUserDefined(); + *replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo(); + replacement->setLine(node->getLine()); + replacement->setType(TType(EbtVoid)); + + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); + } + else if (node->getOp() == EOpFunctionCall) + { + // Handle call sites where the returned array is not assigned. + // Examples where f() is a function returning an array: + // 1. f(); + // 2. another_array == f(); + // 3. another_function(f()); + // 4. return f(); + // Cases 2 to 4 are already converted to simpler cases by SeparateExpressionsReturningArrays, so we + // only need to worry about the case where a function call returning an array forms an expression by + // itself. + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + if (parentBlock) + { + nextTemporaryIndex(); + TIntermSequence replacements; + replacements.push_back(createTempDeclaration(node->getType())); + TIntermSymbol *returnSymbol = createTempSymbol(node->getType()); + replacements.push_back(CreateReplacementCall(node, returnSymbol)); + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); + } + return false; + } + } + } + return true; +} + +bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node) +{ + if (mInFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn) + { + // Instead of returning a value, assign to the out parameter and then return. + TIntermSequence replacements; + + TIntermTyped *expression = node->getExpression(); + ASSERT(expression != nullptr); + TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType()); + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, returnValueSymbol, expression); + replacementAssignment->setLine(expression->getLine()); + replacements.push_back(replacementAssignment); + + TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr); + replacementBranch->setLine(node->getLine()); + replacements.push_back(replacementBranch); + + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements)); + } + return false; +} + +bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (node->getOp() == EOpAssign && node->getLeft()->isArray()) + { + TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); + if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined()) + { + TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft()); + queueReplacement(node, replacementCall, OriginalNode::IS_DROPPED); + } + } + return false; +} + +} // namespace + +void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex) +{ + ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex); +} + +} // namespace sh |