Remove dynamic indexing of matrices and vectors in HLSL

HLSL doesn't support dynamic indexing of matrices and vectors, so replace
that with helper functions that unroll dynamic indexing into switch/case
and static indexing.

Both the indexed vector/matrix expression and the index may have side
effects, and these will be evaluated correctly. If necessary, index
expressions that have side effects will be written to a temporary
variable that will replace the index.

Besides dEQP tests, this change is tested by a WebGL 2 conformance test.

In the case that a dynamic index is out-of-range, the base ESSL 3.00 spec
allows undefined behavior. KHR_robust_buffer_access_behavior adds the
requirement that program termination should not occur and that
out-of-range reads must return either a value from the active program's
memory or zero, and out-of-range writes should only affect the active
program's memory or do nothing. This patch clamps out-of-range indices so
that either the first or last item of the matrix/vector is accessed.

The code is not transformed in case the it fits within the limited subset
of ESSL 1.00 given in Appendix A of the spec. If the code isn't within
the restricted subset, even ESSL 1.00 shaders may require this
workaround.

BUG=angleproject:1116
TEST=dEQP-GLES3.functional.shaders.indexing.* (all pass after change)
     WebGL 2 conformance tests (glsl3/vector-dynamic-indexing.html)

Change-Id: I024722ef4ca1e14d5ad47fdc540397e18858bed6
Reviewed-on: https://chromium-review.googlesource.com/290515
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 187ad14..e9665f9 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -311,17 +311,13 @@
 
 bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
 {
-    TIntermSequence::size_type itPosition = 0;
-    for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
+    if (position > mSequence.size())
     {
-        if (itPosition == position)
-        {
-            mSequence.insert(it, insertions.begin(), insertions.end());
-            return true;
-        }
-        ++itPosition;
+        return false;
     }
-    return false;
+    auto it = mSequence.begin() + position;
+    mSequence.insert(it, insertions.begin(), insertions.end());
+    return true;
 }
 
 void TIntermAggregate::setPrecisionFromChildren()
@@ -2550,9 +2546,20 @@
     {
         const NodeInsertMultipleEntry &insertion = mInsertions[ii];
         ASSERT(insertion.parent);
-        bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
-        ASSERT(inserted);
-        UNUSED_ASSERTION_VARIABLE(inserted);
+        if (!insertion.insertionsAfter.empty())
+        {
+            bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
+                                                               insertion.insertionsAfter);
+            ASSERT(inserted);
+            UNUSED_ASSERTION_VARIABLE(inserted);
+        }
+        if (!insertion.insertionsBefore.empty())
+        {
+            bool inserted =
+                insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
+            ASSERT(inserted);
+            UNUSED_ASSERTION_VARIABLE(inserted);
+        }
     }
     for (size_t ii = 0; ii < mReplacements.size(); ++ii)
     {