Index: llvm/include/llvm/Analysis/ValueTracking.h =================================================================== --- llvm/include/llvm/Analysis/ValueTracking.h +++ llvm/include/llvm/Analysis/ValueTracking.h @@ -405,6 +405,23 @@ knownNot(fcSNan); } + /// Propagate knowledge from a source value that could be a denormal or + /// zero. We have to be conservative since output flushing is not guaranteed, + /// so known-never-zero may not hold. + /// + /// This assumes a copy-like operation and will replace any currently known + /// information. + void propagateDenormal(const KnownFPClass &Src, const Function &F, Type *Ty); + + /// Report known classes if \p Src is evaluated through a potentially + /// canonicalizing operation. We can assume signaling nans will not be + /// introduced, but cannot assume a denormal will be flushed under FTZ/DAZ. + /// + /// This assumes a copy-like operation and will replace any currently known + /// information. + void propagateCanonicalizingSrc(const KnownFPClass &Src, const Function &F, + Type *Ty); + void resetAll() { *this = KnownFPClass(); } }; Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4099,6 +4099,39 @@ llvm_unreachable("covered switch over denormal mode"); } +void KnownFPClass::propagateDenormal(const KnownFPClass &Src, const Function &F, + Type *Ty) { + KnownFPClasses = Src.KnownFPClasses; + // If we aren't assuming the source can't be a zero, we don't have to check if + // a denormal input could be flushed. + if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero()) + return; + + // If we know the input can't be a denormal, it can't be flushed to 0. + if (Src.isKnownNeverSubnormal()) + return; + + DenormalMode Mode = F.getDenormalMode(Ty->getScalarType()->getFltSemantics()); + + if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE()) + KnownFPClasses |= fcPosZero; + + if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) { + KnownFPClasses |= fcNegZero; + if (Mode.Input == DenormalMode::PositiveZero || + Mode.Output == DenormalMode::PositiveZero || + Mode.Input == DenormalMode::Dynamic || + Mode.Output == DenormalMode::Dynamic) + KnownFPClasses |= fcPosZero; + } +} + +void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src, + const Function &F, Type *Ty) { + propagateDenormal(Src, F, Ty); + propagateNaN(Src, /*PreserveSign=*/true); +} + /// Returns a pair of values, which if passed to llvm.is.fpclass, returns the /// same result as an fcmp with the given operands. std::pair llvm::fcmpToClassTest(FCmpInst::Predicate Pred, @@ -4781,6 +4814,61 @@ Known.knownNot(fcNegative); break; } + case Intrinsic::ldexp: { + KnownFPClass KnownSrc; + computeKnownFPClass(II->getArgOperand(0), DemandedElts, + InterestedClasses, KnownSrc, Depth + 1, Q, TLI); + Known.propagateNaN(KnownSrc, /*PropagateSign=*/true); + + // Sign is preserved, but underflows may produce zeroes. + if (KnownSrc.isKnownNever(fcNegative)) + Known.knownNot(fcNegative); + else if (KnownSrc.cannotBeOrderedLessThanZero()) + Known.knownNot(KnownFPClass::OrderedLessThanZeroMask); + + if (KnownSrc.isKnownNever(fcPositive)) + Known.knownNot(fcPositive); + else if (KnownSrc.cannotBeOrderedGreaterThanZero()) + Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask); + + // Can refine inf/zero handling based on the exponent operand. + const FPClassTest ExpInfoMask = fcZero | fcSubnormal | fcInf; + if ((InterestedClasses & ExpInfoMask) == fcNone) + break; + if ((KnownSrc.KnownFPClasses & ExpInfoMask) == fcNone) + break; + + const Value *ExpArg = II->getArgOperand(1); + KnownBits ExpKnownBits( + ExpArg->getType()->getScalarType()->getIntegerBitWidth()); + computeKnownBits(ExpArg, ExpKnownBits, Depth + 1, Q); + + const Function *F = II->getFunction(); + + if (ExpKnownBits.isZero()) { + // ldexp(x, 0) -> x, so propagate everything. + Known.propagateCanonicalizingSrc(KnownSrc, *II->getFunction(), + II->getType()); + } else if (ExpKnownBits.isNegative()) { + // If we know the power is < 0, can't introduce inf + if (KnownSrc.isKnownNeverPosInfinity()) + Known.knownNot(fcPosInf); + if (KnownSrc.isKnownNeverNegInfinity()) + Known.knownNot(fcNegInf); + } else if (ExpKnownBits.isNonNegative()) { + // If we know the power is >= 0, can't introduce subnormal or zero + if (KnownSrc.isKnownNeverPosSubnormal()) + Known.knownNot(fcPosSubnormal); + if (KnownSrc.isKnownNeverNegSubnormal()) + Known.knownNot(fcNegSubnormal); + if (F && KnownSrc.isKnownNeverLogicalPosZero(*F, II->getType())) + Known.knownNot(fcPosZero); + if (F && KnownSrc.isKnownNeverLogicalNegZero(*F, II->getType())) + Known.knownNot(fcNegZero); + } + + break; + } case Intrinsic::arithmetic_fence: { computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses, Known, Depth + 1, Q, TLI); Index: llvm/test/Transforms/Attributor/nofpclass-ldexp.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-ldexp.ll +++ llvm/test/Transforms/Attributor/nofpclass-ldexp.ll @@ -26,9 +26,9 @@ } define float @ret_ldexp_f32_0_nopsub(float nofpclass(psub) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopsub +; CHECK-LABEL: define nofpclass(psub) float @ret_ldexp_f32_0_nopsub ; CHECK-SAME: (float nofpclass(psub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -36,9 +36,9 @@ } define float @ret_ldexp_f32_0_nonsub(float nofpclass(nsub) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nonsub +; CHECK-LABEL: define nofpclass(nsub) float @ret_ldexp_f32_0_nonsub ; CHECK-SAME: (float nofpclass(nsub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -46,9 +46,9 @@ } define float @ret_ldexp_f32_0_nosub(float nofpclass(sub) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub +; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_0_nosub ; CHECK-SAME: (float nofpclass(sub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -56,9 +56,9 @@ } define float @ret_ldexp_f32_0_nosub_nosnan(float nofpclass(sub snan) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_nosnan +; CHECK-LABEL: define nofpclass(snan sub) float @ret_ldexp_f32_0_nosub_nosnan ; CHECK-SAME: (float nofpclass(snan sub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -66,9 +66,9 @@ } define float @ret_ldexp_f32_0_nopsub_nopzero(float nofpclass(psub pzero) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopsub_nopzero +; CHECK-LABEL: define nofpclass(pzero psub) float @ret_ldexp_f32_0_nopsub_nopzero ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pzero psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -76,9 +76,9 @@ } define float @ret_ldexp_f32_0_nonsub_nonzero(float nofpclass(nsub nzero) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nonsub_nonzero +; CHECK-LABEL: define nofpclass(nzero nsub) float @ret_ldexp_f32_0_nonsub_nonzero ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -86,9 +86,9 @@ } define float @ret_ldexp_f32_0_nosub_nozero(float nofpclass(sub zero) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_nozero +; CHECK-LABEL: define nofpclass(zero sub) float @ret_ldexp_f32_0_nosub_nozero ; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(zero sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -96,9 +96,9 @@ } define float @ret_ldexp_f32_0_nopsub_daz(float nofpclass(psub) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopsub_daz +; CHECK-LABEL: define nofpclass(psub) float @ret_ldexp_f32_0_nopsub_daz ; CHECK-SAME: (float nofpclass(psub) [[ARG0:%.*]]) #[[ATTR2:[0-9]+]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -106,9 +106,9 @@ } define float @ret_ldexp_f32_0_nonsub_daz(float nofpclass(nsub) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nonsub_daz +; CHECK-LABEL: define nofpclass(nsub) float @ret_ldexp_f32_0_nonsub_daz ; CHECK-SAME: (float nofpclass(nsub) [[ARG0:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -116,9 +116,9 @@ } define float @ret_ldexp_f32_0_nosub_daz(float nofpclass(sub) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_daz +; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_0_nosub_daz ; CHECK-SAME: (float nofpclass(sub) [[ARG0:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -126,9 +126,9 @@ } define float @ret_ldexp_f32_0_nosub_nosnan_daz(float nofpclass(sub snan) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_nosnan_daz +; CHECK-LABEL: define nofpclass(snan sub) float @ret_ldexp_f32_0_nosub_nosnan_daz ; CHECK-SAME: (float nofpclass(snan sub) [[ARG0:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -136,9 +136,9 @@ } define float @ret_ldexp_f32_0_nopsub_nopzero_daz(float nofpclass(psub pzero) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopsub_nopzero_daz +; CHECK-LABEL: define nofpclass(pzero psub) float @ret_ldexp_f32_0_nopsub_nopzero_daz ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG0:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pzero psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -146,9 +146,9 @@ } define float @ret_ldexp_f32_0_nonsub_nonzero_daz(float nofpclass(nsub nzero) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nonsub_nonzero_daz +; CHECK-LABEL: define nofpclass(nzero nsub) float @ret_ldexp_f32_0_nonsub_nonzero_daz ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG0:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -156,9 +156,9 @@ } define float @ret_ldexp_f32_0_nosub_nozero_daz(float nofpclass(sub zero) %arg0) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_nozero_daz +; CHECK-LABEL: define nofpclass(zero sub) float @ret_ldexp_f32_0_nosub_nozero_daz ; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(zero sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -166,9 +166,9 @@ } define float @ret_ldexp_f32_0_nopsub_dapz(float nofpclass(psub) %arg0) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopsub_dapz +; CHECK-LABEL: define nofpclass(psub) float @ret_ldexp_f32_0_nopsub_dapz ; CHECK-SAME: (float nofpclass(psub) [[ARG0:%.*]]) #[[ATTR3:[0-9]+]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -176,9 +176,9 @@ } define float @ret_ldexp_f32_0_nonsub_dapz(float nofpclass(nsub) %arg0) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nonsub_dapz +; CHECK-LABEL: define nofpclass(nsub) float @ret_ldexp_f32_0_nonsub_dapz ; CHECK-SAME: (float nofpclass(nsub) [[ARG0:%.*]]) #[[ATTR3]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -186,9 +186,9 @@ } define float @ret_ldexp_f32_0_nosub_dapz(float nofpclass(sub) %arg0) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_dapz +; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_0_nosub_dapz ; CHECK-SAME: (float nofpclass(sub) [[ARG0:%.*]]) #[[ATTR3]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -196,9 +196,9 @@ } define float @ret_ldexp_f32_0_nopsub_nopzero_dapz(float nofpclass(psub pzero) %arg0) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopsub_nopzero_dapz +; CHECK-LABEL: define nofpclass(psub) float @ret_ldexp_f32_0_nopsub_nopzero_dapz ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG0:%.*]]) #[[ATTR3]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -206,9 +206,9 @@ } define float @ret_ldexp_f32_0_nonsub_nonzero_dapz(float nofpclass(nsub nzero) %arg0) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nonsub_nonzero_dapz +; CHECK-LABEL: define nofpclass(nzero nsub) float @ret_ldexp_f32_0_nonsub_nonzero_dapz ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG0:%.*]]) #[[ATTR3]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -216,9 +216,9 @@ } define float @ret_ldexp_f32_0_nosub_nozero_dapz(float nofpclass(sub zero) %arg0) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nosub_nozero_dapz +; CHECK-LABEL: define nofpclass(zero sub) float @ret_ldexp_f32_0_nosub_nozero_dapz ; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR3]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(zero sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -226,9 +226,9 @@ } define float @ret_ldexp_f32_0_nopnorm(float nofpclass(pnorm) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopnorm +; CHECK-LABEL: define nofpclass(pnorm) float @ret_ldexp_f32_0_nopnorm ; CHECK-SAME: (float nofpclass(pnorm) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -236,9 +236,9 @@ } define float @ret_ldexp_f32_0_nnorm(float nofpclass(nnorm) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nnorm +; CHECK-LABEL: define nofpclass(nnorm) float @ret_ldexp_f32_0_nnorm ; CHECK-SAME: (float nofpclass(nnorm) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -246,9 +246,9 @@ } define float @ret_ldexp_f32_0_nopnorm_nonsub(float nofpclass(pnorm nsub) %arg0) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_0_nopnorm_nonsub +; CHECK-LABEL: define nofpclass(nsub pnorm) float @ret_ldexp_f32_0_nopnorm_nonsub ; CHECK-SAME: (float nofpclass(nsub pnorm) [[ARG0:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nsub pnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 0) @@ -286,9 +286,9 @@ } define float @ret_ldexp_f32_nonan(float nofpclass(nan) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_nonan +; CHECK-LABEL: define nofpclass(nan) float @ret_ldexp_f32_nonan ; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -296,9 +296,9 @@ } define float @ret_ldexp_f32_nosnan(float nofpclass(snan) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_nosnan +; CHECK-LABEL: define nofpclass(snan) float @ret_ldexp_f32_nosnan ; CHECK-SAME: (float nofpclass(snan) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -316,9 +316,9 @@ } define float @ret_ldexp_f32_noneg(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_ldexp_f32_noneg ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -326,9 +326,9 @@ } define float @ret_ldexp_f32_noneg_nonzero(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_nonzero +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_ldexp_f32_noneg_nonzero ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -336,9 +336,9 @@ } define float @ret_ldexp_f32_noneg_nozero(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_nozero +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_ldexp_f32_noneg_nozero ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -366,9 +366,9 @@ } define float @ret_ldexp_f32_noneg_ftz_daz(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_ftz_daz +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_ldexp_f32_noneg_ftz_daz ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -376,9 +376,9 @@ } define float @ret_ldexp_f32_noneg_nonzero_ftz_daz(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_nonzero_ftz_daz +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_ldexp_f32_noneg_nonzero_ftz_daz ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -386,9 +386,9 @@ } define float @ret_ldexp_f32_noneg_nonzero_ftpz_dapz(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #2 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_nonzero_ftpz_dapz +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_ldexp_f32_noneg_nonzero_ftpz_dapz ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR3]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -416,9 +416,9 @@ } define float @ret_ldexp_f32_noneg_ftz_ieee(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #3 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_ftz_ieee +; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_ldexp_f32_noneg_ftz_ieee ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR4:[0-9]+]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -426,9 +426,9 @@ } define float @ret_ldexp_f32_noneg_nonzero_ftz_ieee(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #3 { -; CHECK-LABEL: define float @ret_ldexp_f32_noneg_nonzero_ftz_ieee +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_ldexp_f32_noneg_nonzero_ftz_ieee ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR4]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -436,9 +436,9 @@ } define float @ret_ldexp_f32_nopos(float nofpclass(pinf psub pnorm) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_nopos +; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @ret_ldexp_f32_nopos ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf psub pnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -446,9 +446,9 @@ } define float @ret_ldexp_f32_nopos_nopzero(float nofpclass(pinf psub pnorm pzero) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_nopos_nopzero +; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_ldexp_f32_nopos_nopzero ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf pzero psub pnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -456,9 +456,9 @@ } define float @ret_ldexp_f32_nopos_nozero(float nofpclass(pinf psub pnorm zero) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_nopos_nozero +; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_ldexp_f32_nopos_nozero ; CHECK-SAME: (float nofpclass(pinf zero psub pnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf pzero psub pnorm) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -486,9 +486,9 @@ } define float @ret_ldexp_f32_noinf_nonan(float nofpclass(inf nan) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_noinf_nonan +; CHECK-LABEL: define nofpclass(nan) float @ret_ldexp_f32_noinf_nonan ; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %call = call float @llvm.ldexp.f32.i32(float %arg0, i32 %arg1) @@ -520,10 +520,10 @@ } define float @ret_ldexp_f32_known_pos_exp_nosub(float nofpclass(sub) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_pos_exp_nosub +; CHECK-LABEL: define nofpclass(sub) float @ret_ldexp_f32_known_pos_exp_nosub ; CHECK-SAME: (float nofpclass(sub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[AND_ARG1:%.*]] = and i32 [[ARG1]], 127 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %and.arg1 = and i32 %arg1, 127 @@ -544,10 +544,10 @@ } define float @ret_ldexp_f32_known_pos_exp_nopsub(float nofpclass(psub) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_pos_exp_nopsub +; CHECK-LABEL: define nofpclass(psub) float @ret_ldexp_f32_known_pos_exp_nopsub ; CHECK-SAME: (float nofpclass(psub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[AND_ARG1:%.*]] = and i32 [[ARG1]], 127 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %and.arg1 = and i32 %arg1, 127 @@ -568,10 +568,10 @@ } define float @ret_ldexp_f32_known_pos_exp_nonsub(float nofpclass(nsub) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_pos_exp_nonsub +; CHECK-LABEL: define nofpclass(nsub) float @ret_ldexp_f32_known_pos_exp_nonsub ; CHECK-SAME: (float nofpclass(nsub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[AND_ARG1:%.*]] = and i32 [[ARG1]], 127 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %and.arg1 = and i32 %arg1, 127 @@ -604,10 +604,10 @@ } define float @ret_ldexp_f32_known_neg_exp_noinf(float nofpclass(inf) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_neg_exp_noinf +; CHECK-LABEL: define nofpclass(inf) float @ret_ldexp_f32_known_neg_exp_noinf ; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[OR_ARG1:%.*]] = or i32 [[ARG1]], -16 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[OR_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[OR_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %or.arg1 = or i32 %arg1, -16 @@ -628,10 +628,10 @@ } define <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf(<2 x float> nofpclass(inf) %arg0, <2 x i32> %arg1) #0 { -; CHECK-LABEL: define <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf +; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_ldexp_v2f32_known_neg_exp_noinf ; CHECK-SAME: (<2 x float> nofpclass(inf) [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[OR_ARG1:%.*]] = or <2 x i32> [[ARG1]], -; CHECK-NEXT: [[CALL:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[OR_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[ARG0]], <2 x i32> [[OR_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret <2 x float> [[CALL]] ; %or.arg1 = or <2 x i32> %arg1, @@ -652,10 +652,10 @@ } define float @ret_ldexp_f32_known_neg_exp_nopinf(float nofpclass(pinf) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_neg_exp_nopinf +; CHECK-LABEL: define nofpclass(pinf) float @ret_ldexp_f32_known_neg_exp_nopinf ; CHECK-SAME: (float nofpclass(pinf) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[OR_ARG1:%.*]] = or i32 [[ARG1]], -16 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[OR_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[OR_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %or.arg1 = or i32 %arg1, -16 @@ -676,10 +676,10 @@ } define float @ret_ldexp_f32_known_neg_exp_noninf(float nofpclass(ninf) %arg0, i32 %arg1) #0 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_neg_exp_noninf +; CHECK-LABEL: define nofpclass(ninf) float @ret_ldexp_f32_known_neg_exp_noninf ; CHECK-SAME: (float nofpclass(ninf) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[OR_ARG1:%.*]] = or i32 [[ARG1]], -16 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[OR_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[OR_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %or.arg1 = or i32 %arg1, -16 @@ -688,10 +688,10 @@ } define float @ret_ldexp_f32_known_pos_exp_nopsub_nopzero_daz(float nofpclass(psub pzero) %arg0, i32 %arg1) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_pos_exp_nopsub_nopzero_daz +; CHECK-LABEL: define nofpclass(pzero psub) float @ret_ldexp_f32_known_pos_exp_nopsub_nopzero_daz ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[AND_ARG1:%.*]] = and i32 [[ARG1]], 127 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pzero psub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %and.arg1 = and i32 %arg1, 127 @@ -712,10 +712,10 @@ } define float @ret_ldexp_f32_known_pos_exp_nonsub_nonzero_daz(float nofpclass(nsub nzero) %arg0, i32 %arg1) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_pos_exp_nonsub_nonzero_daz +; CHECK-LABEL: define nofpclass(nzero nsub) float @ret_ldexp_f32_known_pos_exp_nonsub_nonzero_daz ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[AND_ARG1:%.*]] = and i32 [[ARG1]], 127 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero nsub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %and.arg1 = and i32 %arg1, 127 @@ -736,10 +736,10 @@ } define float @ret_ldexp_f32_known_pos_exp_nosub_nozero_daz(float nofpclass(sub zero) %arg0, i32 %arg1) #1 { -; CHECK-LABEL: define float @ret_ldexp_f32_known_pos_exp_nosub_nozero_daz +; CHECK-LABEL: define nofpclass(zero sub) float @ret_ldexp_f32_known_pos_exp_nosub_nozero_daz ; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[AND_ARG1:%.*]] = and i32 [[ARG1]], 127 -; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] +; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(zero sub) float @llvm.ldexp.f32.i32(float [[ARG0]], i32 [[AND_ARG1]]) #[[ATTR5]] ; CHECK-NEXT: ret float [[CALL]] ; %and.arg1 = and i32 %arg1, 127 Index: llvm/test/Transforms/Inline/simplify-instruction-computeKnownFPClass-context.ll =================================================================== --- llvm/test/Transforms/Inline/simplify-instruction-computeKnownFPClass-context.ll +++ llvm/test/Transforms/Inline/simplify-instruction-computeKnownFPClass-context.ll @@ -168,5 +168,24 @@ ret void } +define i1 @simplify_fcmp_ord_ldexp_caller(double nofpclass(zero inf) %i0) { +; CHECK-LABEL: define i1 @simplify_fcmp_ord_ldexp_caller +; CHECK-SAME: (double nofpclass(inf zero) [[I0:%.*]]) { +; CHECK-NEXT: [[LDEXP_I:%.*]] = call double @llvm.ldexp.f64.i32(double [[I0]], i32 42) +; CHECK-NEXT: [[CMP_I:%.*]] = fcmp one double [[LDEXP_I]], 0x7FF0000000000000 +; CHECK-NEXT: ret i1 [[CMP_I]] +; + %call = call i1 @simplify_fcmp_ord_ldexp_callee(double %i0) + ret i1 %call +} + +define internal i1 @simplify_fcmp_ord_ldexp_callee(double %a) { + %ldexp = call double @llvm.ldexp.f64.i32(double %a, i32 42) + %cmp = fcmp one double %ldexp, 0x7FF0000000000000 + ret i1 %cmp +} + +declare double @llvm.ldexp.f64.i32(double, i32) + attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #1 = { nocallback nofree nosync nounwind willreturn memory(none) }