Improve dead-variable elimination.

We will now consider any variable with no reads as a candidate for
elimination. This requires us to look inside expressions, but in
practice we only care about binary expressions since `a = b` is the
only way to write to a variable without also reading from it. (Even
`a *= b` is considered a read-write; that is relaxed at followup CL
http://review.skia.org/582822, further improving these results.)

Changes in various existing tests were added to counteract this
optimization; otherwise the output would have large portions missing.

Change-Id: I3bb62069f10ff244d0b10d993e913062197fcb04
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/583096
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/resources/sksl/inliner/TrivialArgumentsInlineDirectly.sksl b/resources/sksl/inliner/TrivialArgumentsInlineDirectly.sksl
index fe4366c..0acb174 100644
--- a/resources/sksl/inliner/TrivialArgumentsInlineDirectly.sksl
+++ b/resources/sksl/inliner/TrivialArgumentsInlineDirectly.sksl
@@ -98,5 +98,7 @@
     var = func3(s.h4.yyy + s.h4.zzz);              // binary expression
     var = func4(s.h4.y001);                        // compound ctor, not compile-time constant
 
+    var[0] += mat[0][0];
+
     return colorGreen;
 }
diff --git a/resources/sksl/inliner/TrivialArgumentsInlineDirectlyES3.sksl b/resources/sksl/inliner/TrivialArgumentsInlineDirectlyES3.sksl
index 6d2b255..e4d08be 100644
--- a/resources/sksl/inliner/TrivialArgumentsInlineDirectlyES3.sksl
+++ b/resources/sksl/inliner/TrivialArgumentsInlineDirectlyES3.sksl
@@ -28,6 +28,7 @@
     // when inlining occurs.
     var = func1(colorGreen[i]);           // non-constant indexing
     var = funcA5(half[5](1, 2, 3, 4, 5)); // array with slotCount > 4
+    i *= int(var.x);
 
     return colorGreen;
 }
diff --git a/resources/sksl/shared/Assignment.sksl b/resources/sksl/shared/Assignment.sksl
index 7b683d6..8aa7dc5 100644
--- a/resources/sksl/shared/Assignment.sksl
+++ b/resources/sksl/shared/Assignment.sksl
@@ -17,7 +17,7 @@
     /* assign to swizzle */              half4 x; x.w = 0; x.yx = half2(0);
     /* assign to array of scalar */      int ai[1]; ai[0] = 0;
     /* assign to array of vector */      int4 ai4[1]; ai4[0] = int4(1,2,3,4);
-    /* assign to array of matrix */      half3x3 ah2x4[1]; ah2x4[0] = half3x3(1,2,3,4,5,6,7,8,9);
+    /* assign to array of matrix */      half3x3 ah3x3[1]; ah3x3[0] = half3x3(1,2,3,4,5,6,7,8,9);
     /* assign to array swizzle */        float4 af4[1]; af4[0].x = 0; af4[0].ywxz = float4(1);
 
     /* assign to struct variable */      S s; s.f = 0;
@@ -38,10 +38,11 @@
                                          +s.h4 = half4(1); +s.ah4[0] = half4(2);
 
     // Keep these variables alive
-    af4[0] *= float(ah2x4[0][0][0]);
+    af4[0] *= float(ah3x3[0][0][0]);
     i4.y *= i;
     x.y *= l;
     s.f *= l;
+    f3x3[0][0] *= s.f;
 
     return colorGreen;
 }
diff --git a/src/sksl/SkSLAnalysis.h b/src/sksl/SkSLAnalysis.h
index 0ef8173..667c3cc 100644
--- a/src/sksl/SkSLAnalysis.h
+++ b/src/sksl/SkSLAnalysis.h
@@ -110,6 +110,11 @@
 
 bool StatementWritesToVariable(const Statement& stmt, const Variable& var);
 
+/**
+ * Returns true if the expression can be assigned-into. Pass `info` if you want to know the
+ * VariableReference that will be written to. Pass `errors` to report an error for expressions that
+ * are not actually writable.
+ */
 struct AssignmentInfo {
     VariableReference* fAssignedVar = nullptr;
 };
diff --git a/src/sksl/ir/SkSLBinaryExpression.cpp b/src/sksl/ir/SkSLBinaryExpression.cpp
index 5473480..556f30d 100644
--- a/src/sksl/ir/SkSLBinaryExpression.cpp
+++ b/src/sksl/ir/SkSLBinaryExpression.cpp
@@ -266,4 +266,14 @@
                  this->right()->description() + ")";
 }
 
+VariableReference* BinaryExpression::isAssignmentIntoVariable() {
+    if (this->getOperator().isAssignment()) {
+        Analysis::AssignmentInfo assignmentInfo;
+        if (Analysis::IsAssignable(*this->left(), &assignmentInfo, /*errors=*/nullptr)) {
+            return assignmentInfo.fAssignedVar;
+        }
+    }
+    return nullptr;
+}
+
 }  // namespace SkSL
diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h
index 243c81a..f4042d1 100644
--- a/src/sksl/ir/SkSLBinaryExpression.h
+++ b/src/sksl/ir/SkSLBinaryExpression.h
@@ -21,6 +21,7 @@
 
 class Context;
 class Type;
+class VariableReference;
 
 /**
  * A binary operation.
@@ -88,6 +89,13 @@
 
     std::string description() const override;
 
+    /**
+     * If the expression is an assignment like `a = 1` or `a += sin(b)`, returns the
+     * VariableReference that will be written to. For other types of expressions, returns null.
+     * Complex expressions that contain inner assignments, like `(a = b) * 2`, will return null.
+     */
+    VariableReference* isAssignmentIntoVariable();
+
 private:
     static bool CheckRef(const Expression& expr);
 
diff --git a/src/sksl/transform/SkSLEliminateDeadLocalVariables.cpp b/src/sksl/transform/SkSLEliminateDeadLocalVariables.cpp
index 38a7046..795701e 100644
--- a/src/sksl/transform/SkSLEliminateDeadLocalVariables.cpp
+++ b/src/sksl/transform/SkSLEliminateDeadLocalVariables.cpp
@@ -10,9 +10,11 @@
 #include "include/private/SkSLProgramElement.h"
 #include "include/private/SkSLStatement.h"
 #include "include/private/SkTHash.h"
+#include "src/sksl/SkSLAnalysis.h"
 #include "src/sksl/SkSLCompiler.h"
 #include "src/sksl/SkSLProgramSettings.h"
 #include "src/sksl/analysis/SkSLProgramUsage.h"
+#include "src/sksl/ir/SkSLBinaryExpression.h"
 #include "src/sksl/ir/SkSLExpression.h"
 #include "src/sksl/ir/SkSLExpressionStatement.h"
 #include "src/sksl/ir/SkSLFunctionDefinition.h"
@@ -20,6 +22,7 @@
 #include "src/sksl/ir/SkSLProgram.h"
 #include "src/sksl/ir/SkSLVarDeclarations.h"
 #include "src/sksl/ir/SkSLVariable.h"
+#include "src/sksl/ir/SkSLVariableReference.h"
 #include "src/sksl/transform/SkSLProgramWriter.h"
 #include "src/sksl/transform/SkSLTransform.h"
 
@@ -42,8 +45,25 @@
         using ProgramWriter::visitProgramElement;
 
         bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
-            // We don't need to look inside expressions at all.
-            return false;
+            if (expr->is<BinaryExpression>()) {
+                // Search for expressions of the form `deadVar = anyExpression`.
+                BinaryExpression& binary = expr->as<BinaryExpression>();
+                if (VariableReference* assignedVar = binary.isAssignmentIntoVariable()) {
+                    if (fDeadVariables.contains(assignedVar->variable())) {
+                        // Replace `deadVar = anyExpression` with `anyExpression`.
+                        fUsage->remove(binary.left().get());
+                        expr = std::move(binary.right());
+
+                        // If `anyExpression` is now a lone ExpressionStatement, it's highly likely
+                        // that we can eliminate it entirely. This flag will let us know to check.
+                        fAssignmentWasEliminated = true;
+                    }
+                }
+            }
+            if (expr->is<VariableReference>()) {
+                SkASSERT(!fDeadVariables.contains(expr->as<VariableReference>().variable()));
+            }
+            return INHERITED::visitExpressionPtr(expr);
         }
 
         bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
@@ -54,6 +74,7 @@
                 SkASSERT(counts);
                 SkASSERT(counts->fDeclared);
                 if (CanEliminate(var, *counts)) {
+                    fDeadVariables.add(var);
                     if (var->initialValue()) {
                         // The variable has an initial-value expression, which might have side
                         // effects. ExpressionStatement::Make will preserve side effects, but
@@ -72,24 +93,35 @@
                 }
                 return false;
             }
-            return INHERITED::visitStatementPtr(stmt);
+
+            bool result = INHERITED::visitStatementPtr(stmt);
+
+            // If we eliminated an assignment above, we may have left behind an inert
+            // ExpressionStatement.
+            if (fAssignmentWasEliminated) {
+                fAssignmentWasEliminated = false;
+                if (stmt->is<ExpressionStatement>()) {
+                    ExpressionStatement& exprStmt = stmt->as<ExpressionStatement>();
+                    if (!Analysis::HasSideEffects(*exprStmt.expression())) {
+                        // The expression-statement was inert; eliminate it entirely.
+                        fUsage->remove(&exprStmt);
+                        stmt = Nop::Make();
+                    }
+                }
+            }
+
+            return result;
         }
 
         static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) {
-            if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) {
-                return false;
-            }
-            if (var->initialValue()) {
-                SkASSERT(counts.fWrite >= 1);
-                return counts.fWrite == 1;
-            } else {
-                return counts.fWrite == 0;
-            }
+            return counts.fDeclared && !counts.fRead && var->storage() == VariableStorage::kLocal;
         }
 
         bool fMadeChanges = false;
         const Context& fContext;
         ProgramUsage* fUsage;
+        SkTHashSet<const Variable*> fDeadVariables;
+        bool fAssignmentWasEliminated = false;
 
         using INHERITED = ProgramWriter;
     };
diff --git a/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl b/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
index eb9f621..8777f07 100644
--- a/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
+++ b/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
@@ -68,5 +68,6 @@
     var = _7_h3.xyzx * _7_h3.xyzx;
     vec4 _8_h4 = vec4(s.h4.y, 0.0, 0.0, 1.0);
     var = _8_h4 * _8_h4;
+    var.x += mat[0].x;
     return colorGreen;
 }
diff --git a/tests/sksl/inliner/TrivialArgumentsInlineDirectlyES3.glsl b/tests/sksl/inliner/TrivialArgumentsInlineDirectlyES3.glsl
index 31083e5..5f8714e 100644
--- a/tests/sksl/inliner/TrivialArgumentsInlineDirectlyES3.glsl
+++ b/tests/sksl/inliner/TrivialArgumentsInlineDirectlyES3.glsl
@@ -11,5 +11,6 @@
     var = vec4(_0_h) * vec4(_0_h);
     float _1_a[5] = float[5](1.0, 2.0, 3.0, 4.0, 5.0);
     var = vec4(_1_a[0], _1_a[1], _1_a[2], _1_a[3]) * _1_a[4];
+    i *= int(var.x);
     return colorGreen;
 }
diff --git a/tests/sksl/shared/Assignment.asm.frag b/tests/sksl/shared/Assignment.asm.frag
index 8ae8296..6ccbb63 100644
--- a/tests/sksl/shared/Assignment.asm.frag
+++ b/tests/sksl/shared/Assignment.asm.frag
@@ -22,7 +22,7 @@
 OpName %x "x"
 OpName %ai "ai"
 OpName %ai4 "ai4"
-OpName %ah2x4 "ah2x4"
+OpName %ah3x3 "ah3x3"
 OpName %af4 "af4"
 OpName %s "s"
 OpName %l "l"
@@ -62,7 +62,7 @@
 OpDecorate %130 RelaxedPrecision
 OpDecorate %131 RelaxedPrecision
 OpDecorate %134 RelaxedPrecision
-OpDecorate %138 RelaxedPrecision
+OpDecorate %144 RelaxedPrecision
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
@@ -150,7 +150,7 @@
 %x = OpVariable %_ptr_Function_v4float Function
 %ai = OpVariable %_ptr_Function__arr_int_int_1 Function
 %ai4 = OpVariable %_ptr_Function__arr_v4int_int_1 Function
-%ah2x4 = OpVariable %_ptr_Function__arr_mat3v3float_int_1 Function
+%ah3x3 = OpVariable %_ptr_Function__arr_mat3v3float_int_1 Function
 %af4 = OpVariable %_ptr_Function__arr_v4float_int_1 Function
 %s = OpVariable %_ptr_Function_S Function
 %l = OpVariable %_ptr_Function_float Function
@@ -166,7 +166,7 @@
 OpStore %72 %int_0
 %76 = OpAccessChain %_ptr_Function_v4int %ai4 %int_0
 OpStore %76 %45
-%80 = OpAccessChain %_ptr_Function_mat3v3float %ah2x4 %int_0
+%80 = OpAccessChain %_ptr_Function_mat3v3float %ah3x3 %int_0
 OpStore %80 %62
 %84 = OpAccessChain %_ptr_Function_v4float %af4 %int_0
 %85 = OpAccessChain %_ptr_Function_float %84 %int_0
@@ -208,7 +208,7 @@
 OpStore %116 %115
 %117 = OpAccessChain %_ptr_Function_v4float %af4 %int_0
 %118 = OpLoad %v4float %117
-%119 = OpAccessChain %_ptr_Function_v3float %ah2x4 %int_0 %int_0
+%119 = OpAccessChain %_ptr_Function_v3float %ah3x3 %int_0 %int_0
 %121 = OpLoad %v3float %119
 %122 = OpCompositeExtract %float %121 0
 %123 = OpVectorTimesScalar %v4float %118 %122
@@ -228,7 +228,14 @@
 %134 = OpLoad %float %l
 %135 = OpFMul %float %133 %134
 OpStore %132 %135
-%136 = OpAccessChain %_ptr_Uniform_v4float %19 %int_0
-%138 = OpLoad %v4float %136
-OpReturnValue %138
+%136 = OpAccessChain %_ptr_Function_v3float %f3x3 %int_0
+%137 = OpAccessChain %_ptr_Function_float %136 %int_0
+%138 = OpLoad %float %137
+%139 = OpAccessChain %_ptr_Function_float %s %int_0
+%140 = OpLoad %float %139
+%141 = OpFMul %float %138 %140
+OpStore %137 %141
+%142 = OpAccessChain %_ptr_Uniform_v4float %19 %int_0
+%144 = OpLoad %v4float %142
+OpReturnValue %144
 OpFunctionEnd
diff --git a/tests/sksl/shared/Assignment.glsl b/tests/sksl/shared/Assignment.glsl
index 8d4d3a20..d9cbe52 100644
--- a/tests/sksl/shared/Assignment.glsl
+++ b/tests/sksl/shared/Assignment.glsl
@@ -23,8 +23,8 @@
     ai[0] = 0;
     ivec4 ai4[1];
     ai4[0] = ivec4(1, 2, 3, 4);
-    mat3 ah2x4[1];
-    ah2x4[0] = mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+    mat3 ah3x3[1];
+    ah3x3[0] = mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
     vec4 af4[1];
     af4[0].x = 0.0;
     af4[0].ywxz = vec4(1.0);
@@ -42,9 +42,10 @@
     s.af[0] = 2.0;
     s.h4 = vec4(1.0);
     s.ah4[0] = vec4(2.0);
-    af4[0] *= ah2x4[0][0].x;
+    af4[0] *= ah3x3[0][0].x;
     i4.y *= i;
     x.y *= l;
     s.f *= l;
+    f3x3[0].x *= s.f;
     return colorGreen;
 }
diff --git a/tests/sksl/shared/Assignment.metal b/tests/sksl/shared/Assignment.metal
index b9f9b0f..32e19e1 100644
--- a/tests/sksl/shared/Assignment.metal
+++ b/tests/sksl/shared/Assignment.metal
@@ -37,8 +37,8 @@
     ai[0] = 0;
     array<int4, 1> ai4;
     ai4[0] = int4(1, 2, 3, 4);
-    array<half3x3, 1> ah2x4;
-    ah2x4[0] = half3x3(half3(1.0h, 2.0h, 3.0h), half3(4.0h, 5.0h, 6.0h), half3(7.0h, 8.0h, 9.0h));
+    array<half3x3, 1> ah3x3;
+    ah3x3[0] = half3x3(half3(1.0h, 2.0h, 3.0h), half3(4.0h, 5.0h, 6.0h), half3(7.0h, 8.0h, 9.0h));
     array<float4, 1> af4;
     af4[0].x = 0.0;
     af4[0].ywxz = float4(1.0);
@@ -56,10 +56,11 @@
     s.af[0] = 2.0;
     s.h4 = half4(1.0h);
     s.ah4[0] = half4(2.0h);
-    af4[0] *= float(ah2x4[0][0].x);
+    af4[0] *= float(ah3x3[0][0].x);
     i4.y = i4.y * i;
     x.y = x.y * l;
     s.f *= float(l);
+    f3x3[0].x = f3x3[0].x * s.f;
     _out.sk_FragColor = _uniforms.colorGreen;
     return _out;
 }
diff --git a/tests/sksl/shared/Discard.asm.frag b/tests/sksl/shared/Discard.asm.frag
index e78a58a..11bb1e2 100644
--- a/tests/sksl/shared/Discard.asm.frag
+++ b/tests/sksl/shared/Discard.asm.frag
@@ -6,12 +6,10 @@
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %sk_FragColor "sk_FragColor"
 OpName %main "main"
-OpName %x "x"
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
 OpDecorate %sk_FragColor Index 0
-OpDecorate %x RelaxedPrecision
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
@@ -21,11 +19,7 @@
 %sk_FragColor = OpVariable %_ptr_Output_v4float Output
 %void = OpTypeVoid
 %11 = OpTypeFunction %void
-%_ptr_Function_float = OpTypePointer Function %float
-%float_1 = OpConstant %float 1
 %main = OpFunction %void None %11
 %12 = OpLabel
-%x = OpVariable %_ptr_Function_float Function
-OpStore %x %float_1
 OpKill
 OpFunctionEnd
diff --git a/tests/sksl/shared/Discard.glsl b/tests/sksl/shared/Discard.glsl
index 2ec0746..4c0db9e 100644
--- a/tests/sksl/shared/Discard.glsl
+++ b/tests/sksl/shared/Discard.glsl
@@ -1,9 +1,7 @@
 
 out vec4 sk_FragColor;
 void main() {
-    float x;
     {
-        x = 1.0;
         discard;
     }
 }
diff --git a/tests/sksl/shared/Discard.metal b/tests/sksl/shared/Discard.metal
index 0b6cb56..97aec04 100644
--- a/tests/sksl/shared/Discard.metal
+++ b/tests/sksl/shared/Discard.metal
@@ -9,9 +9,7 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    half x;
     {
-        x = 1.0h;
         discard_fragment();
     }
     return _out;
diff --git a/tests/sksl/shared/Ossfuzz37677.asm.frag b/tests/sksl/shared/Ossfuzz37677.asm.frag
index 7cef52f..e2489c6 100644
--- a/tests/sksl/shared/Ossfuzz37677.asm.frag
+++ b/tests/sksl/shared/Ossfuzz37677.asm.frag
@@ -9,9 +9,6 @@
 OpMemberName %_UniformBuffer 0 "colorGreen"
 OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
-OpName %x "x"
-OpName %y "y"
-OpName %z "z"
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -21,8 +18,7 @@
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %_arr_int_int_1 ArrayStride 16
-OpDecorate %39 RelaxedPrecision
+OpDecorate %30 RelaxedPrecision
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
@@ -40,13 +36,9 @@
 %19 = OpConstantComposite %v2float %float_0 %float_0
 %_ptr_Function_v2float = OpTypePointer Function %v2float
 %23 = OpTypeFunction %v4float %_ptr_Function_v2float
-%int = OpTypeInt 32 1
-%int_1 = OpConstant %int 1
-%_arr_int_int_1 = OpTypeArray %int %int_1
-%_ptr_Function__arr_int_int_1 = OpTypePointer Function %_arr_int_int_1
-%_ptr_Function_int = OpTypePointer Function %int
-%int_0 = OpConstant %int 0
 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
 %_entrypoint_v = OpFunction %void None %15
 %16 = OpLabel
 %20 = OpVariable %_ptr_Function_v2float Function
@@ -58,15 +50,7 @@
 %main = OpFunction %v4float None %23
 %24 = OpFunctionParameter %_ptr_Function_v2float
 %25 = OpLabel
-%x = OpVariable %_ptr_Function__arr_int_int_1 Function
-%y = OpVariable %_ptr_Function_int Function
-%z = OpVariable %_ptr_Function_int Function
-OpStore %y %int_0
-OpStore %z %int_0
-OpStore %y %int_0
-%35 = OpAccessChain %_ptr_Function_int %x %int_0
-%36 = OpLoad %int %35
-%37 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%39 = OpLoad %v4float %37
-OpReturnValue %39
+%26 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%30 = OpLoad %v4float %26
+OpReturnValue %30
 OpFunctionEnd
diff --git a/tests/sksl/shared/Ossfuzz37677.glsl b/tests/sksl/shared/Ossfuzz37677.glsl
index 0c1488f..97458bf 100644
--- a/tests/sksl/shared/Ossfuzz37677.glsl
+++ b/tests/sksl/shared/Ossfuzz37677.glsl
@@ -2,9 +2,5 @@
 out vec4 sk_FragColor;
 uniform vec4 colorGreen;
 vec4 main() {
-    int x[1];
-    int y = 0;
-    int z = 0;
-    (0, x[y = z]);
     return colorGreen;
 }
diff --git a/tests/sksl/shared/Ossfuzz37677.metal b/tests/sksl/shared/Ossfuzz37677.metal
index b093aa3..67bb975 100644
--- a/tests/sksl/shared/Ossfuzz37677.metal
+++ b/tests/sksl/shared/Ossfuzz37677.metal
@@ -12,10 +12,6 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    array<int, 1> x;
-    int y = 0;
-    int z = 0;
-    (0, x[y = z]);
     _out.sk_FragColor = _uniforms.colorGreen;
     return _out;
 }
diff --git a/tests/sksl/shared/UnusedVariables.asm.frag b/tests/sksl/shared/UnusedVariables.asm.frag
index 862e19f..84946d9 100644
--- a/tests/sksl/shared/UnusedVariables.asm.frag
+++ b/tests/sksl/shared/UnusedVariables.asm.frag
@@ -8,7 +8,6 @@
 OpName %_entrypoint_v "_entrypoint_v"
 OpName %userfunc_ff "userfunc_ff"
 OpName %main "main"
-OpName %a "a"
 OpName %b "b"
 OpName %c "c"
 OpName %x "x"
@@ -17,11 +16,11 @@
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
 OpDecorate %sk_FragColor Index 0
-OpDecorate %67 RelaxedPrecision
-OpDecorate %69 RelaxedPrecision
+OpDecorate %63 RelaxedPrecision
+OpDecorate %65 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %71 RelaxedPrecision
 OpDecorate %72 RelaxedPrecision
-OpDecorate %75 RelaxedPrecision
-OpDecorate %76 RelaxedPrecision
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
@@ -67,63 +66,55 @@
 %main = OpFunction %v4float None %28
 %29 = OpFunctionParameter %_ptr_Function_v2float
 %30 = OpLabel
-%a = OpVariable %_ptr_Function_float Function
 %b = OpVariable %_ptr_Function_float Function
 %c = OpVariable %_ptr_Function_float Function
-%44 = OpVariable %_ptr_Function_float Function
-%47 = OpVariable %_ptr_Function_float Function
+%40 = OpVariable %_ptr_Function_float Function
+%43 = OpVariable %_ptr_Function_float Function
 %x = OpVariable %_ptr_Function_int Function
 %d = OpVariable %_ptr_Function_float Function
-OpStore %a %float_1
 OpStore %b %float_2
 OpStore %c %float_3
-%37 = OpFAdd %float %float_3 %float_77
-OpStore %a %37
+%36 = OpFAdd %float %float_3 %float_77
+OpStore %b %36
 %38 = OpFAdd %float %float_3 %float_77
-OpStore %b %38
-%40 = OpFAdd %float %float_3 %float_77
-%39 = OpExtInst %float %1 Sin %40
-OpStore %a %39
+%37 = OpExtInst %float %1 Sin %38
+OpStore %b %37
+%39 = OpFAdd %float %float_3 %float_77
+OpStore %40 %39
+%41 = OpFunctionCall %float %userfunc_ff %40
 %42 = OpFAdd %float %float_3 %float_77
-%41 = OpExtInst %float %1 Sin %42
-OpStore %b %41
-%43 = OpFAdd %float %float_3 %float_77
-OpStore %44 %43
-%45 = OpFunctionCall %float %userfunc_ff %44
-OpStore %a %45
-%46 = OpFAdd %float %float_3 %float_77
-OpStore %47 %46
-%48 = OpFunctionCall %float %userfunc_ff %47
-OpStore %b %48
+OpStore %43 %42
+%44 = OpFunctionCall %float %userfunc_ff %43
+OpStore %b %44
 OpStore %x %int_0
-OpBranch %53
+OpBranch %49
+%49 = OpLabel
+OpLoopMerge %53 %52 None
+OpBranch %50
+%50 = OpLabel
+%54 = OpLoad %int %x
+%56 = OpSLessThan %bool %54 %int_1
+OpBranchConditional %56 %51 %53
+%51 = OpLabel
+OpBranch %52
+%52 = OpLabel
+%57 = OpLoad %int %x
+%58 = OpIAdd %int %57 %int_1
+OpStore %x %58
+OpBranch %49
 %53 = OpLabel
-OpLoopMerge %57 %56 None
-OpBranch %54
-%54 = OpLabel
-%58 = OpLoad %int %x
-%60 = OpSLessThan %bool %58 %int_1
-OpBranchConditional %60 %55 %57
-%55 = OpLabel
-OpBranch %56
-%56 = OpLabel
-%61 = OpLoad %int %x
-%62 = OpIAdd %int %61 %int_1
-OpStore %x %62
-OpBranch %53
-%57 = OpLabel
-%64 = OpLoad %float %c
-OpStore %d %64
+%60 = OpLoad %float %c
+OpStore %d %60
 OpStore %b %float_3
-%65 = OpFAdd %float %64 %float_1
-OpStore %d %65
-%66 = OpFOrdEqual %bool %float_3 %float_2
-%67 = OpSelect %float %66 %float_1 %float_0
-%69 = OpSelect %float %true %float_1 %float_0
-%71 = OpFOrdEqual %bool %65 %float_5
-%72 = OpSelect %float %71 %float_1 %float_0
-%74 = OpFOrdEqual %bool %65 %float_4
-%75 = OpSelect %float %74 %float_1 %float_0
-%76 = OpCompositeConstruct %v4float %67 %69 %72 %75
-OpReturnValue %76
+%61 = OpFAdd %float %60 %float_1
+OpStore %d %61
+%62 = OpFOrdEqual %bool %float_3 %float_2
+%63 = OpSelect %float %62 %float_1 %float_0
+%65 = OpSelect %float %true %float_1 %float_0
+%67 = OpFOrdEqual %bool %61 %float_5
+%68 = OpSelect %float %67 %float_1 %float_0
+%70 = OpFOrdEqual %bool %61 %float_4
+%71 = OpSelect %float %70 %float_1 %float_0
+%72 = OpCompositeConstruct %v4float %63 %65 %68 %71
+OpReturnValue %72
 OpFunctionEnd
diff --git a/tests/sksl/shared/UnusedVariables.glsl b/tests/sksl/shared/UnusedVariables.glsl
index e602ffd..a04adb9 100644
--- a/tests/sksl/shared/UnusedVariables.glsl
+++ b/tests/sksl/shared/UnusedVariables.glsl
@@ -4,14 +4,11 @@
     return v + 1.0;
 }
 vec4 main() {
-    float a = 1.0;
     float b = 2.0;
     float c = 3.0;
-    a = c + 77.0;
     b = c + 77.0;
-    a = sin(c + 77.0);
     b = sin(c + 77.0);
-    a = userfunc_ff(c + 77.0);
+    userfunc_ff(c + 77.0);
     b = userfunc_ff(c + 77.0);
     for (int x = 0;x < 1; ++x) {
         continue;
diff --git a/tests/sksl/shared/UnusedVariables.metal b/tests/sksl/shared/UnusedVariables.metal
index c855e70..74b96aa 100644
--- a/tests/sksl/shared/UnusedVariables.metal
+++ b/tests/sksl/shared/UnusedVariables.metal
@@ -12,14 +12,11 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    float a = 1.0;
     float b = 2.0;
     float c = 3.0;
-    a = c + 77.0;
     b = c + 77.0;
-    a = sin(c + 77.0);
     b = sin(c + 77.0);
-    a = userfunc_ff(c + 77.0);
+    userfunc_ff(c + 77.0);
     b = userfunc_ff(c + 77.0);
     for (int x = 0;x < 1; ++x) {
         continue;
diff --git a/tests/sksl/spirv/ConstantVectorize.asm.frag b/tests/sksl/spirv/ConstantVectorize.asm.frag
index e81718c..e2489c6 100644
--- a/tests/sksl/spirv/ConstantVectorize.asm.frag
+++ b/tests/sksl/spirv/ConstantVectorize.asm.frag
@@ -9,8 +9,6 @@
 OpMemberName %_UniformBuffer 0 "colorGreen"
 OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
-OpName %a "a"
-OpName %b "b"
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -20,7 +18,7 @@
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %38 RelaxedPrecision
+OpDecorate %30 RelaxedPrecision
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
@@ -38,8 +36,6 @@
 %19 = OpConstantComposite %v2float %float_0 %float_0
 %_ptr_Function_v2float = OpTypePointer Function %v2float
 %23 = OpTypeFunction %v4float %_ptr_Function_v2float
-%float_3 = OpConstant %float 3
-%30 = OpConstantComposite %v2float %float_3 %float_3
 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
@@ -54,16 +50,7 @@
 %main = OpFunction %v4float None %23
 %24 = OpFunctionParameter %_ptr_Function_v2float
 %25 = OpLabel
-%a = OpVariable %_ptr_Function_v2float Function
-%b = OpVariable %_ptr_Function_v2float Function
-%28 = OpLoad %v2float %24
-%27 = OpExtInst %v2float %1 FMax %28 %30
-OpStore %a %27
-%33 = OpLoad %v2float %24
-%32 = OpExtInst %v2float %1 FMin %33 %30
-OpStore %b %32
-OpStore %a %32
-%34 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%38 = OpLoad %v4float %34
-OpReturnValue %38
+%26 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%30 = OpLoad %v4float %26
+OpReturnValue %30
 OpFunctionEnd