Move VerifyStaticTests from Compiler to Analysis.

This doesn't rely on anything Compiler-specific, and can just be a plain
Analysis pass.

Change-Id: I8564ae2a750c6daa6c449e6fa56355cc047f7010
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/444496
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
John Stiles 2021-09-01 11:35:59 -04:00 committed by SkCQ
parent d2f53f9e3e
commit 0fc6bedf5a
4 changed files with 56 additions and 55 deletions

View File

@ -1251,6 +1251,57 @@ bool Analysis::CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
return !visitor.fFoundReturn;
}
void Analysis::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);
}
bool visitExpression(const Expression&) override {
// We aren't looking for anything inside an Expression, so skip them entirely.
return false;
}
private:
using INHERITED = ProgramVisitor;
ErrorReporter* fReporter;
};
// If invalid static tests are permitted, we don't need to check anything.
if (program.fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
return;
}
// Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
StaticTestVerifier visitor{program.fContext->fErrors};
for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
if (element->is<FunctionDefinition>()) {
visitor.visitProgramElement(*element);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// ProgramVisitor

View File

@ -150,6 +150,10 @@ struct Analysis {
// Detects functions that fail to return a value on at least one path.
static bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl,
const Statement& body);
// Reports leftover @if and @switch statements in a program as errors. These should have been
// optimized away during compilation, as their tests should be constant-evaluatable.
static void VerifyStaticTests(const Program& program);
};
/**

View File

@ -489,57 +489,6 @@ std::unique_ptr<Program> Compiler::convertProgram(
#endif // SKSL_DSL_PARSER
}
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);
}
bool visitExpression(const Expression&) override {
// We aren't looking for anything inside an Expression, so skip them entirely.
return false;
}
private:
using INHERITED = ProgramVisitor;
ErrorReporter* fReporter;
};
// If invalid static tests are permitted, we don't need to check anything.
if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
return;
}
// Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
StaticTestVerifier visitor{&this->errorReporter()};
for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
if (element->is<FunctionDefinition>()) {
visitor.visitProgramElement(*element);
}
}
}
bool Compiler::optimize(LoadedModule& module) {
SkASSERT(!this->errorCount());
@ -856,7 +805,7 @@ bool Compiler::optimize(Program& program) {
}
if (this->errorCount() == 0) {
this->verifyStaticTests(program);
Analysis::VerifyStaticTests(program);
}
return this->errorCount() == 0;

View File

@ -225,9 +225,6 @@ private:
std::shared_ptr<SymbolTable> makeRootSymbolTable();
std::shared_ptr<SymbolTable> makePrivateSymbolTable(std::shared_ptr<SymbolTable> parent);
/** Verifies that @if and @switch statements were actually optimized away. */
void verifyStaticTests(const Program& program);
/** Optimize every function in the program. */
bool optimize(Program& program);