[llvm-branch-commits] [llvm] InstCombine: Implement SimplifyDemandedFPClass for fma (PR #175616)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jan 15 13:57:34 PST 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/175616

>From adab85ebe9519123b5f2c6dc560b5417986edc75 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 12 Jan 2026 14:49:56 +0100
Subject: [PATCH 1/2] 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           | 93 ++++++++++++++-----
 .../simplify-demanded-fpclass-fma.ll          | 47 ++++------
 2 files changed, 88 insertions(+), 52 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 78d7be41fae67..77dba8bc62da5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2033,6 +2033,29 @@ 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 in \p Known)
+static FastMathFlags
+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) {
+    if (all_of(Known, [](const KnownFPClass &KnownSrc) {
+          return KnownSrc.isKnownNeverInfinity();
+        }))
+      FMF.setNoInfs();
+  }
+
+  return FMF;
+}
+
 static Value *
 simplifyDemandedFPClassMinMax(KnownFPClass &Known, Intrinsic::ID IID,
                               const CallInst *CI, FPClassTest DemandedMask,
@@ -2128,25 +2151,6 @@ simplifyDemandedFPClassMinMax(KnownFPClass &Known, Intrinsic::ID IID,
                             /*IsCanonicalizing=*/true);
 }
 
-/// 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)
-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();
-
-  if (!FMF.noInfs() && (ValidResults & fcInf) == fcNone &&
-      KnownLHS.isKnownNeverInfinity() && KnownRHS.isKnownNeverInfinity())
-    FMF.setNoInfs();
-
-  return FMF;
-}
-
 Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
                                                     FPClassTest DemandedMask,
                                                     KnownFPClass &Known,
@@ -2262,7 +2266,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;
@@ -2429,7 +2433,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;
@@ -2523,6 +2527,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 60b377c1a7ddf1df637edbdc2ca9a40c0d5ef6f8 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 13 Jan 2026 22:58:05 +0100
Subject: [PATCH 2/2] 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 77dba8bc62da5..3c15400d90b48 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();
@@ -2564,8 +2564,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);



More information about the llvm-branch-commits mailing list