diff options
author | Kyungwoo Lee <kyulee@microsoft.com> | 2016-04-18 10:42:51 -0700 |
---|---|---|
committer | Kyungwoo Lee <kyulee@microsoft.com> | 2016-04-18 17:46:40 -0700 |
commit | 75c97cff492584075b6e13d67a901c69c34ad4f9 (patch) | |
tree | 45d58e70072962b1c4c15dc53c5980c63b7416d6 /src/jit/utils.cpp | |
parent | 83e52facfec1ae6002ed9d0a474c300ab3dbe2fe (diff) | |
download | coreclr-75c97cff492584075b6e13d67a901c69c34ad4f9.tar.gz coreclr-75c97cff492584075b6e13d67a901c69c34ad4f9.tar.bz2 coreclr-75c97cff492584075b6e13d67a901c69c34ad4f9.zip |
ARM64: Fix Round Operation
Math.Round is implemented as a target intrinsic for Arm64.
JIT emitted `frinta` which rounds the ties to away.
As described in MSDN
https://msdn.microsoft.com/en-us/library/system.math.round(v=vs.110).aspx#Round2_Example,
we should round the ties to even.
So, I corrected `frintn` instruction instead for such intrinsic expansion.
I've also identified that `EvalMathFuncUnary` incorrectly folds the round
operation when the argument is constant at the compile time.
The logic itself is not the right semantic as described above in MSDN.
I made a separate helper function which is essentially a duplicate of
classlib. This is not Arm64 specific fix but applies to all other targets.
So, I just fixed it while I'm here.
Diffstat (limited to 'src/jit/utils.cpp')
-rw-r--r-- | src/jit/utils.cpp | 26 |
1 files changed, 26 insertions, 0 deletions
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; +} |