Add WGSL support for comma-expressions.

We can now use `assembleExpression` to cause side effects from the
left-hand side to occur, and then just discard the result.

Change-Id: I9e52110879e0916f7f9dce1257c62e04603aa3c1
Bug: skia:13092
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/706976
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Arman Uguray <armansito@google.com>
Commit-Queue: Arman Uguray <armansito@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 8a51c77..ec324e7 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -404,6 +404,8 @@
   "shared/ArrayFollowedByScalar.sksl",
   "shared/ArrayIndexTypes.sksl",
   "shared/ArrayTypes.sksl",
+  "shared/CommaMixedTypes.sksl",
+  "shared/CommaSideEffects.sksl",
   "shared/ConstArray.sksl",
   "shared/ConstantIf.sksl",
   "shared/FunctionAnonymousParameters.sksl",
@@ -414,6 +416,7 @@
   "shared/IntegerDivisionES3.sksl",
   "shared/LogicalAndShortCircuit.sksl",
   "shared/LogicalOrShortCircuit.sksl",
+  "shared/Matrices.sksl",
   "shared/MatrixConstructorsES2.sksl",
   "shared/MatrixConstructorsES3.sksl",
   "shared/MatrixEquality.sksl",
@@ -452,7 +455,6 @@
   "wgsl/MainDoesNotHaveFragCoordParameter.sksl",
   "wgsl/MainHasFragCoordParameter.sksl",
   "wgsl/MainHasVoidReturn.sksl",
-  "wgsl/Matrices.sksl",
   "wgsl/MatrixConstructorDiagonal.sksl",
   "wgsl/OutParams.sksl",
   "wgsl/TernaryThenShortCircuit.sksl",
diff --git a/resources/sksl/BUILD.bazel b/resources/sksl/BUILD.bazel
index fcc6177..ff45544 100644
--- a/resources/sksl/BUILD.bazel
+++ b/resources/sksl/BUILD.bazel
@@ -1064,7 +1064,6 @@
         "wgsl/MainDoesNotHaveFragCoordParameter.sksl",
         "wgsl/MainHasFragCoordParameter.sksl",
         "wgsl/MainHasVoidReturn.sksl",
-        "wgsl/Matrices.sksl",
         "wgsl/MatrixConstructorDiagonal.sksl",
         "wgsl/OutParams.sksl",
         "wgsl/TernaryThenShortCircuit.sksl",
@@ -1082,6 +1081,8 @@
         "shared/ArrayFollowedByScalar.sksl",
         "shared/ArrayIndexTypes.sksl",
         "shared/ArrayTypes.sksl",
+        "shared/CommaMixedTypes.sksl",
+        "shared/CommaSideEffects.sksl",
         "shared/ConstArray.sksl",
         "shared/ConstantIf.sksl",
         "shared/FunctionAnonymousParameters.sksl",
@@ -1092,6 +1093,7 @@
         "shared/IntegerDivisionES3.sksl",
         "shared/LogicalAndShortCircuit.sksl",
         "shared/LogicalOrShortCircuit.sksl",
+        "shared/Matrices.sksl",
         "shared/MatrixConstructorsES2.sksl",
         "shared/MatrixConstructorsES3.sksl",
         "shared/MatrixEquality.sksl",
diff --git a/resources/sksl/wgsl/Matrices.sksl b/resources/sksl/wgsl/Matrices.sksl
deleted file mode 100644
index edfefc2..0000000
--- a/resources/sksl/wgsl/Matrices.sksl
+++ /dev/null
@@ -1,90 +0,0 @@
-// TODO(skia:13902): Remove this test in favor of shared/Matrices.sksl when WGSL codegen can handle
-// the comma-separated statement syntax (exercised by the `test_comma()` function in that file).
-
-uniform half4 colorGreen, colorRed;
-
-bool test_float() {
-    bool ok = true;
-
-    float2x2 m1 = float2x2(float4(1, 2, 3, 4));
-    ok = ok && (m1 == float2x2(1, 2, 3, 4));
-
-    // This generates {5, 0, 0, 5} on some Radeon GPUs.
-//    float2x2 m2 = float2x2(float4(5));
-//    ok = ok && (m2 == float2x2(5, 5, 5, 5));
-
-    float2x2 m3 = float2x2(m1);
-    ok = ok && (m3 == float2x2(1, 2, 3, 4));
-
-    float2x2 m4 = float2x2(6);
-    ok = ok && (m4 == float2x2(6, 0, 0, 6));
-
-    m3 *= m4;
-    ok = ok && (m3 == float2x2(6, 12, 18, 24));
-
-    float2x2 m5 = float2x2(m1[1][1]);
-    ok = ok && (m5 == float2x2(4, 0, 0, 4));
-
-    m1 += m5;
-    ok = ok && (m1 == float2x2(5, 2, 3, 8));
-
-    float2x2 m7 = float2x2(5, float3(6, 7, 8));
-    ok = ok && (m7 == float2x2(5, 6, 7, 8));
-
-    float3x3 m9 = float3x3(9);
-    ok = ok && (m9 == float3x3(9, 0, 0, 0, 9, 0, 0, 0, 9));
-
-    float4x4 m10 = float4x4(11);
-    ok = ok && (m10 == float4x4(11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11));
-
-    float4x4 m11 = float4x4(20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20);
-    m11 -= m10;
-    ok = ok && (m11 == float4x4(9, 20, 20, 20, 20, 9, 20, 20, 20, 20, 9, 20, 20, 20, 20, 9));
-
-    return ok;
-}
-
-bool test_half() {
-    bool ok = true;
-
-    half2x2 m1 = half2x2(half4(1, 2, 3, 4));
-    ok = ok && (m1 == half2x2(1, 2, 3, 4));
-
-    // This generates {5, 0, 0, 5} on some Radeon GPUs.
-//    half2x2 m2 = half2x2(half4(5));
-//    ok = ok && (m2 == half2x2(5, 5, 5, 5));
-
-    half2x2 m3 = half2x2(m1);
-    ok = ok && (m3 == half2x2(1, 2, 3, 4));
-
-    half2x2 m4 = half2x2(6);
-    ok = ok && (m4 == half2x2(6, 0, 0, 6));
-
-    m3 *= m4;
-    ok = ok && (m3 == half2x2(6, 12, 18, 24));
-
-    half2x2 m5 = half2x2(m1[1][1]);
-    ok = ok && (m5 == half2x2(4, 0, 0, 4));
-
-    m1 += m5;
-    ok = ok && (m1 == half2x2(5, 2, 3, 8));
-
-    half2x2 m7 = half2x2(5, half3(6, 7, 8));
-    ok = ok && (m7 == half2x2(5, 6, 7, 8));
-
-    half3x3 m9 = half3x3(9);
-    ok = ok && (m9 == half3x3(9, 0, 0, 0, 9, 0, 0, 0, 9));
-
-    half4x4 m10 = half4x4(11);
-    ok = ok && (m10 == half4x4(11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11));
-
-    half4x4 m11 = half4x4(20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20);
-    m11 -= m10;
-    ok = ok && (m11 == half4x4(9, 20, 20, 20, 20, 9, 20, 20, 20, 20, 9, 20, 20, 20, 20, 9));
-
-    return ok;
-}
-
-half4 main(float2 coords) {
-    return test_float() && test_half() ? colorGreen : colorRed;
-}
diff --git a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
index 043d487..7cb468c 100644
--- a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
@@ -1177,6 +1177,15 @@
         return expr;
     }
 
+    // Handle comma-expressions.
+    if (op.kind() == OperatorKind::COMMA) {
+        // The result from the left-expression is ignored, but its side effects must occur.
+        this->assembleExpression(left, Precedence::kStatement);
+
+        // Evaluate the right side normally.
+        return this->assembleExpression(right, parentPrecedence);
+    }
+
     // Handle assignment-expressions.
     if (op.isAssignment()) {
         std::unique_ptr<LValue> lvalue = this->makeLValue(left);
diff --git a/tests/sksl/shared/CommaMixedTypes.wgsl b/tests/sksl/shared/CommaMixedTypes.wgsl
new file mode 100644
index 0000000..ae2a6e7
--- /dev/null
+++ b/tests/sksl/shared/CommaMixedTypes.wgsl
@@ -0,0 +1,28 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+struct _GlobalUniforms {
+    colorGreen: vec4<f32>,
+    unknownInput: f32,
+};
+@binding(0) @group(0) var<uniform> _globalUniforms: _GlobalUniforms;
+fn mat2x2f32_diagonal(x: f32) -> mat2x2<f32> {
+    return mat2x2<f32>(x, 0.0, 0.0, x);
+}
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var result: vec4<f32>;
+    result.x = _globalUniforms.colorGreen.x;
+    result.y = _globalUniforms.colorGreen.y;
+    result.z = _globalUniforms.colorGreen.z;
+    result.w = _globalUniforms.colorGreen.w;
+    return result;
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}
diff --git a/tests/sksl/shared/CommaSideEffects.wgsl b/tests/sksl/shared/CommaSideEffects.wgsl
new file mode 100644
index 0000000..4f0dec1
--- /dev/null
+++ b/tests/sksl/shared/CommaSideEffects.wgsl
@@ -0,0 +1,42 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+struct _GlobalUniforms {
+    colorRed: vec4<f32>,
+    colorGreen: vec4<f32>,
+    colorWhite: vec4<f32>,
+    colorBlack: vec4<f32>,
+};
+@binding(0) @group(0) var<uniform> _globalUniforms: _GlobalUniforms;
+fn _outParamHelper_0_setToColorBlack_vh4(d: ptr<function, vec4<f32>>) {
+    var _var0: vec4<f32>;
+    setToColorBlack_vh4(&_var0);
+    (*d) = _var0;
+}
+fn setToColorBlack_vh4(x: ptr<function, vec4<f32>>) {
+    (*x) = _globalUniforms.colorBlack;
+}
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var a: vec4<f32>;
+    var b: vec4<f32>;
+    var c: vec4<f32>;
+    var d: vec4<f32>;
+    b = _globalUniforms.colorRed;
+    c = _globalUniforms.colorGreen;
+    _outParamHelper_0_setToColorBlack_vh4(&d);
+    a = _globalUniforms.colorWhite;
+    a = a * a;
+    b = b * b;
+    c = c * c;
+    d = d * d;
+    return select(_globalUniforms.colorRed, _globalUniforms.colorGreen, vec4<bool>(((all(a == _globalUniforms.colorWhite) && all(b == _globalUniforms.colorRed)) && all(c == _globalUniforms.colorGreen)) && all(d == _globalUniforms.colorBlack)));
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}
diff --git a/tests/sksl/wgsl/Matrices.wgsl b/tests/sksl/shared/Matrices.wgsl
similarity index 91%
rename from tests/sksl/wgsl/Matrices.wgsl
rename to tests/sksl/shared/Matrices.wgsl
index 5df1caf..25a3b1a 100644
--- a/tests/sksl/wgsl/Matrices.wgsl
+++ b/tests/sksl/shared/Matrices.wgsl
@@ -59,6 +59,13 @@
     ok = ok && mat4x4f32_eq_mat4x4f32(m11, mat4x4<f32>(vec4<f32>(9.0, 20.0, 20.0, 20.0), vec4<f32>(20.0, 9.0, 20.0, 20.0), vec4<f32>(20.0, 20.0, 9.0, 20.0), vec4<f32>(20.0, 20.0, 20.0, 9.0)));
     return ok;
 }
+fn test_comma_b() -> bool {
+    var x: mat2x2<f32>;
+    var y: mat2x2<f32>;
+    x = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
+    y = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
+    return mat2x2f32_eq_mat2x2f32(x, y);
+}
 fn main(coords: vec2<f32>) -> vec4<f32> {
     var _0_ok: bool = true;
     var _1_m1: mat2x2<f32> = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
@@ -78,9 +85,16 @@
     _0_ok = _0_ok && mat4x4f32_eq_mat4x4f32(_8_m11, mat4x4<f32>(vec4<f32>(9.0, 20.0, 20.0, 20.0), vec4<f32>(20.0, 9.0, 20.0, 20.0), vec4<f32>(20.0, 20.0, 9.0, 20.0), vec4<f32>(20.0, 20.0, 20.0, 9.0)));
     var _skTemp0: vec4<f32>;
     var _skTemp1: bool;
+    var _skTemp2: bool;
     if _0_ok {
-        let _skTemp2 = test_half_b();
-        _skTemp1 = _skTemp2;
+        let _skTemp3 = test_half_b();
+        _skTemp2 = _skTemp3;
+    } else {
+        _skTemp2 = false;
+    }
+    if _skTemp2 {
+        let _skTemp4 = test_comma_b();
+        _skTemp1 = _skTemp4;
     } else {
         _skTemp1 = false;
     }