Convert IRGenerator::convertIf to IfStatement::Make.
This lets the Rehydrator and Inliner benefit from static optimization
opportunities, like converting `if (false) {...}` to a Nop.
Change-Id: I70b4fceab84c50ea270dc894b0d6fe0e7e2369eb
Bug: skia:11342
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/375777
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/gn/sksl.gni b/gn/sksl.gni
index d0c23df..4e94736 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -107,6 +107,7 @@
"$_src/sksl/ir/SkSLFunctionPrototype.h",
"$_src/sksl/ir/SkSLFunctionReference.h",
"$_src/sksl/ir/SkSLIRNode.h",
+ "$_src/sksl/ir/SkSLIfStatement.cpp",
"$_src/sksl/ir/SkSLIfStatement.h",
"$_src/sksl/ir/SkSLIndexExpression.h",
"$_src/sksl/ir/SkSLInlineMarker.h",
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 4c8102e..353a186 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -561,45 +561,22 @@
if (!ifTrue) {
return nullptr;
}
+ if (this->detectVarDeclarationWithoutScope(*ifTrue)) {
+ return nullptr;
+ }
std::unique_ptr<Statement> ifFalse;
if (iter != n.end()) {
ifFalse = this->convertStatement(*(iter++));
if (!ifFalse) {
return nullptr;
}
+ if (this->detectVarDeclarationWithoutScope(*ifFalse)) {
+ return nullptr;
+ }
}
bool isStatic = n.getBool();
- return this->convertIf(n.fOffset, isStatic, std::move(test), std::move(ifTrue),
- std::move(ifFalse));
-}
-
-std::unique_ptr<Statement> IRGenerator::convertIf(int offset, bool isStatic,
- std::unique_ptr<Expression> test,
- std::unique_ptr<Statement> ifTrue,
- std::unique_ptr<Statement> ifFalse) {
- test = this->coerce(std::move(test), *fContext.fTypes.fBool);
- if (!test) {
- return nullptr;
- }
- if (this->detectVarDeclarationWithoutScope(*ifTrue)) {
- return nullptr;
- }
- if (ifFalse && this->detectVarDeclarationWithoutScope(*ifFalse)) {
- return nullptr;
- }
- if (test->is<BoolLiteral>()) {
- // Static Boolean values can fold down to a single branch.
- if (test->as<BoolLiteral>().value()) {
- return ifTrue;
- }
- if (ifFalse) {
- return ifFalse;
- }
- // False, but no else-clause. Not an error, so don't return null!
- return std::make_unique<Nop>();
- }
- return std::make_unique<IfStatement>(offset, isStatic, std::move(test), std::move(ifTrue),
- std::move(ifFalse));
+ return IfStatement::Make(fContext, n.fOffset, isStatic, std::move(test),
+ std::move(ifTrue), std::move(ifFalse));
}
std::unique_ptr<Statement> IRGenerator::convertFor(int offset,
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 8a59453..7e98bb9 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -212,10 +212,6 @@
std::unique_ptr<Expression> convertIdentifier(int offset, StringFragment identifier);
std::unique_ptr<Expression> convertIdentifier(const ASTNode& identifier);
std::unique_ptr<Statement> convertIf(const ASTNode& s);
- std::unique_ptr<Statement> convertIf(int offset, bool isStatic,
- std::unique_ptr<Expression> test,
- std::unique_ptr<Statement> ifTrue,
- std::unique_ptr<Statement> ifFalse);
std::unique_ptr<InterfaceBlock> convertInterfaceBlock(const ASTNode& s);
Modifiers convertModifiers(const Modifiers& m);
std::unique_ptr<Expression> convertPrefixExpression(const ASTNode& expression);
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index e8ac206..59e6966 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -467,8 +467,8 @@
}
case Statement::Kind::kIf: {
const IfStatement& i = statement.as<IfStatement>();
- return std::make_unique<IfStatement>(offset, i.isStatic(), expr(i.test()),
- stmt(i.ifTrue()), stmt(i.ifFalse()));
+ return IfStatement::Make(*fContext, offset, i.isStatic(), expr(i.test()),
+ stmt(i.ifTrue()), stmt(i.ifFalse()));
}
case Statement::Kind::kInlineMarker:
case Statement::Kind::kNop:
diff --git a/src/sksl/SkSLRehydrator.cpp b/src/sksl/SkSLRehydrator.cpp
index e935d48..a220235 100644
--- a/src/sksl/SkSLRehydrator.cpp
+++ b/src/sksl/SkSLRehydrator.cpp
@@ -386,9 +386,8 @@
std::unique_ptr<Expression> test = this->expression();
std::unique_ptr<Statement> ifTrue = this->statement();
std::unique_ptr<Statement> ifFalse = this->statement();
- return std::unique_ptr<Statement>(new IfStatement(-1, isStatic, std::move(test),
- std::move(ifTrue),
- std::move(ifFalse)));
+ return IfStatement::Make(fContext, /*offset=*/-1, isStatic, std::move(test),
+ std::move(ifTrue), std::move(ifFalse));
}
case Rehydrator::kInlineMarker_Command: {
const FunctionDeclaration* funcDecl = this->symbolRef<FunctionDeclaration>(
diff --git a/src/sksl/dsl/DSLCore.cpp b/src/sksl/dsl/DSLCore.cpp
index ebe5719..1200be1 100644
--- a/src/sksl/dsl/DSLCore.cpp
+++ b/src/sksl/dsl/DSLCore.cpp
@@ -98,8 +98,8 @@
}
static DSLStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse) {
- return DSLWriter::IRGenerator().convertIf(/*offset=*/-1, /*isStatic=*/false, test.release(),
- ifTrue.release(), ifFalse.release());
+ return IfStatement::Make(DSLWriter::Context(), /*offset=*/-1, /*isStatic=*/false,
+ test.release(), ifTrue.release(), ifFalse.release());
}
static DSLStatement Return(DSLExpression value) {
diff --git a/src/sksl/ir/SkSLIfStatement.cpp b/src/sksl/ir/SkSLIfStatement.cpp
new file mode 100644
index 0000000..2b7237f
--- /dev/null
+++ b/src/sksl/ir/SkSLIfStatement.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/sksl/SkSLContext.h"
+#include "src/sksl/ir/SkSLBoolLiteral.h"
+#include "src/sksl/ir/SkSLIfStatement.h"
+#include "src/sksl/ir/SkSLNop.h"
+#include "src/sksl/ir/SkSLType.h"
+
+namespace SkSL {
+
+std::unique_ptr<Statement> IfStatement::clone() const {
+ return std::make_unique<IfStatement>(fOffset, this->isStatic(), this->test()->clone(),
+ this->ifTrue()->clone(),
+ this->ifFalse() ? this->ifFalse()->clone() : nullptr);
+}
+
+String IfStatement::description() const {
+ String result;
+ if (this->isStatic()) {
+ result += "@";
+ }
+ result += "if (" + this->test()->description() + ") " + this->ifTrue()->description();
+ if (this->ifFalse()) {
+ result += " else " + this->ifFalse()->description();
+ }
+ return result;
+}
+
+std::unique_ptr<Statement> IfStatement::Make(const Context& context, int offset, bool isStatic,
+ std::unique_ptr<Expression> test,
+ std::unique_ptr<Statement> ifTrue,
+ std::unique_ptr<Statement> ifFalse) {
+ test = context.fTypes.fBool->coerceExpression(std::move(test), context);
+ if (!test) {
+ return nullptr;
+ }
+ if (test->is<BoolLiteral>()) {
+ // Static Boolean values can fold down to a single branch.
+ if (test->as<BoolLiteral>().value()) {
+ return ifTrue;
+ }
+ if (ifFalse) {
+ return ifFalse;
+ }
+ // False, but no else-clause. Not an error, so don't return null!
+ return std::make_unique<Nop>();
+ }
+ return std::make_unique<IfStatement>(offset, isStatic, std::move(test), std::move(ifTrue),
+ std::move(ifFalse));
+}
+
+} // namespace SkSL
diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h
index 56aaab9..07df587 100644
--- a/src/sksl/ir/SkSLIfStatement.h
+++ b/src/sksl/ir/SkSLIfStatement.h
@@ -11,6 +11,8 @@
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLStatement.h"
+#include <memory>
+
namespace SkSL {
/**
@@ -20,6 +22,8 @@
public:
static constexpr Kind kStatementKind = Kind::kIf;
+ // Use IfStatement::Make to automatically flatten out `if` statements that can be resolved at
+ // IR generation time.
IfStatement(int offset, bool isStatic, std::unique_ptr<Expression> test,
std::unique_ptr<Statement> ifTrue, std::unique_ptr<Statement> ifFalse)
: INHERITED(offset, kStatementKind)
@@ -28,6 +32,11 @@
, fIfFalse(std::move(ifFalse))
, fIsStatic(isStatic) {}
+ static std::unique_ptr<Statement> Make(const Context& context, int offset, bool isStatic,
+ std::unique_ptr<Expression> test,
+ std::unique_ptr<Statement> ifTrue,
+ std::unique_ptr<Statement> ifFalse);
+
bool isStatic() const {
return fIsStatic;
}
@@ -56,25 +65,9 @@
return fIfFalse;
}
- std::unique_ptr<Statement> clone() const override {
- return std::unique_ptr<Statement>(new IfStatement(fOffset, this->isStatic(),
- this->test()->clone(),
- this->ifTrue()->clone(),
- this->ifFalse() ? this->ifFalse()->clone()
- : nullptr));
- }
+ std::unique_ptr<Statement> clone() const override;
- String description() const override {
- String result;
- if (this->isStatic()) {
- result += "@";
- }
- result += "if (" + this->test()->description() + ") " + this->ifTrue()->description();
- if (this->ifFalse()) {
- result += " else " + this->ifFalse()->description();
- }
- return result;
- }
+ String description() const override;
private:
std::unique_ptr<Expression> fTest;