Generate performance warnings in HLSL translation
Generate performance warnings for some code that undergoes heavy
emulation when translated to HLSL:
1. Dynamic indexing of vectors and matrices.
2. Non-empty fall-through cases in switch/case.
The warnings are generated only when code is translated to HLSL.
Generating them in the parsing stage would add too much maintenance
burden.
Improves switch statement fall-through handling in cases where an
empty fall-through case follows a non-empty one so that extra
performance warnings are not generated.
BUG=angleproject:1116
Change-Id: I7c85d78fe7c4f8e6042bda72ceaaf6e37dadfe6c
Reviewed-on: https://chromium-review.googlesource.com/732986
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/RemoveSwitchFallThrough.cpp b/src/compiler/translator/RemoveSwitchFallThrough.cpp
index 10da1df..ab2045d 100644
--- a/src/compiler/translator/RemoveSwitchFallThrough.cpp
+++ b/src/compiler/translator/RemoveSwitchFallThrough.cpp
@@ -10,6 +10,7 @@
#include "compiler/translator/RemoveSwitchFallThrough.h"
+#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/IntermTraverse.h"
namespace sh
@@ -21,10 +22,12 @@
class RemoveSwitchFallThroughTraverser : public TIntermTraverser
{
public:
- static TIntermBlock *removeFallThrough(TIntermBlock *statementList);
+ static TIntermBlock *removeFallThrough(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics);
private:
- RemoveSwitchFallThroughTraverser(TIntermBlock *statementList);
+ RemoveSwitchFallThroughTraverser(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics);
void visitSymbol(TIntermSymbol *node) override;
void visitConstantUnion(TIntermConstantUnion *node) override;
@@ -49,11 +52,14 @@
bool mLastStatementWasBreak;
TIntermBlock *mPreviousCase;
std::vector<TIntermBlock *> mCasesSharingBreak;
+ PerformanceDiagnostics *mPerfDiagnostics;
};
-TIntermBlock *RemoveSwitchFallThroughTraverser::removeFallThrough(TIntermBlock *statementList)
+TIntermBlock *RemoveSwitchFallThroughTraverser::removeFallThrough(
+ TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics)
{
- RemoveSwitchFallThroughTraverser rm(statementList);
+ RemoveSwitchFallThroughTraverser rm(statementList, perfDiagnostics);
ASSERT(statementList);
statementList->traverse(&rm);
ASSERT(rm.mPreviousCase || statementList->getSequence()->empty());
@@ -69,11 +75,14 @@
return rm.mStatementListOut;
}
-RemoveSwitchFallThroughTraverser::RemoveSwitchFallThroughTraverser(TIntermBlock *statementList)
+RemoveSwitchFallThroughTraverser::RemoveSwitchFallThroughTraverser(
+ TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics)
: TIntermTraverser(true, false, false),
mStatementList(statementList),
mLastStatementWasBreak(false),
- mPreviousCase(nullptr)
+ mPreviousCase(nullptr),
+ mPerfDiagnostics(perfDiagnostics)
{
mStatementListOut = new TIntermBlock();
}
@@ -158,14 +167,10 @@
mCasesSharingBreak.push_back(mPreviousCase);
if (mLastStatementWasBreak)
{
- bool labelsWithNoStatements = true;
for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
{
- if (mCasesSharingBreak.at(i)->getSequence()->size() > 1)
- {
- labelsWithNoStatements = false;
- }
- if (labelsWithNoStatements)
+ ASSERT(!mCasesSharingBreak.at(i)->getSequence()->empty());
+ if (mCasesSharingBreak.at(i)->getSequence()->size() == 1)
{
// Fall-through is allowed in case the label has no statements.
outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0);
@@ -173,6 +178,13 @@
else
{
// Include all the statements that this case can fall through under the same label.
+ if (mCasesSharingBreak.size() > i + 1u)
+ {
+ mPerfDiagnostics->warning(mCasesSharingBreak.at(i)->getLine(),
+ "Performance: non-empty fall-through cases in "
+ "switch statements generate extra code.",
+ "switch");
+ }
for (size_t j = i; j < mCasesSharingBreak.size(); ++j)
{
size_t startIndex =
@@ -192,6 +204,7 @@
handlePreviousCase();
mPreviousCase = new TIntermBlock();
mPreviousCase->getSequence()->push_back(node);
+ mPreviousCase->setLine(node->getLine());
// Don't traverse the condition of the case statement
return false;
}
@@ -248,9 +261,10 @@
} // anonymous namespace
-TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList)
+TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList,
+ PerformanceDiagnostics *perfDiagnostics)
{
- return RemoveSwitchFallThroughTraverser::removeFallThrough(statementList);
+ return RemoveSwitchFallThroughTraverser::removeFallThrough(statementList, perfDiagnostics);
}
} // namespace sh