Use GetOperatorString when writing GLSL unary built-in calls

GetOperatorString is now used when writing GLSL for built-in calls
that fall under TIntermUnary. Component-wise not TOperator enum is
renamed for consistency.

This also cleans up some unnecessary creation of string objects when
writing built-in functions.

BUG=angleproject:1682
TEST=angle_unittests, angle_end2end_tests, WebGL conformance tests

Change-Id: I89b2ef222bf5af479d4977417f320789b58ace85
Reviewed-on: https://chromium-review.googlesource.com/424552
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/compiler/translator/BuiltInFunctionEmulator.cpp
index 38e8ea7..57e5ba2 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -228,10 +228,10 @@
 }
 
 // static
-TString BuiltInFunctionEmulator::GetEmulatedFunctionName(const TString &name)
+void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
 {
-    ASSERT(name[name.length() - 1] == '(');
-    return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
+    ASSERT(name[strlen(name) - 1] != '(');
+    out << "webgl_" << name << "_emu";
 }
 
 BuiltInFunctionEmulator::FunctionId::FunctionId()
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.h b/src/compiler/translator/BuiltInFunctionEmulator.h
index 137a2c5..620fd89 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.h
+++ b/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -27,8 +27,8 @@
 
     void Cleanup();
 
-    // "name(" becomes "webgl_name_emu(".
-    static TString GetEmulatedFunctionName(const TString &name);
+    // "name" gets written as "webgl_name_emu".
+    static void WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name);
 
     bool IsOutputEmpty() const;
 
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index ec95ead..780728b 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -676,12 +676,12 @@
     switch (node->getOp())
     {
         case EOpNegative:
-        case EOpVectorLogicalNot:
         case EOpLogicalNot:
         case EOpPostIncrement:
         case EOpPostDecrement:
         case EOpPreIncrement:
         case EOpPreDecrement:
+        case EOpLogicalNotComponentWise:
             break;
         default:
             if (canRoundFloat(node->getType()) && visit == PreVisit)
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index aa47fbf..b369223 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -272,7 +272,7 @@
                               bvec);
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAny, bool1, "any", bvec);
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAll, bool1, "all", bvec);
-    symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorLogicalNot, bvec, "not", bvec);
+    symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLogicalNotComponentWise, bvec, "not", bvec);
 
     const TType *sampler2D   = TCache::getType(EbtSampler2D);
     const TType *samplerCube = TCache::getType(EbtSamplerCube);
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 9888c5b..61fcb40 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -2123,7 +2123,7 @@
                 }
                 break;
 
-            case EOpVectorLogicalNot:
+            case EOpLogicalNotComponentWise:
                 ASSERT(getType().getBasicType() == EbtBool);
                 resultArray[i].setBConst(!operandArray[i].getBConst());
                 break;
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index 99127c0..9044340 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -18,8 +18,6 @@
             return "+";
         case EOpLogicalNot:
             return "!";
-        case EOpVectorLogicalNot:
-            return "not";
         case EOpBitwiseNot:
             return "~";
 
@@ -251,6 +249,8 @@
             return "any";
         case EOpAll:
             return "all";
+        case EOpLogicalNotComponentWise:
+            return "not";
 
         case EOpKill:
             return "kill";
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index b88773e..0415070 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -25,7 +25,6 @@
     EOpNegative,
     EOpPositive,
     EOpLogicalNot,
-    EOpVectorLogicalNot,
     EOpBitwiseNot,
 
     EOpPostIncrement,
@@ -34,7 +33,8 @@
     EOpPreDecrement,
 
     //
-    // binary operations
+    // binary operations (ones with special GLSL syntax are used in TIntermBinary nodes, others in
+    // TIntermAggregate nodes)
     //
 
     EOpAdd,
@@ -82,7 +82,7 @@
     EOpIndexDirectInterfaceBlock,
 
     //
-    // Built-in functions potentially mapped to operators
+    // Built-in functions mapped to operators (either unary or with multiple parameters)
     //
 
     EOpRadians,
@@ -161,6 +161,7 @@
 
     EOpAny,
     EOpAll,
+    EOpLogicalNotComponentWise,
 
     //
     // Branch
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 790a1bf..e7684ed 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -143,13 +143,24 @@
                                                   TOperator op,
                                                   bool useEmulatedFunction)
 {
-    TString opStr(GetOperatorString(op));
-    opStr += "(";
-    if (useEmulatedFunction)
+    TInfoSinkBase &out = objSink();
+    if (visit == PreVisit)
     {
-        opStr = BuiltInFunctionEmulator::GetEmulatedFunctionName(opStr);
+        const char *opStr(GetOperatorString(op));
+        if (useEmulatedFunction)
+        {
+            BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
+        }
+        else
+        {
+            out << opStr;
+        }
+        out << "(";
     }
-    writeTriplet(visit, opStr.c_str(), ", ", ")");
+    else
+    {
+        writeTriplet(visit, nullptr, ", ", ")");
+    }
 }
 
 void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
@@ -641,9 +652,6 @@
         case EOpPositive:
             preString = "(+";
             break;
-        case EOpVectorLogicalNot:
-            preString = "not(";
-            break;
         case EOpLogicalNot:
             preString = "(!";
             break;
@@ -667,171 +675,62 @@
             break;
 
         case EOpRadians:
-            preString = "radians(";
-            break;
         case EOpDegrees:
-            preString = "degrees(";
-            break;
         case EOpSin:
-            preString = "sin(";
-            break;
         case EOpCos:
-            preString = "cos(";
-            break;
         case EOpTan:
-            preString = "tan(";
-            break;
         case EOpAsin:
-            preString = "asin(";
-            break;
         case EOpAcos:
-            preString = "acos(";
-            break;
         case EOpAtan:
-            preString = "atan(";
-            break;
-
         case EOpSinh:
-            preString = "sinh(";
-            break;
         case EOpCosh:
-            preString = "cosh(";
-            break;
         case EOpTanh:
-            preString = "tanh(";
-            break;
         case EOpAsinh:
-            preString = "asinh(";
-            break;
         case EOpAcosh:
-            preString = "acosh(";
-            break;
         case EOpAtanh:
-            preString = "atanh(";
-            break;
-
         case EOpExp:
-            preString = "exp(";
-            break;
         case EOpLog:
-            preString = "log(";
-            break;
         case EOpExp2:
-            preString = "exp2(";
-            break;
         case EOpLog2:
-            preString = "log2(";
-            break;
         case EOpSqrt:
-            preString = "sqrt(";
-            break;
         case EOpInverseSqrt:
-            preString = "inversesqrt(";
-            break;
-
         case EOpAbs:
-            preString = "abs(";
-            break;
         case EOpSign:
-            preString = "sign(";
-            break;
         case EOpFloor:
-            preString = "floor(";
-            break;
         case EOpTrunc:
-            preString = "trunc(";
-            break;
         case EOpRound:
-            preString = "round(";
-            break;
         case EOpRoundEven:
-            preString = "roundEven(";
-            break;
         case EOpCeil:
-            preString = "ceil(";
-            break;
         case EOpFract:
-            preString = "fract(";
-            break;
         case EOpIsNan:
-            preString = "isnan(";
-            break;
         case EOpIsInf:
-            preString = "isinf(";
-            break;
-
         case EOpFloatBitsToInt:
-            preString = "floatBitsToInt(";
-            break;
         case EOpFloatBitsToUint:
-            preString = "floatBitsToUint(";
-            break;
         case EOpIntBitsToFloat:
-            preString = "intBitsToFloat(";
-            break;
         case EOpUintBitsToFloat:
-            preString = "uintBitsToFloat(";
-            break;
-
         case EOpPackSnorm2x16:
-            preString = "packSnorm2x16(";
-            break;
         case EOpPackUnorm2x16:
-            preString = "packUnorm2x16(";
-            break;
         case EOpPackHalf2x16:
-            preString = "packHalf2x16(";
-            break;
         case EOpUnpackSnorm2x16:
-            preString = "unpackSnorm2x16(";
-            break;
         case EOpUnpackUnorm2x16:
-            preString = "unpackUnorm2x16(";
-            break;
         case EOpUnpackHalf2x16:
-            preString = "unpackHalf2x16(";
-            break;
-
         case EOpLength:
-            preString = "length(";
-            break;
         case EOpNormalize:
-            preString = "normalize(";
-            break;
-
         case EOpDFdx:
-            preString = "dFdx(";
-            break;
         case EOpDFdy:
-            preString = "dFdy(";
-            break;
         case EOpFwidth:
-            preString = "fwidth(";
-            break;
-
         case EOpTranspose:
-            preString = "transpose(";
-            break;
         case EOpDeterminant:
-            preString = "determinant(";
-            break;
         case EOpInverse:
-            preString = "inverse(";
-            break;
-
         case EOpAny:
-            preString = "any(";
-            break;
         case EOpAll:
-            preString = "all(";
-            break;
-
+        case EOpLogicalNotComponentWise:
+            writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
+            return true;
         default:
             UNREACHABLE();
     }
 
-    if (visit == PreVisit && node->getUseEmulatedFunction())
-        preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
     writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
 
     return true;
@@ -976,7 +875,6 @@
 {
     bool visitChildren       = true;
     TInfoSinkBase &out       = objSink();
-    bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
     switch (node->getOp())
     {
         case EOpPrototype:
@@ -1074,7 +972,7 @@
         case EOpMemoryBarrierImage:
         case EOpMemoryBarrierShared:
         case EOpGroupMemoryBarrier:
-            writeBuiltInFunctionTriplet(visit, node->getOp(), useEmulatedFunction);
+            writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
             break;
         default:
             UNREACHABLE();
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 1e08490..eda90a0 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1199,9 +1199,6 @@
         case EOpPositive:
             outputTriplet(out, visit, "(+", "", ")");
             break;
-        case EOpVectorLogicalNot:
-            outputTriplet(out, visit, "(!", "", ")");
-            break;
         case EOpLogicalNot:
             outputTriplet(out, visit, "(!", "", ")");
             break;
@@ -1254,16 +1251,10 @@
             outputTriplet(out, visit, "tanh(", "", ")");
             break;
         case EOpAsinh:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "asinh(");
-            break;
         case EOpAcosh:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "acosh(");
-            break;
         case EOpAtanh:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "atanh(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpExp:
             outputTriplet(out, visit, "exp(", "", ")");
@@ -1300,7 +1291,7 @@
             break;
         case EOpRoundEven:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "roundEven(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpCeil:
             outputTriplet(out, visit, "ceil(", "", ")");
@@ -1310,7 +1301,7 @@
             break;
         case EOpIsNan:
             if (node->getUseEmulatedFunction())
-                writeEmulatedFunctionTriplet(out, visit, "isnan(");
+                writeEmulatedFunctionTriplet(out, visit, node->getOp());
             else
                 outputTriplet(out, visit, "isnan(", "", ")");
             mRequiresIEEEStrictCompiling = true;
@@ -1331,28 +1322,13 @@
             outputTriplet(out, visit, "asfloat(", "", ")");
             break;
         case EOpPackSnorm2x16:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
-            break;
         case EOpPackUnorm2x16:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
-            break;
         case EOpPackHalf2x16:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
-            break;
         case EOpUnpackSnorm2x16:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
-            break;
         case EOpUnpackUnorm2x16:
-            ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
-            break;
         case EOpUnpackHalf2x16:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpLength:
             outputTriplet(out, visit, "length(", "", ")");
@@ -1398,7 +1374,7 @@
             break;
         case EOpInverse:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "inverse(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
 
         case EOpAny:
@@ -1407,6 +1383,9 @@
         case EOpAll:
             outputTriplet(out, visit, "all(", "", ")");
             break;
+        case EOpLogicalNotComponentWise:
+            outputTriplet(out, visit, "(!", "", ")");
+            break;
         default:
             UNREACHABLE();
     }
@@ -1866,7 +1845,7 @@
             break;
         case EOpMod:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "mod(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpModf:
             outputTriplet(out, visit, "modf(", ", ", ")");
@@ -1877,7 +1856,7 @@
         case EOpAtan:
             ASSERT(node->getSequence()->size() == 2);  // atan(x) is a unary operator
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "atan(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpMin:
             outputTriplet(out, visit, "min(", ", ", ")");
@@ -1897,7 +1876,7 @@
                 // y, genBType a)",
                 // so use emulated version.
                 ASSERT(node->getUseEmulatedFunction());
-                writeEmulatedFunctionTriplet(out, visit, "mix(");
+                writeEmulatedFunctionTriplet(out, visit, node->getOp());
             }
             else
             {
@@ -1922,7 +1901,7 @@
             break;
         case EOpFaceForward:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "faceforward(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpReflect:
             outputTriplet(out, visit, "reflect(", ", ", ")");
@@ -1932,7 +1911,7 @@
             break;
         case EOpOuterProduct:
             ASSERT(node->getUseEmulatedFunction());
-            writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;
         case EOpMulMatrixComponentWise:
             outputTriplet(out, visit, "(", " * ", ")");
@@ -2634,10 +2613,18 @@
     return constUnionIterated;
 }
 
-void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr)
+void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
 {
-    TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
-    outputTriplet(out, visit, preString.c_str(), ", ", ")");
+    if (visit == PreVisit)
+    {
+        const char *opStr = GetOperatorString(op);
+        BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
+        out << "(";
+    }
+    else
+    {
+        outputTriplet(out, visit, nullptr, ", ", ")");
+    }
 }
 
 bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index cd4c64b..0c7d482 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -109,7 +109,7 @@
 
     void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
 
-    void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr);
+    void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op);
     void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
 
     // Returns true if it found a 'same symbol' initializer (initializer that references the
@@ -122,7 +122,6 @@
                                      TIntermSymbol *symbolNode,
                                      TIntermTyped *expression);
 
-    void writeDeferredGlobalInitializers(TInfoSinkBase &out);
     void writeIfElse(TInfoSinkBase &out, TIntermIfElse *node);
 
     // Returns the function name
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index e2b33cd..088448b 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -300,9 +300,8 @@
         case EOpPositive:
             out << "Positive sign";
             break;
-        case EOpVectorLogicalNot:
         case EOpLogicalNot:
-            out << "Negate conditional";
+            out << "negation";
             break;
         case EOpBitwiseNot:
             out << "bit-wise not";
@@ -474,6 +473,9 @@
         case EOpAll:
             out << "all";
             break;
+        case EOpLogicalNotComponentWise:
+            out << "component-wise not";
+            break;
 
         default:
             out.prefix(SH_ERROR);