Prevent comma operator constant-folding or constant-expression-usage.

OpenGL docs specifically insist that the sequence (comma) operator
should not be treated as a constant-expression so that attempts to
declare multidimensional arrays with a comma will fail:
http://screen/vJEpAe9yNmbzZTm

(See "12.43 Sequence operator and constant expressions" in the OpenGL
ES3 documentation or read skia:13311 for details.)

In practice, we don't get much benefit from optimizing away unused
comma-expressions; it improves some synthetic tests, but realistically
this will not help Skia in any real-world scenario. The constant folder
no longer attempts this optimization, and comma-expressions are now
rejected in a constant-expression context.

Change-Id: Ic5dea6ff90e36614b548c1ce89a444e81da944ae
Bug: skia:13311
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/539565
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Arman Uguray <armansito@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index cff2d44..ad45dfa 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -45,6 +45,7 @@
   "/sksl/errors/BreakOutsideLoop.rts",
   "/sksl/errors/CallNonFunction.rts",
   "/sksl/errors/CanExitWithoutReturningValue.sksl",
+  "/sksl/errors/CommasAsConstantExpressions.rts",
   "/sksl/errors/ComparisonDimensional.rts",
   "/sksl/errors/ConstructorArgumentCount.rts",
   "/sksl/errors/ConstructorTypeMismatch.rts",
diff --git a/resources/sksl/errors/CommasAsConstantExpressions.rts b/resources/sksl/errors/CommasAsConstantExpressions.rts
new file mode 100644
index 0000000..27bcb60
--- /dev/null
+++ b/resources/sksl/errors/CommasAsConstantExpressions.rts
@@ -0,0 +1,9 @@
+int a[1, 2];
+int b[(3, 4)];
+const int d = (5, 6);
+
+/*%%*
+array size must be an integer
+array size must be an integer
+'const' variable initializer must be a constant expression
+*%%*/
diff --git a/src/sksl/SkSLConstantFolder.cpp b/src/sksl/SkSLConstantFolder.cpp
index 6ab79c5..135cacc 100644
--- a/src/sksl/SkSLConstantFolder.cpp
+++ b/src/sksl/SkSLConstantFolder.cpp
@@ -503,14 +503,6 @@
     const Expression* left = GetConstantValueForVariable(leftExpr);
     const Expression* right = GetConstantValueForVariable(rightExpr);
 
-    // If this is the comma operator, the left side is evaluated but not otherwise used in any way.
-    // So if the left side has no side effects, it can just be eliminated entirely.
-    if (op.kind() == Operator::Kind::COMMA && !left->hasSideEffects()) {
-        std::unique_ptr<Expression> result = right->clone();
-        result->fPosition = pos;
-        return result;
-    }
-
     // If this is the assignment operator, and both sides are the same trivial expression, this is
     // self-assignment (i.e., `var = var`) and can be reduced to just a variable reference (`var`).
     // This can happen when other parts of the assignment are optimized away.
diff --git a/src/sksl/analysis/BUILD.bazel b/src/sksl/analysis/BUILD.bazel
index 9ac7b6c..1eb262b 100644
--- a/src/sksl/analysis/BUILD.bazel
+++ b/src/sksl/analysis/BUILD.bazel
@@ -83,7 +83,9 @@
         ":SkSLProgramVisitor_hdr",
         "//include/core:SkTypes_hdr",
         "//include/private:SkSLModifiers_hdr",
+        "//include/sksl:SkSLOperator_hdr",
         "//src/sksl:SkSLAnalysis_hdr",
+        "//src/sksl/ir:SkSLBinaryExpression_hdr",
         "//src/sksl/ir:SkSLExpression_hdr",
         "//src/sksl/ir:SkSLVariableReference_hdr",
         "//src/sksl/ir:SkSLVariable_hdr",
diff --git a/src/sksl/analysis/SkSLIsConstantExpression.cpp b/src/sksl/analysis/SkSLIsConstantExpression.cpp
index 86fccac..534aa1c 100644
--- a/src/sksl/analysis/SkSLIsConstantExpression.cpp
+++ b/src/sksl/analysis/SkSLIsConstantExpression.cpp
@@ -7,8 +7,10 @@
 
 #include "include/core/SkTypes.h"
 #include "include/private/SkSLModifiers.h"
+#include "include/sksl/SkSLOperator.h"
 #include "src/sksl/SkSLAnalysis.h"
 #include "src/sksl/analysis/SkSLProgramVisitor.h"
+#include "src/sksl/ir/SkSLBinaryExpression.h"
 #include "src/sksl/ir/SkSLExpression.h"
 #include "src/sksl/ir/SkSLVariable.h"
 #include "src/sksl/ir/SkSLVariableReference.h"
@@ -47,8 +49,14 @@
                 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end();
             }
 
-            // ... expressions composed of both of the above
+            // ... not a sequence expression (skia:13311)...
             case Expression::Kind::kBinary:
+                if (e.as<BinaryExpression>().getOperator().kind() == Operator::Kind::COMMA) {
+                    return true;
+                }
+                [[fallthrough]];
+
+            // ... expressions composed of both of the above
             case Expression::Kind::kConstructorArray:
             case Expression::Kind::kConstructorArrayCast:
             case Expression::Kind::kConstructorCompound:
diff --git a/src/sksl/ir/SkSLTernaryExpression.cpp b/src/sksl/ir/SkSLTernaryExpression.cpp
index c8368b5..c221b7b 100644
--- a/src/sksl/ir/SkSLTernaryExpression.cpp
+++ b/src/sksl/ir/SkSLTernaryExpression.cpp
@@ -82,13 +82,18 @@
         }
     }
 
-    // A ternary with matching true- and false-cases can be reduced to `(test, ifTrue)`.
-    // If `test` has no side-effects, it will be optimized away by the constant-folder as well.
+    // A ternary with matching true- and false-cases does not need to branch.
     if (context.fConfig->fSettings.fOptimize) {
         const Expression* ifTrueExpr  = ConstantFolder::GetConstantValueForVariable(*ifTrue);
         const Expression* ifFalseExpr = ConstantFolder::GetConstantValueForVariable(*ifFalse);
 
         if (Analysis::IsSameExpressionTree(*ifTrueExpr, *ifFalseExpr)) {
+            // If `test` has no side-effects, we can eliminate it too, and just return `ifTrue`.
+            if (!test->hasSideEffects()) {
+                ifTrue->fPosition = pos;
+                return ifTrue;
+            }
+            // Return a comma-expression containing `(test, ifTrue)`.
             return BinaryExpression::Make(context, pos, std::move(test),
                                           Operator::Kind::COMMA, std::move(ifTrue));
         }
diff --git a/tests/sksl/errors/CommasAsConstantExpressions.glsl b/tests/sksl/errors/CommasAsConstantExpressions.glsl
new file mode 100644
index 0000000..fb02049
--- /dev/null
+++ b/tests/sksl/errors/CommasAsConstantExpressions.glsl
@@ -0,0 +1,12 @@
+### Compilation failed:
+
+error: 1: array size must be an integer
+int a[1, 2];
+      ^^^^
+error: 2: array size must be an integer
+int b[(3, 4)];
+      ^^^^^^
+error: 3: 'const' variable initializer must be a constant expression
+const int d = (5, 6);
+              ^^^^^^
+3 errors
diff --git a/tests/sksl/shared/CommaMixedTypes.asm.frag b/tests/sksl/shared/CommaMixedTypes.asm.frag
index faddb69..3239219 100644
--- a/tests/sksl/shared/CommaMixedTypes.asm.frag
+++ b/tests/sksl/shared/CommaMixedTypes.asm.frag
@@ -22,15 +22,15 @@
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
 OpDecorate %result RelaxedPrecision
-OpDecorate %32 RelaxedPrecision
-OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
 OpDecorate %37 RelaxedPrecision
-OpDecorate %38 RelaxedPrecision
-OpDecorate %42 RelaxedPrecision
 OpDecorate %43 RelaxedPrecision
-OpDecorate %47 RelaxedPrecision
-OpDecorate %48 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
 OpDecorate %51 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %64 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -49,12 +49,23 @@
 %_ptr_Function_v2float = OpTypePointer Function %v2float
 %23 = OpTypeFunction %v4float %_ptr_Function_v2float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
 %int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int_0 = OpConstant %int 0
 %_ptr_Function_float = OpTypePointer Function %float
-%int_1 = OpConstant %int 1
+%float_2 = OpConstant %float 2
+%41 = OpConstantComposite %v2float %float_2 %float_2
+%float_3 = OpConstant %float 3
+%v3float = OpTypeVector %float 3
+%48 = OpConstantComposite %v3float %float_3 %float_3 %float_3
 %int_2 = OpConstant %int 2
+%float_4 = OpConstant %float 4
+%55 = OpConstantComposite %v2float %float_4 %float_0
+%56 = OpConstantComposite %v2float %float_0 %float_4
+%mat2v2float = OpTypeMatrix %v2float 2
+%58 = OpConstantComposite %mat2v2float %55 %56
 %int_3 = OpConstant %int 3
 %_entrypoint_v = OpFunction %void None %15
 %16 = OpLabel
@@ -68,26 +79,28 @@
 %24 = OpFunctionParameter %_ptr_Function_v2float
 %25 = OpLabel
 %result = OpVariable %_ptr_Function_v4float Function
-%28 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%32 = OpLoad %v4float %28
-%33 = OpCompositeExtract %float %32 0
-%34 = OpAccessChain %_ptr_Function_float %result %int_0
-OpStore %34 %33
-%36 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%37 = OpLoad %v4float %36
-%38 = OpCompositeExtract %float %37 1
-%39 = OpAccessChain %_ptr_Function_float %result %int_1
-OpStore %39 %38
-%41 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%42 = OpLoad %v4float %41
-%43 = OpCompositeExtract %float %42 2
-%44 = OpAccessChain %_ptr_Function_float %result %int_2
-OpStore %44 %43
-%46 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%47 = OpLoad %v4float %46
-%48 = OpCompositeExtract %float %47 3
-%49 = OpAccessChain %_ptr_Function_float %result %int_3
-OpStore %49 %48
-%51 = OpLoad %v4float %result
-OpReturnValue %51
+%28 = OpAccessChain %_ptr_Uniform_float %10 %int_1
+%32 = OpLoad %float %28
+%33 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%36 = OpLoad %v4float %33
+%37 = OpCompositeExtract %float %36 0
+%38 = OpAccessChain %_ptr_Function_float %result %int_0
+OpStore %38 %37
+%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%43 = OpLoad %v4float %42
+%44 = OpCompositeExtract %float %43 1
+%45 = OpAccessChain %_ptr_Function_float %result %int_1
+OpStore %45 %44
+%49 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%50 = OpLoad %v4float %49
+%51 = OpCompositeExtract %float %50 2
+%52 = OpAccessChain %_ptr_Function_float %result %int_2
+OpStore %52 %51
+%59 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%60 = OpLoad %v4float %59
+%61 = OpCompositeExtract %float %60 3
+%62 = OpAccessChain %_ptr_Function_float %result %int_3
+OpStore %62 %61
+%64 = OpLoad %v4float %result
+OpReturnValue %64
 OpFunctionEnd
diff --git a/tests/sksl/shared/CommaMixedTypes.glsl b/tests/sksl/shared/CommaMixedTypes.glsl
index 6c91771..058f3db 100644
--- a/tests/sksl/shared/CommaMixedTypes.glsl
+++ b/tests/sksl/shared/CommaMixedTypes.glsl
@@ -4,9 +4,9 @@
 uniform float unknownInput;
 vec4 main() {
     vec4 result;
-    result.x = colorGreen.x;
-    result.y = colorGreen.y;
-    result.z = colorGreen.z;
-    result.w = colorGreen.w;
+    result.x = (unknownInput, colorGreen.x);
+    result.y = (vec2(2.0), colorGreen.y);
+    result.z = (vec3(3.0), colorGreen.z);
+    result.w = (mat2(4.0), colorGreen.w);
     return result;
 }
diff --git a/tests/sksl/shared/CommaMixedTypes.metal b/tests/sksl/shared/CommaMixedTypes.metal
index 7057115..e23239e 100644
--- a/tests/sksl/shared/CommaMixedTypes.metal
+++ b/tests/sksl/shared/CommaMixedTypes.metal
@@ -14,10 +14,10 @@
     Outputs _out;
     (void)_out;
     half4 result;
-    result.x = _uniforms.colorGreen.x;
-    result.y = _uniforms.colorGreen.y;
-    result.z = _uniforms.colorGreen.z;
-    result.w = _uniforms.colorGreen.w;
+    result.x = (_uniforms.unknownInput, _uniforms.colorGreen.x);
+    result.y = (float2(2.0), _uniforms.colorGreen.y);
+    result.z = (half3(3.0h), _uniforms.colorGreen.z);
+    result.w = (float2x2(4.0), _uniforms.colorGreen.w);
     _out.sk_FragColor = result;
     return _out;
 }
diff --git a/tests/sksl/shared/OperatorsES3.asm.frag b/tests/sksl/shared/OperatorsES3.asm.frag
index b760ef6..f2cf6f6 100644
--- a/tests/sksl/shared/OperatorsES3.asm.frag
+++ b/tests/sksl/shared/OperatorsES3.asm.frag
@@ -14,6 +14,11 @@
 OpName %x "x"
 OpName %y "y"
 OpName %z "z"
+OpName %b "b"
+OpName %c "c"
+OpName %d "d"
+OpName %e "e"
+OpName %f "f"
 OpName %w "w"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -27,9 +32,13 @@
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %99 RelaxedPrecision
 OpDecorate %101 RelaxedPrecision
 OpDecorate %102 RelaxedPrecision
+OpDecorate %116 RelaxedPrecision
+OpDecorate %117 RelaxedPrecision
+OpDecorate %147 RelaxedPrecision
+OpDecorate %149 RelaxedPrecision
+OpDecorate %150 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -56,19 +65,22 @@
 %int_2 = OpConstant %int 2
 %int_4 = OpConstant %int 4
 %int_1 = OpConstant %int 1
+%_ptr_Function_bool = OpTypePointer Function %bool
+%true = OpConstantTrue %bool
+%float_4 = OpConstant %float 4
+%false = OpConstantFalse %bool
+%_ptr_Uniform_float = OpTypePointer Uniform %float
 %float_12 = OpConstant %float 12
 %float_10 = OpConstant %float 10
 %int_0 = OpConstant %int 0
 %int_n1 = OpConstant %int -1
 %int_5 = OpConstant %int 5
-%float_6 = OpConstant %float 6
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int_6 = OpConstant %int 6
+%float_6 = OpConstant %float 6
 %v2int = OpTypeVector %int 2
 %_ptr_Function_v2int = OpTypePointer Function %v2int
-%false = OpConstantFalse %bool
-%true = OpConstantTrue %bool
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %_entrypoint_v = OpFunction %void None %15
 %16 = OpLabel
 %20 = OpVariable %_ptr_Function_v2float Function
@@ -83,8 +95,13 @@
 %x = OpVariable %_ptr_Function_float Function
 %y = OpVariable %_ptr_Function_float Function
 %z = OpVariable %_ptr_Function_int Function
+%b = OpVariable %_ptr_Function_bool Function
+%c = OpVariable %_ptr_Function_bool Function
+%d = OpVariable %_ptr_Function_bool Function
+%e = OpVariable %_ptr_Function_bool Function
+%f = OpVariable %_ptr_Function_bool Function
 %w = OpVariable %_ptr_Function_v2int Function
-%92 = OpVariable %_ptr_Function_v4float Function
+%141 = OpVariable %_ptr_Function_v4float Function
 OpStore %x %float_1
 OpStore %y %float_2
 OpStore %z %int_3
@@ -104,75 +121,132 @@
 %48 = OpShiftRightArithmetic %int %47 %int_2
 %50 = OpShiftLeftLogical %int %48 %int_1
 OpStore %z %50
-%52 = OpFAdd %float %40 %float_12
-OpStore %x %52
-%53 = OpFSub %float %52 %float_12
-OpStore %x %53
-%55 = OpFDiv %float %42 %float_10
-OpStore %y %55
-%56 = OpFMul %float %53 %55
-OpStore %x %56
-%58 = OpBitwiseOr %int %50 %int_0
-OpStore %z %58
-%60 = OpBitwiseAnd %int %58 %int_n1
-OpStore %z %60
-%61 = OpBitwiseXor %int %60 %int_0
-OpStore %z %61
-%62 = OpShiftRightArithmetic %int %61 %int_2
-OpStore %z %62
-%63 = OpShiftLeftLogical %int %62 %int_4
-OpStore %z %63
-%65 = OpSMod %int %63 %int_5
-OpStore %z %65
-OpStore %x %float_6
-OpStore %y %float_6
-OpStore %z %int_6
-%71 = OpNot %int %int_5
-%72 = OpCompositeConstruct %v2int %71 %71
-OpStore %w %72
-%73 = OpNot %v2int %72
-OpStore %w %73
-%75 = OpCompositeExtract %int %73 0
-%76 = OpIEqual %bool %75 %int_5
+%55 = OpFOrdGreaterThan %bool %40 %float_4
+%56 = OpFOrdLessThan %bool %40 %float_2
+%57 = OpLogicalEqual %bool %55 %56
+OpSelectionMerge %59 None
+OpBranchConditional %57 %59 %58
+%58 = OpLabel
+%61 = OpAccessChain %_ptr_Uniform_float %10 %int_2
+%63 = OpLoad %float %61
+%64 = OpFOrdGreaterThanEqual %bool %float_2 %63
+OpSelectionMerge %66 None
+OpBranchConditional %64 %65 %66
+%65 = OpLabel
+%67 = OpFOrdLessThanEqual %bool %42 %40
+OpBranch %66
+%66 = OpLabel
+%68 = OpPhi %bool %false %58 %67 %65
+OpBranch %59
+%59 = OpLabel
+%69 = OpPhi %bool %true %25 %68 %66
+OpStore %b %69
+%71 = OpAccessChain %_ptr_Uniform_float %10 %int_2
+%72 = OpLoad %float %71
+%73 = OpFOrdGreaterThan %bool %72 %float_2
+OpStore %c %73
+%75 = OpLogicalNotEqual %bool %69 %73
+OpStore %d %75
 OpSelectionMerge %78 None
-OpBranchConditional %76 %77 %78
+OpBranchConditional %69 %77 %78
 %77 = OpLabel
-%79 = OpCompositeExtract %int %73 1
-%80 = OpIEqual %bool %79 %int_5
 OpBranch %78
 %78 = OpLabel
-%81 = OpPhi %bool %false %25 %80 %77
-OpSelectionMerge %83 None
-OpBranchConditional %81 %82 %83
+%79 = OpPhi %bool %false %59 %73 %77
+OpStore %e %79
+OpSelectionMerge %82 None
+OpBranchConditional %69 %82 %81
+%81 = OpLabel
+OpBranch %82
 %82 = OpLabel
-OpBranch %83
-%83 = OpLabel
-%85 = OpPhi %bool %false %78 %true %82
-OpSelectionMerge %87 None
-OpBranchConditional %85 %86 %87
-%86 = OpLabel
-OpBranch %87
-%87 = OpLabel
-%88 = OpPhi %bool %false %83 %true %86
-OpSelectionMerge %90 None
-OpBranchConditional %88 %89 %90
-%89 = OpLabel
-OpBranch %90
-%90 = OpLabel
-%91 = OpPhi %bool %false %87 %true %89
-OpSelectionMerge %96 None
-OpBranchConditional %91 %94 %95
-%94 = OpLabel
-%97 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%99 = OpLoad %v4float %97
-OpStore %92 %99
-OpBranch %96
-%95 = OpLabel
-%100 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
-%101 = OpLoad %v4float %100
-OpStore %92 %101
-OpBranch %96
-%96 = OpLabel
-%102 = OpLoad %v4float %92
-OpReturnValue %102
+%83 = OpPhi %bool %true %78 %73 %81
+OpStore %f %83
+%85 = OpFAdd %float %40 %float_12
+OpStore %x %85
+%86 = OpFSub %float %85 %float_12
+OpStore %x %86
+%88 = OpFDiv %float %42 %float_10
+OpStore %y %88
+%89 = OpFMul %float %86 %88
+OpStore %x %89
+%91 = OpBitwiseOr %int %50 %int_0
+OpStore %z %91
+%93 = OpBitwiseAnd %int %91 %int_n1
+OpStore %z %93
+%94 = OpBitwiseXor %int %93 %int_0
+OpStore %z %94
+%95 = OpShiftRightArithmetic %int %94 %int_2
+OpStore %z %95
+%96 = OpShiftLeftLogical %int %95 %int_4
+OpStore %z %96
+%98 = OpSMod %int %96 %int_5
+OpStore %z %98
+%99 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%101 = OpLoad %v4float %99
+%102 = OpVectorShuffle %v2float %101 %101 0 1
+%104 = OpConvertSToF %float %int_6
+OpStore %x %104
+%105 = OpSelect %float %69 %float_1 %float_0
+%106 = OpSelect %float %73 %float_1 %float_0
+%107 = OpFMul %float %105 %106
+%108 = OpSelect %float %75 %float_1 %float_0
+%109 = OpFMul %float %107 %108
+%110 = OpSelect %float %79 %float_1 %float_0
+%111 = OpFMul %float %109 %110
+%112 = OpSelect %float %83 %float_1 %float_0
+%113 = OpFMul %float %111 %112
+OpStore %y %float_6
+%115 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%116 = OpLoad %v4float %115
+%117 = OpVectorShuffle %v2float %116 %116 2 3
+OpStore %z %int_6
+%121 = OpNot %int %int_5
+%122 = OpCompositeConstruct %v2int %121 %121
+OpStore %w %122
+%123 = OpNot %v2int %122
+OpStore %w %123
+%124 = OpCompositeExtract %int %123 0
+%125 = OpIEqual %bool %124 %int_5
+OpSelectionMerge %127 None
+OpBranchConditional %125 %126 %127
+%126 = OpLabel
+%128 = OpCompositeExtract %int %123 1
+%129 = OpIEqual %bool %128 %int_5
+OpBranch %127
+%127 = OpLabel
+%130 = OpPhi %bool %false %82 %129 %126
+OpSelectionMerge %132 None
+OpBranchConditional %130 %131 %132
+%131 = OpLabel
+%133 = OpFOrdEqual %bool %104 %float_6
+OpBranch %132
+%132 = OpLabel
+%134 = OpPhi %bool %false %127 %133 %131
+OpSelectionMerge %136 None
+OpBranchConditional %134 %135 %136
+%135 = OpLabel
+OpBranch %136
+%136 = OpLabel
+%137 = OpPhi %bool %false %132 %true %135
+OpSelectionMerge %139 None
+OpBranchConditional %137 %138 %139
+%138 = OpLabel
+OpBranch %139
+%139 = OpLabel
+%140 = OpPhi %bool %false %136 %true %138
+OpSelectionMerge %145 None
+OpBranchConditional %140 %143 %144
+%143 = OpLabel
+%146 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%147 = OpLoad %v4float %146
+OpStore %141 %147
+OpBranch %145
+%144 = OpLabel
+%148 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%149 = OpLoad %v4float %148
+OpStore %141 %149
+OpBranch %145
+%145 = OpLabel
+%150 = OpLoad %v4float %141
+OpReturnValue %150
 OpFunctionEnd
diff --git a/tests/sksl/shared/OperatorsES3.glsl b/tests/sksl/shared/OperatorsES3.glsl
index 25ea4ba..baa204f 100644
--- a/tests/sksl/shared/OperatorsES3.glsl
+++ b/tests/sksl/shared/OperatorsES3.glsl
@@ -10,6 +10,11 @@
     x = (x - x) + ((y * x) * x) * (y - x);
     y = (x / y) / x;
     z = (((z / 2) % 3 << 4) >> 2) << 1;
+    bool b = x > 4.0 == x < 2.0 || 2.0 >= unknownInput && y <= x;
+    bool c = unknownInput > 2.0;
+    bool d = b ^^ c;
+    bool e = b && c;
+    bool f = b || c;
     x += 12.0;
     x -= 12.0;
     x *= (y /= 10.0);
@@ -19,9 +24,9 @@
     z >>= 2;
     z <<= 4;
     z %= 5;
-    x = 6.0;
-    y = 6.0;
-    z = 6;
+    x = float((colorGreen.xy, 6));
+    y = ((((float(b) * float(c)) * float(d)) * float(e)) * float(f), 6.0);
+    z = int((colorRed.zw, 6));
     ivec2 w = ivec2(~5);
     w = ~w;
     return (((w.x == 5 && w.y == 5) && x == 6.0) && y == 6.0) && z == 6 ? colorGreen : colorRed;
diff --git a/tests/sksl/shared/OperatorsES3.metal b/tests/sksl/shared/OperatorsES3.metal
index 8d3ef54..ac66f0a 100644
--- a/tests/sksl/shared/OperatorsES3.metal
+++ b/tests/sksl/shared/OperatorsES3.metal
@@ -20,6 +20,11 @@
     x = (x - x) + ((y * x) * x) * (y - x);
     y = (x / y) / x;
     z = (((z / 2) % 3 << 4) >> 2) << 1;
+    bool b = x > 4.0 == x < 2.0 || 2.0 >= _uniforms.unknownInput && y <= x;
+    bool c = _uniforms.unknownInput > 2.0;
+    bool d = b != c;
+    bool e = b && c;
+    bool f = b || c;
     x += 12.0;
     x -= 12.0;
     x *= (y /= 10.0);
@@ -29,9 +34,9 @@
     z >>= 2;
     z <<= 4;
     z %= 5;
-    x = 6.0;
-    y = 6.0;
-    z = 6;
+    x = float((_uniforms.colorGreen.xy, 6));
+    y = float(((((float(b) * float(c)) * float(d)) * float(e)) * float(f), 6.0));
+    z = int((_uniforms.colorRed.zw, 6));
     int2 w = int2(~5);
     w = ~w;
     _out.sk_FragColor = (((w.x == 5 && w.y == 5) && x == 6.0) && y == 6.0) && z == 6 ? _uniforms.colorGreen : _uniforms.colorRed;
diff --git a/tests/sksl/shared/Ossfuzz37677.glsl b/tests/sksl/shared/Ossfuzz37677.glsl
index ac468b2..0c1488f 100644
--- a/tests/sksl/shared/Ossfuzz37677.glsl
+++ b/tests/sksl/shared/Ossfuzz37677.glsl
@@ -5,6 +5,6 @@
     int x[1];
     int y = 0;
     int z = 0;
-    x[y = z];
+    (0, x[y = z]);
     return colorGreen;
 }
diff --git a/tests/sksl/shared/Ossfuzz37677.metal b/tests/sksl/shared/Ossfuzz37677.metal
index 7cb347b..b093aa3 100644
--- a/tests/sksl/shared/Ossfuzz37677.metal
+++ b/tests/sksl/shared/Ossfuzz37677.metal
@@ -15,7 +15,7 @@
     array<int, 1> x;
     int y = 0;
     int z = 0;
-    x[y = z];
+    (0, x[y = z]);
     _out.sk_FragColor = _uniforms.colorGreen;
     return _out;
 }