Improve constant folding for boolean vectors.

The additional tests from http://review.skia.org/441238 uncovered a gap
in the constant folder's abilities; it was not able to fold away
boolean vector comparisons even when they were constant. These are ES2
constant-expressions, so folding them properly is a requirement.

Change-Id: Ia0b4d5d1215c5fc2b247ac3f0dec4c8747d2153e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/441579
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/resources/sksl/folding/BoolFolding.sksl b/resources/sksl/folding/BoolFolding.sksl
index d2a3073..5bd19ba 100644
--- a/resources/sksl/folding/BoolFolding.sksl
+++ b/resources/sksl/folding/BoolFolding.sksl
@@ -21,7 +21,13 @@
     bool o = any(not(bool2(0 == 1, FALSE)));                   // all true
     bool p = all(not(bool4(1 == 1, !false, 123 > 12, TRUE)));  // none are true
 
-    return a && !b && c && !d && e && !f && g && !h && i && !j && k && !l && m && !n && o && !p;
+    bool q = bool4(true) == bool4(true, true, true, true);
+    bool r = bool4(true) == bool4(true, false, true, true);
+    bool s = bool4(true, true, true, true) == bool4(true);
+    bool t = bool4(true, true, true, false) == bool4(true);
+
+    return a && !b && c && !d && e && !f && g && !h && i && !j && k && !l && m && !n && o && !p
+             && q && !r && s && !t;
 }
 
 half4 main(float2 coords) {
diff --git a/src/sksl/SkSLConstantFolder.cpp b/src/sksl/SkSLConstantFolder.cpp
index bff7bd8..295ec2a 100644
--- a/src/sksl/SkSLConstantFolder.cpp
+++ b/src/sksl/SkSLConstantFolder.cpp
@@ -63,6 +63,28 @@
     return eliminate_no_op_boolean(right, op, left);
 }
 
+static std::unique_ptr<Expression> simplify_vector_equality(const Context& context,
+                                                            const Expression& left,
+                                                            Operator op,
+                                                            const Expression& right) {
+    if (op.kind() == Token::Kind::TK_EQEQ || op.kind() == Token::Kind::TK_NEQ) {
+        bool equality = (op.kind() == Token::Kind::TK_EQEQ);
+
+        switch (left.compareConstant(right)) {
+            case Expression::ComparisonResult::kNotEqual:
+                equality = !equality;
+                [[fallthrough]];
+
+            case Expression::ComparisonResult::kEqual:
+                return BoolLiteral::Make(context, left.fOffset, equality);
+
+            case Expression::ComparisonResult::kUnknown:
+                break;
+        }
+    }
+    return nullptr;
+}
+
 // 'T' is the actual stored type of the literal data (SKSL_FLOAT or SKSL_INT).
 // 'U' is an unsigned version of that, used to perform addition, subtraction, and multiplication,
 // to avoid signed-integer overflow errors. This mimics the use of URESULT vs. RESULT when doing
@@ -76,21 +98,9 @@
     SkASSERT(left.type() == right.type());
     const Type& type = left.type();
 
-    // Handle boolean operations: == !=
-    if (op.kind() == Token::Kind::TK_EQEQ || op.kind() == Token::Kind::TK_NEQ) {
-        bool equality = (op.kind() == Token::Kind::TK_EQEQ);
-
-        switch (left.compareConstant(right)) {
-            case Expression::ComparisonResult::kNotEqual:
-                equality = !equality;
-                [[fallthrough]];
-
-            case Expression::ComparisonResult::kEqual:
-                return BoolLiteral::Make(context, left.fOffset, equality);
-
-            case Expression::ComparisonResult::kUnknown:
-                return nullptr;
-        }
+    // Handle equality operations: == !=
+    if (std::unique_ptr<Expression> result = simplify_vector_equality(context, left, op, right)) {
+        return result;
     }
 
     // Handle floating-point arithmetic: + - * /
@@ -522,6 +532,9 @@
         if (leftType.componentType().isInteger()) {
             return simplify_vector<SKSL_INT, SKSL_UINT>(context, *left, op, *right);
         }
+        if (leftType.componentType().isBoolean()) {
+            return simplify_vector_equality(context, *left, op, *right);
+        }
         return nullptr;
     }
 
@@ -535,6 +548,10 @@
             return simplify_vector<SKSL_INT, SKSL_UINT>(context, *left, op,
                                                         splat_scalar(*right, left->type()));
         }
+        if (rightType.isBoolean()) {
+            return simplify_vector_equality(context, *left, op,
+                                            splat_scalar(*right, left->type()));
+        }
         return nullptr;
     }
 
@@ -548,6 +565,10 @@
             return simplify_vector<SKSL_INT, SKSL_UINT>(context, splat_scalar(*left, right->type()),
                                                         op, *right);
         }
+        if (leftType.isBoolean()) {
+            return simplify_vector_equality(context, splat_scalar(*left, right->type()),
+                                            op, *right);
+        }
         return nullptr;
     }
 
diff --git a/tests/sksl/folding/BoolFolding.glsl b/tests/sksl/folding/BoolFolding.glsl
index 6aea1a5..ff382db 100644
--- a/tests/sksl/folding/BoolFolding.glsl
+++ b/tests/sksl/folding/BoolFolding.glsl
@@ -19,5 +19,9 @@
     bool _15_n = false;
     bool _16_o = true;
     bool _17_p = 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 ? colorGreen : colorRed;
+    bool _18_q = true;
+    bool _19_r = false;
+    bool _20_s = true;
+    bool _21_t = 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 ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/shared/MatrixToVectorCast.asm.frag b/tests/sksl/shared/MatrixToVectorCast.asm.frag
index 3825e71..f99d0d2 100644
--- a/tests/sksl/shared/MatrixToVectorCast.asm.frag
+++ b/tests/sksl/shared/MatrixToVectorCast.asm.frag
@@ -65,10 +65,9 @@
 OpDecorate %107 RelaxedPrecision
 OpDecorate %109 RelaxedPrecision
 OpDecorate %116 RelaxedPrecision
-OpDecorate %122 RelaxedPrecision
-OpDecorate %131 RelaxedPrecision
-OpDecorate %133 RelaxedPrecision
-OpDecorate %134 RelaxedPrecision
+OpDecorate %125 RelaxedPrecision
+OpDecorate %127 RelaxedPrecision
+OpDecorate %128 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -120,7 +119,7 @@
 %25 = OpFunctionParameter %_ptr_Function_v2float
 %26 = OpLabel
 %ok = OpVariable %_ptr_Function_bool Function
-%123 = OpVariable %_ptr_Function_v4float Function
+%117 = OpVariable %_ptr_Function_v4float Function
 OpStore %ok %true
 %31 = OpLoad %bool %ok
 OpSelectionMerge %33 None
@@ -209,29 +208,19 @@
 %115 = OpPhi %bool %false %68 %114 %94
 OpStore %ok %115
 %116 = OpLoad %bool %ok
-OpSelectionMerge %118 None
-OpBranchConditional %116 %117 %118
-%117 = OpLabel
-%119 = OpLogicalEqual %v4bool %112 %112
-%120 = OpAll %bool %119
-OpBranch %118
-%118 = OpLabel
-%121 = OpPhi %bool %false %95 %120 %117
-OpStore %ok %121
-%122 = OpLoad %bool %ok
-OpSelectionMerge %127 None
-OpBranchConditional %122 %125 %126
-%125 = OpLabel
-%128 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%131 = OpLoad %v4float %128
-OpStore %123 %131
-OpBranch %127
-%126 = OpLabel
-%132 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
-%133 = OpLoad %v4float %132
-OpStore %123 %133
-OpBranch %127
-%127 = OpLabel
-%134 = OpLoad %v4float %123
-OpReturnValue %134
+OpSelectionMerge %121 None
+OpBranchConditional %116 %119 %120
+%119 = OpLabel
+%122 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%125 = OpLoad %v4float %122
+OpStore %117 %125
+OpBranch %121
+%120 = OpLabel
+%126 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%127 = OpLoad %v4float %126
+OpStore %117 %127
+OpBranch %121
+%121 = OpLabel
+%128 = OpLoad %v4float %117
+OpReturnValue %128
 OpFunctionEnd
diff --git a/tests/sksl/shared/MatrixToVectorCast.glsl b/tests/sksl/shared/MatrixToVectorCast.glsl
index 7a4504a..0a382d9 100644
--- a/tests/sksl/shared/MatrixToVectorCast.glsl
+++ b/tests/sksl/shared/MatrixToVectorCast.glsl
@@ -9,6 +9,5 @@
     ok = ok && vec4(testMatrix2x2) == vec4(1.0, 2.0, 3.0, 4.0);
     ok = ok && ivec4(vec4(testMatrix2x2)) == ivec4(1, 2, 3, 4);
     ok = ok && bvec4(vec4(testMatrix2x2)) == bvec4(true, true, true, true);
-    ok = ok && bvec4(true, true, true, true) == bvec4(true);
     return ok ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/shared/MatrixToVectorCast.metal b/tests/sksl/shared/MatrixToVectorCast.metal
index e2586d2..8a681dd 100644
--- a/tests/sksl/shared/MatrixToVectorCast.metal
+++ b/tests/sksl/shared/MatrixToVectorCast.metal
@@ -23,7 +23,6 @@
     ok = ok && all(float4_from_float2x2(_uniforms.testMatrix2x2) == float4(1.0, 2.0, 3.0, 4.0));
     ok = ok && all(int4(float4_from_float2x2(_uniforms.testMatrix2x2)) == int4(1, 2, 3, 4));
     ok = ok && all(bool4(float4_from_float2x2(_uniforms.testMatrix2x2)) == bool4(true, true, true, true));
-    ok = ok && all(bool4(true, true, true, true) == bool4(true));
     _out.sk_FragColor = ok ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }