Split sequence operator when necessary

Split sequence operators if some of their operands generate statements
in subsequent AST transformations to guarantee the right order of
execution. For now, this is supported for expressions that return
arrays and unfolded short-circuiting operators, which is enough to get
WebGL 2 tests passing. A trickier corner case with dynamic indexing of
vectors as an l-value is left to be addressed later.

BUG=angleproject:1341
TEST=angle_end2end_tests, WebGL 2 conformance test:
     conformance2/glsl3/array-in-complex-expression.html

Change-Id: I9301edd3366be7607a8aa4c42a5ec13928749e10
Reviewed-on: https://chromium-review.googlesource.com/361694
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 8736e93..b4c53f3 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -436,6 +436,18 @@
 
 class GLSLTest_ES3 : public GLSLTest
 {
+    void SetUp() override
+    {
+        ANGLETest::SetUp();
+
+        mSimpleVSSource =
+            "#version 300 es\n"
+            "in vec4 inputAttribute;"
+            "void main()"
+            "{"
+            "    gl_Position = inputAttribute;"
+            "}";
+    }
 };
 
 TEST_P(GLSLTest, NamelessScopedStructs)
@@ -1888,6 +1900,59 @@
     EXPECT_NE(0u, program);
 }
 
+// Sequence operator evaluates operands from left to right (ESSL 3.00 section 5.9).
+// The function call that returns the array needs to be evaluated after ++j for the expression to
+// return the correct value (true).
+TEST_P(GLSLTest_ES3, SequenceOperatorEvaluationOrderArray)
+{
+    const std::string &fragmentShaderSource =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "out vec4 my_FragColor; \n"
+        "int[2] func(int param) {\n"
+        "    return int[2](param, param);\n"
+        "}\n"
+        "void main() {\n"
+        "    int a[2]; \n"
+        "    for (int i = 0; i < 2; ++i) {\n"
+        "        a[i] = 1;\n"
+        "    }\n"
+        "    int j = 0; \n"
+        "    bool result = ((++j), (a == func(j)));\n"
+        "    my_FragColor = vec4(0.0, (result ? 1.0 : 0.0), 0.0, 1.0);\n"
+        "}\n";
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    ASSERT_NE(0u, program);
+
+    drawQuad(program, "inputAttribute", 0.5f);
+
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Sequence operator evaluates operands from left to right (ESSL 3.00 section 5.9).
+// The short-circuiting expression needs to be evaluated after ++j for the expression to return the
+// correct value (true).
+TEST_P(GLSLTest_ES3, SequenceOperatorEvaluationOrderShortCircuit)
+{
+    const std::string &fragmentShaderSource =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "out vec4 my_FragColor; \n"
+        "void main() {\n"
+        "    int j = 0; \n"
+        "    bool result = ((++j), (j == 1 ? true : (++j == 3)));\n"
+        "    my_FragColor = vec4(0.0, ((result && j == 1) ? 1.0 : 0.0), 0.0, 1.0);\n"
+        "}\n";
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    ASSERT_NE(0u, program);
+
+    drawQuad(program, "inputAttribute", 0.5f);
+
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
 ANGLE_INSTANTIATE_TEST(GLSLTest,
                        ES2_D3D9(),