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)
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
{
public:
static void apply(TIntermNode *root);
static void apply(TIntermNode *root, unsigned int *temporaryIndex);
private:
ArrayReturnValueToOutParameterTraverser();
......@@ -50,9 +68,10 @@ class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
bool mInFunctionWithArrayReturnValue;
};
void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root)
void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex)
{
ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam;
arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex);
root->traverse(&arrayReturnValueToOutParam);
arrayReturnValueToOutParam.updateTree();
}
......@@ -107,12 +126,26 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter
}
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:
// f();
// another_function(f());
// another_array == f();
UNIMPLEMENTED();
// 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.
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
TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined())
{
TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
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());
TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacementCall, false));
}
}
......@@ -179,7 +200,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi
} // namespace
void ArrayReturnValueToOutParameter(TIntermNode *root)
void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex)
{
ArrayReturnValueToOutParameterTraverser::apply(root);
ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex);
}
......@@ -11,6 +11,6 @@
class TIntermNode;
void ArrayReturnValueToOutParameter(TIntermNode *root);
void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex);
#endif // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
......@@ -729,6 +729,8 @@ class TIntermTraverser : angle::NonCopyable
// Helper to create a temporary symbol node.
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.
TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer);
// Create a node that assigns rightNode to the current temporary symbol.
......
......@@ -50,6 +50,12 @@ TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
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)
{
......
......@@ -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
// 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(),
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