Allow prefix-expressions in IsSameExpressionTree.

This will allow expressions like `-x == -x` or `!y == !y` to be detected
as matching expressions (which enables various constant-folding paths).

(Also, migrated the analysis code into a separate cpp.)

Change-Id: I3e317fdaed3762f8fa19e684a5ed557fc9348c7c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/527617
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2022-04-05 13:57:51 -04:00 committed by SkCQ
parent 759deb9ec2
commit d0242346b8
6 changed files with 124 additions and 65 deletions

View File

@ -87,6 +87,7 @@ skia_sksl_sources = [
"$_src/sksl/analysis/SkSLFinalizationChecks.cpp",
"$_src/sksl/analysis/SkSLGetLoopUnrollInfo.cpp",
"$_src/sksl/analysis/SkSLIsConstantExpression.cpp",
"$_src/sksl/analysis/SkSLIsSameExpressionTree.cpp",
"$_src/sksl/analysis/SkSLNoOpErrorReporter.h",
"$_src/sksl/analysis/SkSLProgramUsage.cpp",
"$_src/sksl/analysis/SkSLProgramVisitor.h",

View File

@ -45,6 +45,7 @@ cc_library(
"//src/sksl/analysis:SkSLFinalizationChecks_src",
"//src/sksl/analysis:SkSLGetLoopUnrollInfo_src",
"//src/sksl/analysis:SkSLIsConstantExpression_src",
"//src/sksl/analysis:SkSLIsSameExpressionTree_src",
"//src/sksl/analysis:SkSLProgramUsage_src",
"//src/sksl/analysis:SkSLSwitchCaseContainsExit_src",
"//src/sksl/codegen:SkSLGLSLCodeGenerator_src",

View File

@ -445,69 +445,6 @@ bool Analysis::IsTrivialExpression(const Expression& expr) {
IsTrivialExpression(*expr.as<IndexExpression>().base()));
}
bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
if (left.kind() != right.kind() || !left.type().matches(right.type())) {
return false;
}
// This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
// instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
// Since this is intended to be used for optimization purposes, handling the common cases is
// sufficient.
switch (left.kind()) {
case Expression::Kind::kLiteral:
return left.as<Literal>().value() == right.as<Literal>().value();
case Expression::Kind::kConstructorArray:
case Expression::Kind::kConstructorArrayCast:
case Expression::Kind::kConstructorCompound:
case Expression::Kind::kConstructorCompoundCast:
case Expression::Kind::kConstructorDiagonalMatrix:
case Expression::Kind::kConstructorMatrixResize:
case Expression::Kind::kConstructorScalarCast:
case Expression::Kind::kConstructorStruct:
case Expression::Kind::kConstructorSplat: {
if (left.kind() != right.kind()) {
return false;
}
const AnyConstructor& leftCtor = left.asAnyConstructor();
const AnyConstructor& rightCtor = right.asAnyConstructor();
const auto leftSpan = leftCtor.argumentSpan();
const auto rightSpan = rightCtor.argumentSpan();
if (leftSpan.size() != rightSpan.size()) {
return false;
}
for (size_t index = 0; index < leftSpan.size(); ++index) {
if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
return false;
}
}
return true;
}
case Expression::Kind::kFieldAccess:
return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
IsSameExpressionTree(*left.as<FieldAccess>().base(),
*right.as<FieldAccess>().base());
case Expression::Kind::kIndex:
return IsSameExpressionTree(*left.as<IndexExpression>().index(),
*right.as<IndexExpression>().index()) &&
IsSameExpressionTree(*left.as<IndexExpression>().base(),
*right.as<IndexExpression>().base());
case Expression::Kind::kSwizzle:
return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
case Expression::Kind::kVariableReference:
return left.as<VariableReference>().variable() ==
right.as<VariableReference>().variable();
default:
return false;
}
}
class ES2IndexingVisitor : public ProgramVisitor {
public:
ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}

View File

@ -163,3 +163,26 @@ generated_cc_atom(
visibility = ["//:__subpackages__"],
deps = ["//include/sksl:SkSLErrorReporter_hdr"],
)
generated_cc_atom(
name = "SkSLIsSameExpressionTree_src",
srcs = ["SkSLIsSameExpressionTree.cpp"],
visibility = ["//:__subpackages__"],
deps = [
"//include/core:SkSpan_hdr",
"//include/core:SkTypes_hdr",
"//include/private:SkSLDefines_hdr",
"//include/private:SkTArray_hdr",
"//include/sksl:SkSLOperator_hdr",
"//src/sksl:SkSLAnalysis_hdr",
"//src/sksl/ir:SkSLConstructor_hdr",
"//src/sksl/ir:SkSLExpression_hdr",
"//src/sksl/ir:SkSLFieldAccess_hdr",
"//src/sksl/ir:SkSLIndexExpression_hdr",
"//src/sksl/ir:SkSLLiteral_hdr",
"//src/sksl/ir:SkSLPrefixExpression_hdr",
"//src/sksl/ir:SkSLSwizzle_hdr",
"//src/sksl/ir:SkSLType_hdr",
"//src/sksl/ir:SkSLVariableReference_hdr",
],
)

View File

@ -0,0 +1,97 @@
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include "include/private/SkSLDefines.h"
#include "include/private/SkTArray.h"
#include "include/sksl/SkSLOperator.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLFieldAccess.h"
#include "src/sksl/ir/SkSLIndexExpression.h"
#include "src/sksl/ir/SkSLLiteral.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVariableReference.h"
#include <memory>
namespace SkSL {
bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
if (left.kind() != right.kind() || !left.type().matches(right.type())) {
return false;
}
// This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
// instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
// Since this is intended to be used for optimization purposes, handling the common cases is
// sufficient.
switch (left.kind()) {
case Expression::Kind::kLiteral:
return left.as<Literal>().value() == right.as<Literal>().value();
case Expression::Kind::kConstructorArray:
case Expression::Kind::kConstructorArrayCast:
case Expression::Kind::kConstructorCompound:
case Expression::Kind::kConstructorCompoundCast:
case Expression::Kind::kConstructorDiagonalMatrix:
case Expression::Kind::kConstructorMatrixResize:
case Expression::Kind::kConstructorScalarCast:
case Expression::Kind::kConstructorStruct:
case Expression::Kind::kConstructorSplat: {
if (left.kind() != right.kind()) {
return false;
}
const AnyConstructor& leftCtor = left.asAnyConstructor();
const AnyConstructor& rightCtor = right.asAnyConstructor();
const auto leftSpan = leftCtor.argumentSpan();
const auto rightSpan = rightCtor.argumentSpan();
if (leftSpan.size() != rightSpan.size()) {
return false;
}
for (size_t index = 0; index < leftSpan.size(); ++index) {
if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
return false;
}
}
return true;
}
case Expression::Kind::kFieldAccess:
return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
IsSameExpressionTree(*left.as<FieldAccess>().base(),
*right.as<FieldAccess>().base());
case Expression::Kind::kIndex:
return IsSameExpressionTree(*left.as<IndexExpression>().index(),
*right.as<IndexExpression>().index()) &&
IsSameExpressionTree(*left.as<IndexExpression>().base(),
*right.as<IndexExpression>().base());
case Expression::Kind::kPrefix:
return (left.as<PrefixExpression>().getOperator().kind() ==
right.as<PrefixExpression>().getOperator().kind()) &&
IsSameExpressionTree(*left.as<PrefixExpression>().operand(),
*right.as<PrefixExpression>().operand());
case Expression::Kind::kSwizzle:
return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
case Expression::Kind::kVariableReference:
return left.as<VariableReference>().variable() ==
right.as<VariableReference>().variable();
default:
return false;
}
}
} // namespace SkSL

View File

@ -23,7 +23,7 @@ vec4 main() {
bool _19_r = false;
bool _20_s = true;
bool _21_t = false;
bool _22_u = !_0_a == !_0_a;
bool _23_v = !_0_a != !_0_a;
bool _22_u = true;
bool _23_v = false;
return ((((((((((((((((((((_0_a && !_1_b) && _2_c) && !_3_d) && _4_e) && !_5_f) && _6_g) && !_7_h) && _8_i) && !_9_j) && _12_k) && !_13_l) && _14_m) && !_15_n) && _16_o) && !_17_p) && _18_q) && !_19_r) && _20_s) && !_21_t) && _22_u) && !_23_v ? colorGreen : colorRed;
}