Store unmangled function names in the AST

This makes the code simpler across the board. There are a few cases
where mangled names still need to be generated in AST traversers, but
they are outweighed by much leaner output code for all function nodes.

BUG=angleproject:1490
TEST=angle_unittests, angle_end2end_tests

Change-Id: Id3638e0fca6019bbbe6fc5e1b7763870591da2d8
Reviewed-on: https://chromium-review.googlesource.com/461077
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/ASTMetadataHLSL.cpp b/src/compiler/translator/ASTMetadataHLSL.cpp
index e0de596..80a8ab6 100644
--- a/src/compiler/translator/ASTMetadataHLSL.cpp
+++ b/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -128,9 +128,8 @@
             }
             else if (node->getOp() == EOpCallBuiltInFunction)
             {
-                TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
-
-                if (mGradientBuiltinFunctions.find(name) != mGradientBuiltinFunctions.end())
+                if (mGradientBuiltinFunctions.find(node->getFunctionSymbolInfo()->getName()) !=
+                    mGradientBuiltinFunctions.end())
                 {
                     onGradient();
                 }
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 8ebd231..9cedfab 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -760,7 +760,7 @@
     // Search from main, starting from the end of the DAG as it usually is the root.
     for (size_t i = mCallDag.size(); i-- > 0;)
     {
-        if (mCallDag.getRecordFromIndex(i).name == "main(")
+        if (mCallDag.getRecordFromIndex(i).name == "main")
         {
             internalTagUsedFunction(i);
             return true;
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 888d336..80d5c1e 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -431,7 +431,7 @@
                                                  TString name,
                                                  TIntermSequence *arguments)
 {
-    TName nameObj(TFunction::GetMangledNameFromCall(name, *arguments));
+    TName nameObj(name);
     nameObj.setInternal(true);
     TIntermAggregate *callNode =
         TIntermAggregate::Create(type, EOpCallInternalRawFunction, arguments);
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 3a8fdc0..dd80396 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -630,7 +630,7 @@
 
 void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
 {
-    setName(function.getMangledName());
+    setName(function.getName());
     setId(TSymbolUniqueId(function));
 }
 
@@ -3379,7 +3379,6 @@
 TName TIntermTraverser::GetInternalFunctionName(const char *name)
 {
     TString nameStr(name);
-    nameStr = TFunction::mangleName(nameStr);
     TName nameObj(nameStr);
     nameObj.setInternal(true);
     return nameObj;
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index 513c111..93729d5 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -550,7 +550,7 @@
 
     const TString &getName() const { return mName.getString(); }
     void setName(const TString &name) { mName.setString(name); }
-    bool isMain() const { return mName.getString() == "main("; }
+    bool isMain() const { return mName.getString() == "main"; }
 
     void setId(const TSymbolUniqueId &functionId);
     const TSymbolUniqueId &getId() const;
diff --git a/src/compiler/translator/OutputGLSL.cpp b/src/compiler/translator/OutputGLSL.cpp
index 7084872..af1b77c 100644
--- a/src/compiler/translator/OutputGLSL.cpp
+++ b/src/compiler/translator/OutputGLSL.cpp
@@ -66,7 +66,7 @@
     }
 }
 
-TString TOutputGLSL::translateTextureFunction(TString &name)
+TString TOutputGLSL::translateTextureFunction(const TString &name)
 {
     static const char *simpleRename[] = {"texture2DLodEXT",
                                          "texture2DLod",
diff --git a/src/compiler/translator/OutputGLSL.h b/src/compiler/translator/OutputGLSL.h
index d910c00..17682ff 100644
--- a/src/compiler/translator/OutputGLSL.h
+++ b/src/compiler/translator/OutputGLSL.h
@@ -28,7 +28,7 @@
   protected:
     bool writeVariablePrecision(TPrecision) override;
     void visitSymbol(TIntermSymbol *node) override;
-    TString translateTextureFunction(TString &name) override;
+    TString translateTextureFunction(const TString &name) override;
 };
 
 }  // namespace sh
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index b5a8b1e..fee3836 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -926,7 +926,7 @@
     if (type.isArray())
         out << arrayBrackets(type);
 
-    out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+    out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
 
     out << "(";
     writeFunctionParameters(*(node->getSequence()));
@@ -946,7 +946,17 @@
         case EOpCallBuiltInFunction:
             // Function call.
             if (visit == PreVisit)
-                out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
+            {
+                if (node->getOp() == EOpCallBuiltInFunction)
+                {
+                    out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
+                }
+                else
+                {
+                    out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
+                }
+                out << "(";
+            }
             else if (visit == InVisit)
                 out << ", ";
             else
@@ -1196,22 +1206,17 @@
     return hashName(name);
 }
 
-TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
+TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
 {
-    TString mangledStr = mangledName.getString();
-    TString name       = TFunction::unmangleName(mangledStr);
-    if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
-        return translateTextureFunction(name);
-    if (mangledName.isInternal())
+    if (info.isMain() || info.getNameObj().isInternal())
     {
         // Internal function names are outputted as-is - they may refer to functions manually added
         // to the output shader source that are not included in the AST at all.
-        return name;
+        return info.getName();
     }
     else
     {
-        TName nameObj(name);
-        return hashName(nameObj);
+        return hashName(info.getNameObj());
     }
 }
 
diff --git a/src/compiler/translator/OutputGLSLBase.h b/src/compiler/translator/OutputGLSLBase.h
index 4c26c73..af3019c 100644
--- a/src/compiler/translator/OutputGLSLBase.h
+++ b/src/compiler/translator/OutputGLSLBase.h
@@ -70,10 +70,10 @@
 
     // Same as hashName(), but without hashing built-in variables.
     TString hashVariableName(const TName &name);
-    // Same as hashName(), but without hashing built-in functions and with unmangling.
-    TString hashFunctionNameIfNeeded(const TName &mangledName);
+    // Same as hashName(), but without hashing internal functions or "main".
+    TString hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info);
     // Used to translate function names for differences between ESSL and GLSL
-    virtual TString translateTextureFunction(TString &name) { return name; }
+    virtual TString translateTextureFunction(const TString &name) { return name; }
 
   private:
     bool structDeclared(const TStructure *structure) const;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 87a7767..c0129da 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1590,7 +1590,7 @@
     }
     else
     {
-        out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
+        out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
             << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
     }
 
@@ -1722,7 +1722,7 @@
 
     TIntermSequence *arguments = node->getSequence();
 
-    TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+    TString name = DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
     out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
         << (mOutputLod0Function ? "Lod0(" : "(");
 
@@ -1776,7 +1776,7 @@
                 ASSERT(index != CallDAG::InvalidIndex);
                 lod0 &= mASTMetadataList[index].mNeedsLod0;
 
-                out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
+                out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
                 out << DisambiguateFunctionName(node->getSequence());
                 out << (lod0 ? "Lod0(" : "(");
             }
@@ -1784,11 +1784,11 @@
             {
                 // This path is used for internal functions that don't have their definitions in the
                 // AST, such as precision emulation functions.
-                out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
+                out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
             }
             else
             {
-                TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
+                const TString &name    = node->getFunctionSymbolInfo()->getName();
                 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
                 int coords = 0;  // textureSize(gsampler2DMS) doesn't have a second argument.
                 if (arguments->size() > 1)
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index bdd68f3..f469746 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1443,11 +1443,9 @@
             TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped();
             if (!checkCanBeLValue(argument->getLine(), "assign", argument))
             {
-                TString unmangledName =
-                    TFunction::unmangleName(fnCall->getFunctionSymbolInfo()->getName());
                 error(argument->getLine(),
                       "Constant value cannot be passed for 'out' or 'inout' parameters.",
-                      unmangledName.c_str());
+                      fnCall->getFunctionSymbolInfo()->getName().c_str());
                 return;
             }
         }
@@ -4277,16 +4275,13 @@
     const TString &name        = functionCall->getFunctionSymbolInfo()->getName();
     TIntermNode *offset        = nullptr;
     TIntermSequence *arguments = functionCall->getSequence();
-    if (name.compare(0, 16, "texelFetchOffset") == 0 ||
-        name.compare(0, 16, "textureLodOffset") == 0 ||
-        name.compare(0, 20, "textureProjLodOffset") == 0 ||
-        name.compare(0, 17, "textureGradOffset") == 0 ||
-        name.compare(0, 21, "textureProjGradOffset") == 0)
+    if (name == "texelFetchOffset" || name == "textureLodOffset" ||
+        name == "textureProjLodOffset" || name == "textureGradOffset" ||
+        name == "textureProjGradOffset")
     {
         offset = arguments->back();
     }
-    else if (name.compare(0, 13, "textureOffset") == 0 ||
-             name.compare(0, 17, "textureProjOffset") == 0)
+    else if (name == "textureOffset" || name == "textureProjOffset")
     {
         // A bias parameter might follow the offset parameter.
         ASSERT(arguments->size() >= 3);
@@ -4297,9 +4292,8 @@
         TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
         if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
         {
-            TString unmangledName = TFunction::unmangleName(name);
             error(functionCall->getLine(), "Texture offset must be a constant expression",
-                  unmangledName.c_str());
+                  name.c_str());
         }
         else
         {
diff --git a/src/compiler/translator/RewriteTexelFetchOffset.cpp b/src/compiler/translator/RewriteTexelFetchOffset.cpp
index 3be83df..554b044 100644
--- a/src/compiler/translator/RewriteTexelFetchOffset.cpp
+++ b/src/compiler/translator/RewriteTexelFetchOffset.cpp
@@ -71,7 +71,7 @@
         return true;
     }
 
-    if (node->getFunctionSymbolInfo()->getName().compare(0, 16, "texelFetchOffset") != 0)
+    if (node->getFunctionSymbolInfo()->getName() != "texelFetchOffset")
     {
         return true;
     }
@@ -80,16 +80,10 @@
     const TIntermSequence *sequence = node->getSequence();
     ASSERT(sequence->size() == 4u);
 
-    // Decide if there is a 2DArray sampler.
-    bool is2DArray = node->getFunctionSymbolInfo()->getName().find("s2a1") != TString::npos;
-
-    // Create new argument list from node->getName().
-    // e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;"
-    TString newArgs = node->getFunctionSymbolInfo()->getName().substr(
-        16, node->getFunctionSymbolInfo()->getName().length() - 20);
-    TString newName           = "texelFetch" + newArgs;
-    TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion);
-    ASSERT(texelFetchSymbol && texelFetchSymbol->isFunction());
+    // Decide if the sampler is a 2DArray sampler. In that case position is ivec3 and offset is
+    // ivec2.
+    bool is2DArray = sequence->at(1)->getAsTyped()->getNominalSize() == 3 &&
+                     sequence->at(3)->getAsTyped()->getNominalSize() == 2;
 
     // Create new node that represents the call of function texelFetch.
     // Its argument list will be: texelFetch(sampler, Position+offset, lod).
@@ -135,6 +129,11 @@
 
     ASSERT(texelFetchArguments->size() == 3u);
 
+    // Get the symbol of the texel fetch function to use.
+    TString mangledName = TFunction::GetMangledNameFromCall("texelFetch", *texelFetchArguments);
+    TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(mangledName, shaderVersion);
+    ASSERT(texelFetchSymbol && texelFetchSymbol->isFunction());
+
     TIntermAggregate *texelFetchNode = TIntermAggregate::CreateBuiltInFunctionCall(
         *static_cast<const TFunction *>(texelFetchSymbol), texelFetchArguments);
     texelFetchNode->setLine(node->getLine());
diff --git a/src/compiler/translator/SymbolTable.h b/src/compiler/translator/SymbolTable.h
index 5f3e5d3..4ab958a 100644
--- a/src/compiler/translator/SymbolTable.h
+++ b/src/compiler/translator/SymbolTable.h
@@ -175,10 +175,6 @@
     bool isFunction() const override { return true; }
 
     static TString mangleName(const TString &name) { return name + '('; }
-    static TString unmangleName(const TString &mangledName)
-    {
-        return TString(mangledName.c_str(), mangledName.find_first_of('('));
-    }
 
     void addParameter(const TConstParameter &p)
     {
diff --git a/src/compiler/translator/UtilsHLSL.cpp b/src/compiler/translator/UtilsHLSL.cpp
index e3be724..accb3b5 100644
--- a/src/compiler/translator/UtilsHLSL.cpp
+++ b/src/compiler/translator/UtilsHLSL.cpp
@@ -241,18 +241,6 @@
     }
 }
 
-TString DecorateFunctionIfNeeded(const TName &name)
-{
-    if (name.isInternal())
-    {
-        return TFunction::unmangleName(name.getString());
-    }
-    else
-    {
-        return Decorate(TFunction::unmangleName(name.getString()));
-    }
-}
-
 TString TypeString(const TType &type)
 {
     const TStructure *structure = type.getStruct();
diff --git a/src/compiler/translator/UtilsHLSL.h b/src/compiler/translator/UtilsHLSL.h
index 61fd1ef..37edce4 100644
--- a/src/compiler/translator/UtilsHLSL.h
+++ b/src/compiler/translator/UtilsHLSL.h
@@ -65,8 +65,6 @@
 // Prepends an underscore to avoid naming clashes
 TString Decorate(const TString &string);
 TString DecorateIfNeeded(const TName &name);
-// Decorates and also unmangles the function name
-TString DecorateFunctionIfNeeded(const TName &name);
 TString DecorateUniform(const TName &name, const TType &type);
 TString DecorateField(const TString &string, const TStructure &structure);
 TString DecoratePrivate(const TString &privateText);
diff --git a/src/compiler/translator/ValidateLimitations.cpp b/src/compiler/translator/ValidateLimitations.cpp
index 0369eaa..e647e4c 100644
--- a/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/compiler/translator/ValidateLimitations.cpp
@@ -402,8 +402,11 @@
 
     bool valid                = true;
     TSymbolTable &symbolTable = GetGlobalParseContext()->symbolTable;
-    TSymbol *symbol           = symbolTable.find(node->getFunctionSymbolInfo()->getName(),
-                                       GetGlobalParseContext()->getShaderVersion());
+    // TODO(oetuaho@nvidia.com): It would be neater to leverage TIntermLValueTrackingTraverser to
+    // keep track of out parameters, rather than doing a symbol table lookup here.
+    TString mangledName = TFunction::GetMangledNameFromCall(
+        node->getFunctionSymbolInfo()->getName(), *node->getSequence());
+    TSymbol *symbol = symbolTable.find(mangledName, GetGlobalParseContext()->getShaderVersion());
     ASSERT(symbol && symbol->isFunction());
     TFunction *function = static_cast<TFunction *>(symbol);
     for (ParamIndex::const_iterator i = pIndex.begin(); i != pIndex.end(); ++i)
diff --git a/src/compiler/translator/ValidateMultiviewWebGL.cpp b/src/compiler/translator/ValidateMultiviewWebGL.cpp
index fa6cf02..79524fc 100644
--- a/src/compiler/translator/ValidateMultiviewWebGL.cpp
+++ b/src/compiler/translator/ValidateMultiviewWebGL.cpp
@@ -363,7 +363,7 @@
             mValid = false;
         }
         else if (node->getOp() == EOpCallBuiltInFunction &&
-                 TFunction::unmangleName(node->getFunctionSymbolInfo()->getName()) == "imageStore")
+                 node->getFunctionSymbolInfo()->getName() == "imageStore")
         {
             // TODO(oetuaho@nvidia.com): Record which built-in functions have side effects in
             // the symbol info instead.
diff --git a/src/tests/compiler_tests/TypeTracking_test.cpp b/src/tests/compiler_tests/TypeTracking_test.cpp
index a2e20ed..0b71e9c 100644
--- a/src/tests/compiler_tests/TypeTracking_test.cpp
+++ b/src/tests/compiler_tests/TypeTracking_test.cpp
@@ -75,7 +75,7 @@
     std::string mInfoLog;
 };
 
-TEST_F(TypeTrackingTest, FunctionPrototypeMangling)
+TEST_F(TypeTrackingTest, FunctionPrototype)
 {
     const std::string &shaderString =
         "precision mediump float;\n"
@@ -90,7 +90,7 @@
         "}\n";
     compile(shaderString);
     ASSERT_FALSE(foundErrorInIntermediateTree());
-    ASSERT_TRUE(foundInIntermediateTree("Function Prototype: fun(f1;"));
+    ASSERT_TRUE(foundInIntermediateTree("Function Prototype: fun"));
 }
 
 TEST_F(TypeTrackingTest, BuiltInFunctionResultPrecision)
@@ -233,7 +233,7 @@
         "}\n";
     compile(shaderString);
     ASSERT_FALSE(foundErrorInIntermediateTree());
-    ASSERT_TRUE(foundInIntermediateTree("texture2D(s21;vf2; (lowp 4-component vector of float)"));
+    ASSERT_TRUE(foundInIntermediateTree("texture2D (lowp 4-component vector of float)"));
 }
 
 TEST_F(TypeTrackingTest, TextureCubeResultTypeAndPrecision)
@@ -250,7 +250,7 @@
         "}\n";
     compile(shaderString);
     ASSERT_FALSE(foundErrorInIntermediateTree());
-    ASSERT_TRUE(foundInIntermediateTree("textureCube(sC1;vf3; (lowp 4-component vector of float)"));
+    ASSERT_TRUE(foundInIntermediateTree("textureCube (lowp 4-component vector of float)"));
 }
 
 TEST_F(TypeTrackingTest, TextureSizeResultTypeAndPrecision)
@@ -271,7 +271,7 @@
         "}\n";
     compile(shaderString);
     ASSERT_FALSE(foundErrorInIntermediateTree());
-    ASSERT_TRUE(foundInIntermediateTree("textureSize(s21;i1; (highp 2-component vector of int)"));
+    ASSERT_TRUE(foundInIntermediateTree("textureSize (highp 2-component vector of int)"));
 }
 
 TEST_F(TypeTrackingTest, BuiltInConstructorResultTypeAndPrecision)
diff --git a/src/tests/test_utils/compiler_test.cpp b/src/tests/test_utils/compiler_test.cpp
index 93d47d8..600e747 100644
--- a/src/tests/test_utils/compiler_test.cpp
+++ b/src/tests/test_utils/compiler_test.cpp
@@ -20,14 +20,18 @@
 class FunctionCallFinder : public TIntermTraverser
 {
   public:
-    FunctionCallFinder(const TString &functionName)
-        : TIntermTraverser(true, false, false), mFunctionName(functionName), mNodeFound(nullptr)
+    FunctionCallFinder(const TString &functionMangledName)
+        : TIntermTraverser(true, false, false),
+          mFunctionMangledName(functionMangledName),
+          mNodeFound(nullptr)
     {
     }
 
     bool visitAggregate(Visit visit, TIntermAggregate *node) override
     {
-        if (node->isFunctionCall() && node->getFunctionSymbolInfo()->getName() == mFunctionName)
+        if (node->isFunctionCall() &&
+            TFunction::GetMangledNameFromCall(node->getFunctionSymbolInfo()->getName(),
+                                              *node->getSequence()) == mFunctionMangledName)
         {
             mNodeFound = node;
             return false;
@@ -39,7 +43,7 @@
     const TIntermAggregate *getNode() const { return mNodeFound; }
 
   private:
-    TString mFunctionName;
+    TString mFunctionMangledName;
     TIntermAggregate *mNodeFound;
 };
 
@@ -208,9 +212,9 @@
     return true;
 }
 
-const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName)
+const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionMangledName)
 {
-    FunctionCallFinder finder(functionName);
+    FunctionCallFinder finder(functionMangledName);
     root->traverse(&finder);
     return finder.getNode();
 }