Commit c1f14fbe by Olli Etuaho Committed by Commit Bot

Remove empty switch statements from translated shaders

The native HLSL compiler does not accept switch statements with an empty statement list. The simplest way to accommodate this is to simply remove them from the AST after parsing and some initial pruning. This is done by the new RemoveEmptySwitchStatements traverser. It preserves init statements of switch statements in case they have side effects. So for example switch(++i) {} gets translated to ++i; BUG=angleproject:2206 TEST=angle_end2end_tests Change-Id: I550a3c9b010a3566016bdfd93344ac30fd860604 Reviewed-on: https://chromium-review.googlesource.com/742922Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent b8ee9dd3
......@@ -107,6 +107,8 @@
'compiler/translator/RegenerateStructNames.h',
'compiler/translator/RemoveArrayLengthMethod.cpp',
'compiler/translator/RemoveArrayLengthMethod.h',
'compiler/translator/RemoveEmptySwitchStatements.cpp',
'compiler/translator/RemoveEmptySwitchStatements.h',
'compiler/translator/RemoveInvariantDeclaration.cpp',
'compiler/translator/RemoveInvariantDeclaration.h',
'compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp',
......
......@@ -28,6 +28,7 @@
#include "compiler/translator/PruneNoOps.h"
#include "compiler/translator/RegenerateStructNames.h"
#include "compiler/translator/RemoveArrayLengthMethod.h"
#include "compiler/translator/RemoveEmptySwitchStatements.h"
#include "compiler/translator/RemoveInvariantDeclaration.h"
#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h"
#include "compiler/translator/RemovePow.h"
......@@ -393,6 +394,9 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success)
RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable);
// Remove empty switch statements - this makes output simpler.
RemoveEmptySwitchStatements(root);
// Create the function DAG and check there is no recursion
if (success)
success = initCallDag(root);
......
//
// Copyright (c) 2017 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.
//
// RemoveEmptySwitchStatements.cpp: Remove switch statements that have an empty statement list.
#include "compiler/translator/RemoveEmptySwitchStatements.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
{
namespace
{
class RemoveEmptySwitchStatementsTraverser : public TIntermTraverser
{
public:
RemoveEmptySwitchStatementsTraverser() : TIntermTraverser(true, false, false) {}
bool visitSwitch(Visit visit, TIntermSwitch *node);
};
bool RemoveEmptySwitchStatementsTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
{
if (node->getStatementList()->getSequence()->empty())
{
// Just output the init statement.
if (node->getInit()->hasSideEffects())
{
queueReplacement(node->getInit(), OriginalNode::IS_DROPPED);
}
else
{
TIntermSequence emptyReplacement;
ASSERT(getParentNode()->getAsBlock());
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(),
node, emptyReplacement));
}
return false; // Nothing inside the child nodes to traverse.
}
return true;
}
} // anonymous namespace
void RemoveEmptySwitchStatements(TIntermBlock *root)
{
RemoveEmptySwitchStatementsTraverser traverser;
root->traverse(&traverser);
traverser.updateTree();
}
} // namespace sh
//
// Copyright (c) 2017 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.
//
// RemoveEmptySwitchStatements.h: Remove switch statements that have an empty statement list.
#ifndef COMPILER_TRANSLATOR_REMOVEEMPTYSWITCHSTATEMENTS_H_
#define COMPILER_TRANSLATOR_REMOVEEMPTYSWITCHSTATEMENTS_H_
namespace sh
{
class TIntermBlock;
void RemoveEmptySwitchStatements(TIntermBlock *root);
}
#endif // COMPILER_TRANSLATOR_REMOVEEMPTYSWITCHSTATEMENTS_H_
\ No newline at end of file
......@@ -3691,6 +3691,30 @@ TEST_P(GLSLTest_ES3, NestedSwitchWithVariableDeclarationInside)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that an empty switch/case statement is translated in a way that compiles and executes the
// init-statement.
TEST_P(GLSLTest_ES3, EmptySwitch)
{
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
uniform int u_zero;
out vec4 my_FragColor;
void main()
{
int i = u_zero;
switch(++i) {}
my_FragColor = (i == 1) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
})";
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
drawQuad(program.get(), "inputAttribute", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(),
......
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