Add ESSL 3.10 ldexp/frexp builtins

This adds new built-ins found in ESSL 3.10 section 8.3 Common
Functions.

This includes constant folding support for ldexp and support for both
GLSL and HLSL output. In HLSL these functions need to be emulated.

BUG=angleproject:1730
TEST=angle_unittests

Change-Id: I1330e69978b0cf53efbc3416150194764414e96c
Reviewed-on: https://chromium-review.googlesource.com/435342
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
index 3f8acde..6d4ace3 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -126,6 +126,68 @@
                              "}\n"
                              "\n");
 
+    emu->addEmulatedFunction(EOpFrexp, float1, int1,
+                             "float webgl_frexp_emu(float x, out int exp)\n"
+                             "{\n"
+                             "    float fexp;\n"
+                             "    float mantissa = frexp(abs(x), fexp) * sign(x);\n"
+                             "    exp = int(fexp);\n"
+                             "    return mantissa;\n"
+                             "}\n"
+                             "\n");
+    emu->addEmulatedFunction(EOpFrexp, float2, int2,
+                             "float2 webgl_frexp_emu(float2 x, out int2 exp)\n"
+                             "{\n"
+                             "    float2 fexp;\n"
+                             "    float2 mantissa = frexp(abs(x), fexp) * sign(x);\n"
+                             "    exp = int2(fexp);\n"
+                             "    return mantissa;\n"
+                             "}\n"
+                             "\n");
+    emu->addEmulatedFunction(EOpFrexp, float3, int3,
+                             "float3 webgl_frexp_emu(float3 x, out int3 exp)\n"
+                             "{\n"
+                             "    float3 fexp;\n"
+                             "    float3 mantissa = frexp(abs(x), fexp) * sign(x);\n"
+                             "    exp = int3(fexp);\n"
+                             "    return mantissa;\n"
+                             "}\n"
+                             "\n");
+    emu->addEmulatedFunction(EOpFrexp, float4, int4,
+                             "float4 webgl_frexp_emu(float4 x, out int4 exp)\n"
+                             "{\n"
+                             "    float4 fexp;\n"
+                             "    float4 mantissa = frexp(abs(x), fexp) * sign(x);\n"
+                             "    exp = int4(fexp);\n"
+                             "    return mantissa;\n"
+                             "}\n"
+                             "\n");
+
+    emu->addEmulatedFunction(EOpLdexp, float1, int1,
+                             "float webgl_ldexp_emu(float x, int exp)\n"
+                             "{\n"
+                             "    return ldexp(x, float(exp));\n"
+                             "}\n"
+                             "\n");
+    emu->addEmulatedFunction(EOpLdexp, float2, int2,
+                             "float2 webgl_ldexp_emu(float2 x, int2 exp)\n"
+                             "{\n"
+                             "    return ldexp(x, float2(exp));\n"
+                             "}\n"
+                             "\n");
+    emu->addEmulatedFunction(EOpLdexp, float3, int3,
+                             "float3 webgl_ldexp_emu(float3 x, int3 exp)\n"
+                             "{\n"
+                             "    return ldexp(x, float3(exp));\n"
+                             "}\n"
+                             "\n");
+    emu->addEmulatedFunction(EOpLdexp, float4, int4,
+                             "float4 webgl_ldexp_emu(float4 x, int4 exp)\n"
+                             "{\n"
+                             "    return ldexp(x, float4(exp));\n"
+                             "}\n"
+                             "\n");
+
     emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1,
                              "float webgl_faceforward_emu(float N, float I, float Nref)\n"
                              "{\n"
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index 8a6a63a..1bad320 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -111,6 +111,7 @@
     symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSmoothStep, genType, float1, float1, genType);
 
     const TType *outGenType = TCache::getType(EbtGenType, EvqOut);
+    const TType *outGenIType = TCache::getType(EbtGenIType, EvqOut);
 
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpModf, genType, genType, outGenType);
 
@@ -121,6 +122,9 @@
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpIntBitsToFloat, genType, genIType);
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUintBitsToFloat, genType, genUType);
 
+    symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpFrexp, genType, genType, outGenIType);
+    symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpLdexp, genType, genType, genIType);
+
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpPackSnorm2x16, uint1, float2);
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpPackUnorm2x16, uint1, float2);
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpPackHalf2x16, uint1, float2);
@@ -234,7 +238,6 @@
     // Integer functions
     //
     const TType *outGenUType = TCache::getType(EbtGenUType, EvqOut);
-    const TType *outGenIType = TCache::getType(EbtGenIType, EvqOut);
 
     symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldExtract, genIType, genIType, int1,
                                 int1);
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 4039305..1401af7 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -3012,6 +3012,25 @@
             break;
         }
 
+        case EOpLdexp:
+        {
+            resultArray = new TConstantUnion[maxObjectSize];
+            for (size_t i = 0; i < maxObjectSize; i++)
+            {
+                float x = unionArrays[0][i].getFConst();
+                int exp = unionArrays[1][i].getIConst();
+                if (exp > 128)
+                {
+                    UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
+                }
+                else
+                {
+                    resultArray[i].setFConst(gl::Ldexp(x, exp));
+                }
+            }
+            break;
+        }
+
         case EOpFaceForward:
         {
             ASSERT(basicType == EbtFloat);
diff --git a/src/compiler/translator/Intermediate.cpp b/src/compiler/translator/Intermediate.cpp
index 084df31..0b38eb5 100644
--- a/src/compiler/translator/Intermediate.cpp
+++ b/src/compiler/translator/Intermediate.cpp
@@ -273,6 +273,7 @@
         case EOpMix:
         case EOpStep:
         case EOpSmoothStep:
+        case EOpLdexp:
         case EOpMulMatrixComponentWise:
         case EOpOuterProduct:
         case EOpEqualComponentWise:
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index 64e8052..fc2a981 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -197,6 +197,11 @@
         case EOpUintBitsToFloat:
             return "uintBitsToFloat";
 
+        case EOpFrexp:
+            return "frexp";
+        case EOpLdexp:
+            return "ldexp";
+
         case EOpPackSnorm2x16:
             return "packSnorm2x16";
         case EOpPackUnorm2x16:
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index 18e7ca5..83b957d 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -143,6 +143,9 @@
     EOpIntBitsToFloat,
     EOpUintBitsToFloat,
 
+    EOpFrexp,
+    EOpLdexp,
+
     EOpPackSnorm2x16,
     EOpPackUnorm2x16,
     EOpPackHalf2x16,
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 4ae8651..7831b33 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -937,6 +937,8 @@
         case EOpMix:
         case EOpStep:
         case EOpSmoothStep:
+        case EOpFrexp:
+        case EOpLdexp:
         case EOpDistance:
         case EOpDot:
         case EOpCross:
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index df0fa9f..60dcfd3 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1993,6 +1993,11 @@
         case EOpSmoothStep:
             outputTriplet(out, visit, "smoothstep(", ", ", ")");
             break;
+        case EOpFrexp:
+        case EOpLdexp:
+            ASSERT(node->getUseEmulatedFunction());
+            writeEmulatedFunctionTriplet(out, visit, node->getOp());
+            break;
         case EOpDistance:
             outputTriplet(out, visit, "distance(", ", ", ")");
             break;