Implement user-defined name hashing.

ANGLEBUG=315
Review URL: https://codereview.appspot.com/6818109

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1469 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/Compiler.cpp b/src/compiler/Compiler.cpp
index b067fed..ab12ac9 100644
--- a/src/compiler/Compiler.cpp
+++ b/src/compiler/Compiler.cpp
@@ -195,7 +195,8 @@
         // Call mapLongVariableNames() before collectAttribsUniforms() so in
         // collectAttribsUniforms() we already have the mapped symbol names and
         // we could composite mapped and original variable names.
-        if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
+        // Also, if we hash all the names, then no need to do this for long names.
+        if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
             mapLongVariableNames(root);
 
         if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
@@ -244,6 +245,8 @@
     uniforms.clear();
 
     builtInFunctionEmulator.Cleanup();
+
+    nameMap.clear();
 }
 
 bool TCompiler::detectRecursion(TIntermNode* root)
@@ -319,7 +322,7 @@
 
 void TCompiler::collectAttribsUniforms(TIntermNode* root)
 {
-    CollectAttribsUniforms collect(attribs, uniforms);
+    CollectAttribsUniforms collect(attribs, uniforms, hashFunction);
     root->traverse(&collect);
 }
 
diff --git a/src/compiler/Intermediate.cpp b/src/compiler/Intermediate.cpp
index 92c4505..9032b3a 100644
--- a/src/compiler/Intermediate.cpp
+++ b/src/compiler/Intermediate.cpp
@@ -12,6 +12,7 @@
 #include <limits.h>
 #include <algorithm>
 
+#include "compiler/HashNames.h"
 #include "compiler/localintermediate.h"
 #include "compiler/QualifierAlive.h"
 #include "compiler/RemoveTree.h"
@@ -1445,3 +1446,14 @@
     return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
 }
 
+// static
+TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
+{
+    if (hashFunction == NULL || name.empty())
+        return name;
+    khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
+    TStringStream stream;
+    stream << HASHED_NAME_PREFIX << std::hex << number;
+    TString hashedName = stream.str();
+    return hashedName;
+}
diff --git a/src/compiler/OutputESSL.cpp b/src/compiler/OutputESSL.cpp
index 64ee92d..0331752 100644
--- a/src/compiler/OutputESSL.cpp
+++ b/src/compiler/OutputESSL.cpp
@@ -6,8 +6,11 @@
 
 #include "compiler/OutputESSL.h"
 
-TOutputESSL::TOutputESSL(TInfoSinkBase& objSink)
-    : TOutputGLSLBase(objSink)
+TOutputESSL::TOutputESSL(TInfoSinkBase& objSink,
+                         ShHashFunction64 hashFunction,
+                         NameMap& nameMap,
+                         TSymbolTable& symbolTable)
+    : TOutputGLSLBase(objSink, hashFunction, nameMap, symbolTable)
 {
 }
 
diff --git a/src/compiler/OutputESSL.h b/src/compiler/OutputESSL.h
index 4fa73c8..dd8c5ab 100644
--- a/src/compiler/OutputESSL.h
+++ b/src/compiler/OutputESSL.h
@@ -12,7 +12,10 @@
 class TOutputESSL : public TOutputGLSLBase
 {
 public:
-    TOutputESSL(TInfoSinkBase& objSink);
+    TOutputESSL(TInfoSinkBase& objSink,
+                ShHashFunction64 hashFunction,
+                NameMap& nameMap,
+                TSymbolTable& symbolTable);
 
 protected:
     virtual bool writeVariablePrecision(TPrecision precision);
diff --git a/src/compiler/OutputGLSL.cpp b/src/compiler/OutputGLSL.cpp
index dd31b4b..5873042 100644
--- a/src/compiler/OutputGLSL.cpp
+++ b/src/compiler/OutputGLSL.cpp
@@ -6,8 +6,11 @@
 
 #include "compiler/OutputGLSL.h"
 
-TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
-    : TOutputGLSLBase(objSink)
+TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink,
+                         ShHashFunction64 hashFunction,
+                         NameMap& nameMap,
+                         TSymbolTable& symbolTable)
+    : TOutputGLSLBase(objSink, hashFunction, nameMap, symbolTable)
 {
 }
 
diff --git a/src/compiler/OutputGLSL.h b/src/compiler/OutputGLSL.h
index 0fe2356..9030212 100644
--- a/src/compiler/OutputGLSL.h
+++ b/src/compiler/OutputGLSL.h
@@ -12,7 +12,10 @@
 class TOutputGLSL : public TOutputGLSLBase
 {
 public:
-    TOutputGLSL(TInfoSinkBase& objSink);
+    TOutputGLSL(TInfoSinkBase& objSink,
+                ShHashFunction64 hashFunction,
+                NameMap& nameMap,
+                TSymbolTable& symbolTable);
 
 protected:
     virtual bool writeVariablePrecision(TPrecision);
diff --git a/src/compiler/OutputGLSLBase.cpp b/src/compiler/OutputGLSLBase.cpp
index 552fa50..ed86c68 100644
--- a/src/compiler/OutputGLSLBase.cpp
+++ b/src/compiler/OutputGLSLBase.cpp
@@ -9,35 +9,6 @@
 
 namespace
 {
-TString getTypeName(const TType& type)
-{
-    TInfoSinkBase out;
-    if (type.isMatrix())
-    {
-        out << "mat";
-        out << type.getNominalSize();
-    }
-    else if (type.isVector())
-    {
-        switch (type.getBasicType())
-        {
-            case EbtFloat: out << "vec"; break;
-            case EbtInt: out << "ivec"; break;
-            case EbtBool: out << "bvec"; break;
-            default: UNREACHABLE(); break;
-        }
-        out << type.getNominalSize();
-    }
-    else
-    {
-        if (type.getBasicType() == EbtStruct)
-            out << type.getTypeName();
-        else
-            out << type.getBasicString();
-    }
-    return TString(out.c_str());
-}
-
 TString arrayBrackets(const TType& type)
 {
     ASSERT(type.isArray());
@@ -66,10 +37,16 @@
 }
 }  // namespace
 
-TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink)
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
+                                 ShHashFunction64 hashFunction,
+                                 NameMap& nameMap,
+                                 TSymbolTable& symbolTable)
     : TIntermTraverser(true, true, true),
       mObjSink(objSink),
-      mDeclaringVariables(false)
+      mDeclaringVariables(false),
+      mHashFunction(hashFunction),
+      mNameMap(nameMap),
+      mSymbolTable(symbolTable)
 {
 }
 
@@ -101,7 +78,7 @@
     if ((type.getBasicType() == EbtStruct) &&
         (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
     {
-        out << "struct " << type.getTypeName() << "{\n";
+        out << "struct " << hashName(type.getTypeName()) << "{\n";
         const TTypeList* structure = type.getStruct();
         ASSERT(structure != NULL);
         for (size_t i = 0; i < structure->size(); ++i)
@@ -110,7 +87,7 @@
             ASSERT(fieldType != NULL);
             if (writeVariablePrecision(fieldType->getPrecision()))
                 out << " ";
-            out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
+            out << getTypeName(*fieldType) << " " << hashName(fieldType->getFieldName());
             if (fieldType->isArray())
                 out << arrayBrackets(*fieldType);
             out << ";\n";
@@ -140,7 +117,7 @@
 
         const TString& name = arg->getSymbol();
         if (!name.empty())
-            out << " " << name;
+            out << " " << hashName(name);
         if (type.isArray())
             out << arrayBrackets(type);
 
@@ -157,7 +134,7 @@
 
     if (type.getBasicType() == EbtStruct)
     {
-        out << type.getTypeName() << "(";
+        out << hashName(type.getTypeName()) << "(";
         const TTypeList* structure = type.getStruct();
         ASSERT(structure != NULL);
         for (size_t i = 0; i < structure->size(); ++i)
@@ -196,7 +173,7 @@
     if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
         out << mLoopUnroll.GetLoopIndexValue(node);
     else
-        out << node->getSymbol();
+        out << hashVariableName(node->getSymbol());
 
     if (mDeclaringVariables && node->getType().isArray())
         out << arrayBrackets(node->getType());
@@ -243,7 +220,7 @@
             {
                 out << ".";
                 // TODO(alokp): ASSERT
-                out << node->getType().getFieldName();
+                out << hashName(node->getType().getFieldName());
                 visitChildren = false;
             }
             break;
@@ -467,7 +444,7 @@
             // Function declaration.
             ASSERT(visit == PreVisit);
             writeVariableType(node->getType());
-            out << " " << node->getName();
+            out << " " << hashName(node->getName());
 
             out << "(";
             writeFunctionParameters(node->getSequence());
@@ -480,7 +457,7 @@
             // Function definition.
             ASSERT(visit == PreVisit);
             writeVariableType(node->getType());
-            out << " " << TFunction::unmangleName(node->getName());
+            out << " " << hashFunctionName(node->getName());
 
             incrementDepth();
             // Function definition node contains one or two children nodes
@@ -510,8 +487,7 @@
             // Function call.
             if (visit == PreVisit)
             {
-                TString functionName = TFunction::unmangleName(node->getName());
-                out << functionName << "(";
+                out << hashFunctionName(node->getName()) << "(";
             }
             else if (visit == InVisit)
             {
@@ -572,7 +548,7 @@
             {
                 const TType& type = node->getType();
                 ASSERT(type.getBasicType() == EbtStruct);
-                out << type.getTypeName() << "(";
+                out << hashName(type.getTypeName()) << "(";
             }
             else if (visit == InVisit)
             {
@@ -718,3 +694,59 @@
         out << "{\n}\n";  // Empty code block.
     }
 }
+
+TString TOutputGLSLBase::getTypeName(const TType& type)
+{
+    TInfoSinkBase out;
+    if (type.isMatrix())
+    {
+        out << "mat";
+        out << type.getNominalSize();
+    }
+    else if (type.isVector())
+    {
+        switch (type.getBasicType())
+        {
+            case EbtFloat: out << "vec"; break;
+            case EbtInt: out << "ivec"; break;
+            case EbtBool: out << "bvec"; break;
+            default: UNREACHABLE(); break;
+        }
+        out << type.getNominalSize();
+    }
+    else
+    {
+        if (type.getBasicType() == EbtStruct)
+            out << hashName(type.getTypeName());
+        else
+            out << type.getBasicString();
+    }
+    return TString(out.c_str());
+}
+
+TString TOutputGLSLBase::hashName(const TString& name)
+{
+    if (mHashFunction == NULL || name.empty())
+        return name;
+    NameMap::const_iterator it = mNameMap.find(name.c_str());
+    if (it != mNameMap.end())
+        return it->second.c_str();
+    TString hashedName = TIntermTraverser::hash(name, mHashFunction);
+    mNameMap[name.c_str()] = hashedName.c_str();
+    return hashedName;
+}
+
+TString TOutputGLSLBase::hashVariableName(const TString& name)
+{
+    if (mSymbolTable.findBuiltIn(name) != NULL)
+        return name;
+    return hashName(name);
+}
+
+TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
+{
+    TString name = TFunction::unmangleName(mangled_name);
+    if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
+        return name;
+    return hashName(name);
+}
diff --git a/src/compiler/OutputGLSLBase.h b/src/compiler/OutputGLSLBase.h
index efd0b5f..01e9d4a 100644
--- a/src/compiler/OutputGLSLBase.h
+++ b/src/compiler/OutputGLSLBase.h
@@ -16,7 +16,10 @@
 class TOutputGLSLBase : public TIntermTraverser
 {
 public:
-    TOutputGLSLBase(TInfoSinkBase& objSink);
+    TOutputGLSLBase(TInfoSinkBase& objSink,
+                    ShHashFunction64 hashFunction,
+                    NameMap& nameMap,
+                    TSymbolTable& symbolTable);
 
 protected:
     TInfoSinkBase& objSink() { return mObjSink; }
@@ -25,6 +28,7 @@
     virtual bool writeVariablePrecision(TPrecision precision) = 0;
     void writeFunctionParameters(const TIntermSequence& args);
     const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
+    TString getTypeName(const TType& type);
 
     virtual void visitSymbol(TIntermSymbol* node);
     virtual void visitConstantUnion(TIntermConstantUnion* node);
@@ -37,6 +41,15 @@
 
     void visitCodeBlock(TIntermNode* node);
 
+
+    // Return the original name if hash function pointer is NULL;
+    // otherwise return the hashed name.
+    TString hashName(const TString& name);
+    // Same as hashName(), but without hashing built-in variables.
+    TString hashVariableName(const TString& name);
+    // Same as hashName(), but without hashing built-in functions.
+    TString hashFunctionName(const TString& mangled_name);
+
 private:
     TInfoSinkBase& mObjSink;
     bool mDeclaringVariables;
@@ -48,6 +61,12 @@
     DeclaredStructs mDeclaredStructs;
 
     ForLoopUnroll mLoopUnroll;
+
+    // name hashing.
+    ShHashFunction64 mHashFunction;
+    NameMap& mNameMap;
+
+    TSymbolTable& mSymbolTable;
 };
 
 #endif  // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
diff --git a/src/compiler/ShHandle.h b/src/compiler/ShHandle.h
index 0c77bb0..23f0cf3 100644
--- a/src/compiler/ShHandle.h
+++ b/src/compiler/ShHandle.h
@@ -70,7 +70,8 @@
     int getMappedNameMaxLength() const;
 
     ShHashFunction64 getHashFunction() const { return hashFunction; }
-    const NameMap& getNameMap() const { return nameMap; }
+    NameMap& getNameMap() { return nameMap; }
+    TSymbolTable& getSymbolTable() { return symbolTable; }
 
 protected:
     ShShaderType getShaderType() const { return shaderType; }
diff --git a/src/compiler/TranslatorESSL.cpp b/src/compiler/TranslatorESSL.cpp
index e3a2c2a..f718f1e 100644
--- a/src/compiler/TranslatorESSL.cpp
+++ b/src/compiler/TranslatorESSL.cpp
@@ -23,7 +23,7 @@
         sink, getShaderType() == SH_FRAGMENT_SHADER);
 
     // Write translated shader.
-    TOutputESSL outputESSL(sink);
+    TOutputESSL outputESSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
     root->traverse(&outputESSL);
 }
 
diff --git a/src/compiler/TranslatorGLSL.cpp b/src/compiler/TranslatorGLSL.cpp
index bb07a1e..1e3ff38 100644
--- a/src/compiler/TranslatorGLSL.cpp
+++ b/src/compiler/TranslatorGLSL.cpp
@@ -36,6 +36,6 @@
         sink, false);
 
     // Write translated shader.
-    TOutputGLSL outputGLSL(sink);
+    TOutputGLSL outputGLSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
     root->traverse(&outputGLSL);
 }
diff --git a/src/compiler/VariableInfo.cpp b/src/compiler/VariableInfo.cpp
index 3ff2836..eb6bea9 100644
--- a/src/compiler/VariableInfo.cpp
+++ b/src/compiler/VariableInfo.cpp
@@ -77,23 +77,25 @@
 static void getUserDefinedVariableInfo(const TType& type,
                                        const TString& name,
                                        const TString& mappedName,
-                                       TVariableInfoList& infoList);
+                                       TVariableInfoList& infoList,
+                                       ShHashFunction64 hashFunction);
 
 // Returns info for an attribute or uniform.
 static void getVariableInfo(const TType& type,
                             const TString& name,
                             const TString& mappedName,
-                            TVariableInfoList& infoList)
+                            TVariableInfoList& infoList,
+                            ShHashFunction64 hashFunction)
 {
     if (type.getBasicType() == EbtStruct) {
         if (type.isArray()) {
             for (int i = 0; i < type.getArraySize(); ++i) {
                 TString lname = name + arrayBrackets(i);
                 TString lmappedName = mappedName + arrayBrackets(i);
-                getUserDefinedVariableInfo(type, lname, lmappedName, infoList);
+                getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction);
             }
         } else {
-            getUserDefinedVariableInfo(type, name, mappedName, infoList);
+            getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction);
         }
     } else {
         getBuiltInVariableInfo(type, name, mappedName, infoList);
@@ -124,7 +126,8 @@
 void getUserDefinedVariableInfo(const TType& type,
                                 const TString& name,
                                 const TString& mappedName,
-                                TVariableInfoList& infoList)
+                                TVariableInfoList& infoList,
+                                ShHashFunction64 hashFunction)
 {
     ASSERT(type.getBasicType() == EbtStruct);
 
@@ -133,8 +136,9 @@
         const TType* fieldType = (*structure)[i].type;
         getVariableInfo(*fieldType,
                         name + "." + fieldType->getFieldName(),
-                        mappedName + "." + fieldType->getFieldName(),
-                        infoList);
+                        mappedName + "." + TIntermTraverser::hash(fieldType->getFieldName(), hashFunction),
+                        infoList,
+                        hashFunction);
     }
 }
 
@@ -149,9 +153,11 @@
 }
 
 CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs,
-                                               TVariableInfoList& uniforms)
+                                               TVariableInfoList& uniforms,
+                                               ShHashFunction64 hashFunction)
     : mAttribs(attribs),
-      mUniforms(uniforms)
+      mUniforms(uniforms),
+      mHashFunction(hashFunction)
 {
 }
 
@@ -206,10 +212,16 @@
                 // cannot be initialized in a shader, we must have only
                 // TIntermSymbol nodes in the sequence.
                 ASSERT(variable != NULL);
+                TString processedSymbol;
+                if (mHashFunction == NULL)
+                    processedSymbol = variable->getSymbol();
+                else
+                    processedSymbol = TIntermTraverser::hash(variable->getOriginalSymbol(), mHashFunction);
                 getVariableInfo(variable->getType(),
                                 variable->getOriginalSymbol(),
-                                variable->getSymbol(),
-                                infoList);
+                                processedSymbol,
+                                infoList,
+                                mHashFunction);
             }
         }
         break;
diff --git a/src/compiler/VariableInfo.h b/src/compiler/VariableInfo.h
index fdcc08f..4130a58 100644
--- a/src/compiler/VariableInfo.h
+++ b/src/compiler/VariableInfo.h
@@ -27,7 +27,8 @@
 class CollectAttribsUniforms : public TIntermTraverser {
 public:
     CollectAttribsUniforms(TVariableInfoList& attribs,
-                           TVariableInfoList& uniforms);
+                           TVariableInfoList& uniforms,
+                           ShHashFunction64 hashFunction);
 
     virtual void visitSymbol(TIntermSymbol*);
     virtual void visitConstantUnion(TIntermConstantUnion*);
@@ -41,6 +42,8 @@
 private:
     TVariableInfoList& mAttribs;
     TVariableInfoList& mUniforms;
+
+    ShHashFunction64 mHashFunction;
 };
 
 #endif  // COMPILER_VARIABLE_INFO_H_
diff --git a/src/compiler/intermediate.h b/src/compiler/intermediate.h
index af78fa0..293db94 100644
--- a/src/compiler/intermediate.h
+++ b/src/compiler/intermediate.h
@@ -16,6 +16,8 @@
 #ifndef __INTERMEDIATE_H
 #define __INTERMEDIATE_H
 
+#include "GLSLANG/ShaderLang.h"
+
 #include "compiler/Common.h"
 #include "compiler/Types.h"
 #include "compiler/ConstantUnion.h"
@@ -545,6 +547,10 @@
     void incrementDepth() {depth++;}
     void decrementDepth() {depth--;}
 
+    // Return the original name if hash function pointer is NULL;
+    // otherwise return the hashed name.
+    static TString hash(const TString& name, ShHashFunction64 hashFunction);
+
     const bool preVisit;
     const bool inVisit;
     const bool postVisit;