diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h index b3c18bcf6b34b..e50b97ac7f00d 100644 --- a/llvm/include/llvm/Support/KnownFPClass.h +++ b/llvm/include/llvm/Support/KnownFPClass.h @@ -155,6 +155,11 @@ struct KnownFPClass { signBitMustBeZero(); } + /// Apply the canonicalize intrinsic to this value. This is essentially a + /// stronger form of propagateCanonicalizingSrc. + LLVM_ABI void + canonicalize(DenormalMode DenormMode = DenormalMode::getDynamic()); + /// Return true if the sign bit must be 0, ignoring the sign of nans. bool signBitIsZeroOrNaN() const { return isKnownNever(fcNegative); } diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 0321c08f55776..f7fdf9f1c0985 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -5269,58 +5269,15 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, break; } case Intrinsic::canonicalize: { - KnownFPClass KnownSrc; computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses, - KnownSrc, Q, Depth + 1); - - // This is essentially a stronger form of - // propagateCanonicalizingSrc. Other "canonicalizing" operations don't - // actually have an IR canonicalization guarantee. - - // Canonicalize may flush denormals to zero, so we have to consider the - // denormal mode to preserve known-not-0 knowledge. - Known.KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan; - - // Stronger version of propagateNaN - // Canonicalize is guaranteed to quiet signaling nans. - if (KnownSrc.isKnownNeverNaN()) - Known.knownNot(fcNan); - else - Known.knownNot(fcSNan); + Known, Q, Depth + 1); const Function *F = II->getFunction(); - if (!F) - break; - - // If the parent function flushes denormals, the canonical output cannot - // be a denormal. - const fltSemantics &FPType = - II->getType()->getScalarType()->getFltSemantics(); - DenormalMode DenormMode = F->getDenormalMode(FPType); - if (DenormMode == DenormalMode::getIEEE()) { - if (KnownSrc.isKnownNever(fcPosZero)) - Known.knownNot(fcPosZero); - if (KnownSrc.isKnownNever(fcNegZero)) - Known.knownNot(fcNegZero); - break; - } - - if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero()) - Known.knownNot(fcSubnormal); - - if (DenormMode == DenormalMode::getPreserveSign()) { - if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal)) - Known.knownNot(fcPosZero); - if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal)) - Known.knownNot(fcNegZero); - break; - } - - if (DenormMode.Input == DenormalMode::PositiveZero || - (DenormMode.Output == DenormalMode::PositiveZero && - DenormMode.Input == DenormalMode::IEEE)) - Known.knownNot(fcNegZero); - + DenormalMode DenormMode = + F ? F->getDenormalMode( + II->getType()->getScalarType()->getFltSemantics()) + : DenormalMode::getDynamic(); + Known.canonicalize(DenormMode); break; } case Intrinsic::vector_reduce_fmax: diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp index 43fb2e7108d2b..cb9563e0e52c3 100644 --- a/llvm/lib/Support/KnownFPClass.cpp +++ b/llvm/lib/Support/KnownFPClass.cpp @@ -87,6 +87,54 @@ void KnownFPClass::propagateDenormal(const KnownFPClass &Src, } } +void KnownFPClass::canonicalize(DenormalMode DenormMode) { + KnownFPClass KnownSrc = *this; + *this = KnownFPClass(); + + // This is essentially a stronger form of + // propagateCanonicalizingSrc. Other "canonicalizing" operations don't + // actually have an IR canonicalization guarantee. + + // Canonicalize may flush denormals to zero, so we have to consider the + // denormal mode to preserve known-not-0 knowledge. + KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan; + + // Stronger version of propagateNaN + // Canonicalize is guaranteed to quiet signaling nans. + if (KnownSrc.isKnownNeverNaN()) + knownNot(fcNan); + else + knownNot(fcSNan); + + // FIXME: Missing check of IEEE like types. + + // If the parent function flushes denormals, the canonical output cannot be a + // denormal. + if (DenormMode == DenormalMode::getIEEE()) { + if (KnownSrc.isKnownNever(fcPosZero)) + knownNot(fcPosZero); + if (KnownSrc.isKnownNever(fcNegZero)) + knownNot(fcNegZero); + return; + } + + if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero()) + knownNot(fcSubnormal); + + if (DenormMode == DenormalMode::getPreserveSign()) { + if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal)) + knownNot(fcPosZero); + if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal)) + knownNot(fcNegZero); + return; + } + + if (DenormMode.Input == DenormalMode::PositiveZero || + (DenormMode.Output == DenormalMode::PositiveZero && + DenormMode.Input == DenormalMode::IEEE)) + knownNot(fcNegZero); +} + void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src, DenormalMode Mode) { propagateDenormal(Src, Mode); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 550dfc57a348b..3df89c930967e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -2106,6 +2106,79 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V, Known.copysign(KnownSign); break; } + case Intrinsic::canonicalize: { + Type *EltTy = VTy->getScalarType(); + + // TODO: This could have more refined support for PositiveZero denormal + // mode. + if (EltTy->isIEEELikeFPTy()) { + DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics()); + + FPClassTest SrcDemandedMask = DemandedMask; + + // A demanded quiet nan result may have come from a signaling nan, so we + // need to expand the demanded mask. + if ((DemandedMask & fcQNan) != fcNone) + SrcDemandedMask |= fcSNan; + + // This cannot have produced a signaling nan, so we can trim any snan + // inputs. + if ((DemandedMask & fcSNan) != fcNone) + SrcDemandedMask &= ~fcSNan; + + if (Mode != DenormalMode::getIEEE()) { + // Any zero results may have come from flushed denormals. + if (DemandedMask & fcPosZero) + SrcDemandedMask |= fcPosSubnormal; + if (DemandedMask & fcNegZero) + SrcDemandedMask |= fcNegSubnormal; + } + + if (Mode == DenormalMode::getPreserveSign()) { + // If a denormal input will be flushed, and we don't need zeros, we + // don't need denormals either. + if ((DemandedMask & fcPosZero) == fcNone) + SrcDemandedMask &= ~fcPosSubnormal; + + if ((DemandedMask & fcNegZero) == fcNone) + SrcDemandedMask &= ~fcNegSubnormal; + } + + KnownFPClass KnownSrc; + + // Simplify upstream operations before trying to simplify this call. + if (SimplifyDemandedFPClass(I, 0, SrcDemandedMask, KnownSrc, Depth + 1)) + return I; + + Known = KnownSrc; + + // Perform the canonicalization to see if this folded to a constant. + Known.canonicalize(Mode); + + if (Constant *SingleVal = + getFPClassConstant(VTy, DemandedMask & Known.KnownFPClasses)) + return SingleVal; + + if (Mode == DenormalMode::getIEEE()) { + // For IEEE handling, there is only a bit change for nan inputs, so we + // can drop it if we do not demand nan results or we know the input + // isn't a nan. + if (KnownSrc.isKnownNeverNaN() || (DemandedMask & fcNan) == fcNone) + return CI->getArgOperand(0); + } else { + // Nan handling is the same as the IEEE case, but we also need to + // avoid denormal inputs to drop the canonicalize. + if ((KnownSrc.isKnownNeverNaN() || + (DemandedMask & fcNan) == fcNone) && + KnownSrc.isKnownNeverSubnormal()) + return CI->getArgOperand(0); + } + + return nullptr; + } + + [[fallthrough]]; + } default: Known = computeKnownFPClass(I, ~DemandedMask, CxtI, Depth + 1); break; diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll index b23e0a5e7c615..0c305762d5c36 100644 --- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll +++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll @@ -71,8 +71,7 @@ define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_ ; CHECK-LABEL: define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_psub_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[PSUB]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %psub = call float @returns_psub() @@ -85,8 +84,7 @@ define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_ ; CHECK-LABEL: define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_nsub_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[NSUB]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %nsub = call float @returns_nsub() @@ -99,8 +97,7 @@ define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_su ; CHECK-LABEL: define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_sub_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %sub = call float @returns_sub() @@ -112,8 +109,7 @@ define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_su define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[PSUB]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[PSUB]] ; %psub = call float @returns_psub() %canon = call float @llvm.canonicalize.f32(float %psub) @@ -123,8 +119,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() { define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSUB]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[NSUB]] ; %nsub = call float @returns_nsub() %canon = call float @llvm.canonicalize.f32(float %nsub) @@ -134,8 +129,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() { define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SUB]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[SUB]] ; %sub = call float @returns_sub() %canon = call float @llvm.canonicalize.f32(float %sub) @@ -180,8 +174,7 @@ define nofpclass(zero) <2 x float> @ret_nofpclass_zero__canonicalize_daz_vec(<2 ; CHECK-LABEL: define nofpclass(zero) <2 x float> @ret_nofpclass_zero__canonicalize_daz_vec( ; CHECK-SAME: <2 x float> [[X:%.*]], <2 x i1> [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB:%.*]] = call <2 x float> @returns_sub_vec() -; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> [[X]], <2 x float> [[SUB]] -; CHECK-NEXT: [[CANON:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) ; CHECK-NEXT: ret <2 x float> [[CANON]] ; %sub = call <2 x float> @returns_sub_vec() @@ -194,8 +187,7 @@ define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz(float ; CHECK-LABEL: define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB_OR_ZERO:%.*]] = call float @returns_sub_zero() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB_OR_ZERO]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %sub_or_zero = call float @returns_sub_zero() @@ -207,8 +199,7 @@ define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz(float define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_ieee(float %unknown) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_ieee( ; CHECK-SAME: float [[UNKNOWN:%.*]]) { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[UNKNOWN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[UNKNOWN]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon @@ -308,8 +299,7 @@ define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_select_unknown_or ; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %snan = call float @returns_snan() @@ -323,9 +313,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_select_unknown_or_s ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[X]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %x, float %snan @@ -337,8 +325,7 @@ define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_ ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]] -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %snan = call float @returns_snan() @@ -354,8 +341,7 @@ define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_ieee(float nofpclass(nan) %x, i1 %cond) { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_ieee( ; CHECK-SAME: float nofpclass(nan) [[X:%.*]], i1 [[COND:%.*]]) { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon @@ -385,8 +371,7 @@ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_src_daz(fl define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_daz(float nofpclass(nan sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_daz( ; CHECK-SAME: float nofpclass(nan sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon @@ -395,8 +380,7 @@ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_dynamic(float nofpclass(nan sub) %x, i1 %cond) #1 { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_dynamic( ; CHECK-SAME: float nofpclass(nan sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon @@ -406,8 +390,7 @@ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz(float nofpclass(sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon @@ -438,8 +421,7 @@ define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_no_sub_src_daz(fl define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_dynamic(float nofpclass(sub) %x, i1 %cond) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_dynamic( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon @@ -517,8 +499,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_dynamic() define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_ninf__dynamic(i1 %cond, float nofpclass(sub norm zero pinf) %must.be.ninf.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_ninf__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(pinf zero sub norm) [[MUST_BE_NINF_OR_NAN:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_NINF_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float 0xFFF0000000000000 ; %canon = call float @llvm.canonicalize.f32(float %must.be.ninf.or.nan) ret float %canon @@ -527,8 +508,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_ninf__dynamic( define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pinf__dynamic(i1 %cond, float nofpclass(sub norm zero pinf) %must.be.pinf.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pinf__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(pinf zero sub norm) [[MUST_BE_PINF_OR_NAN:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_PINF_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float 0xFFF0000000000000 ; %canon = call float @llvm.canonicalize.f32(float %must.be.pinf.or.nan) ret float %canon @@ -537,8 +517,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pinf__dynamic( define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_inf__dynamic(i1 %cond, float nofpclass(sub norm zero) %must.be.inf.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_inf__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(zero sub norm) [[MUST_BE_INF_OR_NAN:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_INF_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[MUST_BE_INF_OR_NAN]] ; %canon = call float @llvm.canonicalize.f32(float %must.be.inf.or.nan) ret float %canon @@ -547,8 +526,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_inf__dynamic(i define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pzero__dynamic(i1 %cond, float nofpclass(sub norm nzero inf) %must.be.pzero.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pzero__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf nzero sub norm) [[MUST_BE_PZERO_OR_NAN:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_PZERO_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float 0.000000e+00 ; %canon = call float @llvm.canonicalize.f32(float %must.be.pzero.or.nan) ret float %canon @@ -557,8 +535,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pzero__dynamic define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nzero__dynamic(i1 %cond, float nofpclass(sub norm pzero inf) %must.be.nzero.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nzero__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf pzero sub norm) [[MUST_BE_NZERO_OR_NAN:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_NZERO_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float -0.000000e+00 ; %canon = call float @llvm.canonicalize.f32(float %must.be.nzero.or.nan) ret float %canon @@ -567,8 +544,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nzero__dynamic define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__ieee(i1 %cond, float nofpclass(sub norm inf) %must.be.zero.or.nan) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__ieee( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_ZERO_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[MUST_BE_ZERO_OR_NAN]] ; %canon = call float @llvm.canonicalize.f32(float %must.be.zero.or.nan) ret float %canon @@ -577,8 +553,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__ieee(i1 define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dynamic(i1 %cond, float nofpclass(sub norm inf) %must.be.zero.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[MUST_BE_ZERO_OR_NAN]]) -; CHECK-NEXT: ret float [[CANON]] +; CHECK-NEXT: ret float [[MUST_BE_ZERO_OR_NAN]] ; %canon = call float @llvm.canonicalize.f32(float %must.be.zero.or.nan) ret float %canon