diff options
author | Kyungwoo Lee <kyulee@microsoft.com> | 2016-04-18 18:37:52 -0700 |
---|---|---|
committer | Kyungwoo Lee <kyulee@microsoft.com> | 2016-04-18 18:37:52 -0700 |
commit | fdc7e90413f080a2871749f009c775b5d06c8522 (patch) | |
tree | 45d58e70072962b1c4c15dc53c5980c63b7416d6 /src | |
parent | 83e52facfec1ae6002ed9d0a474c300ab3dbe2fe (diff) | |
parent | 75c97cff492584075b6e13d67a901c69c34ad4f9 (diff) | |
download | coreclr-fdc7e90413f080a2871749f009c775b5d06c8522.tar.gz coreclr-fdc7e90413f080a2871749f009c775b5d06c8522.tar.bz2 coreclr-fdc7e90413f080a2871749f009c775b5d06c8522.zip |
Merge pull request #4392 from kyulee1/fixround
ARM64: Fix Round Operation
Diffstat (limited to 'src')
-rw-r--r-- | src/jit/codegenarm64.cpp | 2 | ||||
-rw-r--r-- | src/jit/utils.cpp | 26 | ||||
-rw-r--r-- | src/jit/utils.h | 2 | ||||
-rw-r--r-- | src/jit/valuenum.cpp | 2 |
4 files changed, 30 insertions, 2 deletions
diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp index f6305b8966..1473171863 100644 --- a/src/jit/codegenarm64.cpp +++ b/src/jit/codegenarm64.cpp @@ -6519,7 +6519,7 @@ CodeGen::genIntrinsic(GenTreePtr treeNode) case CORINFO_INTRINSIC_Round: genConsumeOperands(treeNode->AsOp()); - getEmitter()->emitInsBinary(INS_frinta, emitTypeSize(treeNode), treeNode, srcNode); + getEmitter()->emitInsBinary(INS_frintn, emitTypeSize(treeNode), treeNode, srcNode); break; case CORINFO_INTRINSIC_Sqrt: diff --git a/src/jit/utils.cpp b/src/jit/utils.cpp index c86d124b1b..f92335e9b6 100644 --- a/src/jit/utils.cpp +++ b/src/jit/utils.cpp @@ -1614,3 +1614,29 @@ unsigned __int64 FloatingPointUtils::convertDoubleToUInt64(double d) { return u64; } + +// Rounds a double-precision floating-point value to the nearest integer, +// and rounds midpoint values to the nearest even number. +// Note this should align with classlib in floatnative.cpp +// Specializing for x86 using a x87 instruction is optional since +// this outcome is identical across targets. +double FloatingPointUtils::round(double d) +{ + // If the number has no fractional part do nothing + // This shortcut is necessary to workaround precision loss in borderline cases on some platforms + if (d == (double)(__int64)d) + return d; + + double tempVal = (d + 0.5); + //We had a number that was equally close to 2 integers. + //We need to return the even one. + double flrTempVal = floor(tempVal); + if (flrTempVal == tempVal) { + if (fmod(tempVal, 2.0) != 0) { + flrTempVal -= 1.0; + } + } + + flrTempVal = _copysign(flrTempVal, d); + return flrTempVal; +} diff --git a/src/jit/utils.h b/src/jit/utils.h index 7f141637f9..242a862b2b 100644 --- a/src/jit/utils.h +++ b/src/jit/utils.h @@ -538,6 +538,8 @@ public: static float convertUInt64ToFloat(unsigned __int64 u64); static unsigned __int64 convertDoubleToUInt64(double d); + + static double round(double d); }; #endif // _UTILS_H_ diff --git a/src/jit/valuenum.cpp b/src/jit/valuenum.cpp index 6471075ecd..f928d607ee 100644 --- a/src/jit/valuenum.cpp +++ b/src/jit/valuenum.cpp @@ -3082,7 +3082,7 @@ ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, CorInfoIntrinsics gtMat res = fabs(arg0Val); // The result and params are doubles. break; case CORINFO_INTRINSIC_Round: - res = (arg0Val > 0.0 ? floor(arg0Val + 0.5) : ceil(arg0Val - 0.5)); + res = FloatingPointUtils::round(arg0Val); break; default: unreached(); // the above are the only math intrinsics at the time of this writing. |