Set proper precision on loop index for variable init

Previously the index variable was missing a precision. This may have
been behind loop-based init failing on some Android platforms.

BUG=chromium:735497
TEST=angle_unittests

Change-Id: I0307891dfb2edf6c52efd5b495f602b380263d65
Reviewed-on: https://chromium-review.googlesource.com/822413
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index abb60cc..e4559aa 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -602,7 +602,10 @@
     bool initializeLocalsAndGlobals =
         (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && !IsOutputHLSL(getOutputType());
     bool canUseLoopsToInitialize = !(compileOptions & SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES);
-    DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize, &symbolTable);
+    bool highPrecisionSupported =
+        shaderType != GL_FRAGMENT_SHADER || compileResources.FragmentPrecisionHigh;
+    DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize,
+                            highPrecisionSupported, &symbolTable);
 
     if (initializeLocalsAndGlobals)
     {
@@ -623,7 +626,7 @@
         }
 
         InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize,
-                                      &getSymbolTable());
+                                      highPrecisionSupported, &getSymbolTable());
     }
 
     if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE))
@@ -1067,7 +1070,7 @@
     sh::ShaderVariable var(GL_FLOAT_VEC4);
     var.name = "gl_Position";
     list.push_back(var);
-    InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false);
+    InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false, false);
 }
 
 void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
@@ -1109,7 +1112,7 @@
             list.push_back(var);
         }
     }
-    InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false);
+    InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false, false);
 }
 
 const TExtensionBehavior &TCompiler::getExtensionBehavior() const
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index 67d51ea..1cef1a5 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -30,6 +30,7 @@
 void GetDeferredInitializers(TIntermDeclaration *declaration,
                              bool initializeUninitializedGlobals,
                              bool canUseLoopsToInitialize,
+                             bool highPrecisionSupported,
                              TIntermSequence *deferredInitializersOut,
                              TSymbolTable *symbolTable)
 {
@@ -83,8 +84,8 @@
 
         if (symbolNode->getQualifier() == EvqGlobal && symbolNode->getSymbol() != "")
         {
-            TIntermSequence *initCode =
-                CreateInitCode(symbolNode, canUseLoopsToInitialize, symbolTable);
+            TIntermSequence *initCode = CreateInitCode(symbolNode, canUseLoopsToInitialize,
+                                                       highPrecisionSupported, symbolTable);
             deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(),
                                             initCode->end());
         }
@@ -121,6 +122,7 @@
 void DeferGlobalInitializers(TIntermBlock *root,
                              bool initializeUninitializedGlobals,
                              bool canUseLoopsToInitialize,
+                             bool highPrecisionSupported,
                              TSymbolTable *symbolTable)
 {
     TIntermSequence *deferredInitializers = new TIntermSequence();
@@ -133,7 +135,8 @@
         if (declaration)
         {
             GetDeferredInitializers(declaration, initializeUninitializedGlobals,
-                                    canUseLoopsToInitialize, deferredInitializers, symbolTable);
+                                    canUseLoopsToInitialize, highPrecisionSupported,
+                                    deferredInitializers, symbolTable);
         }
     }
 
diff --git a/src/compiler/translator/DeferGlobalInitializers.h b/src/compiler/translator/DeferGlobalInitializers.h
index 86930a5..0ca2c4d 100644
--- a/src/compiler/translator/DeferGlobalInitializers.h
+++ b/src/compiler/translator/DeferGlobalInitializers.h
@@ -25,6 +25,7 @@
 void DeferGlobalInitializers(TIntermBlock *root,
                              bool initializeUninitializedGlobals,
                              bool canUseLoopsToInitialize,
+                             bool highPrecisionSupported,
                              TSymbolTable *symbolTable);
 
 }  // namespace sh
diff --git a/src/compiler/translator/InitializeVariables.cpp b/src/compiler/translator/InitializeVariables.cpp
index aa1a042..86c3d23 100644
--- a/src/compiler/translator/InitializeVariables.cpp
+++ b/src/compiler/translator/InitializeVariables.cpp
@@ -22,11 +22,13 @@
 
 void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
                               bool canUseLoopsToInitialize,
+                              bool highPrecisionSupported,
                               TIntermSequence *initSequenceOut,
                               TSymbolTable *symbolTable);
 
 void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
                                bool canUseLoopsToInitialize,
+                               bool highPrecisionSupported,
                                TIntermSequence *initSequenceOut,
                                TSymbolTable *symbolTable);
 
@@ -38,19 +40,20 @@
 
 void AddZeroInitSequence(const TIntermTyped *initializedNode,
                          bool canUseLoopsToInitialize,
+                         bool highPrecisionSupported,
                          TIntermSequence *initSequenceOut,
                          TSymbolTable *symbolTable)
 {
     if (initializedNode->isArray())
     {
-        AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, initSequenceOut,
-                                 symbolTable);
+        AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported,
+                                 initSequenceOut, symbolTable);
     }
     else if (initializedNode->getType().isStructureContainingArrays() ||
              initializedNode->getType().isNamelessStruct())
     {
-        AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, initSequenceOut,
-                                  symbolTable);
+        AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported,
+                                  initSequenceOut, symbolTable);
     }
     else
     {
@@ -60,6 +63,7 @@
 
 void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
                                bool canUseLoopsToInitialize,
+                               bool highPrecisionSupported,
                                TIntermSequence *initSequenceOut,
                                TSymbolTable *symbolTable)
 {
@@ -72,12 +76,14 @@
         // Structs can't be defined inside structs, so the type of a struct field can't be a
         // nameless struct.
         ASSERT(!element->getType().isNamelessStruct());
-        AddZeroInitSequence(element, canUseLoopsToInitialize, initSequenceOut, symbolTable);
+        AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported,
+                            initSequenceOut, symbolTable);
     }
 }
 
 void AddArrayZeroInitStatementList(const TIntermTyped *initializedNode,
                                    bool canUseLoopsToInitialize,
+                                   bool highPrecisionSupported,
                                    TIntermSequence *initSequenceOut,
                                    TSymbolTable *symbolTable)
 {
@@ -85,20 +91,24 @@
     {
         TIntermBinary *element =
             new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
-        AddZeroInitSequence(element, canUseLoopsToInitialize, initSequenceOut, symbolTable);
+        AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported,
+                            initSequenceOut, symbolTable);
     }
 }
 
 void AddArrayZeroInitForLoop(const TIntermTyped *initializedNode,
+                             bool highPrecisionSupported,
                              TIntermSequence *initSequenceOut,
                              TSymbolTable *symbolTable)
 {
     ASSERT(initializedNode->isArray());
     TSymbolUniqueId indexSymbol(symbolTable);
 
-    TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexSymbol, TType(EbtInt), EvqTemporary);
+    TType indexType(EbtInt, highPrecisionSupported ? EbpHigh : EbpMedium);
+
+    TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexSymbol, indexType, EvqTemporary);
     TIntermDeclaration *indexInit =
-        CreateTempInitDeclarationNode(indexSymbol, CreateZeroNode(TType(EbtInt)), EvqTemporary);
+        CreateTempInitDeclarationNode(indexSymbol, CreateZeroNode(indexType), EvqTemporary);
     TIntermConstantUnion *arraySizeNode = CreateIndexNode(initializedNode->getOutermostArraySize());
     TIntermBinary *indexSmallerThanSize =
         new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode);
@@ -109,7 +119,7 @@
 
     TIntermBinary *element = new TIntermBinary(EOpIndexIndirect, initializedNode->deepCopy(),
                                                indexSymbolNode->deepCopy());
-    AddZeroInitSequence(element, true, forLoopBodySeq, symbolTable);
+    AddZeroInitSequence(element, true, highPrecisionSupported, forLoopBodySeq, symbolTable);
 
     TIntermLoop *forLoop =
         new TIntermLoop(ELoopFor, indexInit, indexSmallerThanSize, indexIncrement, forLoopBody);
@@ -118,6 +128,7 @@
 
 void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
                               bool canUseLoopsToInitialize,
+                              bool highPrecisionSupported,
                               TIntermSequence *initSequenceOut,
                               TSymbolTable *symbolTable)
 {
@@ -135,12 +146,13 @@
     {
         // Fragment outputs should not be indexed by non-constant indices.
         // Also it doesn't make sense to use loops to initialize very small arrays.
-        AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize, initSequenceOut,
-                                      symbolTable);
+        AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize,
+                                      highPrecisionSupported, initSequenceOut, symbolTable);
     }
     else
     {
-        AddArrayZeroInitForLoop(initializedNode, initSequenceOut, symbolTable);
+        AddArrayZeroInitForLoop(initializedNode, highPrecisionSupported, initSequenceOut,
+                                symbolTable);
     }
 }
 
@@ -149,7 +161,8 @@
                     TSymbolTable *symbolTable,
                     int shaderVersion,
                     const TExtensionBehavior &extensionBehavior,
-                    bool canUseLoopsToInitialize)
+                    bool canUseLoopsToInitialize,
+                    bool highPrecisionSupported)
 {
     for (const auto &var : variables)
     {
@@ -183,8 +196,8 @@
         }
         ASSERT(initializedSymbol != nullptr);
 
-        TIntermSequence *initCode =
-            CreateInitCode(initializedSymbol, canUseLoopsToInitialize, symbolTable);
+        TIntermSequence *initCode = CreateInitCode(initializedSymbol, canUseLoopsToInitialize,
+                                                   highPrecisionSupported, symbolTable);
         mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
     }
 }
@@ -194,10 +207,12 @@
   public:
     InitializeLocalsTraverser(int shaderVersion,
                               TSymbolTable *symbolTable,
-                              bool canUseLoopsToInitialize)
+                              bool canUseLoopsToInitialize,
+                              bool highPrecisionSupported)
         : TIntermTraverser(true, false, false, symbolTable),
           mShaderVersion(shaderVersion),
-          mCanUseLoopsToInitialize(canUseLoopsToInitialize)
+          mCanUseLoopsToInitialize(canUseLoopsToInitialize),
+          mHighPrecisionSupported(highPrecisionSupported)
     {
     }
 
@@ -235,8 +250,8 @@
                     // this declarator.
                     ASSERT(node->getSequence()->size() == 1);
                     insertStatementsInParentBlock(
-                        TIntermSequence(),
-                        *CreateInitCode(symbol, mCanUseLoopsToInitialize, mSymbolTable));
+                        TIntermSequence(), *CreateInitCode(symbol, mCanUseLoopsToInitialize,
+                                                           mHighPrecisionSupported, mSymbolTable));
                 }
                 else
                 {
@@ -252,25 +267,30 @@
   private:
     int mShaderVersion;
     bool mCanUseLoopsToInitialize;
+    bool mHighPrecisionSupported;
 };
 
 }  // namespace anonymous
 
 TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
                                 bool canUseLoopsToInitialize,
+                                bool highPrecisionSupported,
                                 TSymbolTable *symbolTable)
 {
     TIntermSequence *initCode = new TIntermSequence();
-    AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, initCode, symbolTable);
+    AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, highPrecisionSupported,
+                        initCode, symbolTable);
     return initCode;
 }
 
 void InitializeUninitializedLocals(TIntermBlock *root,
                                    int shaderVersion,
                                    bool canUseLoopsToInitialize,
+                                   bool highPrecisionSupported,
                                    TSymbolTable *symbolTable)
 {
-    InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize);
+    InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize,
+                                        highPrecisionSupported);
     root->traverse(&traverser);
     traverser.updateTree();
 }
@@ -280,11 +300,12 @@
                          TSymbolTable *symbolTable,
                          int shaderVersion,
                          const TExtensionBehavior &extensionBehavior,
-                         bool canUseLoopsToInitialize)
+                         bool canUseLoopsToInitialize,
+                         bool highPrecisionSupported)
 {
     TIntermBlock *body = FindMainBody(root);
     InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior,
-                   canUseLoopsToInitialize);
+                   canUseLoopsToInitialize, highPrecisionSupported);
 }
 
 }  // namespace sh
diff --git a/src/compiler/translator/InitializeVariables.h b/src/compiler/translator/InitializeVariables.h
index 1a7b3c0..f9a83f1 100644
--- a/src/compiler/translator/InitializeVariables.h
+++ b/src/compiler/translator/InitializeVariables.h
@@ -25,12 +25,14 @@
 // may be an array, struct or any combination of these, as long as it contains only basic types.
 TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
                                 bool canUseLoopsToInitialize,
+                                bool highPrecisionSupported,
                                 TSymbolTable *symbolTable);
 
 // Initialize all uninitialized local variables, so that undefined behavior is avoided.
 void InitializeUninitializedLocals(TIntermBlock *root,
                                    int shaderVersion,
                                    bool canUseLoopsToInitialize,
+                                   bool highPrecisionSupported,
                                    TSymbolTable *symbolTable);
 
 // This function can initialize all the types that CreateInitCode is able to initialize. All
@@ -46,7 +48,8 @@
                          TSymbolTable *symbolTable,
                          int shaderVersion,
                          const TExtensionBehavior &extensionBehavior,
-                         bool canUseLoopsToInitialize);
+                         bool canUseLoopsToInitialize,
+                         bool highPrecisionSupported);
 
 }  // namespace sh