https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/175616
>From f3a855449e79a090c8821e4d2ef58dd7d34ddc4e Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Mon, 12 Jan 2026 14:49:56 +0100 Subject: [PATCH 1/3] InstCombine: Implement SimplifyDemandedFPClass for fma This can't do much filtering on the sources, except for nans. We can also attempt to introduce ninf/nnan. --- .../InstCombineSimplifyDemanded.cpp | 79 +++++++++++++++---- .../simplify-demanded-fpclass-fma.ll | 47 ++++------- 2 files changed, 81 insertions(+), 45 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 05ed123b8be75..cde505dd4496c 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -2033,21 +2033,25 @@ static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask, } } -/// Try to set an inferred no-nans or no-infs in \p FMF. \p -/// ValidResults is a mask of known valid results for the operator -/// (already computed from the result, and the known operand inputs, -/// \p KnownLHS and \p KnownRHS) +/// Try to set an inferred no-nans or no-infs in \p FMF. \p ValidResults is a +/// mask of known valid results for the operator (already computed from the +/// result, and the known operand inputs in \p Known) static FastMathFlags -inferFastMathValueFlagsBinOp(FastMathFlags FMF, FPClassTest ValidResults, - const KnownFPClass &KnownLHS, - const KnownFPClass &KnownRHS) { - if (!FMF.noNaNs() && (ValidResults & fcNan) == fcNone && - KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN()) - FMF.setNoNaNs(); +inferFastMathValueFlags(FastMathFlags FMF, FPClassTest ValidResults, + std::initializer_list<const KnownFPClass> Known) { + if (!FMF.noNaNs() && (ValidResults & fcNan) == fcNone) { + if (all_of(Known, [](const KnownFPClass &KnownSrc) { + return KnownSrc.isKnownNeverNaN(); + })) + FMF.setNoNaNs(); + } - if (!FMF.noInfs() && (ValidResults & fcInf) == fcNone && - KnownLHS.isKnownNeverInfinity() && KnownRHS.isKnownNeverInfinity()) - FMF.setNoInfs(); + if (!FMF.noInfs() && (ValidResults & fcInf) == fcNone) { + if (all_of(Known, [](const KnownFPClass &KnownSrc) { + return KnownSrc.isKnownNeverInfinity(); + })) + FMF.setNoInfs(); + } return FMF; } @@ -2167,7 +2171,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I, return I->getOperand(0); FastMathFlags InferredFMF = - inferFastMathValueFlagsBinOp(FMF, ValidResults, KnownLHS, KnownRHS); + inferFastMathValueFlags(FMF, ValidResults, {KnownLHS, KnownRHS}); if (InferredFMF != FMF) { I->setFastMathFlags(InferredFMF); return I; @@ -2428,6 +2432,53 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I, Known.copysign(KnownSign); break; } + case Intrinsic::fma: + case Intrinsic::fmuladd: { + // We can't do any simplification on the source besides stripping out + // unneeded nans. + FPClassTest SrcDemandedMask = (DemandedMask & fcNan) | ~fcNan; + + KnownFPClass KnownSrc[3]; + + Type *EltTy = VTy->getScalarType(); + if (CI->getArgOperand(0) == CI->getArgOperand(1) && + isGuaranteedNotToBeUndef(CI->getArgOperand(0), SQ.AC, CxtI, SQ.DT, + Depth + 1)) { + if (SimplifyDemandedFPClass(CI, 0, SrcDemandedMask, KnownSrc[0], + Depth + 1) || + SimplifyDemandedFPClass(CI, 2, SrcDemandedMask, KnownSrc[2], + Depth + 1)) + return I; + + KnownSrc[1] = KnownSrc[0]; + DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics()); + Known = KnownFPClass::fma_square(KnownSrc[0], KnownSrc[2], Mode); + } else { + for (int OpIdx = 0; OpIdx != 3; ++OpIdx) { + if (SimplifyDemandedFPClass(CI, OpIdx, SrcDemandedMask, + KnownSrc[OpIdx], Depth + 1)) + return CI; + } + + DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics()); + Known = KnownFPClass::fma(KnownSrc[0], KnownSrc[1], KnownSrc[2], Mode); + } + + FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses; + if (Constant *SingleVal = + getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true)) + return SingleVal; + + FastMathFlags InferredFMF = inferFastMathValueFlags( + FMF, ValidResults, {KnownSrc[0], KnownSrc[1], KnownSrc[2]}); + if (InferredFMF != FMF) { + CI->dropUBImplyingAttrsAndMetadata(); + CI->setFastMathFlags(InferredFMF); + return I; + } + + break; + } case Intrinsic::maximum: case Intrinsic::minimum: case Intrinsic::maximumnum: diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fma.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fma.ll index 3309a475bbf80..2634ee5c0afb7 100644 --- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fma.ll +++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fma.ll @@ -6,8 +6,7 @@ declare nofpclass(inf norm sub zero) half @returns_nan() define nofpclass(inf norm sub zero) half @ret_only_nan(half %x, half %y, half %z) { ; CHECK-LABEL: define nofpclass(inf zero sub norm) half @ret_only_nan( ; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]], half [[Z:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[X]], half [[Y]], half [[Z]]) -; CHECK-NEXT: ret half [[RESULT]] +; CHECK-NEXT: ret half 0xH7E00 ; %result = call half @llvm.fma.f16(half %x, half %y, half %z) ret half %result @@ -16,8 +15,7 @@ define nofpclass(inf norm sub zero) half @ret_only_nan(half %x, half %y, half %z define nofpclass(inf norm sub zero) <2 x half> @ret_only_nan_vec(<2 x half> %x, <2 x half> %y, <2 x half> %z) { ; CHECK-LABEL: define nofpclass(inf zero sub norm) <2 x half> @ret_only_nan_vec( ; CHECK-SAME: <2 x half> [[X:%.*]], <2 x half> [[Y:%.*]], <2 x half> [[Z:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call <2 x half> @llvm.fma.v2f16(<2 x half> [[X]], <2 x half> [[Y]], <2 x half> [[Z]]) -; CHECK-NEXT: ret <2 x half> [[RESULT]] +; CHECK-NEXT: ret <2 x half> splat (half 0xH7E00) ; %result = call <2 x half> @llvm.fma.v2f16(<2 x half> %x, <2 x half> %y, <2 x half> %z) ret <2 x half> %result @@ -132,8 +130,7 @@ define nofpclass(nan inf) half @ret_no_nans_no_infs(half %x, half %y, half %z) { define nofpclass(inf norm sub zero) half @ret_only_nan__square(half noundef %x, half %z) { ; CHECK-LABEL: define nofpclass(inf zero sub norm) half @ret_only_nan__square( ; CHECK-SAME: half noundef [[X:%.*]], half [[Z:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[X]], half [[X]], half [[Z]]) -; CHECK-NEXT: ret half [[RESULT]] +; CHECK-NEXT: ret half 0xH7E00 ; %result = call half @llvm.fma.f16(half %x, half %x, half %z) ret half %result @@ -143,8 +140,7 @@ define nofpclass(nan) half @ret_nonan__select_nan_or_unknown_src0(i1 %cond, half ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__select_nan_or_unknown_src0( ; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN0:%.*]], half [[UNKNOWN1:%.*]], half [[UNKNOWN2:%.*]]) { ; CHECK-NEXT: [[NAN:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN:%.*]] = select i1 [[COND]], half [[NAN]], half [[UNKNOWN0]] -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[NAN_OR_UNKNOWN]], half [[UNKNOWN1]], half [[UNKNOWN2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[UNKNOWN0]], half [[UNKNOWN1]], half [[UNKNOWN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %nan = call half @returns_nan() @@ -157,8 +153,7 @@ define nofpclass(nan) half @ret_nonan__select_nan_or_unknown_src1(i1 %cond, half ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__select_nan_or_unknown_src1( ; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN0:%.*]], half [[UNKNOWN1:%.*]], half [[UNKNOWN2:%.*]]) { ; CHECK-NEXT: [[NAN:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN:%.*]] = select i1 [[COND]], half [[NAN]], half [[UNKNOWN1]] -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[UNKNOWN0]], half [[NAN_OR_UNKNOWN]], half [[UNKNOWN2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[UNKNOWN0]], half [[UNKNOWN1]], half [[UNKNOWN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %nan = call half @returns_nan() @@ -171,8 +166,7 @@ define nofpclass(nan) half @ret_nonan__select_nan_or_unknown_src2(i1 %cond, half ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__select_nan_or_unknown_src2( ; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN0:%.*]], half [[UNKNOWN1:%.*]], half [[UNKNOWN2:%.*]]) { ; CHECK-NEXT: [[NAN:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN:%.*]] = select i1 [[COND]], half [[NAN]], half [[UNKNOWN2]] -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[UNKNOWN0]], half [[UNKNOWN1]], half [[NAN_OR_UNKNOWN]]) +; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[UNKNOWN0]], half [[UNKNOWN1]], half [[UNKNOWN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %nan = call half @returns_nan() @@ -185,12 +179,9 @@ define nofpclass(nan) half @ret_nonan__fma__select_nan_or_unknown_all_src(i1 %co ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__fma__select_nan_or_unknown_all_src( ; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN0:%.*]], half [[UNKNOWN1:%.*]], half [[UNKNOWN2:%.*]]) { ; CHECK-NEXT: [[NAN0:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN0:%.*]] = select i1 [[COND]], half [[NAN0]], half [[UNKNOWN0]] ; CHECK-NEXT: [[NAN1:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN1:%.*]] = select i1 [[COND]], half [[NAN1]], half [[UNKNOWN1]] ; CHECK-NEXT: [[NAN2:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN2:%.*]] = select i1 [[COND]], half [[NAN2]], half [[UNKNOWN2]] -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[NAN_OR_UNKNOWN0]], half [[NAN_OR_UNKNOWN1]], half [[NAN_OR_UNKNOWN2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[UNKNOWN0]], half [[UNKNOWN1]], half [[UNKNOWN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %nan0 = call half @returns_nan() @@ -207,12 +198,9 @@ define nofpclass(nan) half @ret_nonan__fmuladd__select_nan_or_unknown_all_src(i1 ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__fmuladd__select_nan_or_unknown_all_src( ; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN0:%.*]], half [[UNKNOWN1:%.*]], half [[UNKNOWN2:%.*]]) { ; CHECK-NEXT: [[NAN0:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN0:%.*]] = select i1 [[COND]], half [[NAN0]], half [[UNKNOWN0]] ; CHECK-NEXT: [[NAN1:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN1:%.*]] = select i1 [[COND]], half [[NAN1]], half [[UNKNOWN1]] ; CHECK-NEXT: [[NAN2:%.*]] = call half @returns_nan() -; CHECK-NEXT: [[NAN_OR_UNKNOWN2:%.*]] = select i1 [[COND]], half [[NAN2]], half [[UNKNOWN2]] -; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fmuladd.f16(half [[NAN_OR_UNKNOWN0]], half [[NAN_OR_UNKNOWN1]], half [[NAN_OR_UNKNOWN2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fmuladd.f16(half [[UNKNOWN0]], half [[UNKNOWN1]], half [[UNKNOWN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %nan0 = call half @returns_nan() @@ -228,7 +216,7 @@ define nofpclass(nan) half @ret_nonan__fmuladd__select_nan_or_unknown_all_src(i1 define nofpclass(nan) half @ret_nonan__fmuladd__no_nan_all_src(i1 %cond, half nofpclass(nan) %not.nan0, half nofpclass(nan) %not.nan1, half nofpclass(nan) %not.nan2) { ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__fmuladd__no_nan_all_src( ; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(nan) [[NOT_NAN0:%.*]], half nofpclass(nan) [[NOT_NAN1:%.*]], half nofpclass(nan) [[NOT_NAN2:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call nsz half @llvm.fmuladd.f16(half [[NOT_NAN0]], half [[NOT_NAN1]], half [[NOT_NAN2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call nnan nsz half @llvm.fmuladd.f16(half [[NOT_NAN0]], half [[NOT_NAN1]], half [[NOT_NAN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call nsz half @llvm.fmuladd.f16(half %not.nan0, half %not.nan1, half %not.nan2) @@ -238,7 +226,7 @@ define nofpclass(nan) half @ret_nonan__fmuladd__no_nan_all_src(i1 %cond, half no define nofpclass(inf) half @ret_noinf__fmuladd__no_inf_all_src(i1 %cond, half nofpclass(inf) %not.inf0, half nofpclass(inf) %not.inf1, half nofpclass(inf) %not.inf2) { ; CHECK-LABEL: define nofpclass(inf) half @ret_noinf__fmuladd__no_inf_all_src( ; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(inf) [[NOT_INF0:%.*]], half nofpclass(inf) [[NOT_INF1:%.*]], half nofpclass(inf) [[NOT_INF2:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call nsz half @llvm.fmuladd.f16(half [[NOT_INF0]], half [[NOT_INF1]], half [[NOT_INF2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call ninf nsz half @llvm.fmuladd.f16(half [[NOT_INF0]], half [[NOT_INF1]], half [[NOT_INF2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call nsz half @llvm.fmuladd.f16(half %not.inf0, half %not.inf1, half %not.inf2) @@ -248,7 +236,7 @@ define nofpclass(inf) half @ret_noinf__fmuladd__no_inf_all_src(i1 %cond, half no define nofpclass(nan inf) half @ret_noinf_nonan__fmuladd__no_inf_all_src(i1 %cond, half nofpclass(nan inf) %not.nan.or.inf0, half nofpclass(nan inf) %not.nan.or.inf1, half nofpclass(nan inf) %not.nan.or.inf2) { ; CHECK-LABEL: define nofpclass(nan inf) half @ret_noinf_nonan__fmuladd__no_inf_all_src( ; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(nan inf) [[NOT_NAN_OR_INF0:%.*]], half nofpclass(nan inf) [[NOT_NAN_OR_INF1:%.*]], half nofpclass(nan inf) [[NOT_NAN_OR_INF2:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call nsz half @llvm.fmuladd.f16(half [[NOT_NAN_OR_INF0]], half [[NOT_NAN_OR_INF1]], half [[NOT_NAN_OR_INF2]]) +; CHECK-NEXT: [[RESULT:%.*]] = call nnan ninf nsz half @llvm.fmuladd.f16(half [[NOT_NAN_OR_INF0]], half [[NOT_NAN_OR_INF1]], half [[NOT_NAN_OR_INF2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call nsz half @llvm.fmuladd.f16(half %not.nan.or.inf0, half %not.nan.or.inf1, half %not.nan.or.inf2) @@ -258,7 +246,7 @@ define nofpclass(nan inf) half @ret_noinf_nonan__fmuladd__no_inf_all_src(i1 %con define nofpclass(nan) half @ret_nonan__fmuladd__no_nan_all_src__drop_ub_attrs_md(i1 %cond, half nofpclass(nan) %not.nan0, half nofpclass(nan) %not.nan1, half nofpclass(nan) %not.nan2) { ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__fmuladd__no_nan_all_src__drop_ub_attrs_md( ; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(nan) [[NOT_NAN0:%.*]], half nofpclass(nan) [[NOT_NAN1:%.*]], half nofpclass(nan) [[NOT_NAN2:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call noundef half @llvm.fmuladd.f16(half [[NOT_NAN0]], half [[NOT_NAN1]], half noundef [[NOT_NAN2]]), !noundef [[META0:![0-9]+]], !unknown.md [[META0]] +; CHECK-NEXT: [[RESULT:%.*]] = call nnan half @llvm.fmuladd.f16(half [[NOT_NAN0]], half [[NOT_NAN1]], half [[NOT_NAN2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call noundef half @llvm.fmuladd.f16(half %not.nan0, half %not.nan1, half noundef %not.nan2), !unknown.md !0, !noundef !0 @@ -268,7 +256,7 @@ define nofpclass(nan) half @ret_nonan__fmuladd__no_nan_all_src__drop_ub_attrs_md define nofpclass(nan inf) half @ret_noinf_nonan__fmuladd__no_inf_all_src__drop_ub_attrs_md(half nofpclass(nan inf) %not.nan.or.inf0, half nofpclass(nan inf) %not.nan.or.inf1, half nofpclass(nan inf) %not.nan.or.inf2) { ; CHECK-LABEL: define nofpclass(nan inf) half @ret_noinf_nonan__fmuladd__no_inf_all_src__drop_ub_attrs_md( ; CHECK-SAME: half nofpclass(nan inf) [[NOT_NAN_OR_INF0:%.*]], half nofpclass(nan inf) [[NOT_NAN_OR_INF1:%.*]], half nofpclass(nan inf) [[NOT_NAN_OR_INF2:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call noundef half @llvm.fmuladd.f16(half [[NOT_NAN_OR_INF0]], half [[NOT_NAN_OR_INF1]], half [[NOT_NAN_OR_INF2]]), !noundef [[META0]], !unknown.md [[META0]] +; CHECK-NEXT: [[RESULT:%.*]] = call nnan ninf half @llvm.fmuladd.f16(half [[NOT_NAN_OR_INF0]], half [[NOT_NAN_OR_INF1]], half [[NOT_NAN_OR_INF2]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call noundef half @llvm.fmuladd.f16(half %not.nan.or.inf0, half %not.nan.or.inf1, half %not.nan.or.inf2), !unknown.md !0, !noundef !0 @@ -278,7 +266,7 @@ define nofpclass(nan inf) half @ret_noinf_nonan__fmuladd__no_inf_all_src__drop_u define nofpclass(nan) half @ret_nonan__fma_square__no_nan_all_src(half nofpclass(nan) %not.nan0, half nofpclass(nan) %not.nan1) { ; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__fma_square__no_nan_all_src( ; CHECK-SAME: half nofpclass(nan) [[NOT_NAN0:%.*]], half nofpclass(nan) [[NOT_NAN1:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call noundef half @llvm.fma.f16(half [[NOT_NAN0]], half [[NOT_NAN0]], half [[NOT_NAN1]]), !noundef [[META0]], !unknown.md [[META0]] +; CHECK-NEXT: [[RESULT:%.*]] = call nnan half @llvm.fma.f16(half [[NOT_NAN0]], half [[NOT_NAN0]], half [[NOT_NAN1]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call noundef half @llvm.fma.f16(half %not.nan0, half %not.nan0, half %not.nan1), !unknown.md !0, !noundef !0 @@ -288,7 +276,7 @@ define nofpclass(nan) half @ret_nonan__fma_square__no_nan_all_src(half nofpclass define nofpclass(inf) half @ret_noinf__fma_square__no_inf_all_src(half nofpclass(inf) %not.nan0, half nofpclass(inf) %not.nan1) { ; CHECK-LABEL: define nofpclass(inf) half @ret_noinf__fma_square__no_inf_all_src( ; CHECK-SAME: half nofpclass(inf) [[NOT_NAN0:%.*]], half nofpclass(inf) [[NOT_NAN1:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call noundef half @llvm.fma.f16(half [[NOT_NAN0]], half [[NOT_NAN0]], half [[NOT_NAN1]]), !noundef [[META0]], !unknown.md [[META0]] +; CHECK-NEXT: [[RESULT:%.*]] = call ninf half @llvm.fma.f16(half [[NOT_NAN0]], half [[NOT_NAN0]], half [[NOT_NAN1]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call noundef half @llvm.fma.f16(half %not.nan0, half %not.nan0, half %not.nan1), !unknown.md !0, !noundef !0 @@ -298,7 +286,7 @@ define nofpclass(inf) half @ret_noinf__fma_square__no_inf_all_src(half nofpclass define nofpclass(nan inf) half @ret_nonan_noinf__fma_square__no_nan_no_inf_all_src(half nofpclass(nan inf) %not.nan0, half nofpclass(nan inf) %not.nan1) { ; CHECK-LABEL: define nofpclass(nan inf) half @ret_nonan_noinf__fma_square__no_nan_no_inf_all_src( ; CHECK-SAME: half nofpclass(nan inf) [[NOT_NAN0:%.*]], half nofpclass(nan inf) [[NOT_NAN1:%.*]]) { -; CHECK-NEXT: [[RESULT:%.*]] = call nsz noundef half @llvm.fma.f16(half [[NOT_NAN0]], half [[NOT_NAN0]], half [[NOT_NAN1]]), !noundef [[META0]], !unknown.md [[META0]] +; CHECK-NEXT: [[RESULT:%.*]] = call nnan ninf nsz half @llvm.fma.f16(half [[NOT_NAN0]], half [[NOT_NAN0]], half [[NOT_NAN1]]) ; CHECK-NEXT: ret half [[RESULT]] ; %result = call nsz noundef half @llvm.fma.f16(half %not.nan0, half %not.nan0, half %not.nan1), !unknown.md !0, !noundef !0 @@ -311,6 +299,3 @@ define nofpclass(nan inf) half @ret_nonan_noinf__fma_square__no_nan_no_inf_all_s -;. -; CHECK: [[META0]] = !{} -;. >From b931e9c69cea30776a52d58733ec08920f96eeaf Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Tue, 13 Jan 2026 22:58:05 +0100 Subject: [PATCH 2/3] Address comments --- .../InstCombine/InstCombineSimplifyDemanded.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index cde505dd4496c..67563041e16ad 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -2038,16 +2038,16 @@ static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask, /// result, and the known operand inputs in \p Known) static FastMathFlags inferFastMathValueFlags(FastMathFlags FMF, FPClassTest ValidResults, - std::initializer_list<const KnownFPClass> Known) { + ArrayRef<const KnownFPClass> Known) { if (!FMF.noNaNs() && (ValidResults & fcNan) == fcNone) { - if (all_of(Known, [](const KnownFPClass &KnownSrc) { + if (all_of(Known, [](const KnownFPClass KnownSrc) { return KnownSrc.isKnownNeverNaN(); })) FMF.setNoNaNs(); } if (!FMF.noInfs() && (ValidResults & fcInf) == fcNone) { - if (all_of(Known, [](const KnownFPClass &KnownSrc) { + if (all_of(Known, [](const KnownFPClass KnownSrc) { return KnownSrc.isKnownNeverInfinity(); })) FMF.setNoInfs(); @@ -2469,8 +2469,8 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I, getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true)) return SingleVal; - FastMathFlags InferredFMF = inferFastMathValueFlags( - FMF, ValidResults, {KnownSrc[0], KnownSrc[1], KnownSrc[2]}); + FastMathFlags InferredFMF = + inferFastMathValueFlags(FMF, ValidResults, KnownSrc); if (InferredFMF != FMF) { CI->dropUBImplyingAttrsAndMetadata(); CI->setFastMathFlags(InferredFMF); >From 8e00be6df3ea0200ba92a8b07e4434b6168b3201 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Wed, 14 Jan 2026 17:13:46 +0100 Subject: [PATCH 3/3] Update for inferFastMathValueFlagsBinOp removal --- llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 67563041e16ad..3bbc4a913ada6 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -2338,7 +2338,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I, return SingleVal; FastMathFlags InferredFMF = - inferFastMathValueFlagsBinOp(FMF, ValidResults, KnownLHS, KnownRHS); + inferFastMathValueFlags(FMF, ValidResults, {KnownLHS, KnownRHS}); if (InferredFMF != FMF) { I->setFastMathFlags(InferredFMF); return I; _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
