Track where l-values are required in AST traversal

This functionality is refactored out of EmulatePrecision to be a common
feature of TIntermTraverser. This is done since tracking where l-values
are required will be useful for other traversers. For example, it will
be needed for converting dynamic indexing of matrices and vectors to
function calls. This change adds some overhead to all tree traversers,
but the overhead is expected to be small for typical shaders which don't
contain too many user-defined functions.

BUG=angleproject:1116
TEST=angle_unittests

Change-Id: I54d34c2b5093ef028f2b24d854c11c0195dc1dbb
Reviewed-on: https://chromium-review.googlesource.com/290514
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index c4659d5..befb319 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -292,16 +292,12 @@
 }  // namespace anonymous
 
 EmulatePrecision::EmulatePrecision()
-    : TIntermTraverser(true, true, true),
-      mDeclaringVariables(false),
-      mInLValue(false),
-      mInFunctionCallOutParameter(false)
+    : TIntermTraverser(true, true, true), mDeclaringVariables(false)
 {}
 
 void EmulatePrecision::visitSymbol(TIntermSymbol *node)
 {
-    if (canRoundFloat(node->getType()) &&
-        !mDeclaringVariables && !mInLValue && !mInFunctionCallOutParameter)
+    if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere())
     {
         TIntermNode *parent = getParentNode();
         TIntermNode *replacement = createRoundingFunctionCallNode(node);
@@ -314,14 +310,6 @@
 {
     bool visitChildren = true;
 
-    if (node->isAssignment())
-    {
-        if (visit == PreVisit)
-            mInLValue = true;
-        else if (visit == InVisit)
-            mInLValue = false;
-    }
-
     TOperator op = node->getOp();
 
     // RHS of initialize is not being declared.
@@ -415,22 +403,9 @@
     {
       case EOpSequence:
       case EOpConstructStruct:
-        // No special handling
-        break;
       case EOpFunction:
-        if (visit == PreVisit)
-        {
-            const TIntermSequence &sequence = *(node->getSequence());
-            TIntermSequence::const_iterator seqIter = sequence.begin();
-            TIntermAggregate *params = (*seqIter)->getAsAggregate();
-            ASSERT(params != NULL);
-            ASSERT(params->getOp() == EOpParameters);
-            mFunctionMap[node->getName()] = params->getSequence();
-        }
         break;
       case EOpPrototype:
-        if (visit == PreVisit)
-            mFunctionMap[node->getName()] = node->getSequence();
         visitChildren = false;
         break;
       case EOpParameters:
@@ -457,50 +432,17 @@
       case EOpFunctionCall:
       {
         // Function call.
-        bool inFunctionMap = (mFunctionMap.find(node->getName()) != mFunctionMap.end());
         if (visit == PreVisit)
         {
             // User-defined function return values are not rounded, this relies on that
             // calculations producing the value were rounded.
             TIntermNode *parent = getParentNode();
-            if (canRoundFloat(node->getType()) && !inFunctionMap && parentUsesResult(parent, node))
+            if (canRoundFloat(node->getType()) && !isInFunctionMap(node) &&
+                parentUsesResult(parent, node))
             {
                 TIntermNode *replacement = createRoundingFunctionCallNode(node);
                 mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
             }
-
-            if (inFunctionMap)
-            {
-                mSeqIterStack.push_back(mFunctionMap[node->getName()]->begin());
-                if (mSeqIterStack.back() != mFunctionMap[node->getName()]->end())
-                {
-                    TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier();
-                    mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut);
-                }
-            }
-            else
-            {
-                // The function is not user-defined - it is likely built-in texture function.
-                // Assume that those do not have out parameters.
-                mInFunctionCallOutParameter = false;
-            }
-        }
-        else if (visit == InVisit)
-        {
-            if (inFunctionMap)
-            {
-                ++mSeqIterStack.back();
-                TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier();
-                mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut);
-            }
-        }
-        else
-        {
-            if (inFunctionMap)
-            {
-                mSeqIterStack.pop_back();
-                mInFunctionCallOutParameter = false;
-            }
         }
         break;
       }
@@ -523,15 +465,10 @@
       case EOpNegative:
       case EOpVectorLogicalNot:
       case EOpLogicalNot:
-        break;
       case EOpPostIncrement:
       case EOpPostDecrement:
       case EOpPreIncrement:
       case EOpPreDecrement:
-        if (visit == PreVisit)
-            mInLValue = true;
-        else if (visit == PostVisit)
-            mInLValue = false;
         break;
       default:
         if (canRoundFloat(node->getType()) && visit == PreVisit)