Always create TFunctions for function call nodes

This simplifies code and ensures that nodes get consistent data.

In the future function call nodes could have a pointer to the
TFunction instead of converting the same information into a different
data structure.

BUG=angleproject:2267
TEST=angle_unittests, angle_end2end_tests

Change-Id: Ic0c24bb86b44b9bcc4a5da7f6b03701081a3af5c
Reviewed-on: https://chromium-review.googlesource.com/824606
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 85844d6..c1bd1a8 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -427,49 +427,6 @@
            (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
 }
 
-TIntermAggregate *createInternalFunctionCallNode(const TType &type,
-                                                 TString name,
-                                                 TIntermSequence *arguments)
-{
-    TName nameObj(&name);
-    nameObj.setInternal(true);
-    TIntermAggregate *callNode =
-        TIntermAggregate::Create(type, EOpCallInternalRawFunction, arguments);
-    callNode->getFunctionSymbolInfo()->setNameObj(nameObj);
-    return callNode;
-}
-
-TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild)
-{
-    TString roundFunctionName;
-    if (roundedChild->getPrecision() == EbpMedium)
-        roundFunctionName = "angle_frm";
-    else
-        roundFunctionName      = "angle_frl";
-    TIntermSequence *arguments = new TIntermSequence();
-    arguments->push_back(roundedChild);
-    TIntermAggregate *callNode =
-        createInternalFunctionCallNode(roundedChild->getType(), roundFunctionName, arguments);
-    callNode->getFunctionSymbolInfo()->setKnownToNotHaveSideEffects(true);
-    return callNode;
-}
-
-TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
-                                                           TIntermTyped *right,
-                                                           const char *opNameStr)
-{
-    std::stringstream strstr;
-    if (left->getPrecision() == EbpMedium)
-        strstr << "angle_compound_" << opNameStr << "_frm";
-    else
-        strstr << "angle_compound_" << opNameStr << "_frl";
-    TString functionName       = strstr.str().c_str();
-    TIntermSequence *arguments = new TIntermSequence();
-    arguments->push_back(left);
-    arguments->push_back(right);
-    return createInternalFunctionCallNode(left->getType(), functionName, arguments);
-}
-
 bool ParentUsesResult(TIntermNode *parent, TIntermTyped *node)
 {
     if (!parent)
@@ -748,4 +705,50 @@
     }
 }
 
+TFunction *EmulatePrecision::getInternalFunction(TString *functionName,
+                                                 const TType &returnType,
+                                                 TIntermSequence *arguments,
+                                                 bool knownToNotHaveSideEffects)
+{
+    TString mangledName = TFunction::GetMangledNameFromCall(*functionName, *arguments);
+    if (mInternalFunctions.find(mangledName) == mInternalFunctions.end())
+    {
+        mInternalFunctions[mangledName] =
+            new TFunction(mSymbolTable, functionName, new TType(returnType),
+                          SymbolType::AngleInternal, knownToNotHaveSideEffects);
+    }
+    return mInternalFunctions[mangledName];
+}
+
+TIntermAggregate *EmulatePrecision::createRoundingFunctionCallNode(TIntermTyped *roundedChild)
+{
+    const char *roundFunctionName;
+    if (roundedChild->getPrecision() == EbpMedium)
+        roundFunctionName = "angle_frm";
+    else
+        roundFunctionName = "angle_frl";
+    TString *functionName      = NewPoolTString(roundFunctionName);
+    TIntermSequence *arguments = new TIntermSequence();
+    arguments->push_back(roundedChild);
+    return TIntermAggregate::CreateRawFunctionCall(
+        *getInternalFunction(functionName, roundedChild->getType(), arguments, true), arguments);
+}
+
+TIntermAggregate *EmulatePrecision::createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
+                                                                             TIntermTyped *right,
+                                                                             const char *opNameStr)
+{
+    std::stringstream strstr;
+    if (left->getPrecision() == EbpMedium)
+        strstr << "angle_compound_" << opNameStr << "_frm";
+    else
+        strstr << "angle_compound_" << opNameStr << "_frl";
+    TString *functionName      = NewPoolTString(strstr.str().c_str());
+    TIntermSequence *arguments = new TIntermSequence();
+    arguments->push_back(left);
+    arguments->push_back(right);
+    return TIntermAggregate::CreateRawFunctionCall(
+        *getInternalFunction(functionName, left->getType(), arguments, false), arguments);
+}
+
 }  // namespace sh