Support array equality operator in HLSL output

This requires adding functions to the shader source that can do the
comparison for a specific array size.

There's no automated test coverage specifically for this functionality,
since all deqp tests that cover this also require array constructors to
be supported. The change has been tested by manually inspecting shader
output. No regressions were seen in automated tests listed below.

TEST=dEQP-GLES3.functional.shaders.*, angle_unittests
BUG=angleproject:941

Change-Id: Ie2ca7c016a3f0bcb3392a96d6d20d6f803d28bf0
Reviewed-on: https://chromium-review.googlesource.com/261530
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Nicolas Capens <capn@chromium.org>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index 122b81e..4b85580 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -67,6 +67,7 @@
     bool handleExcessiveLoop(TIntermLoop *node);
 
     // Emit one of three strings depending on traverse phase. Called with literal strings so using const char* instead of TString.
+    void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out);
     void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString);
     void outputLineDirective(int line);
     TString argumentString(const TIntermSymbol *symbol);
@@ -76,6 +77,8 @@
     void outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters);
     const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
 
+    void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
+
     void writeEmulatedFunctionTriplet(Visit visit, const char *preStr);
     void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
 
@@ -85,6 +88,7 @@
 
     // Returns the function name
     TString addStructEqualityFunction(const TStructure &structure);
+    TString addArrayEqualityFunction(const TType &type);
 
     sh::GLenum mShaderType;
     int mShaderVersion;
@@ -103,6 +107,7 @@
 
     // A stack is useful when we want to traverse in the header, or in helper functions, but not always
     // write to the body. Instead use an InfoSink stack to keep our current state intact.
+    // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler.
     std::stack<TInfoSinkBase *> mInfoSinkStack;
 
     ReferencedSymbols mReferencedUniforms;
@@ -191,6 +196,15 @@
     };
 
     std::vector<StructEqualityFunction> mStructEqualityFunctions;
+
+    struct ArrayEqualityFunction
+    {
+        TType type;
+        TString functionName;
+        TString functionDefinition;
+    };
+
+    std::vector<ArrayEqualityFunction> mArrayEqualityFunctions;
 };
 
 }