From 2e429e0b21469ef8f14ae6f9c3734edcf31ce031 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 6 Dec 2019 17:03:59 +0100 Subject: [PATCH] Fix #7677: Fix comparisons involving NaN This reverts the fix in 10cc2f895dca32b6389e53470911085af82ab9d4 which was apparently incomplete since it doesn't handle i7677.scala correctly and replace it by the original fix done in scalac in https://github.com/scala/scala/pull/5207. (It might have been possible to fix the dotty version instead, but I'd rather keep the dotty backend as close as possible to the scalac backend). Since this commit contains code from scalac it is: Co-Authored-By: Lukas Rytz --- .../tools/backend/jvm/BCodeBodyBuilder.scala | 26 ++++++++----------- tests/{run-bootstrapped => run}/i6710.scala | 0 tests/run/i7677.scala | 15 +++++++++++ 3 files changed, 26 insertions(+), 15 deletions(-) rename tests/{run-bootstrapped => run}/i6710.scala (100%) create mode 100644 tests/run/i7677.scala diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index bf0f11efb216..845254b44960 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -1224,8 +1224,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { } /* Emit code to compare the two top-most stack values using the 'op' operator. */ - private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label): Unit = { - if (targetIfNoJump == success) genCJUMP(failure, success, op.negate(), tk, targetIfNoJump) + private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label, negated: Boolean = false): Unit = { + if (targetIfNoJump == success) genCJUMP(failure, success, op.negate(), tk, targetIfNoJump, negated = !negated) else { if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT bc.emitIF_ICMP(op, success) @@ -1233,14 +1233,11 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { bc.emitIF_ACMP(op, success) } else { import Primitives._ + def useCmpG = if (negated) op == GT || op == GE else op == LT || op == LE (tk: @unchecked) match { case LONG => emit(asm.Opcodes.LCMP) - case FLOAT => - if (op == LT || op == LE) emit(asm.Opcodes.FCMPL) - else emit(asm.Opcodes.FCMPG) - case DOUBLE => - if (op == LT || op == LE) emit(asm.Opcodes.DCMPL) - else emit(asm.Opcodes.DCMPG) + case FLOAT => emit(if (useCmpG) asm.Opcodes.FCMPG else asm.Opcodes.FCMPL) + case DOUBLE => emit(if (useCmpG) asm.Opcodes.DCMPG else asm.Opcodes.DCMPL) } bc.emitIF(op, success) } @@ -1249,9 +1246,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { } /* Emits code to compare (and consume) stack-top and zero using the 'op' operator */ - private def genCZJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label): Unit = { + private def genCZJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label, negated: Boolean = false): Unit = { import Primitives._ - if (targetIfNoJump == success) genCZJUMP(failure, success, op.negate(), tk, targetIfNoJump) + if (targetIfNoJump == success) genCZJUMP(failure, success, op.negate(), tk, targetIfNoJump, negated = !negated) else { if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT bc.emitIF(op, success) @@ -1261,18 +1258,17 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { case NE => bc emitIFNONNULL success } } else { + def useCmpG = if (negated) op == GT || op == GE else op == LT || op == LE (tk: @unchecked) match { case LONG => emit(asm.Opcodes.LCONST_0) emit(asm.Opcodes.LCMP) case FLOAT => emit(asm.Opcodes.FCONST_0) - if (op == LT || op == LE) emit(asm.Opcodes.FCMPL) - else emit(asm.Opcodes.FCMPG) + emit(if (useCmpG) asm.Opcodes.FCMPG else asm.Opcodes.FCMPL) case DOUBLE => emit(asm.Opcodes.DCONST_0) - if (op == LT || op == LE) emit(asm.Opcodes.DCMPL) - else emit(asm.Opcodes.DCMPG) + emit(if (useCmpG) asm.Opcodes.DCMPG else asm.Opcodes.DCMPL) } bc.emitIF(op, success) } @@ -1287,8 +1283,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { case ScalaPrimitivesOps.NE => Primitives.NE case ScalaPrimitivesOps.LT => Primitives.LT case ScalaPrimitivesOps.LE => Primitives.LE - case ScalaPrimitivesOps.GE => Primitives.GE case ScalaPrimitivesOps.GT => Primitives.GT + case ScalaPrimitivesOps.GE => Primitives.GE } /* diff --git a/tests/run-bootstrapped/i6710.scala b/tests/run/i6710.scala similarity index 100% rename from tests/run-bootstrapped/i6710.scala rename to tests/run/i6710.scala diff --git a/tests/run/i7677.scala b/tests/run/i7677.scala new file mode 100644 index 000000000000..009c2269ceae --- /dev/null +++ b/tests/run/i7677.scala @@ -0,0 +1,15 @@ +object Test { + def main(args: Array[String]): Unit = { + val a: Double = Double.NaN + val eval = (a <= 0) || (10L <= 0) + assert(!eval) + val eval2 = (Double.NaN <= 0) || (10L <= 0) + assert(!eval2) + + val b: Float = Float.NaN + val eval3 = (b <= 0) || (10L <= 0) + assert(!eval3) + val eval4 = (Float.NaN <= 0) || (10L <= 0) + assert(!eval4) + } +}