Move static-switch and static-if tests out of scanCFG.
We don't need to do these tests every time we run CFG optimization; we
can do them once at the end of optimization, as a separate step.
Change-Id: If0e72fbacb938b62387fd2ffdbf34d1153bf3bd4
Bug: skia:11319
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/369481
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 40800b6..c778598 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -1171,14 +1171,14 @@
bool visitStatement(const Statement& stmt) override {
switch (stmt.kind()) {
case Statement::Kind::kBlock:
- return this->INHERITED::visitStatement(stmt);
+ return INHERITED::visitStatement(stmt);
case Statement::Kind::kBreak:
return fInConditional > 0;
case Statement::Kind::kIf: {
++fInConditional;
- bool result = this->INHERITED::visitStatement(stmt);
+ bool result = INHERITED::visitStatement(stmt);
--fInConditional;
return result;
}
@@ -1203,7 +1203,7 @@
bool visitStatement(const Statement& stmt) override {
switch (stmt.kind()) {
case Statement::Kind::kBlock:
- return this->INHERITED::visitStatement(stmt);
+ return INHERITED::visitStatement(stmt);
case Statement::Kind::kBreak:
return true;
@@ -1552,39 +1552,6 @@
} while (optimizationContext.fUpdated);
SkASSERT(!optimizationContext.fNeedsRescan);
- // verify static ifs & switches, clean up dead variable decls
- for (BasicBlock& b : cfg.fBlocks) {
- for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
- !optimizationContext.fNeedsRescan;) {
- if (iter->isStatement()) {
- const Statement& s = **iter->statement();
- switch (s.kind()) {
- case Statement::Kind::kIf:
- if (s.as<IfStatement>().isStatic() &&
- !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
- this->error(s.fOffset, "static if has non-static test");
- }
- ++iter;
- break;
- case Statement::Kind::kSwitch:
- if (s.as<SwitchStatement>().isStatic() &&
- !fIRGenerator->fSettings->fPermitInvalidStaticTests &&
- optimizationContext.fSilences.find(&s) ==
- optimizationContext.fSilences.end()) {
- this->error(s.fOffset, "static switch has non-static test");
- }
- ++iter;
- break;
- default:
- ++iter;
- break;
- }
- } else {
- ++iter;
- }
- }
- }
-
// check for missing return
if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
if (cfg.fBlocks[cfg.fExit].fIsReachable) {
@@ -1652,6 +1619,52 @@
return success ? std::move(program) : nullptr;
}
+void Compiler::verifyStaticTests(const Program& program) {
+ class StaticTestVerifier : public ProgramVisitor {
+ public:
+ StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
+
+ using ProgramVisitor::visitProgramElement;
+
+ bool visitStatement(const Statement& stmt) override {
+ switch (stmt.kind()) {
+ case Statement::Kind::kIf:
+ if (stmt.as<IfStatement>().isStatic()) {
+ fReporter->error(stmt.fOffset, "static if has non-static test");
+ }
+ break;
+
+ case Statement::Kind::kSwitch:
+ if (stmt.as<SwitchStatement>().isStatic()) {
+ fReporter->error(stmt.fOffset, "static switch has non-static test");
+ }
+ break;
+
+ default:
+ break;
+ }
+ return INHERITED::visitStatement(stmt);
+ }
+
+ private:
+ using INHERITED = ProgramVisitor;
+ ErrorReporter* fReporter;
+ };
+
+ // If invalid static tests are permitted, we don't need to check anything.
+ if (fIRGenerator->fSettings->fPermitInvalidStaticTests) {
+ return;
+ }
+
+ // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
+ StaticTestVerifier visitor{this};
+ for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
+ if (element->is<FunctionDefinition>()) {
+ visitor.visitProgramElement(*element);
+ }
+ }
+}
+
bool Compiler::optimize(LoadedModule& module) {
SkASSERT(!fErrorCount);
Program::Settings settings;
@@ -1757,6 +1770,11 @@
break;
}
}
+
+ if (fErrorCount == 0) {
+ this->verifyStaticTests(program);
+ }
+
return fErrorCount == 0;
}