Constant fold float pack/unpack functions

This change adds constant folding support for following floating
point pack and unpack functions:
    - packSnorm2x16, unpackSnorm2x16, packUnorm2x16, unpackUnorm2x16,
      packHalf2x16, and unpackHalf2x16.

BUG=angleproject:913
TEST=angle_unittests(new: MathUtilTest.packAndUnpack*), dEQP Tests
dEQP-GLES3.functional.shaders.constant_expressions.builtin_functions.float_pack_unpack.*
(all 10 tests started passing with this change)

Change-Id: I2b69faebee4127e5e13900b3a9485b7145950277
Reviewed-on: https://chromium-review.googlesource.com/282683
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index a83870a..4a84b24 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -1188,7 +1188,8 @@
     size_t objectSize = getType().getObjectSize();
 
     if (op == EOpAny || op == EOpAll || op == EOpLength || op == EOpTranspose || op == EOpDeterminant ||
-        op == EOpInverse)
+        op == EOpInverse || op == EOpPackSnorm2x16 || op == EOpUnpackSnorm2x16 || op == EOpPackUnorm2x16 ||
+        op == EOpUnpackUnorm2x16 || op == EOpPackHalf2x16 || op == EOpUnpackHalf2x16)
     {
         // Do operations where the return type has a different number of components compared to the operand type.
         TConstantUnion *resultArray = nullptr;
@@ -1296,6 +1297,97 @@
                 return nullptr;
             }
 
+          case EOpPackSnorm2x16:
+            if (getType().getBasicType() == EbtFloat)
+            {
+                ASSERT(getType().getNominalSize() == 2);
+                resultArray = new TConstantUnion();
+                resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+                break;
+            }
+            else
+            {
+                infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+                return nullptr;
+            }
+
+          case EOpUnpackSnorm2x16:
+            if (getType().getBasicType() == EbtUInt)
+            {
+                resultArray = new TConstantUnion[2];
+                float f1, f2;
+                gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
+                resultArray[0].setFConst(f1);
+                resultArray[1].setFConst(f2);
+                break;
+            }
+            else
+            {
+                infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+                return nullptr;
+            }
+
+          case EOpPackUnorm2x16:
+            if (getType().getBasicType() == EbtFloat)
+            {
+                ASSERT(getType().getNominalSize() == 2);
+                resultArray = new TConstantUnion();
+                resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+                break;
+            }
+            else
+            {
+                infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+                return nullptr;
+            }
+
+          case EOpUnpackUnorm2x16:
+            if (getType().getBasicType() == EbtUInt)
+            {
+                resultArray = new TConstantUnion[2];
+                float f1, f2;
+                gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
+                resultArray[0].setFConst(f1);
+                resultArray[1].setFConst(f2);
+                break;
+            }
+            else
+            {
+                infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+                return nullptr;
+            }
+
+          case EOpPackHalf2x16:
+            if (getType().getBasicType() == EbtFloat)
+            {
+                ASSERT(getType().getNominalSize() == 2);
+                resultArray = new TConstantUnion();
+                resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+                break;
+            }
+            else
+            {
+                infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+                return nullptr;
+            }
+
+          case EOpUnpackHalf2x16:
+            if (getType().getBasicType() == EbtUInt)
+            {
+                resultArray = new TConstantUnion[2];
+                float f1, f2;
+                gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
+                resultArray[0].setFConst(f1);
+                resultArray[1].setFConst(f2);
+                break;
+            }
+            else
+            {
+                infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+                return nullptr;
+            }
+            break;
+
           default:
             break;
         }