Commit fc0e2bc0 by Olli Etuaho

Put each array declarator into a separate declaration in HLSL output

Since HLSL doesn't support arrays as l-values, HLSL output needs to split declarators that initialize arrays to variable declaration and assignment implemented via a function call. To prepare for this, it is necessary that each declarator has its own declaration. BUG=angleproject:941 TEST=angle_end2end_tests, WebGL conformance tests Change-Id: I43dee487578561c01dbde90c2f55a93dda2f057a Reviewed-on: https://chromium-review.googlesource.com/266001Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 752ce192
...@@ -153,6 +153,8 @@ ...@@ -153,6 +153,8 @@
'compiler/translator/RemoveSwitchFallThrough.h', 'compiler/translator/RemoveSwitchFallThrough.h',
'compiler/translator/RewriteElseBlocks.cpp', 'compiler/translator/RewriteElseBlocks.cpp',
'compiler/translator/RewriteElseBlocks.h', 'compiler/translator/RewriteElseBlocks.h',
'compiler/translator/SeparateDeclarations.cpp',
'compiler/translator/SeparateDeclarations.h',
'compiler/translator/SimplifyArrayAssignment.cpp', 'compiler/translator/SimplifyArrayAssignment.cpp',
'compiler/translator/SimplifyArrayAssignment.h', 'compiler/translator/SimplifyArrayAssignment.h',
'compiler/translator/StructureHLSL.cpp', 'compiler/translator/StructureHLSL.cpp',
......
...@@ -195,6 +195,20 @@ bool TIntermAggregate::replaceChildNode( ...@@ -195,6 +195,20 @@ bool TIntermAggregate::replaceChildNode(
return false; return false;
} }
bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
{
for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
{
if (*it == original)
{
it = mSequence.erase(it);
it = mSequence.insert(it, replacements.begin(), replacements.end());
return true;
}
}
return false;
}
void TIntermAggregate::setPrecisionFromChildren() void TIntermAggregate::setPrecisionFromChildren()
{ {
if (getBasicType() == EbtBool) if (getBasicType() == EbtBool)
...@@ -1497,4 +1511,12 @@ void TIntermTraverser::updateTree() ...@@ -1497,4 +1511,12 @@ void TIntermTraverser::updateTree()
} }
} }
} }
for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
{
const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
ASSERT(replacement.parent);
bool replaced = replacement.parent->replaceChildNodeWithMultiple(
replacement.original, replacement.replacements);
ASSERT(replaced);
}
} }
...@@ -422,7 +422,7 @@ class TIntermAggregate : public TIntermOperator ...@@ -422,7 +422,7 @@ class TIntermAggregate : public TIntermOperator
virtual void traverse(TIntermTraverser *); virtual void traverse(TIntermTraverser *);
virtual bool replaceChildNode( virtual bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement); TIntermNode *original, TIntermNode *replacement);
bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements);
// Conservatively assume function calls and other aggregate operators have side-effects // Conservatively assume function calls and other aggregate operators have side-effects
virtual bool hasSideEffects() const { return true; } virtual bool hasSideEffects() const { return true; }
...@@ -625,7 +625,7 @@ class TIntermTraverser : angle::NonCopyable ...@@ -625,7 +625,7 @@ class TIntermTraverser : angle::NonCopyable
const bool rightToLeft; const bool rightToLeft;
// If traversers need to replace nodes, they can add the replacements in // If traversers need to replace nodes, they can add the replacements in
// mReplacements during traversal and the user of the traverser should call // mReplacements/mMultiReplacements during traversal and the user of the traverser should call
// this function after traversal to perform them. // this function after traversal to perform them.
void updateTree(); void updateTree();
...@@ -636,6 +636,7 @@ class TIntermTraverser : angle::NonCopyable ...@@ -636,6 +636,7 @@ class TIntermTraverser : angle::NonCopyable
// All the nodes from root to the current node's parent during traversing. // All the nodes from root to the current node's parent during traversing.
TVector<TIntermNode *> mPath; TVector<TIntermNode *> mPath;
// To replace a single node with another on the parent node
struct NodeUpdateEntry struct NodeUpdateEntry
{ {
NodeUpdateEntry(TIntermNode *_parent, NodeUpdateEntry(TIntermNode *_parent,
...@@ -653,9 +654,26 @@ class TIntermTraverser : angle::NonCopyable ...@@ -653,9 +654,26 @@ class TIntermTraverser : angle::NonCopyable
bool originalBecomesChildOfReplacement; bool originalBecomesChildOfReplacement;
}; };
// To replace a single node with multiple nodes on the parent aggregate node
struct NodeReplaceWithMultipleEntry
{
NodeReplaceWithMultipleEntry(TIntermAggregate *_parent, TIntermNode *_original, TIntermSequence _replacements)
: parent(_parent),
original(_original),
replacements(_replacements)
{
}
TIntermAggregate *parent;
TIntermNode *original;
TIntermSequence replacements;
};
// During traversing, save all the changes that need to happen into // During traversing, save all the changes that need to happen into
// mReplacements, then do them by calling updateTree(). // mReplacements/mMultiReplacements, then do them by calling updateTree().
// Multi replacements are processed after single replacements.
std::vector<NodeUpdateEntry> mReplacements; std::vector<NodeUpdateEntry> mReplacements;
std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
}; };
// //
......
//
// 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 SeparateArrayDeclarations function processes declarations that contain array declarators. Each declarator in
// such declarations gets its own declaration.
// This is useful as an intermediate step when initialization needs to be separated from declaration.
// Example:
// int a[1] = int[1](1), b[1] = int[1](2);
// gets transformed when run through this class into the AST equivalent of:
// int a[1] = int[1](1);
// int b[1] = int[1](2);
#include "compiler/translator/SeparateDeclarations.h"
#include "compiler/translator/IntermNode.h"
namespace
{
class SeparateDeclarations : private TIntermTraverser
{
public:
static void apply(TIntermNode *root);
private:
SeparateDeclarations();
bool visitAggregate(Visit, TIntermAggregate *node) override;
};
void SeparateDeclarations::apply(TIntermNode *root)
{
SeparateDeclarations separateDecl;
root->traverse(&separateDecl);
separateDecl.updateTree();
}
SeparateDeclarations::SeparateDeclarations()
: TIntermTraverser(true, false, false)
{
}
bool SeparateDeclarations::visitAggregate(Visit, TIntermAggregate *node)
{
if (node->getOp() == EOpDeclaration)
{
TIntermSequence *sequence = node->getSequence();
bool sequenceContainsArrays = false;
for (size_t ii = 0; ii < sequence->size(); ++ii)
{
TIntermTyped *typed = sequence->at(ii)->getAsTyped();
if (typed != nullptr && typed->isArray())
{
sequenceContainsArrays = true;
break;
}
}
if (sequence->size() > 1 && sequenceContainsArrays)
{
TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
ASSERT(parentAgg != nullptr);
TIntermSequence replacementDeclarations;
for (size_t ii = 0; ii < sequence->size(); ++ii)
{
TIntermAggregate *replacementDeclaration = new TIntermAggregate;
replacementDeclaration->setOp(EOpDeclaration);
replacementDeclaration->getSequence()->push_back(sequence->at(ii));
replacementDeclaration->setLine(sequence->at(ii)->getLine());
replacementDeclarations.push_back(replacementDeclaration);
}
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacementDeclarations));
}
return false;
}
return true;
}
} // namespace
void SeparateArrayDeclarations(TIntermNode *root)
{
SeparateDeclarations::apply(root);
}
//
// 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 SeparateArrayDeclarations function processes declarations that contain array declarators. Each declarator in
// such declarations gets its own declaration.
// This is useful as an intermediate step when initialization needs to be separated from declaration.
// Example:
// int a[1] = int[1](1), b[1] = int[1](2);
// gets transformed when run through this class into the AST equivalent of:
// int a[1] = int[1](1);
// int b[1] = int[1](2);
#ifndef COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
#define COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
class TIntermNode;
void SeparateArrayDeclarations(TIntermNode *root);
#endif // COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "compiler/translator/TranslatorHLSL.h" #include "compiler/translator/TranslatorHLSL.h"
#include "compiler/translator/OutputHLSL.h" #include "compiler/translator/OutputHLSL.h"
#include "compiler/translator/SeparateDeclarations.h"
#include "compiler/translator/SimplifyArrayAssignment.h" #include "compiler/translator/SimplifyArrayAssignment.h"
TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
...@@ -19,6 +20,8 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) ...@@ -19,6 +20,8 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
const ShBuiltInResources &resources = getResources(); const ShBuiltInResources &resources = getResources();
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
SeparateArrayDeclarations(root);
SimplifyArrayAssignment simplify; SimplifyArrayAssignment simplify;
root->traverse(&simplify); root->traverse(&simplify);
......
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