summaryrefslogtreecommitdiff
path: root/src/jit/utils.cpp
diff options
context:
space:
mode:
authorKyungwoo Lee <kyulee@microsoft.com>2016-04-18 10:42:51 -0700
committerKyungwoo Lee <kyulee@microsoft.com>2016-04-18 17:46:40 -0700
commit75c97cff492584075b6e13d67a901c69c34ad4f9 (patch)
tree45d58e70072962b1c4c15dc53c5980c63b7416d6 /src/jit/utils.cpp
parent83e52facfec1ae6002ed9d0a474c300ab3dbe2fe (diff)
downloadcoreclr-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.cpp26
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;
+}