https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/172998
Pattern match a wrapper around llvm.canonicalize which weakens the semantics to not require quieting signaling nans. Depending on the denormal mode and FP type, we can either drop the pattern entirely or reduce it only to a canonicalize call. I'm inventing this pattern to deal with LLVM's lax canonicalization model in math library code. The math library code currently has explicit checks for the denormal mode, and conditionally canonicalizes the result if there is flushing. Semantically, this could be directly replaced with a simple call to llvm.canonicalize, but doing so would incur an additional cost when using standard IEEE behavior. If we do not care about quieting a signaling nan, this should be a no-op unless the denormal mode may flush. This will allow replacement of the conditional code with a zero cost abstraction utility function. Note we need a standard LLVM floating-point operation in the nan case to assert we do not care about preserving the nan payload and sign bit. This could be any no-op fp instruction; a normal choice would be fmul by 1.0. Using that presents an ordering problem - since LLVM fp operations are not required to canonicalize, instcombine would fold out the fmul before reaching this select combine. The galaxy brain solution here is to use fdiv 1.0, %x as the no-op. This is not a no-op - it could potentially return infinity if %x were 0 (or very close to 0) so it will not be dropped. For the purposes here, that's fine since it's only being used as a nan sink. https://alive2.llvm.org/ce/z/QYS4en >From eb788e6d32c6262b26ae6536be72880a2850c9bf Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Fri, 19 Dec 2025 11:08:58 +0100 Subject: [PATCH] InstCombine: Fold out nanless canonicalize pattern Pattern match a wrapper around llvm.canonicalize which weakens the semantics to not require quieting signaling nans. Depending on the denormal mode and FP type, we can either drop the pattern entirely or reduce it only to a canonicalize call. I'm inventing this pattern to deal with LLVM's lax canonicalization model in math library code. The math library code currently has explicit checks for the denormal mode, and conditionally canonicalizes the result if there is flushing. Semantically, this could be directly replaced with a simple call to llvm.canonicalize, but doing so would incur an additional cost when using standard IEEE behavior. If we do not care about quieting a signaling nan, this should be a no-op unless the denormal mode may flush. This will allow replacement of the conditional code with a zero cost abstraction utility function. Note we need a standard LLVM floating-point operation in the nan case to assert we do not care about preserving the nan payload and sign bit. This could be any no-op fp instruction; a normal choice would be fmul by 1.0. Using that presents an ordering problem - since LLVM fp operations are not required to canonicalize, instcombine would fold out the fmul before reaching this select combine. The galaxy brain solution here is to use fdiv 1.0, %x as the no-op. This is not a no-op - it could potentially return infinity if %x were 0 (or very close to 0) so it will not be dropped. For the purposes here, that's fine since it's only being used as a nan sink. https://alive2.llvm.org/ce/z/QYS4en --- .../InstCombine/InstCombineSelect.cpp | 65 +++++++++++ .../nanless-canonicalize-combine.ll | 101 ++++-------------- 2 files changed, 85 insertions(+), 81 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index f52bac5e600cb..33170e12ed629 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -4343,6 +4343,71 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { matchFMulByZeroIfResultEqZero(*this, Cmp0, Cmp1, MatchCmp1, MatchCmp0, SI, SIFPOp->hasNoSignedZeros())) return replaceInstUsesWith(SI, Cmp0); + + if (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO) { + // Fold out only-canonicalize-non-nans pattern. This implements a + // wrapper around llvm.canonicalize which is not required to quiet + // signaling nans or preserve nan payload bits. + // + // %hard.canonical = call @llvm.canonicalize(%x) + // %soft.canonical = fdiv 1.0, %x + // %ord = fcmp ord %x, 0.0 + // %x.canon = select i1 %ord, %hard.canonical, %soft.canonical + // + // With known IEEE handling: + // => %x + // + // With other denormal behaviors or exotic types: + // => llvm.canonicalize(%x) + // + // Note the fdiv could be any value preserving, potentially + // canonicalizing floating-point operation such as fmul by 1.0. However, + // since in the llvm model canonicalization is not mandatory, the fmul + // would have been dropped by the time we reached here. The trick here + // is to use a reciprocal fdiv. It's not a droppable no-op, as it could + // return an infinity if %x were sufficiently small, but in this pattern + // we're only using the output for nan values. + + if (Pred == CmpInst::FCMP_ORD) { + MatchCmp0 = TrueVal; + MatchCmp1 = FalseVal; + } else { + MatchCmp0 = FalseVal; + MatchCmp1 = TrueVal; + } + + if (match(MatchCmp0, m_FCanonicalize(m_Specific(Cmp0))) && + match(Cmp1, m_PosZeroFP())) { + const fltSemantics &FPSem = + SelType->getScalarType()->getFltSemantics(); + if (APFloat::isIEEELikeFP(FPSem)) { + // IEEE handling does not have non-canonical values, so the + // canonicalize can be dropped for direct replacement without + // looking for the intermediate maybe-canonicalizing operation. + if (Cmp0 == MatchCmp1 && SI.getFunction()->getDenormalMode(FPSem) == + DenormalMode::getIEEE()) + return replaceInstUsesWith(SI, Cmp0); + + // If denormals may be flushed, we need to retain the canonicalize + // call. This introduces a canonicalization on the nan path, which + // we are not free to do as that could change the sign bit or + // payload bits. We can only do this if there were a no-op like + // floating-point instruction which may have changed the nan bits + // anyway. + if (match(MatchCmp1, m_FDiv(m_FPOne(), m_Specific(Cmp0)))) { + DenormalMode Mode = SI.getFunction()->getDenormalMode(FPSem); + if (Mode == DenormalMode::getIEEE()) + return replaceInstUsesWith(SI, Cmp0); + + if (Mode.inputsAreZero() || Mode.outputsAreZero()) + return replaceInstUsesWith(SI, MatchCmp0); + } + + // Leave the dynamic mode case alone. This would introduce new + // constraints if the mode may be refined later. + } + } + } } } diff --git a/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll b/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll index 5aa156753e860..0937f6ff19c2b 100644 --- a/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll +++ b/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll @@ -9,11 +9,7 @@ define float @canonicalize_ieee_0(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0:[0-9]+]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x @@ -26,11 +22,7 @@ define float @canonicalize_ieee_0(float %x) #0 { define float @canonicalize_ieee_1(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_1( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], float [[SOFT_CANONICAL]], float [[HARD_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x @@ -44,10 +36,7 @@ define float @canonicalize_ieee_1(float %x) #0 { define float @canonicalize_ieee_0_fmul(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0_fmul( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[X]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fmul float %x, 1.0 @@ -61,10 +50,7 @@ define float @canonicalize_ieee_0_fmul(float %x) #0 { define float @canonicalize_ieee_0_fdiv_commute(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0_fdiv_commute( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[X]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float %x, 1.0 @@ -79,10 +65,7 @@ define float @canonicalize_daz_0(float %x) #1 { ; CHECK-LABEL: define float @canonicalize_daz_0( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[HARD_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x @@ -96,11 +79,8 @@ define float @canonicalize_daz_0(float %x) #1 { define float @canonicalize_daz_1(float %x) #1 { ; CHECK-LABEL: define float @canonicalize_daz_1( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], float [[SOFT_CANONICAL]], float [[HARD_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) +; CHECK-NEXT: ret float [[SOFT_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x @@ -146,11 +126,7 @@ define float @canonicalize_dynamic_1(float %x) #2 { define <2 x float> @canonicalize_ieee_0_vec(<2 x float> %x) #0 { ; CHECK-LABEL: define <2 x float> @canonicalize_ieee_0_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord <2 x float> [[X]], zeroinitializer -; CHECK-NEXT: [[X_CANON:%.*]] = select <2 x i1> [[ORD]], <2 x float> [[HARD_CANONICAL]], <2 x float> [[SOFT_CANONICAL]] -; CHECK-NEXT: ret <2 x float> [[X_CANON]] +; CHECK-NEXT: ret <2 x float> [[X]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x @@ -162,11 +138,7 @@ define <2 x float> @canonicalize_ieee_0_vec(<2 x float> %x) #0 { define <2 x float> @canonicalize_ieee_1_vec(<2 x float> %x) #0 { ; CHECK-LABEL: define <2 x float> @canonicalize_ieee_1_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]] -; CHECK-NEXT: [[UNO:%.*]] = fcmp uno <2 x float> [[X]], zeroinitializer -; CHECK-NEXT: [[X_CANON:%.*]] = select <2 x i1> [[UNO]], <2 x float> [[SOFT_CANONICAL]], <2 x float> [[HARD_CANONICAL]] -; CHECK-NEXT: ret <2 x float> [[X_CANON]] +; CHECK-NEXT: ret <2 x float> [[X]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x @@ -195,10 +167,7 @@ define <2 x float> @canonicalize_daz_0_vec(<2 x float> %x) #1 { ; CHECK-LABEL: define <2 x float> @canonicalize_daz_0_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord <2 x float> [[X]], zeroinitializer -; CHECK-NEXT: [[X_CANON:%.*]] = select <2 x i1> [[ORD]], <2 x float> [[HARD_CANONICAL]], <2 x float> [[SOFT_CANONICAL]] -; CHECK-NEXT: ret <2 x float> [[X_CANON]] +; CHECK-NEXT: ret <2 x float> [[HARD_CANONICAL]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x @@ -210,11 +179,8 @@ define <2 x float> @canonicalize_daz_0_vec(<2 x float> %x) #1 { define <2 x float> @canonicalize_daz_1_vec(<2 x float> %x) #1 { ; CHECK-LABEL: define <2 x float> @canonicalize_daz_1_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR1]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]] -; CHECK-NEXT: [[UNO:%.*]] = fcmp uno <2 x float> [[X]], zeroinitializer -; CHECK-NEXT: [[X_CANON:%.*]] = select <2 x i1> [[UNO]], <2 x float> [[SOFT_CANONICAL]], <2 x float> [[HARD_CANONICAL]] -; CHECK-NEXT: ret <2 x float> [[X_CANON]] +; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) +; CHECK-NEXT: ret <2 x float> [[SOFT_CANONICAL]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x @@ -226,11 +192,7 @@ define <2 x float> @canonicalize_daz_1_vec(<2 x float> %x) #1 { define bfloat @canonicalize_ieee_bf16(bfloat %x) #0 { ; CHECK-LABEL: define bfloat @canonicalize_ieee_bf16( ; CHECK-SAME: bfloat [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call bfloat @llvm.canonicalize.bf16(bfloat [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv bfloat 0xR3F80, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord bfloat [[X]], 0xR0000 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], bfloat [[HARD_CANONICAL]], bfloat [[SOFT_CANONICAL]] -; CHECK-NEXT: ret bfloat [[X_CANON]] +; CHECK-NEXT: ret bfloat [[X]] ; %hard.canonical = call bfloat @llvm.canonicalize.bf16(bfloat %x) %soft.canonical = fdiv bfloat 1.0, %x @@ -242,11 +204,7 @@ define bfloat @canonicalize_ieee_bf16(bfloat %x) #0 { define half @canonicalize_ieee_f16(half %x) #0 { ; CHECK-LABEL: define half @canonicalize_ieee_f16( ; CHECK-SAME: half [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv half 0xH3C00, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], half [[HARD_CANONICAL]], half [[SOFT_CANONICAL]] -; CHECK-NEXT: ret half [[X_CANON]] +; CHECK-NEXT: ret half [[X]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %soft.canonical = fdiv half 1.0, %x @@ -258,11 +216,7 @@ define half @canonicalize_ieee_f16(half %x) #0 { define double @canonicalize_ieee_f64(double %x) #0 { ; CHECK-LABEL: define double @canonicalize_ieee_f64( ; CHECK-SAME: double [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call double @llvm.canonicalize.f64(double [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv double 1.000000e+00, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord double [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], double [[HARD_CANONICAL]], double [[SOFT_CANONICAL]] -; CHECK-NEXT: ret double [[X_CANON]] +; CHECK-NEXT: ret double [[X]] ; %hard.canonical = call double @llvm.canonicalize.f64(double %x) %soft.canonical = fdiv double 1.0, %x @@ -274,10 +228,7 @@ define double @canonicalize_ieee_f64(double %x) #0 { define fp128 @canonicalize_ieee_f128(fp128 %x) #0 { ; CHECK-LABEL: define fp128 @canonicalize_ieee_f128( ; CHECK-SAME: fp128 [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call fp128 @llvm.canonicalize.f128(fp128 [[X]]) -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord fp128 [[X]], 0xL00000000000000000000000000000000 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], fp128 [[HARD_CANONICAL]], fp128 [[X]] -; CHECK-NEXT: ret fp128 [[X_CANON]] +; CHECK-NEXT: ret fp128 [[X]] ; %hard.canonical = call fp128 @llvm.canonicalize.f128(fp128 %x) %ord = fcmp ord fp128 %x, 0xL00000000000000000000000000000000 @@ -503,10 +454,7 @@ define ppc_fp128 @ignore_ppc_fp128(ppc_fp128 %x) #0 { define float @canonicalize_ieee_0_missing_noop(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0_missing_noop( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[X]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %ord = fcmp ord float %x, 0.0 @@ -519,10 +467,7 @@ define float @canonicalize_ieee_0_missing_noop(float %x) #0 { define float @canonicalize_ieee_1_missing_noop(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_1_missing_noop( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], float [[X]], float [[HARD_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %uno = fcmp uno float %x, 0.0 @@ -567,10 +512,7 @@ define float @canonicalize_only_ftz(float %x) "denormal-fp-math"="preserve-sign, ; CHECK-LABEL: define float @canonicalize_only_ftz( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR3:[0-9]+]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[HARD_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x @@ -584,10 +526,7 @@ define float @canonicalize_only_daz(float %x) "denormal-fp-math"="ieee,preserve- ; CHECK-LABEL: define float @canonicalize_only_daz( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) -; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] -; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 -; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] -; CHECK-NEXT: ret float [[X_CANON]] +; CHECK-NEXT: ret float [[HARD_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
