Track parameter qualifiers of functions in call nodes

We now add a reference to TFunction to all TIntermAggregate nodes
where it is possible, including built-in ops. We also make sure
that internal TFunctions added in traversers have correct parameter
qualifiers.

This makes TLValueTrackingTraverser much simpler. Instead of storing
traversed functions or looking up builtin functions from the symbol
table, determining which function parameters are out parameters can
now be done simply by looking it up from the function symbol
associated with the aggregate node.

Symbol instances are no longer deleted when a symbol table level goes
out of scope, and TFunction destructor no longer clears the
parameters. They're all either statically allocated or pool allocated,
so this does not result in leaks.

TEST=angle_unittests
BUG=angleproject:2267

Change-Id: I57e5570da5b5a69a98a8778da3c2dc82b6284738
Reviewed-on: https://chromium-review.googlesource.com/881324
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/compiler/translator/RemoveDynamicIndexing.cpp
index 05593a0..184c711 100644
--- a/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -23,6 +23,8 @@
 namespace
 {
 
+const TType *kIndexType = StaticType::Get<EbtInt, EbpHigh, EvqIn, 1, 1>();
+
 std::string GetIndexFunctionName(const TType &type, bool write)
 {
     TInfoSinkBase nameSink;
@@ -59,31 +61,11 @@
     return nameSink.str();
 }
 
-TIntermSymbol *CreateBaseSymbol(const TType *type, TSymbolTable *symbolTable)
+TIntermSymbol *CreateParameterSymbol(const TConstParameter &parameter, TSymbolTable *symbolTable)
 {
-    TString *baseString = NewPoolTString("base");
-    TVariable *baseVariable =
-        new TVariable(symbolTable, baseString, type, SymbolType::AngleInternal);
-    return new TIntermSymbol(baseVariable);
-}
-
-TIntermSymbol *CreateIndexSymbol(TSymbolTable *symbolTable)
-{
-    TString *indexString     = NewPoolTString("index");
-    TVariable *indexVariable =
-        new TVariable(symbolTable, indexString, StaticType::Get<EbtInt, EbpHigh, EvqIn, 1, 1>(),
-                      SymbolType::AngleInternal);
-    return new TIntermSymbol(indexVariable);
-}
-
-TIntermSymbol *CreateValueSymbol(const TType &type, TSymbolTable *symbolTable)
-{
-    TString *valueString = NewPoolTString("value");
-    TType *valueType     = new TType(type);
-    valueType->setQualifier(EvqIn);
-    TVariable *valueVariable =
-        new TVariable(symbolTable, valueString, valueType, SymbolType::AngleInternal);
-    return new TIntermSymbol(valueVariable);
+    TVariable *variable =
+        new TVariable(symbolTable, parameter.name, parameter.type, SymbolType::AngleInternal);
+    return new TIntermSymbol(variable);
 }
 
 TIntermConstantUnion *CreateIntConstantNode(int i)
@@ -117,6 +99,20 @@
     }
 }
 
+const TType *GetBaseType(const TType &type, bool write)
+{
+    TType *baseType = new TType(type);
+    // Conservatively use highp here, even if the indexed type is not highp. That way the code can't
+    // end up using mediump version of an indexing function for a highp value, if both mediump and
+    // highp values are being indexed in the shader. For HLSL precision doesn't matter, but in
+    // principle this code could be used with multiple backends.
+    baseType->setPrecision(EbpHigh);
+    baseType->setQualifier(EvqInOut);
+    if (!write)
+        baseType->setQualifier(EvqIn);
+    return baseType;
+}
+
 // Generate a read or write function for one field in a vector/matrix.
 // Out-of-range indices are clamped. This is consistent with how ANGLE handles out-of-range
 // indices in other places.
@@ -167,7 +163,6 @@
 {
     ASSERT(!type.isArray());
 
-    const TType *fieldType = GetFieldType(type);
     int numCases    = 0;
     if (type.isMatrix())
     {
@@ -181,24 +176,14 @@
     std::string functionName                = GetIndexFunctionName(type, write);
     TIntermFunctionPrototype *prototypeNode = CreateInternalFunctionPrototypeNode(func);
 
-    TType *baseType = new TType(type);
-    // Conservatively use highp here, even if the indexed type is not highp. That way the code can't
-    // end up using mediump version of an indexing function for a highp value, if both mediump and
-    // highp values are being indexed in the shader. For HLSL precision doesn't matter, but in
-    // principle this code could be used with multiple backends.
-    baseType->setPrecision(EbpHigh);
-    baseType->setQualifier(EvqInOut);
-    if (!write)
-        baseType->setQualifier(EvqIn);
-
-    TIntermSymbol *baseParam = CreateBaseSymbol(baseType, symbolTable);
+    TIntermSymbol *baseParam = CreateParameterSymbol(func.getParam(0), symbolTable);
     prototypeNode->getSequence()->push_back(baseParam);
-    TIntermSymbol *indexParam = CreateIndexSymbol(symbolTable);
+    TIntermSymbol *indexParam = CreateParameterSymbol(func.getParam(1), symbolTable);
     prototypeNode->getSequence()->push_back(indexParam);
     TIntermSymbol *valueParam = nullptr;
     if (write)
     {
-        valueParam = CreateValueSymbol(*fieldType, symbolTable);
+        valueParam = CreateParameterSymbol(func.getParam(2), symbolTable);
         prototypeNode->getSequence()->push_back(valueParam);
     }
 
@@ -280,7 +265,6 @@
 {
   public:
     RemoveDynamicIndexingTraverser(TSymbolTable *symbolTable,
-                                   int shaderVersion,
                                    PerformanceDiagnostics *perfDiagnostics);
 
     bool visitBinary(Visit visit, TIntermBinary *node) override;
@@ -307,16 +291,22 @@
     bool mRemoveIndexSideEffectsInSubtree;
 
     PerformanceDiagnostics *mPerfDiagnostics;
+
+    const TString *mBaseName;
+    const TString *mIndexName;
+    const TString *mValueName;
 };
 
 RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser(
     TSymbolTable *symbolTable,
-    int shaderVersion,
     PerformanceDiagnostics *perfDiagnostics)
-    : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
+    : TLValueTrackingTraverser(true, false, false, symbolTable),
       mUsedTreeInsertion(false),
       mRemoveIndexSideEffectsInSubtree(false),
-      mPerfDiagnostics(perfDiagnostics)
+      mPerfDiagnostics(perfDiagnostics),
+      mBaseName(NewPoolTString("base")),
+      mIndexName(NewPoolTString("index")),
+      mValueName(NewPoolTString("value"))
 {
 }
 
@@ -422,6 +412,9 @@
                 indexingFunction =
                     new TFunction(mSymbolTable, indexingFunctionName, GetFieldType(type),
                                   SymbolType::AngleInternal, true);
+                indexingFunction->addParameter(
+                    TConstParameter(mBaseName, GetBaseType(type, false)));
+                indexingFunction->addParameter(TConstParameter(mIndexName, kIndexType));
                 mIndexedVecAndMatrixTypes[type] = indexingFunction;
             }
             else
@@ -467,8 +460,15 @@
                     TString *functionName = NewPoolTString(
                         GetIndexFunctionName(node->getLeft()->getType(), true).c_str());
                     indexedWriteFunction =
-                        new TFunction(mSymbolTable, functionName, new TType(EbtVoid),
+                        new TFunction(mSymbolTable, functionName, StaticType::GetBasic<EbtVoid>(),
                                       SymbolType::AngleInternal, false);
+                    indexedWriteFunction->addParameter(
+                        TConstParameter(mBaseName, GetBaseType(type, true)));
+                    indexedWriteFunction->addParameter(TConstParameter(mIndexName, kIndexType));
+                    TType *valueType = GetFieldType(type);
+                    valueType->setQualifier(EvqIn);
+                    indexedWriteFunction->addParameter(
+                        TConstParameter(mValueName, static_cast<const TType *>(valueType)));
                     mWrittenVecAndMatrixTypes[type] = indexedWriteFunction;
                 }
                 else
@@ -532,10 +532,9 @@
 
 void RemoveDynamicIndexing(TIntermNode *root,
                            TSymbolTable *symbolTable,
-                           int shaderVersion,
                            PerformanceDiagnostics *perfDiagnostics)
 {
-    RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion, perfDiagnostics);
+    RemoveDynamicIndexingTraverser traverser(symbolTable, perfDiagnostics);
     do
     {
         traverser.nextIteration();