Support constant folding of common built-ins

This change adds constant folding support for unary common built-ins:
abs, sign, floor, trunc, round, roundEven, ceil and fract.

BUG=angleproject:913
TEST= dEQP tests
dEQP-GLES3.functional.shaders.constant_expressions.builtin_functions.common*
(80 out of 210 tests started passing with this change)

Change-Id: I46312fec43084601d4fca8195ddaaa5292f1c02a
Reviewed-on: https://chromium-review.googlesource.com/265967
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 49f688d..4a60dc5 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -11,6 +11,7 @@
 #include <float.h>
 #include <limits.h>
 #include <math.h>
+#include <stdlib.h>
 #include <algorithm>
 
 #include "compiler/translator/HashNames.h"
@@ -1284,6 +1285,106 @@
                     return nullptr;
                 break;
 
+              case EOpAbs:
+                switch (getType().getBasicType())
+                {
+                  case EbtFloat:
+                    tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
+                    break;
+                  case EbtInt:
+                    tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
+                    break;
+                  default:
+                    infoSink.info.message(
+                        EPrefixInternalError, getLine(),
+                        "Unary operation not folded into constant");
+                    return nullptr;
+                }
+                break;
+
+              case EOpSign:
+                switch (getType().getBasicType())
+                {
+                  case EbtFloat:
+                    {
+                        float fConst = unionArray[i].getFConst();
+                        float fResult = 0.0f;
+                        if (fConst > 0.0f)
+                            fResult = 1.0f;
+                        else if (fConst < 0.0f)
+                            fResult = -1.0f;
+                        tempConstArray[i].setFConst(fResult);
+                    }
+                    break;
+                  case EbtInt:
+                    {
+                        int iConst = unionArray[i].getIConst();
+                        int iResult = 0;
+                        if (iConst > 0)
+                            iResult = 1;
+                        else if (iConst < 0)
+                            iResult = -1;
+                        tempConstArray[i].setIConst(iResult);
+                    }
+                    break;
+                  default:
+                    infoSink.info.message(
+                        EPrefixInternalError, getLine(),
+                        "Unary operation not folded into constant");
+                    return nullptr;
+                }
+                break;
+
+              case EOpFloor:
+                if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
+                    return nullptr;
+                break;
+
+              case EOpTrunc:
+                if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
+                    return nullptr;
+                break;
+
+              case EOpRound:
+                if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
+                    return nullptr;
+                break;
+
+              case EOpRoundEven:
+                if (getType().getBasicType() == EbtFloat)
+                {
+                    float x = unionArray[i].getFConst();
+                    float result;
+                    float fractPart = modff(x, &result);
+                    if (fabsf(fractPart) == 0.5f)
+                        result = 2.0f * roundf(x / 2.0f);
+                    else
+                        result = roundf(x);
+                    tempConstArray[i].setFConst(result);
+                    break;
+                }
+                infoSink.info.message(
+                    EPrefixInternalError, getLine(),
+                    "Unary operation not folded into constant");
+                return nullptr;
+
+              case EOpCeil:
+                if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
+                    return nullptr;
+                break;
+
+              case EOpFract:
+                if (getType().getBasicType() == EbtFloat)
+                {
+                    float x = unionArray[i].getFConst();
+                    tempConstArray[i].setFConst(x - floorf(x));
+                    break;
+                }
+                infoSink.info.message(
+                    EPrefixInternalError, getLine(),
+                    "Unary operation not folded into constant");
+                return nullptr;
+
               default:
                 return NULL;
             }