[llvm] ValueTracking: Improve handling for fma/fmuladd (PR #175614)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 21 01:08:09 PST 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/175614
>From 4a3456fd971c68a73546fb7951424c40f243c982 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 21 Jan 2026 09:40:55 +0100
Subject: [PATCH] ValueTracking: Improve handling for fma/fmuladd
The handling for fma was very basic and only handled the
repeated input case. Re-use the fmul and fadd handling for more
accurate sign bit and nan handling.
---
llvm/include/llvm/Support/KnownFPClass.h | 11 ++
llvm/lib/Analysis/ValueTracking.cpp | 42 +++++--
llvm/lib/Support/KnownFPClass.cpp | 38 ++++++-
.../Transforms/Attributor/nofpclass-fma.ll | 104 +++++++++---------
llvm/test/Transforms/InstCombine/fabs.ll | 6 +-
5 files changed, 130 insertions(+), 71 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 3dd2cbad873d2..36db1cdab23d5 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -250,6 +250,17 @@ struct KnownFPClass {
return Known;
}
+ /// Report known values for fma
+ LLVM_ABI static KnownFPClass
+ fma(const KnownFPClass &LHS, const KnownFPClass &RHS,
+ const KnownFPClass &Addend,
+ DenormalMode Mode = DenormalMode::getDynamic());
+
+ /// Report known values for fma squared, squared, addend
+ LLVM_ABI static KnownFPClass
+ fma_square(const KnownFPClass &Squared, const KnownFPClass &Addend,
+ DenormalMode Mode = DenormalMode::getDynamic());
+
/// Report known values for exp, exp2 and exp10.
LLVM_ABI static KnownFPClass exp(const KnownFPClass &Src);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 171952120fc40..d1f620ac9eb3d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5128,21 +5128,39 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
if ((InterestedClasses & fcNegative) == fcNone)
break;
- if (II->getArgOperand(0) != II->getArgOperand(1) ||
- !isGuaranteedNotToBeUndef(II->getArgOperand(0), Q.AC, Q.CxtI, Q.DT,
- Depth + 1))
- break;
+ if (II->getArgOperand(0) == II->getArgOperand(1) &&
+ isGuaranteedNotToBeUndef(II->getArgOperand(0), Q.AC, Q.CxtI, Q.DT,
+ Depth + 1)) {
+ KnownFPClass KnownSrc, KnownAddend;
+ computeKnownFPClass(II->getArgOperand(2), DemandedElts,
+ InterestedClasses, KnownAddend, Q, Depth + 1);
+ computeKnownFPClass(II->getArgOperand(0), DemandedElts,
+ InterestedClasses, KnownSrc, Q, Depth + 1);
- // The multiply cannot be -0 and therefore the add can't be -0
- Known.knownNot(fcNegZero);
+ const Function *F = II->getFunction();
+ const fltSemantics &FltSem =
+ II->getType()->getScalarType()->getFltSemantics();
+ DenormalMode Mode =
+ F ? F->getDenormalMode(FltSem) : DenormalMode::getDynamic();
+
+ Known = KnownFPClass::fma_square(KnownSrc, KnownAddend, Mode);
+ break;
+ }
- // x * x + y is non-negative if y is non-negative.
- KnownFPClass KnownAddend;
- computeKnownFPClass(II->getArgOperand(2), DemandedElts, InterestedClasses,
- KnownAddend, Q, Depth + 1);
+ KnownFPClass KnownSrc[3];
+ for (int I = 0; I != 3; ++I) {
+ computeKnownFPClass(II->getArgOperand(I), DemandedElts,
+ InterestedClasses, KnownSrc[I], Q, Depth + 1);
+ if (KnownSrc[I].isUnknown())
+ return;
+ }
- if (KnownAddend.cannotBeOrderedLessThanZero())
- Known.knownNot(fcNegative);
+ const Function *F = II->getFunction();
+ const fltSemantics &FltSem =
+ II->getType()->getScalarType()->getFltSemantics();
+ DenormalMode Mode =
+ F ? F->getDenormalMode(FltSem) : DenormalMode::getDynamic();
+ Known = KnownFPClass::fma(KnownSrc[0], KnownSrc[1], KnownSrc[2], Mode);
break;
}
case Intrinsic::sqrt:
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index ae8c4a9133897..dc7f6d3ca237d 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -233,9 +233,9 @@ KnownFPClass KnownFPClass::canonicalize(const KnownFPClass &KnownSrc,
return Known;
}
-KnownFPClass KnownFPClass::fadd(const KnownFPClass &KnownLHS,
- const KnownFPClass &KnownRHS,
- DenormalMode Mode) {
+// Handle known sign bit and nan cases for fadd.
+static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS, DenormalMode Mode) {
KnownFPClass Known;
// Adding positive and negative infinity produces NaN.
@@ -246,11 +246,19 @@ KnownFPClass KnownFPClass::fadd(const KnownFPClass &KnownLHS,
if (KnownLHS.cannotBeOrderedLessThanZero() &&
KnownRHS.cannotBeOrderedLessThanZero())
- Known.knownNot(OrderedLessThanZeroMask);
+ Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
KnownRHS.cannotBeOrderedGreaterThanZero())
- Known.knownNot(OrderedGreaterThanZeroMask);
+ Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+
+ return Known;
+}
+
+KnownFPClass KnownFPClass::fadd(const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS,
+ DenormalMode Mode) {
+ KnownFPClass Known = fadd_impl(KnownLHS, KnownRHS, Mode);
// (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
@@ -332,6 +340,26 @@ KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
return Known;
}
+KnownFPClass KnownFPClass::fma(const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS,
+ const KnownFPClass &KnownAddend,
+ DenormalMode Mode) {
+ KnownFPClass Mul = fmul(KnownLHS, KnownRHS, Mode);
+
+ // FMA differs from the base fmul + fadd handling only in the treatment of -0
+ // results.
+ //
+ // If the multiply is a -0 due to rounding, the final -0 + 0 will be -0,
+ // unlike for a separate fadd.
+ return fadd_impl(Mul, KnownAddend, Mode);
+}
+
+KnownFPClass KnownFPClass::fma_square(const KnownFPClass &KnownSquared,
+ const KnownFPClass &KnownAddend,
+ DenormalMode Mode) {
+ return fadd_impl(square(KnownSquared, Mode), KnownAddend, Mode);
+}
+
KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) {
KnownFPClass Known;
Known.knownNot(fcNegative);
diff --git a/llvm/test/Transforms/Attributor/nofpclass-fma.ll b/llvm/test/Transforms/Attributor/nofpclass-fma.ll
index a1e0d1964f0c1..2fd0dd81622f6 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-fma.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-fma.ll
@@ -9,9 +9,9 @@ declare nofpclass(pinf pzero psub pnorm) half @returns_negative_or_nan()
define float @ret_fma_same_mul_arg(float noundef %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) float @ret_fma_same_mul_arg
+; CHECK-LABEL: define float @ret_fma_same_mul_arg
; CHECK-SAME: (float noundef [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) float @llvm.fma.f32(float noundef [[ARG0]], float noundef [[ARG0]], float [[ARG1]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.fma.f32(float noundef [[ARG0]], float noundef [[ARG0]], float [[ARG1]]) #[[ATTR2:[0-9]+]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1)
@@ -29,9 +29,9 @@ define float @ret_fma_same_mul_arg_maybe_undef(float %arg0, float %arg1) {
}
define float @ret_fma_same_mul_arg_positive_addend(float noundef %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fma_same_mul_arg_positive_addend
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_fma_same_mul_arg_positive_addend
; CHECK-SAME: (float noundef [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fma.f32(float noundef [[ARG0]], float noundef [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.fma.f32(float noundef [[ARG0]], float noundef [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1)
@@ -49,9 +49,9 @@ define float @ret_fma_different_mul_arg_positive_addend(float noundef %arg0, flo
}
define float @ret_fmuladd_same_mul_arg(float noundef %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) float @ret_fmuladd_same_mul_arg
+; CHECK-LABEL: define float @ret_fmuladd_same_mul_arg
; CHECK-SAME: (float noundef [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) float @llvm.fmuladd.f32(float noundef [[ARG0]], float noundef [[ARG0]], float [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.fmuladd.f32(float noundef [[ARG0]], float noundef [[ARG0]], float [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.fmuladd.f32(float %arg0, float %arg0, float %arg1)
@@ -69,9 +69,9 @@ define float @ret_fmuladd_same_mul_arg_maybe_undef(float %arg0, float %arg1) {
}
define float @ret_fmuladd_different_same_arg_positive_addend(float noundef %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmuladd_different_same_arg_positive_addend
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_fmuladd_different_same_arg_positive_addend
; CHECK-SAME: (float noundef [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fmuladd.f32(float noundef [[ARG0]], float noundef [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.fmuladd.f32(float noundef [[ARG0]], float noundef [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.fmuladd.f32(float %arg0, float %arg0, float %arg1)
@@ -100,11 +100,11 @@ define half @ret_fma__pos0__neg1__pos2() {
; 2. operand0=positive, operand1=negative, operand2=negative
define half @ret_fma__pos0__neg1__neg2() {
-; CHECK-LABEL: define half @ret_fma__pos0__neg1__neg2() {
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) half @ret_fma__pos0__neg1__neg2() {
; CHECK-NEXT: [[POS0:%.*]] = call half @returns_positive_or_nan()
; CHECK-NEXT: [[NEG1:%.*]] = call half @returns_negative_or_nan()
; CHECK-NEXT: [[NEG2:%.*]] = call half @returns_negative_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[POS0]], half [[NEG1]], half [[NEG2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(pinf psub pnorm) half @llvm.fma.f16(half [[POS0]], half [[NEG1]], half [[NEG2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%pos0 = call half @returns_positive_or_nan()
@@ -116,11 +116,11 @@ define half @ret_fma__pos0__neg1__neg2() {
; 3. operand0=positive, operand1=positive, operand2=positive
define half @ret_fma__pos0__pos1__pos2() {
-; CHECK-LABEL: define half @ret_fma__pos0__pos1__pos2() {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) half @ret_fma__pos0__pos1__pos2() {
; CHECK-NEXT: [[POS0:%.*]] = call half @returns_positive_or_nan()
; CHECK-NEXT: [[POS1:%.*]] = call half @returns_positive_or_nan()
; CHECK-NEXT: [[POS2:%.*]] = call half @returns_positive_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[POS0]], half [[POS1]], half [[POS2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nsub nnorm) half @llvm.fma.f16(half [[POS0]], half [[POS1]], half [[POS2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%pos0 = call half @returns_positive_or_nan()
@@ -148,11 +148,11 @@ define half @ret_fma__pos0__pos1__neg2() {
; 5. operand0=negative, operand1=negative, operand2=positive
define half @ret_fma__neg0__neg1__pos2() {
-; CHECK-LABEL: define half @ret_fma__neg0__neg1__pos2() {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) half @ret_fma__neg0__neg1__pos2() {
; CHECK-NEXT: [[NEG0:%.*]] = call half @returns_negative_or_nan()
; CHECK-NEXT: [[NEG1:%.*]] = call half @returns_negative_or_nan()
; CHECK-NEXT: [[POS2:%.*]] = call half @returns_positive_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[NEG0]], half [[NEG1]], half [[POS2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nsub nnorm) half @llvm.fma.f16(half [[NEG0]], half [[NEG1]], half [[POS2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%neg0 = call half @returns_negative_or_nan()
@@ -196,11 +196,11 @@ define half @ret_fma__neg0__pos1__pos2() {
; 8. operand0=negative, operand1=positive, operand2=negative
define half @ret_fma__neg0__pos1__neg2() {
-; CHECK-LABEL: define half @ret_fma__neg0__pos1__neg2() {
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) half @ret_fma__neg0__pos1__neg2() {
; CHECK-NEXT: [[NEG0:%.*]] = call half @returns_negative_or_nan()
; CHECK-NEXT: [[POS1:%.*]] = call half @returns_positive_or_nan()
; CHECK-NEXT: [[NEG2:%.*]] = call half @returns_negative_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half [[NEG0]], half [[POS1]], half [[NEG2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(pinf psub pnorm) half @llvm.fma.f16(half [[NEG0]], half [[POS1]], half [[NEG2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%neg0 = call half @returns_negative_or_nan()
@@ -231,10 +231,10 @@ define half @ret_fmuladd__pos0__neg1__pos2() {
;---------------------------------------------------------------------
define half @ret_fma__pos01_pos01__pos2() {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) half @ret_fma__pos01_pos01__pos2() {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) half @ret_fma__pos01_pos01__pos2() {
; CHECK-NEXT: [[POS01:%.*]] = call noundef half @returns_positive_or_nan()
; CHECK-NEXT: [[POS2:%.*]] = call half @returns_positive_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fma.f16(half noundef [[POS01]], half noundef [[POS01]], half [[POS2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nsub nnorm) half @llvm.fma.f16(half noundef [[POS01]], half noundef [[POS01]], half [[POS2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%pos01 = call noundef half @returns_positive_or_nan()
@@ -244,10 +244,10 @@ define half @ret_fma__pos01_pos01__pos2() {
}
define half @ret_fma__pos01_pos01__neg2() {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma__pos01_pos01__neg2() {
+; CHECK-LABEL: define half @ret_fma__pos01_pos01__neg2() {
; CHECK-NEXT: [[POS01:%.*]] = call noundef half @returns_positive_or_nan()
; CHECK-NEXT: [[NEG2:%.*]] = call half @returns_negative_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef [[POS01]], half noundef [[POS01]], half [[NEG2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half noundef [[POS01]], half noundef [[POS01]], half [[NEG2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%pos01 = call noundef half @returns_positive_or_nan()
@@ -257,10 +257,10 @@ define half @ret_fma__pos01_pos01__neg2() {
}
define half @ret_fma__neg01_neg01__pos2() {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) half @ret_fma__neg01_neg01__pos2() {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) half @ret_fma__neg01_neg01__pos2() {
; CHECK-NEXT: [[NEG01:%.*]] = call noundef half @returns_negative_or_nan()
; CHECK-NEXT: [[POS2:%.*]] = call half @returns_positive_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fma.f16(half noundef [[NEG01]], half noundef [[NEG01]], half [[POS2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nsub nnorm) half @llvm.fma.f16(half noundef [[NEG01]], half noundef [[NEG01]], half [[POS2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%neg01 = call noundef half @returns_negative_or_nan()
@@ -270,10 +270,10 @@ define half @ret_fma__neg01_neg01__pos2() {
}
define half @ret_fma__neg01_neg01__neg2() {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma__neg01_neg01__neg2() {
+; CHECK-LABEL: define half @ret_fma__neg01_neg01__neg2() {
; CHECK-NEXT: [[NEG01:%.*]] = call noundef half @returns_negative_or_nan()
; CHECK-NEXT: [[NEG2:%.*]] = call half @returns_negative_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef [[NEG01]], half noundef [[NEG01]], half [[NEG2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half noundef [[NEG01]], half noundef [[NEG01]], half [[NEG2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%neg01 = call noundef half @returns_negative_or_nan()
@@ -283,10 +283,10 @@ define half @ret_fma__neg01_neg01__neg2() {
}
define half @ret_fmuladd__pos01_pos01__pos2() {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) half @ret_fmuladd__pos01_pos01__pos2() {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) half @ret_fmuladd__pos01_pos01__pos2() {
; CHECK-NEXT: [[POS01:%.*]] = call noundef half @returns_positive_or_nan()
; CHECK-NEXT: [[POS2:%.*]] = call half @returns_positive_or_nan()
-; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fmuladd.f16(half noundef [[POS01]], half noundef [[POS01]], half [[POS2]])
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(ninf nsub nnorm) half @llvm.fmuladd.f16(half noundef [[POS01]], half noundef [[POS01]], half [[POS2]])
; CHECK-NEXT: ret half [[RESULT]]
;
%pos01 = call noundef half @returns_positive_or_nan()
@@ -332,9 +332,9 @@ define half @ret_fma__no_nan__no_nan__no_nan_inf(half nofpclass(nan) %arg0, half
; can infer no-nan output
define half @ret_fma__no_nan_inf__no_nan_inf__no_nan_inf(half nofpclass(nan inf) %arg0, half nofpclass(nan inf) %arg1, half nofpclass(nan inf) %arg2) {
-; CHECK-LABEL: define half @ret_fma__no_nan_inf__no_nan_inf__no_nan_inf
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma__no_nan_inf__no_nan_inf__no_nan_inf
; CHECK-SAME: (half nofpclass(nan inf) [[ARG0:%.*]], half nofpclass(nan inf) [[ARG1:%.*]], half nofpclass(nan inf) [[ARG2:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half nofpclass(nan inf) [[ARG0]], half nofpclass(nan inf) [[ARG1]], half nofpclass(nan inf) [[ARG2]]) #[[ATTR2]]
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half nofpclass(nan inf) [[ARG0]], half nofpclass(nan inf) [[ARG1]], half nofpclass(nan inf) [[ARG2]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[RESULT]]
;
%result = call half @llvm.fma.f16(half %arg0, half %arg1, half %arg2)
@@ -343,9 +343,9 @@ define half @ret_fma__no_nan_inf__no_nan_inf__no_nan_inf(half nofpclass(nan inf)
; can infer no-nan output
define half @ret_fma__no_nan_zero_inf__no_nan_zero_inf__no_nan_zero_inf(half nofpclass(nan zero) %arg0, half nofpclass(nan zero) %arg1, half nofpclass(nan zero inf) %arg2) {
-; CHECK-LABEL: define half @ret_fma__no_nan_zero_inf__no_nan_zero_inf__no_nan_zero_inf
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma__no_nan_zero_inf__no_nan_zero_inf__no_nan_zero_inf
; CHECK-SAME: (half nofpclass(nan zero) [[ARG0:%.*]], half nofpclass(nan zero) [[ARG1:%.*]], half nofpclass(nan inf zero) [[ARG2:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half nofpclass(nan zero) [[ARG0]], half nofpclass(nan zero) [[ARG1]], half nofpclass(nan inf zero) [[ARG2]]) #[[ATTR2]]
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half nofpclass(nan zero) [[ARG0]], half nofpclass(nan zero) [[ARG1]], half nofpclass(nan inf zero) [[ARG2]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[RESULT]]
;
%result = call half @llvm.fma.f16(half %arg0, half %arg1, half %arg2)
@@ -353,9 +353,9 @@ define half @ret_fma__no_nan_zero_inf__no_nan_zero_inf__no_nan_zero_inf(half nof
}
define half @ret_fma__no_nan_ninf_zero__no_nan_ninf_zero__no_nan_inf(half nofpclass(nan ninf zero) %arg0, half nofpclass(nan ninf zero) %arg1, half nofpclass(nan inf) %arg2) {
-; CHECK-LABEL: define half @ret_fma__no_nan_ninf_zero__no_nan_ninf_zero__no_nan_inf
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma__no_nan_ninf_zero__no_nan_ninf_zero__no_nan_inf
; CHECK-SAME: (half nofpclass(nan ninf zero) [[ARG0:%.*]], half nofpclass(nan ninf zero) [[ARG1:%.*]], half nofpclass(nan inf) [[ARG2:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[RESULT:%.*]] = call half @llvm.fma.f16(half nofpclass(nan ninf zero) [[ARG0]], half nofpclass(nan ninf zero) [[ARG1]], half nofpclass(nan inf) [[ARG2]]) #[[ATTR2]]
+; CHECK-NEXT: [[RESULT:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half nofpclass(nan ninf zero) [[ARG0]], half nofpclass(nan ninf zero) [[ARG1]], half nofpclass(nan inf) [[ARG2]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[RESULT]]
;
%result = call half @llvm.fma.f16(half %arg0, half %arg1, half %arg2)
@@ -364,9 +364,9 @@ define half @ret_fma__no_nan_ninf_zero__no_nan_ninf_zero__no_nan_inf(half nofpcl
; Cannot infer nnan output
define half @ret_fma_square__no_nan__no_nan(half noundef nofpclass(nan) %arg0, half nofpclass(nan) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan__no_nan
+; CHECK-LABEL: define half @ret_fma_square__no_nan__no_nan
; CHECK-SAME: (half noundef nofpclass(nan) [[ARG0:%.*]], half nofpclass(nan) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan) [[ARG0]], half noundef nofpclass(nan) [[ARG0]], half nofpclass(nan) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call half @llvm.fma.f16(half noundef nofpclass(nan) [[ARG0]], half noundef nofpclass(nan) [[ARG0]], half nofpclass(nan) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -374,9 +374,9 @@ define half @ret_fma_square__no_nan__no_nan(half noundef nofpclass(nan) %arg0, h
}
define half @ret_fma_square__no_nan__no_nan_zero(half noundef nofpclass(nan) %arg0, half nofpclass(nan zero) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan__no_nan_zero
+; CHECK-LABEL: define half @ret_fma_square__no_nan__no_nan_zero
; CHECK-SAME: (half noundef nofpclass(nan) [[ARG0:%.*]], half nofpclass(nan zero) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan) [[ARG0]], half noundef nofpclass(nan) [[ARG0]], half nofpclass(nan zero) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call half @llvm.fma.f16(half noundef nofpclass(nan) [[ARG0]], half noundef nofpclass(nan) [[ARG0]], half nofpclass(nan zero) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -384,9 +384,9 @@ define half @ret_fma_square__no_nan__no_nan_zero(half noundef nofpclass(nan) %ar
}
define half @ret_fma_square__no_nan__no_nan_inf_zero(half noundef nofpclass(nan) %arg0, half nofpclass(nan inf zero) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan__no_nan_inf_zero
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma_square__no_nan__no_nan_inf_zero
; CHECK-SAME: (half noundef nofpclass(nan) [[ARG0:%.*]], half nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan) [[ARG0]], half noundef nofpclass(nan) [[ARG0]], half nofpclass(nan inf zero) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half noundef nofpclass(nan) [[ARG0]], half noundef nofpclass(nan) [[ARG0]], half nofpclass(nan inf zero) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -394,9 +394,9 @@ define half @ret_fma_square__no_nan__no_nan_inf_zero(half noundef nofpclass(nan)
}
define half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf_zero(half noundef nofpclass(nan inf zero) %arg0, half nofpclass(nan inf zero) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf_zero
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf_zero
; CHECK-SAME: (half noundef nofpclass(nan inf zero) [[ARG0:%.*]], half nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan inf zero) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan inf zero) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -404,9 +404,9 @@ define half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf_zero(half noundef
}
define half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf(half noundef nofpclass(nan inf zero) %arg0, half nofpclass(nan inf) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf
; CHECK-SAME: (half noundef nofpclass(nan inf zero) [[ARG0:%.*]], half nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan inf) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan inf) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -414,9 +414,9 @@ define half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_inf(half noundef nofp
}
define half @ret_fma_square__no_nan_no_inf__no_nan_inf(half noundef nofpclass(nan inf zero) %arg0, half nofpclass(nan inf) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf__no_nan_inf
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma_square__no_nan_no_inf__no_nan_inf
; CHECK-SAME: (half noundef nofpclass(nan inf zero) [[ARG0:%.*]], half nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan inf) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan inf) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -424,9 +424,9 @@ define half @ret_fma_square__no_nan_no_inf__no_nan_inf(half noundef nofpclass(na
}
define half @ret_fma_square__no_nan_no_inf__no_nan_no_inf(half noundef nofpclass(nan inf) %arg0, half nofpclass(nan inf) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf__no_nan_no_inf
+; CHECK-LABEL: define nofpclass(nan) half @ret_fma_square__no_nan_no_inf__no_nan_no_inf
; CHECK-SAME: (half noundef nofpclass(nan inf) [[ARG0:%.*]], half nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf) [[ARG0]], half noundef nofpclass(nan inf) [[ARG0]], half nofpclass(nan inf) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) half @llvm.fma.f16(half noundef nofpclass(nan inf) [[ARG0]], half noundef nofpclass(nan inf) [[ARG0]], half nofpclass(nan inf) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -434,9 +434,9 @@ define half @ret_fma_square__no_nan_no_inf__no_nan_no_inf(half noundef nofpclass
}
define half @ret_fma_square__no_nan_no_inf__no_nan_no_pinf(half noundef nofpclass(nan inf) %arg0, half nofpclass(nan pinf) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf__no_nan_no_pinf
+; CHECK-LABEL: define half @ret_fma_square__no_nan_no_inf__no_nan_no_pinf
; CHECK-SAME: (half noundef nofpclass(nan inf) [[ARG0:%.*]], half nofpclass(nan pinf) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf) [[ARG0]], half noundef nofpclass(nan inf) [[ARG0]], half nofpclass(nan pinf) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call half @llvm.fma.f16(half noundef nofpclass(nan inf) [[ARG0]], half noundef nofpclass(nan inf) [[ARG0]], half nofpclass(nan pinf) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -444,9 +444,9 @@ define half @ret_fma_square__no_nan_no_inf__no_nan_no_pinf(half noundef nofpclas
}
define half @ret_fma_square__no_nan_no_inf__no_nan_no_ninf(half noundef nofpclass(nan inf) %arg0, half nofpclass(nan ninf) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf__no_nan_no_ninf
+; CHECK-LABEL: define half @ret_fma_square__no_nan_no_inf__no_nan_no_ninf
; CHECK-SAME: (half noundef nofpclass(nan inf) [[ARG0:%.*]], half nofpclass(nan ninf) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf) [[ARG0]], half noundef nofpclass(nan inf) [[ARG0]], half nofpclass(nan ninf) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call half @llvm.fma.f16(half noundef nofpclass(nan inf) [[ARG0]], half noundef nofpclass(nan inf) [[ARG0]], half nofpclass(nan ninf) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
@@ -454,9 +454,9 @@ define half @ret_fma_square__no_nan_no_inf__no_nan_no_ninf(half noundef nofpclas
}
define half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_no_ninf(half noundef nofpclass(nan inf zero) %arg0, half nofpclass(nan ninf) %arg1) {
-; CHECK-LABEL: define nofpclass(nzero) half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_no_ninf
+; CHECK-LABEL: define half @ret_fma_square__no_nan_no_inf_no_zero__no_nan_no_ninf
; CHECK-SAME: (half noundef nofpclass(nan inf zero) [[ARG0:%.*]], half nofpclass(nan ninf) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nzero) half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan ninf) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call half @llvm.fma.f16(half noundef nofpclass(nan inf zero) [[ARG0]], half noundef nofpclass(nan inf zero) [[ARG0]], half nofpclass(nan ninf) [[ARG1]]) #[[ATTR2]]
; CHECK-NEXT: ret half [[CALL]]
;
%call = call half @llvm.fma.f16(half %arg0, half %arg0, half %arg1)
diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll
index 0c3ed56a8347a..5cd740b145f1e 100644
--- a/llvm/test/Transforms/InstCombine/fabs.ll
+++ b/llvm/test/Transforms/InstCombine/fabs.ll
@@ -229,7 +229,8 @@ define float @square_nnan_fma_fabs_nsz_intrinsic_f32(float noundef %x, float %y)
define float @square_nnan_fma_fabs_intrinsic_f32_add_const(float noundef %x) {
; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32_add_const(
; CHECK-NEXT: [[FMA:%.*]] = call nnan float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
-; CHECK-NEXT: ret float [[FMA]]
+; CHECK-NEXT: [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMA]])
+; CHECK-NEXT: ret float [[FABSF]]
;
%fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.0)
%fabsf = call float @llvm.fabs.f32(float %fma)
@@ -272,7 +273,8 @@ define float @square_nnan_nsz_fmuladd_fabs_intrinsic_f32(float noundef %x, float
define float @square_nnan_fmuladd_fabs_intrinsic_f32(float noundef %x) {
; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32(
; CHECK-NEXT: [[FMULADD:%.*]] = call nnan float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
-; CHECK-NEXT: ret float [[FMULADD]]
+; CHECK-NEXT: [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMULADD]])
+; CHECK-NEXT: ret float [[FABSF]]
;
%fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
%fabsf = call float @llvm.fabs.f32(float %fmuladd)
More information about the llvm-commits
mailing list