Fold user-definedness of function nodes into TOperator

Whether a function call is user-defined is not orthogonal to TOperator
associated with the call node - other ops than function calls can't be
user-defined. Because of this it makes sense to store the user-
definedness by having different TOperator enums for different types of
calls.

This patch also tags internal helper functions that have a raw
definition outside the AST with a separate TOperator enum. This way
they can be handled with logic that is easy to understand. Before this,
function calls like this left the user-defined bit unset, despite not
really being built-ins either. The EmulatePrecision traverser uses
this. This is also something that could be used to clean up built-in
emulation in the future.

BUG=angleproject:1490
TEST=angle_unittests

Change-Id: I597fcd9789d0cc22b689ef3ce5a0cc3f621d4859
Reviewed-on: https://chromium-review.googlesource.com/433443
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index b58b27c..8980e69 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -235,7 +235,7 @@
 
 bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
 {
-    ASSERT(callNode->getOp() == EOpFunctionCall);
+    ASSERT(callNode->getOp() == EOpCallFunctionInAST);
     return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
             mFunctionMap.end());
 }
@@ -641,36 +641,43 @@
 
     if (visit)
     {
-        bool inFunctionMap = false;
-        if (node->getOp() == EOpFunctionCall)
+        if (node->getOp() == EOpCallFunctionInAST)
         {
-            inFunctionMap = isInFunctionMap(node);
-            if (!inFunctionMap)
+            if (isInFunctionMap(node))
             {
-                // The function is not user-defined - it is likely built-in texture function.
-                // Assume that those do not have out parameters.
-                setInFunctionCallOutParameter(false);
-            }
-        }
-
-        if (inFunctionMap)
-        {
-            TIntermSequence *params             = getFunctionParameters(node);
-            TIntermSequence::iterator paramIter = params->begin();
-            for (auto *child : *sequence)
-            {
-                ASSERT(paramIter != params->end());
-                TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
-                setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
-
-                child->traverse(this);
-                if (visit && inVisit)
+                TIntermSequence *params             = getFunctionParameters(node);
+                TIntermSequence::iterator paramIter = params->begin();
+                for (auto *child : *sequence)
                 {
-                    if (child != sequence->back())
-                        visit = visitAggregate(InVisit, node);
-                }
+                    ASSERT(paramIter != params->end());
+                    TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
+                    setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
 
-                ++paramIter;
+                    child->traverse(this);
+                    if (visit && inVisit)
+                    {
+                        if (child != sequence->back())
+                            visit = visitAggregate(InVisit, node);
+                    }
+
+                    ++paramIter;
+                }
+            }
+            else
+            {
+                // The node might not be in the function map in case we're in the middle of
+                // transforming the AST, and have inserted function call nodes without inserting the
+                // function definitions yet.
+                setInFunctionCallOutParameter(false);
+                for (auto *child : *sequence)
+                {
+                    child->traverse(this);
+                    if (visit && inVisit)
+                    {
+                        if (child != sequence->back())
+                            visit = visitAggregate(InVisit, node);
+                    }
+                }
             }
 
             setInFunctionCallOutParameter(false);
@@ -680,7 +687,7 @@
             // Find the built-in function corresponding to this op so that we can determine the
             // in/out qualifiers of its parameters.
             TFunction *builtInFunc = nullptr;
-            if (!node->isConstructor() && node->getOp() != EOpFunctionCall)
+            if (!node->isFunctionCall() && !node->isConstructor())
             {
                 builtInFunc = mSymbolTable.findBuiltInOp(node, mShaderVersion);
             }
@@ -689,6 +696,8 @@
 
             for (auto *child : *sequence)
             {
+                // This assumes that raw functions called with
+                // EOpCallInternalRawFunction don't have out parameters.
                 TQualifier qualifier = EvqIn;
                 if (builtInFunc != nullptr)
                     qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();