Implement trunc, round, roundEven (Emulated roundEven)

BUG=angle:934

Change-Id: If33256bf3707f3f0202147276c71f08c65518205
Reviewed-on: https://chromium-review.googlesource.com/254842
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
index 0068249..52f75d0 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -194,6 +194,35 @@
         "    return 0.5 * log((1.0 + x) / (1.0 - x));\n"
         "}\n");
 
+    AddEmulatedFunction(EOpRoundEven, float1,
+        "float webgl_roundEven_emu(in float x) {\n"
+        "    return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n"
+        "}\n");
+    AddEmulatedFunction(EOpRoundEven, float2,
+        "float2 webgl_roundEven_emu(in float2 x) {\n"
+        "    float2 v;\n"
+        "    v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
+        "    v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
+        "    return v;\n"
+        "}\n");
+    AddEmulatedFunction(EOpRoundEven, float3,
+        "float3 webgl_roundEven_emu(in float3 x) {\n"
+        "    float3 v;\n"
+        "    v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
+        "    v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
+        "    v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
+        "    return v;\n"
+        "}\n");
+    AddEmulatedFunction(EOpRoundEven, float4,
+        "float4 webgl_roundEven_emu(in float4 x) {\n"
+        "    float4 v;\n"
+        "    v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
+        "    v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
+        "    v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
+        "    v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n"
+        "    return v;\n"
+        "}\n");
+
     AddEmulatedFunction(EOpPackSnorm2x16, float2,
         "int webgl_toSnorm(in float x) {\n"
         "    return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index 6c87c61..7832c86 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -69,6 +69,9 @@
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSign, genType, "sign", genType);
     symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSign, genIType, "sign", genIType);
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFloor, genType, "floor", genType);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTrunc, genType, "trunc", genType);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRound, genType, "round", genType);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRoundEven, genType, "roundEven", genType);
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCeil, genType, "ceil", genType);
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFract, genType, "fract", genType);
     symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, float1);
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index ef78607..ae4512b 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -91,6 +91,9 @@
       case EOpAbs: return "abs";
       case EOpSign: return "sign";
       case EOpFloor: return "floor";
+      case EOpTrunc: return "trunc";
+      case EOpRound: return "round";
+      case EOpRoundEven: return "roundEven";
       case EOpCeil: return "ceil";
       case EOpFract: return "fract";
       case EOpMod: return "mod";
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index 4884f1c..8290f95 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -111,6 +111,9 @@
     EOpAbs,
     EOpSign,
     EOpFloor,
+    EOpTrunc,
+    EOpRound,
+    EOpRoundEven,
     EOpCeil,
     EOpFract,
     EOpMod,
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index cea2b4a..4827ee1 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -549,6 +549,15 @@
       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;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index fce12f1..faa760f 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1680,6 +1680,12 @@
       case EOpAbs:              outputTriplet(visit, "abs(", "", ")");       break;
       case EOpSign:             outputTriplet(visit, "sign(", "", ")");      break;
       case EOpFloor:            outputTriplet(visit, "floor(", "", ")");     break;
+      case EOpTrunc:            outputTriplet(visit, "trunc(", "", ")");     break;
+      case EOpRound:            outputTriplet(visit, "round(", "", ")");     break;
+      case EOpRoundEven:
+        ASSERT(node->getUseEmulatedFunction());
+        writeEmulatedFunctionTriplet(visit, "roundEven(");
+        break;
       case EOpCeil:             outputTriplet(visit, "ceil(", "", ")");      break;
       case EOpFract:            outputTriplet(visit, "frac(", "", ")");      break;
       case EOpIsNan:            outputTriplet(visit, "isnan(", "", ")");     break;
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index 614cdc4..07c50f0 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -327,6 +327,9 @@
       case EOpAbs:            out << "Absolute value";       break;
       case EOpSign:           out << "Sign";                 break;
       case EOpFloor:          out << "Floor";                break;
+      case EOpTrunc:          out << "Truncate";             break;
+      case EOpRound:          out << "Round";                break;
+      case EOpRoundEven:      out << "Round half even";      break;
       case EOpCeil:           out << "Ceiling";              break;
       case EOpFract:          out << "Fraction";             break;
       case EOpIsNan:          out << "Is not a number";      break;