Commit 4f1af784 by Olli Etuaho

Handle function calls where returned array is not used

This is done by declaring a temporary variable which is passed as the array out parameter defined by ArrayReturnValueToOutParameter. SeparateExpressionsReturningArrays takes care of transforming the rest of the cases where a function call returns an array into form that ArrayReturnValueToOutParameter can handle. BUG=angleproject:971 TEST=WebGL 2 conformance tests, dEQP-GLES3.functional.shaders.arrays.* Change-Id: I70c07712ba5cd91efb4c2e575ecc49b9ef71bfd7 Reviewed-on: https://chromium-review.googlesource.com/273111Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 950457b3
...@@ -36,10 +36,28 @@ TIntermSymbol *CreateReturnValueOutSymbol(const TType &type) ...@@ -36,10 +36,28 @@ TIntermSymbol *CreateReturnValueOutSymbol(const TType &type)
return CreateReturnValueSymbol(outType); return CreateReturnValueSymbol(outType);
} }
TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, TIntermTyped *returnValueTarget)
{
TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
replacementCall->setType(TType(EbtVoid));
replacementCall->setUserDefined();
replacementCall->setName(originalCall->getName());
replacementCall->setFunctionId(originalCall->getFunctionId());
replacementCall->setLine(originalCall->getLine());
TIntermSequence *replacementParameters = replacementCall->getSequence();
TIntermSequence *originalParameters = originalCall->getSequence();
for (auto &param : *originalParameters)
{
replacementParameters->push_back(param);
}
replacementParameters->push_back(returnValueTarget);
return replacementCall;
}
class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
{ {
public: public:
static void apply(TIntermNode *root); static void apply(TIntermNode *root, unsigned int *temporaryIndex);
private: private:
ArrayReturnValueToOutParameterTraverser(); ArrayReturnValueToOutParameterTraverser();
...@@ -50,9 +68,10 @@ class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser ...@@ -50,9 +68,10 @@ class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
bool mInFunctionWithArrayReturnValue; bool mInFunctionWithArrayReturnValue;
}; };
void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root) void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex)
{ {
ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam; ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam;
arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex);
root->traverse(&arrayReturnValueToOutParam); root->traverse(&arrayReturnValueToOutParam);
arrayReturnValueToOutParam.updateTree(); arrayReturnValueToOutParam.updateTree();
} }
...@@ -107,12 +126,26 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter ...@@ -107,12 +126,26 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter
} }
else if (node->getOp() == EOpFunctionCall) else if (node->getOp() == EOpFunctionCall)
{ {
// TODO (oetuaho@nvidia.com): Call sites where the returned array is not assigned are not handled yet. // Handle call sites where the returned array is not assigned.
// Examples where f() is a function returning an array: // Examples where f() is a function returning an array:
// f(); // 1. f();
// another_function(f()); // 2. another_array == f();
// another_array == f(); // 3. another_function(f());
UNIMPLEMENTED(); // 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.
TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence)
{
nextTemporaryIndex();
TIntermSequence replacements;
replacements.push_back(createTempDeclaration(node->getType()));
TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
replacements.push_back(CreateReplacementCall(node, returnSymbol));
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
}
return false;
} }
} }
} }
...@@ -158,19 +191,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi ...@@ -158,19 +191,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi
TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined()) if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined())
{ {
TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall); TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
replacementCall->setType(TType(EbtVoid));
replacementCall->setUserDefined();
replacementCall->setName(rightAgg->getName());
replacementCall->setFunctionId(rightAgg->getFunctionId());
replacementCall->setLine(rightAgg->getLine());
TIntermSequence *replacementParameters = replacementCall->getSequence();
TIntermSequence *originalParameters = rightAgg->getSequence();
for (auto &param : *originalParameters)
{
replacementParameters->push_back(param);
}
replacementParameters->push_back(node->getLeft());
mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacementCall, false)); mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacementCall, false));
} }
} }
...@@ -179,7 +200,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi ...@@ -179,7 +200,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi
} // namespace } // namespace
void ArrayReturnValueToOutParameter(TIntermNode *root) void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex)
{ {
ArrayReturnValueToOutParameterTraverser::apply(root); ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex);
} }
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
class TIntermNode; class TIntermNode;
void ArrayReturnValueToOutParameter(TIntermNode *root); void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex);
#endif // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_ #endif // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
...@@ -729,6 +729,8 @@ class TIntermTraverser : angle::NonCopyable ...@@ -729,6 +729,8 @@ class TIntermTraverser : angle::NonCopyable
// Helper to create a temporary symbol node. // Helper to create a temporary symbol node.
TIntermSymbol *createTempSymbol(const TType &type); TIntermSymbol *createTempSymbol(const TType &type);
// Create a node that declares but doesn't initialize a temporary symbol.
TIntermAggregate *createTempDeclaration(const TType &type);
// Create a node that initializes the current temporary symbol with initializer. // Create a node that initializes the current temporary symbol with initializer.
TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer); TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer);
// Create a node that assigns rightNode to the current temporary symbol. // Create a node that assigns rightNode to the current temporary symbol.
......
...@@ -50,6 +50,12 @@ TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type) ...@@ -50,6 +50,12 @@ TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
return node; return node;
} }
TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
{
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
tempDeclaration->getSequence()->push_back(createTempSymbol(type));
return tempDeclaration;
}
TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer) TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
{ {
......
...@@ -37,7 +37,7 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) ...@@ -37,7 +37,7 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
// HLSL doesn't support arrays as return values, we'll need to make functions that have an array // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
// as a return value to use an out parameter to transfer the array data instead. // as a return value to use an out parameter to transfer the array data instead.
ArrayReturnValueToOutParameter(root); ArrayReturnValueToOutParameter(root, &temporaryIndex);
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions); getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment