Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4358,6 +4358,10 @@ // sitofp and uitofp turn into +0.0 for zero. Known.knownNot(fcNegZero); + + // Integers cannot be subnormal + Known.knownNot(fcSubnormal); + if (IID == Intrinsic::experimental_constrained_uitofp) Known.signBitIsZero(); @@ -4494,6 +4498,9 @@ // Cannot produce nan Known.knownNot(fcNan); + // Integers cannot be subnormal + Known.knownNot(fcSubnormal); + // sitofp and uitofp turn into +0.0 for zero. Known.knownNot(fcNegZero); if (Op->getOpcode() == Instruction::UIToFP) Index: llvm/test/Transforms/Attributor/nofpclass.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass.ll +++ llvm/test/Transforms/Attributor/nofpclass.ll @@ -685,7 +685,7 @@ define float @uitofp_i32_to_f32(i32 %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @uitofp_i32_to_f32 +; CHECK-LABEL: define nofpclass(nan inf nzero sub nnorm) float @uitofp_i32_to_f32 ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG]] to float ; CHECK-NEXT: ret float [[CVT]] @@ -696,7 +696,7 @@ define float @sitofp_i32_to_f32(i32 %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan inf nzero) float @sitofp_i32_to_f32 +; CHECK-LABEL: define nofpclass(nan inf nzero sub) float @sitofp_i32_to_f32 ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG]] to float ; CHECK-NEXT: ret float [[CVT]] @@ -707,7 +707,7 @@ define <2 x float> @uitofp_v2i32_to_v2f32(<2 x i32> %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) <2 x float> @uitofp_v2i32_to_v2f32 +; CHECK-LABEL: define nofpclass(nan inf nzero sub nnorm) <2 x float> @uitofp_v2i32_to_v2f32 ; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = uitofp <2 x i32> [[ARG]] to <2 x float> ; CHECK-NEXT: ret <2 x float> [[CVT]] @@ -718,7 +718,7 @@ define <2 x float> @sitofp_v2i32_to_v2i32(<2 x i32> %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan inf nzero) <2 x float> @sitofp_v2i32_to_v2i32 +; CHECK-LABEL: define nofpclass(nan inf nzero sub) <2 x float> @sitofp_v2i32_to_v2i32 ; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = sitofp <2 x i32> [[ARG]] to <2 x float> ; CHECK-NEXT: ret <2 x float> [[CVT]] @@ -729,7 +729,7 @@ define half @uitofp_i17_to_f16(i17 %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) half @uitofp_i17_to_f16 +; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) half @uitofp_i17_to_f16 ; CHECK-SAME: (i17 [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = uitofp i17 [[ARG]] to half ; CHECK-NEXT: ret half [[CVT]] @@ -740,7 +740,7 @@ define half @sitofp_i17_to_f16(i17 %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan nzero) half @sitofp_i17_to_f16 +; CHECK-LABEL: define nofpclass(nan nzero sub) half @sitofp_i17_to_f16 ; CHECK-SAME: (i17 [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = sitofp i17 [[ARG]] to half ; CHECK-NEXT: ret half [[CVT]] @@ -751,7 +751,7 @@ define <2 x half> @uitofp_v2i17_to_v2f16(<2 x i17> %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) <2 x half> @uitofp_v2i17_to_v2f16 +; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) <2 x half> @uitofp_v2i17_to_v2f16 ; CHECK-SAME: (<2 x i17> [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = uitofp <2 x i17> [[ARG]] to <2 x half> ; CHECK-NEXT: ret <2 x half> [[CVT]] @@ -762,7 +762,7 @@ define <2 x half> @sitofp_v2i17_to_v2i17(<2 x i17> %arg) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan nzero) <2 x half> @sitofp_v2i17_to_v2i17 +; CHECK-LABEL: define nofpclass(nan nzero sub) <2 x half> @sitofp_v2i17_to_v2i17 ; CHECK-SAME: (<2 x i17> [[ARG:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[CVT:%.*]] = sitofp <2 x i17> [[ARG]] to <2 x half> ; CHECK-NEXT: ret <2 x half> [[CVT]] @@ -1232,9 +1232,9 @@ define float @constrained_sitofp(i32 %arg) strictfp { ; CHECK: Function Attrs: nofree norecurse nosync nounwind strictfp willreturn memory(inaccessiblemem: readwrite) -; CHECK-LABEL: define nofpclass(nan nzero) float @constrained_sitofp +; CHECK-LABEL: define nofpclass(nan nzero sub) float @constrained_sitofp ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR5:[0-9]+]] { -; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan nzero) float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR7]] +; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan nzero sub) float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR7]] ; CHECK-NEXT: ret float [[VAL]] ; %val = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %arg, metadata !"round.dynamic", metadata !"fpexcept.strict") @@ -1243,9 +1243,9 @@ define float @constrained_uitofp(i32 %arg) strictfp { ; CHECK: Function Attrs: nofree norecurse nosync nounwind strictfp willreturn memory(inaccessiblemem: readwrite) -; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @constrained_uitofp +; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) float @constrained_uitofp ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR5]] { -; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR7]] +; CHECK-NEXT: [[VAL:%.*]] = call nofpclass(nan ninf nzero sub nnorm) float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR7]] ; CHECK-NEXT: ret float [[VAL]] ; %val = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %arg, metadata !"round.dynamic", metadata !"fpexcept.strict") Index: llvm/unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- llvm/unittests/Analysis/ValueTrackingTest.cpp +++ llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -1527,8 +1527,8 @@ " %A2 = uitofp i16 %arg1 to half" " ret float %A\n" "}\n"); - expectKnownFPClass(fcPosFinite, false, A); - expectKnownFPClass(fcPositive, false, A2); + expectKnownFPClass(fcPosFinite & ~fcSubnormal, false, A); + expectKnownFPClass(fcPositive & ~fcSubnormal, false, A2); } TEST_F(ComputeKnownFPClassTest, SIToFP) { @@ -1539,9 +1539,9 @@ " %A3 = sitofp i17 %arg2 to half" " ret float %A\n" "}\n"); - expectKnownFPClass(fcFinite & ~fcNegZero, std::nullopt, A); - expectKnownFPClass(fcFinite & ~fcNegZero, std::nullopt, A2); - expectKnownFPClass(~(fcNan | fcNegZero), std::nullopt, A3); + expectKnownFPClass(fcFinite & ~fcNegZero & ~fcSubnormal, std::nullopt, A); + expectKnownFPClass(fcFinite & ~fcNegZero & ~fcSubnormal, std::nullopt, A2); + expectKnownFPClass(~(fcNan | fcNegZero | fcSubnormal), std::nullopt, A3); } TEST_F(ComputeKnownFPClassTest, FAdd) {