translator: remove code related to for-loop unrolling

For loop unrolling is not used and causes the translator fuzzer to find
a hang when unrolling tons of nested loops (duh).
Also remove MMap.h which was unused.

This is essentially a revert of https://codereview.appspot.com/4331048

BUG=chromium:665255

Change-Id: Id6940f7e306d4ed53bc992f751e9ffe733190f17
Reviewed-on: https://chromium-review.googlesource.com/412023
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index de9d98f..e49196d 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -16,7 +16,6 @@
 #include "compiler/translator/DeferGlobalInitializers.h"
 #include "compiler/translator/EmulateGLFragColorBroadcast.h"
 #include "compiler/translator/EmulatePrecision.h"
-#include "compiler/translator/ForLoopUnroll.h"
 #include "compiler/translator/Initialize.h"
 #include "compiler/translator/InitializeParseContext.h"
 #include "compiler/translator/InitializeVariables.h"
@@ -370,26 +369,6 @@
             }
         }
 
-        // Unroll for-loop markup needs to happen after validateLimitations pass.
-        if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
-        {
-            ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex,
-                                       shouldRunLoopAndIndexingValidation(compileOptions));
-            root->traverse(&marker);
-        }
-        if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
-        {
-            ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex,
-                                       shouldRunLoopAndIndexingValidation(compileOptions));
-            root->traverse(&marker);
-            if (marker.samplerArrayIndexIsFloatLoopIndex())
-            {
-                infoSink.info.prefix(EPrefixError);
-                infoSink.info << "sampler array index is float loop index";
-                success = false;
-            }
-        }
-
         // Built-in function emulation needs to happen after validateLimitations pass.
         if (success)
         {
@@ -506,17 +485,6 @@
         compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
     }
 
-    ShCompileOptions unrollFlags =
-        SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX | SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
-    if ((compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) != 0 &&
-        (compileOptions & unrollFlags) != 0)
-    {
-        infoSink.info.prefix(EPrefixError);
-        infoSink.info
-            << "Unsupported compile flag combination: unroll & ADD_TRUE_TO_LOOP_CONDITION";
-        return false;
-    }
-
     TScopedPoolAllocator scopedAlloc(&allocator);
     TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
 
diff --git a/src/compiler/translator/ForLoopUnroll.cpp b/src/compiler/translator/ForLoopUnroll.cpp
deleted file mode 100644
index 58cce84..0000000
--- a/src/compiler/translator/ForLoopUnroll.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#include "compiler/translator/ForLoopUnroll.h"
-
-#include "compiler/translator/ValidateLimitations.h"
-#include "angle_gl.h"
-
-namespace sh
-{
-
-bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
-{
-    if (mUnrollCondition != kSamplerArrayIndex)
-        return true;
-
-    // If a sampler array index is also the loop index,
-    //   1) if the index type is integer, mark the loop for unrolling;
-    //   2) if the index type if float, set a flag to later fail compile.
-    switch (node->getOp())
-    {
-      case EOpIndexIndirect:
-        if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode())
-        {
-            TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode();
-            if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty())
-            {
-                mVisitSamplerArrayIndexNodeInsideLoop = true;
-                node->getRight()->traverse(this);
-                mVisitSamplerArrayIndexNodeInsideLoop = false;
-                // We have already visited all the children.
-                return false;
-            }
-        }
-        break;
-      default:
-        break;
-    }
-    return true;
-}
-
-bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
-{
-    bool canBeUnrolled = mHasRunLoopValidation;
-    if (!mHasRunLoopValidation)
-    {
-        canBeUnrolled = ValidateLimitations::IsLimitedForLoop(node);
-    }
-    if (mUnrollCondition == kIntegerIndex && canBeUnrolled)
-    {
-        // Check if loop index type is integer.
-        // This is called after ValidateLimitations pass, so the loop has the limited form specified
-        // in ESSL 1.00 appendix A.
-        TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
-        TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
-        if (symbol->getBasicType() == EbtInt)
-            node->setUnrollFlag(true);
-    }
-
-    TIntermNode *body = node->getBody();
-    if (body != nullptr)
-    {
-        if (canBeUnrolled)
-        {
-            mLoopStack.push(node);
-            body->traverse(this);
-            mLoopStack.pop();
-        }
-        else
-        {
-            body->traverse(this);
-        }
-    }
-    // The loop is fully processed - no need to visit children.
-    return false;
-}
-
-void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol)
-{
-    if (!mVisitSamplerArrayIndexNodeInsideLoop)
-        return;
-    TIntermLoop *loop = mLoopStack.findLoop(symbol);
-    if (loop)
-    {
-        switch (symbol->getBasicType())
-        {
-          case EbtFloat:
-            mSamplerArrayIndexIsFloatLoopIndex = true;
-            break;
-          case EbtInt:
-            loop->setUnrollFlag(true);
-            break;
-          default:
-            UNREACHABLE();
-        }
-    }
-}
-
-}  // namespace sh
diff --git a/src/compiler/translator/ForLoopUnroll.h b/src/compiler/translator/ForLoopUnroll.h
deleted file mode 100644
index cda89b2..0000000
--- a/src/compiler/translator/ForLoopUnroll.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#ifndef COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
-#define COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
-
-#include "compiler/translator/LoopInfo.h"
-
-namespace sh
-{
-
-// This class detects for-loops that needs to be unrolled.
-// Currently we support two unroll conditions:
-//   1) kForLoopWithIntegerIndex: unroll if the index type is integer.
-//   2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index
-//      is also the loop integer index, and reject and fail a compile
-//      where a sampler array index is also the loop float index.
-class ForLoopUnrollMarker : public TIntermTraverser
-{
-  public:
-    enum UnrollCondition
-    {
-        kIntegerIndex,
-        kSamplerArrayIndex
-    };
-
-    ForLoopUnrollMarker(UnrollCondition condition, bool hasRunLoopValidation)
-        : TIntermTraverser(true, false, false),
-          mUnrollCondition(condition),
-          mSamplerArrayIndexIsFloatLoopIndex(false),
-          mVisitSamplerArrayIndexNodeInsideLoop(false),
-          mHasRunLoopValidation(hasRunLoopValidation)
-    {
-    }
-
-    bool visitBinary(Visit, TIntermBinary *node) override;
-    bool visitLoop(Visit, TIntermLoop *node) override;
-    void visitSymbol(TIntermSymbol *node) override;
-
-    bool samplerArrayIndexIsFloatLoopIndex() const
-    {
-        return mSamplerArrayIndexIsFloatLoopIndex;
-    }
-
-  private:
-    UnrollCondition mUnrollCondition;
-    TLoopStack mLoopStack;
-    bool mSamplerArrayIndexIsFloatLoopIndex;
-    bool mVisitSamplerArrayIndexNodeInsideLoop;
-    bool mHasRunLoopValidation;
-};
-
-}  // namespace sh
-
-#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index 94811bd..50b6ff0 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -201,7 +201,7 @@
                 TIntermTyped *cond,
                 TIntermTyped *expr,
                 TIntermBlock *body)
-        : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
+        : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
     {
     }
 
@@ -219,17 +219,12 @@
     void setExpression(TIntermTyped *expression) { mExpr = expression; }
     void setBody(TIntermBlock *body) { mBody = body; }
 
-    void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
-    bool getUnrollFlag() const { return mUnrollFlag; }
-
   protected:
     TLoopType mType;
     TIntermNode *mInit;  // for-loop initialization
     TIntermTyped *mCond; // loop exit condition
     TIntermTyped *mExpr; // for-loop expression
     TIntermBlock *mBody;  // loop body
-
-    bool mUnrollFlag; // Whether the loop should be unrolled or not.
 };
 
 //
diff --git a/src/compiler/translator/LoopInfo.cpp b/src/compiler/translator/LoopInfo.cpp
deleted file mode 100644
index 48fa244..0000000
--- a/src/compiler/translator/LoopInfo.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-//
-// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#include "compiler/translator/LoopInfo.h"
-
-namespace sh
-{
-
-namespace
-{
-
-int EvaluateIntConstant(TIntermConstantUnion *node)
-{
-    ASSERT(node && node->getUnionArrayPointer());
-    return node->getIConst(0);
-}
-
-int GetLoopIntIncrement(TIntermLoop *node)
-{
-    TIntermNode *expr = node->getExpression();
-    // for expression has one of the following forms:
-    //     loop_index++
-    //     loop_index--
-    //     loop_index += constant_expression
-    //     loop_index -= constant_expression
-    //     ++loop_index
-    //     --loop_index
-    // The last two forms are not specified in the spec, but I am assuming
-    // its an oversight.
-    TIntermUnary *unOp = expr->getAsUnaryNode();
-    TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
-
-    TOperator op = EOpNull;
-    TIntermConstantUnion *incrementNode = NULL;
-    if (unOp)
-    {
-        op = unOp->getOp();
-    }
-    else if (binOp)
-    {
-        op = binOp->getOp();
-        ASSERT(binOp->getRight());
-        incrementNode = binOp->getRight()->getAsConstantUnion();
-        ASSERT(incrementNode);
-    }
-
-    int increment = 0;
-    // The operator is one of: ++ -- += -=.
-    switch (op)
-    {
-      case EOpPostIncrement:
-      case EOpPreIncrement:
-        ASSERT(unOp && !binOp);
-        increment = 1;
-        break;
-      case EOpPostDecrement:
-      case EOpPreDecrement:
-        ASSERT(unOp && !binOp);
-        increment = -1;
-        break;
-      case EOpAddAssign:
-        ASSERT(!unOp && binOp);
-        increment = EvaluateIntConstant(incrementNode);
-        break;
-      case EOpSubAssign:
-        ASSERT(!unOp && binOp);
-        increment = - EvaluateIntConstant(incrementNode);
-        break;
-      default:
-        UNREACHABLE();
-    }
-
-    return increment;
-}
-
-}  // namespace anonymous
-
-TLoopIndexInfo::TLoopIndexInfo()
-    : mId(-1),
-      mType(EbtVoid),
-      mInitValue(0),
-      mStopValue(0),
-      mIncrementValue(0),
-      mOp(EOpNull),
-      mCurrentValue(0)
-{
-}
-
-void TLoopIndexInfo::fillInfo(TIntermLoop *node)
-{
-    if (node == NULL)
-        return;
-
-    // Here we assume all the operations are valid, because the loop node is
-    // already validated in ValidateLimitations.
-    TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
-    TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
-    TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
-
-    mId = symbol->getId();
-    mType = symbol->getBasicType();
-
-    if (mType == EbtInt)
-    {
-        TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
-        mInitValue = EvaluateIntConstant(initNode);
-        mCurrentValue = mInitValue;
-        mIncrementValue = GetLoopIntIncrement(node);
-
-        TIntermBinary* binOp = node->getCondition()->getAsBinaryNode();
-        mStopValue = EvaluateIntConstant(
-            binOp->getRight()->getAsConstantUnion());
-        mOp = binOp->getOp();
-    }
-}
-
-bool TLoopIndexInfo::satisfiesLoopCondition() const
-{
-    // Relational operator is one of: > >= < <= == or !=.
-    switch (mOp)
-    {
-      case EOpEqual:
-        return (mCurrentValue == mStopValue);
-      case EOpNotEqual:
-        return (mCurrentValue != mStopValue);
-      case EOpLessThan:
-        return (mCurrentValue < mStopValue);
-      case EOpGreaterThan:
-        return (mCurrentValue > mStopValue);
-      case EOpLessThanEqual:
-        return (mCurrentValue <= mStopValue);
-      case EOpGreaterThanEqual:
-        return (mCurrentValue >= mStopValue);
-      default:
-        UNREACHABLE();
-        return false;
-    }
-}
-
-TLoopInfo::TLoopInfo()
-    : loop(NULL)
-{
-}
-
-TLoopInfo::TLoopInfo(TIntermLoop *node)
-    : loop(node)
-{
-    index.fillInfo(node);
-}
-
-TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol)
-{
-    if (!symbol)
-        return NULL;
-    for (iterator iter = begin(); iter != end(); ++iter)
-    {
-        if (iter->index.getId() == symbol->getId())
-            return iter->loop;
-    }
-    return NULL;
-}
-
-TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol)
-{
-    if (!symbol)
-        return NULL;
-    for (iterator iter = begin(); iter != end(); ++iter)
-    {
-        if (iter->index.getId() == symbol->getId())
-            return &(iter->index);
-    }
-    return NULL;
-}
-
-void TLoopStack::step()
-{
-    ASSERT(!empty());
-    rbegin()->index.step();
-}
-
-bool TLoopStack::satisfiesLoopCondition()
-{
-    ASSERT(!empty());
-    return rbegin()->index.satisfiesLoopCondition();
-}
-
-bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol)
-{
-    TIntermLoop *loop = findLoop(symbol);
-    return loop && loop->getUnrollFlag();
-}
-
-int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol)
-{
-    TLoopIndexInfo *info = getIndexInfo(symbol);
-    ASSERT(info);
-    return info->getCurrentValue();
-}
-
-void TLoopStack::push(TIntermLoop *loop)
-{
-    TLoopInfo info(loop);
-    push_back(info);
-}
-
-void TLoopStack::pop()
-{
-    pop_back();
-}
-
-}  // namespace sh
diff --git a/src/compiler/translator/LoopInfo.h b/src/compiler/translator/LoopInfo.h
deleted file mode 100644
index 393aa64..0000000
--- a/src/compiler/translator/LoopInfo.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#ifndef COMPILER_TRANSLATOR_LOOPINFO_H_
-#define COMPILER_TRANSLATOR_LOOPINFO_H_
-
-#include "compiler/translator/IntermNode.h"
-
-namespace sh
-{
-
-class TLoopIndexInfo
-{
-  public:
-    TLoopIndexInfo();
-
-    // If type is EbtInt, fill all fields of the structure with info
-    // extracted from a loop node.
-    // If type is not EbtInt, only fill id and type.
-    void fillInfo(TIntermLoop *node);
-
-    int getId() const { return mId; }
-    void setId(int id) { mId = id; }
-    TBasicType getType() const { return mType; }
-    void setType(TBasicType type) { mType = type; }
-    int getCurrentValue() const { return mCurrentValue; }
-
-    void step() { mCurrentValue += mIncrementValue; }
-
-    // Check if the current value satisfies the loop condition.
-    bool satisfiesLoopCondition() const;
-
-  private:
-    int mId;
-    TBasicType mType;  // Either EbtInt or EbtFloat
-
-    // Below fields are only valid if the index's type is int.
-    int mInitValue;
-    int mStopValue;
-    int mIncrementValue;
-    TOperator mOp;
-    int mCurrentValue;
-};
-
-struct TLoopInfo
-{
-    TLoopIndexInfo index;
-    TIntermLoop *loop;
-
-    TLoopInfo();
-    TLoopInfo(TIntermLoop *node);
-};
-
-class TLoopStack : public TVector<TLoopInfo>
-{
-  public:
-    // Search loop stack for a loop whose index matches the input symbol.
-    TIntermLoop *findLoop(TIntermSymbol *symbol);
-
-    // Find the loop index info in the loop stack by the input symbol.
-    TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol);
-
-    // Update the currentValue for the next loop iteration.
-    void step();
-
-    // Return false if loop condition is no longer satisfied.
-    bool satisfiesLoopCondition();
-
-    // Check if the symbol is the index of a loop that's unrolled.
-    bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol);
-
-    // Return the current value of a given loop index symbol.
-    int getLoopIndexValue(TIntermSymbol *symbol);
-
-    void push(TIntermLoop *info);
-    void pop();
-};
-
-}  // namespace sh
-
-#endif // COMPILER_TRANSLATOR_LOOPINFO_H_
-
diff --git a/src/compiler/translator/MMap.h b/src/compiler/translator/MMap.h
deleted file mode 100644
index fca8439..0000000
--- a/src/compiler/translator/MMap.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#ifndef COMPILER_TRANSLATOR_MMAP_H_
-#define COMPILER_TRANSLATOR_MMAP_H_
-
-//
-// Encapsulate memory mapped files
-//
-
-class TMMap {
-public:
-    TMMap(const char* fileName) : 
-        fSize(-1), // -1 is the error value returned by GetFileSize()
-        fp(NULL),
-        fBuff(0)   // 0 is the error value returned by MapViewOfFile()
-    {
-        if ((fp = fopen(fileName, "r")) == NULL)
-            return;
-        char c = getc(fp);
-        fSize = 0;
-        while (c != EOF) {
-            fSize++;
-            c = getc(fp);
-        }
-        if (c == EOF)
-            fSize++;
-        rewind(fp);
-        fBuff = (char*)malloc(sizeof(char) * fSize);
-        int count = 0;
-        c = getc(fp);
-        while (c != EOF) {
-            fBuff[count++] = c;
-            c = getc(fp);
-        }
-        fBuff[count++] = c;
-    }
-
-    char* getData() { return fBuff; }
-    int   getSize() { return fSize; }
-
-    ~TMMap() {
-        if (fp != NULL)
-            fclose(fp);
-    }
-    
-private:
-    int             fSize;      // size of file to map in
-    FILE *fp;
-    char*           fBuff;      // the actual data;
-};
-
-#endif // COMPILER_TRANSLATOR_MMAP_H_
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 2c32b2e..6860edc 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -376,10 +376,7 @@
 void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
 {
     TInfoSinkBase &out = objSink();
-    if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
-        out << mLoopUnrollStack.getLoopIndexValue(node);
-    else
-        out << hashVariableName(node->getName());
+    out << hashVariableName(node->getName());
 
     if (mDeclaringVariables && node->getType().isArray())
         out << arrayBrackets(node->getType());
@@ -1124,49 +1121,22 @@
 
     TLoopType loopType = node->getType();
 
-    // Only for loops can be unrolled
-    ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
-
     if (loopType == ELoopFor)  // for loop
     {
-        if (!node->getUnrollFlag())
-        {
-            out << "for (";
-            if (node->getInit())
-                node->getInit()->traverse(this);
-            out << "; ";
+        out << "for (";
+        if (node->getInit())
+            node->getInit()->traverse(this);
+        out << "; ";
 
-            if (node->getCondition())
-                node->getCondition()->traverse(this);
-            out << "; ";
+        if (node->getCondition())
+            node->getCondition()->traverse(this);
+        out << "; ";
 
-            if (node->getExpression())
-                node->getExpression()->traverse(this);
-            out << ")\n";
+        if (node->getExpression())
+            node->getExpression()->traverse(this);
+        out << ")\n";
 
-            visitCodeBlock(node->getBody());
-        }
-        else
-        {
-            // Need to put a one-iteration loop here to handle break.
-            TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
-            TIntermSymbol *indexSymbol =
-                (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
-            TString name = hashVariableName(indexSymbol->getName());
-            out << "for (int " << name << " = 0; "
-                << name << " < 1; "
-                << "++" << name << ")\n";
-
-            out << "{\n";
-            mLoopUnrollStack.push(node);
-            while (mLoopUnrollStack.satisfiesLoopCondition())
-            {
-                visitCodeBlock(node->getBody());
-                mLoopUnrollStack.step();
-            }
-            mLoopUnrollStack.pop();
-            out << "}\n";
-        }
+        visitCodeBlock(node->getBody());
     }
     else if (loopType == ELoopWhile)  // while loop
     {
diff --git a/src/compiler/translator/OutputGLSLBase.h b/src/compiler/translator/OutputGLSLBase.h
index ede4c49..e4db93b 100644
--- a/src/compiler/translator/OutputGLSLBase.h
+++ b/src/compiler/translator/OutputGLSLBase.h
@@ -10,7 +10,6 @@
 #include <set>
 
 #include "compiler/translator/IntermNode.h"
-#include "compiler/translator/LoopInfo.h"
 #include "compiler/translator/ParseContext.h"
 
 namespace sh
@@ -91,9 +90,6 @@
     // This set contains all the ids of the structs from every scope.
     std::set<int> mDeclaredStructs;
 
-    // Stack of loops that need to be unrolled.
-    TLoopStack mLoopUnrollStack;
-
     ShArrayIndexClampingStrategy mClampingStrategy;
 
     // name hashing.
diff --git a/src/compiler/translator/ValidateLimitations.cpp b/src/compiler/translator/ValidateLimitations.cpp
index 75a0c51..29f1aa3 100644
--- a/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/compiler/translator/ValidateLimitations.cpp
@@ -16,6 +16,17 @@
 namespace
 {
 
+int GetLoopSymbolId(TIntermLoop *loop)
+{
+    // Here we assume all the operations are valid, because the loop node is
+    // already validated before this call.
+    TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
+    TIntermBinary *declInit  = (*declSeq)[0]->getAsBinaryNode();
+    TIntermSymbol *symbol    = declInit->getLeft()->getAsSymbolNode();
+
+    return symbol->getId();
+}
+
 // Traverses a node to check if it represents a constant index expression.
 // Definition:
 // constant-index-expressions are a superset of constant-expressions.
@@ -28,10 +39,8 @@
 class ValidateConstIndexExpr : public TIntermTraverser
 {
   public:
-    ValidateConstIndexExpr(TLoopStack& stack)
-        : TIntermTraverser(true, false, false),
-          mValid(true),
-          mLoopStack(stack)
+    ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
+        : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
     {
     }
 
@@ -44,14 +53,15 @@
         // constant index expression.
         if (mValid)
         {
-            mValid = (symbol->getQualifier() == EvqConst) ||
-                     (mLoopStack.findLoop(symbol));
+            bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
+                                          symbol->getId()) != mLoopSymbolIds.end();
+            mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
         }
     }
 
   private:
     bool mValid;
-    TLoopStack& mLoopStack;
+    const std::vector<int> mLoopSymbolIds;
 };
 
 }  // namespace anonymous
@@ -80,9 +90,9 @@
     TIntermNode *body = loop->getBody();
     if (body != nullptr)
     {
-        validate.mLoopStack.push(loop);
+        validate.mLoopSymbolIds.push_back(GetLoopSymbolId(loop));
         body->traverse(&validate);
-        validate.mLoopStack.pop();
+        validate.mLoopSymbolIds.pop_back();
     }
     return (validate.mNumErrors == 0);
 }
@@ -140,9 +150,9 @@
     TIntermNode *body = node->getBody();
     if (body != NULL)
     {
-        mLoopStack.push(node);
+        mLoopSymbolIds.push_back(GetLoopSymbolId(node));
         body->traverse(this);
-        mLoopStack.pop();
+        mLoopSymbolIds.pop_back();
     }
 
     // The loop is fully processed - no need to visit children.
@@ -163,12 +173,13 @@
 
 bool ValidateLimitations::withinLoopBody() const
 {
-    return !mLoopStack.empty();
+    return !mLoopSymbolIds.empty();
 }
 
 bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
 {
-    return mLoopStack.findLoop(symbol) != NULL;
+    return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
+           mLoopSymbolIds.end();
 }
 
 bool ValidateLimitations::validateLoopType(TIntermLoop *node)
@@ -474,7 +485,7 @@
 {
     ASSERT(node != NULL);
 
-    ValidateConstIndexExpr validate(mLoopStack);
+    ValidateConstIndexExpr validate(mLoopSymbolIds);
     node->traverse(&validate);
     return validate.isValid();
 }
diff --git a/src/compiler/translator/ValidateLimitations.h b/src/compiler/translator/ValidateLimitations.h
index 4c84f9d..63db402 100644
--- a/src/compiler/translator/ValidateLimitations.h
+++ b/src/compiler/translator/ValidateLimitations.h
@@ -8,7 +8,6 @@
 #define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
 
 #include "compiler/translator/IntermNode.h"
-#include "compiler/translator/LoopInfo.h"
 
 namespace sh
 {
@@ -58,7 +57,7 @@
     sh::GLenum mShaderType;
     TInfoSinkBase *mSink;
     int mNumErrors;
-    TLoopStack mLoopStack;
+    std::vector<int> mLoopSymbolIds;
     bool mValidateIndexing;
     bool mValidateInnerLoops;
 };