Index: clang/test/CodeGen/builtin-nan-legacy.c =================================================================== --- clang/test/CodeGen/builtin-nan-legacy.c +++ clang/test/CodeGen/builtin-nan-legacy.c @@ -1,5 +1,5 @@ // RUN: %clang -target mipsel-unknown-linux -mnan=legacy -emit-llvm -S %s -o - | FileCheck %s -// CHECK: float 0x7FF4000000000000, float 0x7FF8000000000000 +// CHECK: float 0x7FFC000000000000, float 0x7FF8000000000000 // CHECK: double 0x7FF4000000000000, double 0x7FF8000000000000 float f[] = { Index: clang/test/CodeGen/builtins.c =================================================================== --- clang/test/CodeGen/builtins.c +++ clang/test/CodeGen/builtins.c @@ -168,10 +168,10 @@ f = __builtin_nanf("0xAE98"); // CHECK: float 0x7FF815D300000000 d = __builtin_nan("0xAE98"); // CHECK: double 0x7FF800000000AE98 ld = __builtin_nanl("0xAE98"); // CHECK: x86_fp80 0xK7FFFC00000000000AE98 - f = __builtin_nansf(""); // CHECK: float 0x7FF4000000000000 + f = __builtin_nansf(""); // CHECK: float 0x7FFC000000000000 d = __builtin_nans(""); // CHECK: double 0x7FF4000000000000 ld = __builtin_nansl(""); // CHECK: x86_fp80 0xK7FFFA000000000000000 - f = __builtin_nansf("0xAE98"); // CHECK: float 0x7FF015D300000000 + f = __builtin_nansf("0xAE98"); // CHECK: float 0x7FF815D300000000 d = __builtin_nans("0xAE98"); // CHECK: double 0x7FF000000000AE98 ld = __builtin_nansl("0xAE98");// CHECK: x86_fp80 0xK7FFF800000000000AE98 Index: clang/test/CodeGen/mips-unsupported-nan.c =================================================================== --- clang/test/CodeGen/mips-unsupported-nan.c +++ clang/test/CodeGen/mips-unsupported-nan.c @@ -39,7 +39,7 @@ // CHECK-MIPS64: warning: ignoring '-mnan=2008' option because the 'mips64' architecture does not support it // CHECK-MIPS64R6: warning: ignoring '-mnan=legacy' option because the 'mips64r6' architecture does not support it -// CHECK-NANLEGACY: float 0x7FF4000000000000 +// CHECK-NANLEGACY: float 0x7FFC000000000000 // CHECK-NAN2008: float 0x7FF8000000000000 float f = __builtin_nan(""); Index: llvm/lib/Support/APFloat.cpp =================================================================== --- llvm/lib/Support/APFloat.cpp +++ llvm/lib/Support/APFloat.cpp @@ -2242,11 +2242,15 @@ if (!X86SpecialNan && semantics == &semX87DoubleExtended) APInt::tcSetBit(significandParts(), semantics->precision - 1); - // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) - // does not give you back the same bits. This is dubious, and we - // don't currently do it. You're really supposed to get - // an invalid operation signal at runtime, but nobody does that. - fs = opOK; + // Convert of sNaN creates qNaN and raises an exception (invalid op). + // This also guarantees that a sNaN does not become Inf on a truncation + // that loses all payload bits. + if (isSignaling()) { + makeQuiet(); + fs = opInvalidOp; + } else { + fs = opOK; + } } else { *losesInfo = false; fs = opOK; Index: llvm/test/Transforms/InstCombine/AMDGPU/ldexp.ll =================================================================== --- llvm/test/Transforms/InstCombine/AMDGPU/ldexp.ll +++ llvm/test/Transforms/InstCombine/AMDGPU/ldexp.ll @@ -99,13 +99,13 @@ define void @ldexp_f32_val_nan_strictfp(i32 %y) #0 { ; CHECK-LABEL: @ldexp_f32_val_nan_strictfp( -; CHECK-NEXT: [[PLUS_QNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x7FF0001000000000, i32 [[Y:%.*]]) [[ATTR0:#.*]] +; CHECK-NEXT: [[PLUS_QNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x7FF8001000000000, i32 [[Y:%.*]]) [[ATTR0:#.*]] ; CHECK-NEXT: store volatile float [[PLUS_QNAN]], float addrspace(1)* undef, align 4 -; CHECK-NEXT: [[NEG_QNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0xFFF0000100000000, i32 [[Y]]) [[ATTR0]] +; CHECK-NEXT: [[NEG_QNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0xFFF8000100000000, i32 [[Y]]) [[ATTR0]] ; CHECK-NEXT: store volatile float [[NEG_QNAN]], float addrspace(1)* undef, align 4 -; CHECK-NEXT: [[PLUS_SNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x7FF0000020000000, i32 [[Y]]) [[ATTR0]] +; CHECK-NEXT: [[PLUS_SNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0x7FF8000020000000, i32 [[Y]]) [[ATTR0]] ; CHECK-NEXT: store volatile float [[PLUS_SNAN]], float addrspace(1)* undef, align 4 -; CHECK-NEXT: [[NEG_SNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0xFFF7FFFFE0000000, i32 [[Y]]) [[ATTR0]] +; CHECK-NEXT: [[NEG_SNAN:%.*]] = call float @llvm.amdgcn.ldexp.f32(float 0xFFFFFFFFE0000000, i32 [[Y]]) [[ATTR0]] ; CHECK-NEXT: store volatile float [[NEG_SNAN]], float addrspace(1)* undef, align 4 ; CHECK-NEXT: store volatile float 0x7FF8000000000000, float addrspace(1)* undef, align 4 ; CHECK-NEXT: ret void Index: llvm/test/Transforms/InstSimplify/ConstProp/cast.ll =================================================================== --- llvm/test/Transforms/InstSimplify/ConstProp/cast.ll +++ llvm/test/Transforms/InstSimplify/ConstProp/cast.ll @@ -39,19 +39,25 @@ ret float %i } -; https://llvm.org/PR43907 +; https://llvm.org/PR43907 - make sure that NaN doesn't morph into Inf. +; SNaN becomes QNaN. define float @nan_f64_trunc() { ; CHECK-LABEL: @nan_f64_trunc( -; CHECK-NEXT: ret float 0x7FF0000000000000 +; CHECK-NEXT: ret float 0x7FF8000000000000 ; %f = fptrunc double 0x7FF0000000000001 to float ret float %f } +; Verify again with a vector and different destination type. +; SNaN becomes QNaN (first two elements). +; QNaN remains QNaN (third element). +; Lower 42 bits of NaN source payload are lost. + define <3 x half> @nan_v3f64_trunc() { ; CHECK-LABEL: @nan_v3f64_trunc( -; CHECK-NEXT: ret <3 x half> +; CHECK-NEXT: ret <3 x half> ; %f = fptrunc <3 x double> to <3 x half> ret <3 x half> %f Index: llvm/test/Transforms/InstSimplify/fp-nan.ll =================================================================== --- llvm/test/Transforms/InstSimplify/fp-nan.ll +++ llvm/test/Transforms/InstSimplify/fp-nan.ll @@ -35,7 +35,7 @@ define float @fsub_nan_op1(float %x) { ; CHECK-LABEL: @fsub_nan_op1( -; CHECK-NEXT: ret float 0x7FF1000000000000 +; CHECK-NEXT: ret float 0x7FF9000000000000 ; %r = fsub float %x, 0x7FF1000000000000 ret float %r Index: llvm/test/Transforms/PhaseOrdering/X86/nancvt.ll =================================================================== --- llvm/test/Transforms/PhaseOrdering/X86/nancvt.ll +++ llvm/test/Transforms/PhaseOrdering/X86/nancvt.ll @@ -30,15 +30,15 @@ ; CHECK-NEXT: store volatile i32 2147228864, i32* @var, align 4 ; CHECK-NEXT: store volatile i32 2147228864, i32* @var, align 4 ; CHECK-NEXT: store volatile i32 2147228864, i32* @var, align 4 -; CHECK-NEXT: store volatile i32 2146502828, i32* @var, align 4 +; CHECK-NEXT: store volatile i32 2147027116, i32* @var, align 4 ; CHECK-NEXT: store volatile i32 -1610612736, i32* @var, align 4 -; CHECK-NEXT: store volatile i32 2146502828, i32* @var, align 4 +; CHECK-NEXT: store volatile i32 2147027116, i32* @var, align 4 ; CHECK-NEXT: store volatile i32 -2147483648, i32* @var, align 4 -; CHECK-NEXT: store volatile i32 2146502828, i32* @var, align 4 +; CHECK-NEXT: store volatile i32 2147027116, i32* @var, align 4 ; CHECK-NEXT: store volatile i32 -1073741824, i32* @var, align 4 -; CHECK-NEXT: store volatile i32 2143034560, i32* @var, align 4 -; CHECK-NEXT: store volatile i32 2143034560, i32* @var, align 4 -; CHECK-NEXT: store volatile i32 2143034560, i32* @var, align 4 +; CHECK-NEXT: store volatile i32 2147228864, i32* @var, align 4 +; CHECK-NEXT: store volatile i32 2147228864, i32* @var, align 4 +; CHECK-NEXT: store volatile i32 2147228864, i32* @var, align 4 ; CHECK-NEXT: ret i32 undef ; entry: Index: llvm/unittests/ADT/APFloatTest.cpp =================================================================== --- llvm/unittests/ADT/APFloatTest.cpp +++ llvm/unittests/ADT/APFloatTest.cpp @@ -1816,11 +1816,12 @@ EXPECT_FALSE(losesInfo); test = APFloat::getSNaN(APFloat::IEEEsingle()); - APFloat X87SNaN = APFloat::getSNaN(APFloat::x87DoubleExtended()); APFloat::opStatus status = test.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven, &losesInfo); - EXPECT_TRUE(test.bitwiseIsEqual(X87SNaN)); + // Conversion quiets the SNAN, so now 2 bits of the 64-bit significand should be set. + APInt topTwoBits(64, 0x6000000000000000); + EXPECT_TRUE(test.bitwiseIsEqual(APFloat::getQNaN(APFloat::x87DoubleExtended(), false, &topTwoBits))); EXPECT_FALSE(losesInfo); - EXPECT_EQ(status, APFloat::opOK); + EXPECT_EQ(status, APFloat::opInvalidOp); test = APFloat::getQNaN(APFloat::IEEEsingle()); APFloat X87QNaN = APFloat::getQNaN(APFloat::x87DoubleExtended()); @@ -1832,6 +1833,7 @@ test = APFloat::getSNaN(APFloat::x87DoubleExtended()); test.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven, &losesInfo); + APFloat X87SNaN = APFloat::getSNaN(APFloat::x87DoubleExtended()); EXPECT_TRUE(test.bitwiseIsEqual(X87SNaN)); EXPECT_FALSE(losesInfo); @@ -1841,14 +1843,15 @@ EXPECT_TRUE(test.bitwiseIsEqual(X87QNaN)); EXPECT_FALSE(losesInfo); - // FIXME: This is wrong - NaN becomes Inf. + // The payload is lost in truncation, but we must retain NaN. APInt payload(52, 1); test = APFloat::getSNaN(APFloat::IEEEdouble(), false, &payload); status = test.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &losesInfo); - EXPECT_EQ(0x7f800000, test.bitcastToAPInt()); + EXPECT_EQ(0x7fc00000, test.bitcastToAPInt()); EXPECT_TRUE(losesInfo); - EXPECT_EQ(status, APFloat::opOK); + EXPECT_EQ(status, APFloat::opInvalidOp); + // The payload is lost in truncation. QNaN remains QNaN. test = APFloat::getQNaN(APFloat::IEEEdouble(), false, &payload); status = test.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &losesInfo); EXPECT_EQ(0x7fc00000, test.bitcastToAPInt());