[llvm-branch-commits] [llvm] InstCombine: Handle fsub in SimplifyDemandedFPClass (PR #175852)
Matt Arsenault via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jan 14 08:11:48 PST 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/175852
>From d96ba8b2e5a122703515cb499974cb82d9828214 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 5 Jan 2026 14:20:21 +0100
Subject: [PATCH 1/2] InstCombine: Handle fsub in SimplifyDemandedFPClass
alive2 fails on some of the tests, but this is due to existing
folds in instsimplify and https://github.com/AliveToolkit/alive2/issues/1273
---
llvm/include/llvm/Support/KnownFPClass.h | 5 +
llvm/lib/Analysis/ValueTracking.cpp | 81 +++--------
llvm/lib/Support/KnownFPClass.cpp | 21 +++
.../InstCombineSimplifyDemanded.cpp | 15 +-
.../simplify-demanded-fpclass-fsub.ll | 128 ++++++++----------
5 files changed, 112 insertions(+), 138 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index e2b0d20c790a9..010ca6a3e84ec 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -222,6 +222,11 @@ struct KnownFPClass {
fadd_self(const KnownFPClass &Src,
DenormalMode Mode = DenormalMode::getDynamic());
+ /// Report known values for fsub
+ LLVM_ABI static KnownFPClass
+ fsub(const KnownFPClass &LHS, const KnownFPClass &RHS,
+ DenormalMode Mode = DenormalMode::getDynamic());
+
/// Report known values for fmul
LLVM_ABI static KnownFPClass
fmul(const KnownFPClass &LHS, const KnownFPClass &RHS,
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ece8425aef698..51fbffd6fd371 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5524,78 +5524,37 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
KnownRHS, Q, Depth + 1);
// Special case fadd x, x, which is the canonical form of fmul x, 2.
- bool SelfAdd = Op->getOperand(0) == Op->getOperand(1) &&
- isGuaranteedNotToBeUndef(Op->getOperand(0), Q.AC, Q.CxtI,
- Q.DT, Depth + 1);
- if (SelfAdd)
+ bool Self = Op->getOperand(0) == Op->getOperand(1) &&
+ isGuaranteedNotToBeUndef(Op->getOperand(0), Q.AC, Q.CxtI, Q.DT,
+ Depth + 1);
+ if (Self)
KnownLHS = KnownRHS;
if ((WantNaN && KnownRHS.isKnownNeverNaN()) ||
(WantNegative && KnownRHS.cannotBeOrderedLessThanZero()) ||
WantNegZero || Opc == Instruction::FSub) {
- if (!SelfAdd) {
- // RHS is canonically cheaper to compute. Skip inspecting the LHS if
- // there's no point.
- computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
- KnownLHS, Q, Depth + 1);
- }
-
- // Adding positive and negative infinity produces NaN.
- // TODO: Check sign of infinities.
- if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
- (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
- Known.knownNot(fcNan);
-
// FIXME: Context function should always be passed in separately
const Function *F = cast<Instruction>(Op)->getFunction();
+ const fltSemantics &FltSem =
+ Op->getType()->getScalarType()->getFltSemantics();
+ DenormalMode Mode =
+ F ? F->getDenormalMode(FltSem) : DenormalMode::getDynamic();
- if (Op->getOpcode() == Instruction::FAdd) {
- if (KnownLHS.cannotBeOrderedLessThanZero() &&
- KnownRHS.cannotBeOrderedLessThanZero())
- Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
- if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
- KnownRHS.cannotBeOrderedGreaterThanZero())
- Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
-
- if (!F)
- break;
-
- const fltSemantics &FltSem =
- Op->getType()->getScalarType()->getFltSemantics();
- DenormalMode Mode = F->getDenormalMode(FltSem);
-
- // Doubling 0 will give the same 0.
- if (SelfAdd && KnownRHS.isKnownNeverLogicalPosZero(Mode) &&
- (Mode.Output == DenormalMode::IEEE ||
- (Mode.Output == DenormalMode::PreserveSign &&
- KnownRHS.isKnownNeverPosSubnormal()) ||
- (Mode.Output == DenormalMode::PositiveZero &&
- KnownRHS.isKnownNeverSubnormal())))
- Known.knownNot(fcPosZero);
-
- // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
- if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
- KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
- // Make sure output negative denormal can't flush to -0
- (Mode.Output == DenormalMode::IEEE ||
- Mode.Output == DenormalMode::PositiveZero))
- Known.knownNot(fcNegZero);
+ if (Self && Opc == Instruction::FAdd) {
+ Known = KnownFPClass::fadd_self(KnownLHS, Mode);
} else {
- if (!F)
- break;
+ // RHS is canonically cheaper to compute. Skip inspecting the LHS if
+ // there's no point.
- const fltSemantics &FltSem =
- Op->getType()->getScalarType()->getFltSemantics();
- DenormalMode Mode = F->getDenormalMode(FltSem);
-
- // Only fsub -0, +0 can return -0
- if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
- KnownRHS.isKnownNeverLogicalPosZero(Mode)) &&
- // Make sure output negative denormal can't flush to -0
- (Mode.Output == DenormalMode::IEEE ||
- Mode.Output == DenormalMode::PositiveZero))
- Known.knownNot(fcNegZero);
+ if (!Self) {
+ computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
+ KnownLHS, Q, Depth + 1);
+ }
+
+ Known = Opc == Instruction::FAdd
+ ? KnownFPClass::fadd(KnownLHS, KnownRHS, Mode)
+ : KnownFPClass::fsub(KnownLHS, KnownRHS, Mode);
}
}
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index ae8c4a9133897..dbd5707873f5d 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -279,6 +279,27 @@ KnownFPClass KnownFPClass::fadd_self(const KnownFPClass &KnownSrc,
return Known;
}
+KnownFPClass KnownFPClass::fsub(const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS,
+ DenormalMode Mode) {
+ KnownFPClass Known;
+ // Adding positive and negative infinity produces NaN.
+ // TODO: Check sign of infinities.
+ if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
+ (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
+ Known.knownNot(fcNan);
+
+ // Only fsub -0, +0 can return -0
+ if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
+ KnownRHS.isKnownNeverLogicalPosZero(Mode)) &&
+ // Make sure output negative denormal can't flush to -0
+ (Mode.Output == DenormalMode::IEEE ||
+ Mode.Output == DenormalMode::PositiveZero))
+ Known.knownNot(fcNegZero);
+
+ return Known;
+}
+
KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
const KnownFPClass &KnownRHS,
DenormalMode Mode) {
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 05ed123b8be75..a483f44c01ab8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2081,13 +2081,15 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
Known.fneg();
break;
}
- case Instruction::FAdd: {
+ case Instruction::FAdd:
+ case Instruction::FSub: {
KnownFPClass KnownLHS, KnownRHS;
const SimplifyQuery &SQ = getSimplifyQuery();
// fadd x, x can be handled more aggressively.
if (I->getOperand(0) == I->getOperand(1) &&
+ I->getOpcode() == Instruction::FAdd &&
isGuaranteedNotToBeUndef(I->getOperand(0), SQ.AC, CxtI, SQ.DT,
Depth + 1)) {
Type *EltTy = VTy->getScalarType();
@@ -2141,7 +2143,10 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
Type *EltTy = VTy->getScalarType();
DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics());
- Known = KnownFPClass::fadd(KnownLHS, KnownRHS, Mode);
+
+ Known = I->getOpcode() == Instruction::FAdd
+ ? KnownFPClass::fadd(KnownLHS, KnownRHS, Mode)
+ : KnownFPClass::fsub(KnownLHS, KnownRHS, Mode);
}
FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
@@ -2157,11 +2162,13 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
}
// With nnan: X + {+/-}Inf --> {+/-}Inf
- if (KnownRHS.isKnownAlways(fcInf | fcNan) &&
- KnownLHS.isKnownNever(fcNan))
+ if (I->getOpcode() == Instruction::FAdd &&
+ KnownRHS.isKnownAlways(fcInf | fcNan) && KnownLHS.isKnownNever(fcNan)) {
return I->getOperand(1);
+ }
// With nnan: {+/-}Inf + X --> {+/-}Inf
+ // With nnan: {+/-}Inf - X --> {+/-}Inf
if (KnownLHS.isKnownAlways(fcInf | fcNan) &&
KnownRHS.isKnownNever(fcNan))
return I->getOperand(0);
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fsub.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fsub.ll
index 53c2817612662..b4a98bd59c71c 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fsub.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fsub.ll
@@ -34,8 +34,7 @@ declare void @use(half)
define nofpclass(inf zero sub norm) half @ret_only_nan(half %x, half %y) {
; CHECK-LABEL: define nofpclass(inf zero sub norm) half @ret_only_nan(
; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half 0xH7E00
;
%add = fsub half %x, %y
ret half %add
@@ -64,7 +63,7 @@ define nofpclass(qnan inf zero sub norm) half @ret_only_snan(half %x, half %y) {
define nofpclass(nan inf sub norm) half @ret_only_zero(half %x, half %y) {
; CHECK-LABEL: define nofpclass(nan inf sub norm) half @ret_only_zero(
; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -92,7 +91,7 @@ define nofpclass(nan inf pzero sub norm) half @ret_only_nzero(half %x, half %y)
define nofpclass(nan zero sub norm) half @ret_only_inf(half %x, half %y) {
; CHECK-LABEL: define nofpclass(nan zero sub norm) half @ret_only_inf(
; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -218,9 +217,7 @@ define nofpclass(nan inf) half @ret_nofpclass_inf_nan__fsub_select_unknown_or_in
; CHECK-SAME: i1 [[COND:%.*]], half [[X:%.*]], half [[Y:%.*]]) {
; CHECK-NEXT: [[INF0:%.*]] = call half @returns_inf()
; CHECK-NEXT: [[INF1:%.*]] = call half @returns_inf()
-; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half [[INF0]]
-; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half [[INF1]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X_OR_INF]], [[Y_OR_INF]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%inf0 = call half @returns_inf()
@@ -236,7 +233,7 @@ define nofpclass(inf sub norm) half @nan_result_demands_inf_input_lhs(i1 %cond,
; CHECK-LABEL: define nofpclass(inf sub norm) half @nan_result_demands_inf_input_lhs(
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(nan inf zero) [[Y:%.*]]) {
; CHECK-NEXT: [[PINF:%.*]] = call half @returns_pinf()
-; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half [[PINF]]
+; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half 0xH7C00
; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X_OR_INF]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
@@ -251,7 +248,7 @@ define nofpclass(inf sub norm) half @nan_result_demands_inf_input_rhs(i1 %cond,
; CHECK-LABEL: define nofpclass(inf sub norm) half @nan_result_demands_inf_input_rhs(
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half [[Y:%.*]]) {
; CHECK-NEXT: [[PINF:%.*]] = call half @returns_pinf()
-; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half [[PINF]]
+; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half 0xH7C00
; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y_OR_INF]]
; CHECK-NEXT: ret half [[ADD]]
;
@@ -267,7 +264,7 @@ define nofpclass(nan sub norm zero) half @inf_result_demands_inf_input_lhs(i1 %c
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(zero) [[Y:%.*]]) {
; CHECK-NEXT: [[INF:%.*]] = call half @returns_inf()
; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half [[INF]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X_OR_INF]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X_OR_INF]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%inf = call half @returns_inf()
@@ -282,7 +279,7 @@ define nofpclass(nan sub norm zero) half @inf_result_demands_inf_input_rhs(i1 %c
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(zero) [[Y:%.*]]) {
; CHECK-NEXT: [[INF:%.*]] = call half @returns_inf()
; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half [[INF]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y_OR_INF]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y_OR_INF]]
; CHECK-NEXT: ret half [[ADD]]
;
%inf = call half @returns_inf()
@@ -296,8 +293,8 @@ define nofpclass(nan sub norm zero) half @inf_result_demands_pinf_input_lhs(i1 %
; CHECK-LABEL: define nofpclass(nan zero sub norm) half @inf_result_demands_pinf_input_lhs(
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(zero) [[Y:%.*]]) {
; CHECK-NEXT: [[PINF:%.*]] = call half @returns_pinf()
-; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half [[PINF]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X_OR_INF]], [[Y]]
+; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half 0xH7C00
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X_OR_INF]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%pinf = call half @returns_pinf()
@@ -311,8 +308,8 @@ define nofpclass(nan sub norm zero) half @inf_result_demands_pinf_input_rhs(i1 %
; CHECK-LABEL: define nofpclass(nan zero sub norm) half @inf_result_demands_pinf_input_rhs(
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(zero) [[Y:%.*]]) {
; CHECK-NEXT: [[PINF:%.*]] = call half @returns_pinf()
-; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half [[PINF]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y_OR_INF]]
+; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half 0xH7C00
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y_OR_INF]]
; CHECK-NEXT: ret half [[ADD]]
;
%pinf = call half @returns_pinf()
@@ -326,8 +323,8 @@ define nofpclass(nan sub norm zero) half @inf_result_demands_ninf_input_lhs(i1 %
; CHECK-LABEL: define nofpclass(nan zero sub norm) half @inf_result_demands_ninf_input_lhs(
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(zero) [[Y:%.*]]) {
; CHECK-NEXT: [[NINF:%.*]] = call half @returns_ninf()
-; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half [[NINF]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X_OR_INF]], [[Y]]
+; CHECK-NEXT: [[X_OR_INF:%.*]] = select i1 [[COND]], half [[X]], half 0xHFC00
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X_OR_INF]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%ninf = call half @returns_ninf()
@@ -341,8 +338,8 @@ define nofpclass(nan sub norm zero) half @inf_result_demands_ninf_input_rhs(i1 %
; CHECK-LABEL: define nofpclass(nan zero sub norm) half @inf_result_demands_ninf_input_rhs(
; CHECK-SAME: i1 [[COND:%.*]], half nofpclass(zero) [[X:%.*]], half nofpclass(zero) [[Y:%.*]]) {
; CHECK-NEXT: [[NINF:%.*]] = call half @returns_ninf()
-; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half [[NINF]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y_OR_INF]]
+; CHECK-NEXT: [[Y_OR_INF:%.*]] = select i1 [[COND]], half [[Y]], half 0xHFC00
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y_OR_INF]]
; CHECK-NEXT: ret half [[ADD]]
;
%ninf = call half @returns_ninf()
@@ -367,7 +364,7 @@ define nofpclass(snan) half @no_nans_inputs(half nofpclass(nan) %x, half nofpcla
define nofpclass(nan) half @no_nans_input_and_output(half nofpclass(nan) %x, half nofpclass(nan) %y) {
; CHECK-LABEL: define nofpclass(nan) half @no_nans_input_and_output(
; CHECK-SAME: half nofpclass(nan) [[X:%.*]], half nofpclass(nan) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -390,7 +387,7 @@ define nofpclass(snan) half @no_infs_inputs(half nofpclass(inf) %x, half nofpcla
define nofpclass(inf) half @no_infs_inputs_and_outputs(half nofpclass(inf) %x, half nofpclass(inf) %y) {
; CHECK-LABEL: define nofpclass(inf) half @no_infs_inputs_and_outputs(
; CHECK-SAME: half nofpclass(inf) [[X:%.*]], half nofpclass(inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub ninf half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -401,7 +398,7 @@ define nofpclass(inf) half @no_infs_inputs_and_outputs(half nofpclass(inf) %x, h
define nofpclass(snan) half @no_nans_infs_inputs(half nofpclass(nan inf) %x, half nofpclass(nan inf) %y) {
; CHECK-LABEL: define nofpclass(snan) half @no_nans_infs_inputs(
; CHECK-SAME: half nofpclass(nan inf) [[X:%.*]], half nofpclass(nan inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -412,7 +409,7 @@ define nofpclass(snan) half @no_nans_infs_inputs(half nofpclass(nan inf) %x, hal
define nofpclass(inf) half @no_nans_infs_inputs__noinfs_output(half nofpclass(nan inf) %x, half nofpclass(nan inf) %y) {
; CHECK-LABEL: define nofpclass(inf) half @no_nans_infs_inputs__noinfs_output(
; CHECK-SAME: half nofpclass(nan inf) [[X:%.*]], half nofpclass(nan inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan ninf half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -423,7 +420,7 @@ define nofpclass(inf) half @no_nans_infs_inputs__noinfs_output(half nofpclass(na
define nofpclass(nan) half @no_nans_infs_inputs__nonans_output(half nofpclass(nan inf) %x, half nofpclass(nan inf) %y) {
; CHECK-LABEL: define nofpclass(nan) half @no_nans_infs_inputs__nonans_output(
; CHECK-SAME: half nofpclass(nan inf) [[X:%.*]], half nofpclass(nan inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -434,7 +431,7 @@ define nofpclass(nan) half @no_nans_infs_inputs__nonans_output(half nofpclass(na
define nofpclass(nzero) half @inferred_nan_output__noinfs_only_lhs(half nofpclass(nan inf) %x, half nofpclass(nan) %y) {
; CHECK-LABEL: define nofpclass(nzero) half @inferred_nan_output__noinfs_only_lhs(
; CHECK-SAME: half nofpclass(nan inf) [[X:%.*]], half nofpclass(nan) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -445,7 +442,7 @@ define nofpclass(nzero) half @inferred_nan_output__noinfs_only_lhs(half nofpclas
define nofpclass(nzero) half @inferred_nan_output__noinfs_only_rhs(half nofpclass(nan) %x, half nofpclass(nan inf) %y) {
; CHECK-LABEL: define nofpclass(nzero) half @inferred_nan_output__noinfs_only_rhs(
; CHECK-SAME: half nofpclass(nan) [[X:%.*]], half nofpclass(nan inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[X]], [[Y]]
; CHECK-NEXT: ret half [[ADD]]
;
%add = fsub half %x, %y
@@ -516,7 +513,7 @@ define nofpclass(nan) half @ret_nonan_fabs_fsub_known_positive_or_nan_sources()
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan_fabs_fsub_known_positive_or_nan_sources() {
; CHECK-NEXT: [[POSITIVE_OR_NAN0:%.*]] = call half @returns_positive_or_nan()
; CHECK-NEXT: [[POSITIVE_OR_NAN1:%.*]] = call half @returns_positive_or_nan()
-; CHECK-NEXT: [[KNOWN_POSITIVE_ADD:%.*]] = fsub half [[POSITIVE_OR_NAN0]], [[POSITIVE_OR_NAN1]]
+; CHECK-NEXT: [[KNOWN_POSITIVE_ADD:%.*]] = fsub nnan half [[POSITIVE_OR_NAN0]], [[POSITIVE_OR_NAN1]]
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[KNOWN_POSITIVE_ADD]])
; CHECK-NEXT: ret half [[FABS]]
;
@@ -532,9 +529,7 @@ define nofpclass(nan) half @ret_nonan_fabs_fsub_known_positive_sources() {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan_fabs_fsub_known_positive_sources() {
; CHECK-NEXT: [[POSITIVE0:%.*]] = call half @returns_positive()
; CHECK-NEXT: [[POSITIVE1:%.*]] = call half @returns_positive()
-; CHECK-NEXT: [[KNOWN_POSITIVE_ADD:%.*]] = fsub half [[POSITIVE1]], [[POSITIVE1]]
-; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[KNOWN_POSITIVE_ADD]])
-; CHECK-NEXT: ret half [[FABS]]
+; CHECK-NEXT: ret half 0xH0000
;
%positive0 = call half @returns_positive()
%positive1 = call half @returns_positive()
@@ -595,7 +590,7 @@ define nofpclass(nan) half @ret_nonan__unknown__fsub__inf(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__unknown__fsub__inf(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[INF:%.*]] = call half @returns_inf()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[INF]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[UNKNOWN]], [[INF]]
; CHECK-NEXT: ret half [[ADD]]
;
%inf = call half @returns_inf()
@@ -607,8 +602,7 @@ define nofpclass(nan) half @ret_nonan__inf__fsub__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__inf__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[INF:%.*]] = call half @returns_inf()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[INF]], [[UNKNOWN]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[INF]]
;
%inf = call half @returns_inf()
%add = fsub half %inf, %unknown
@@ -619,7 +613,7 @@ define nofpclass(nan) half @ret_nonan__unknown__fsub__inf_or_nan(half %unknown)
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__unknown__fsub__inf_or_nan(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[INF_OR_NAN:%.*]] = call half @returns_inf_or_nan()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[INF_OR_NAN]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[UNKNOWN]], [[INF_OR_NAN]]
; CHECK-NEXT: ret half [[ADD]]
;
%inf.or.nan = call half @returns_inf_or_nan()
@@ -631,8 +625,7 @@ define nofpclass(nan) half @ret_nonan__inf_or_nan__fsub__unknown(half %unknown)
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__inf_or_nan__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[INF_OR_NAN:%.*]] = call half @returns_inf_or_nan()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[INF_OR_NAN]], [[UNKNOWN]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[INF_OR_NAN]]
;
%inf.or.nan = call half @returns_inf_or_nan()
%add = fsub half %inf.or.nan, %unknown
@@ -667,7 +660,7 @@ define nofpclass(nan) half @ret_nonan__unknown__fsub__zero(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__unknown__fsub__zero(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[ZERO:%.*]] = call half @returns_zero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[ZERO]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[UNKNOWN]], [[ZERO]]
; CHECK-NEXT: ret half [[ADD]]
;
%zero = call half @returns_zero()
@@ -679,7 +672,7 @@ define nofpclass(nan) half @ret_nonan__zero__fsub__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__zero__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[ZERO:%.*]] = call half @returns_zero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[ZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half [[ZERO]], [[UNKNOWN]]
; CHECK-NEXT: ret half [[ADD]]
;
%zero = call half @returns_zero()
@@ -691,8 +684,7 @@ define nofpclass(snan) half @unknown__fsub__pzero(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @unknown__fsub__pzero(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[UNKNOWN]]
;
%pzero = call half @returns_pzero()
%add = fsub half %unknown, %pzero
@@ -703,7 +695,7 @@ define nofpclass(snan) half @pzero__fsub__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub half 0xH0000, [[UNKNOWN]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -715,8 +707,7 @@ define nofpclass(nan) half @ret_nonan__unknown__fsub__pzero(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__unknown__fsub__pzero(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[UNKNOWN]]
;
%pzero = call half @returns_pzero()
%add = fsub half %unknown, %pzero
@@ -727,7 +718,7 @@ define nofpclass(nan) half @ret_nonan__pzero__fsub__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__pzero__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub nnan half 0xH0000, [[UNKNOWN]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -739,7 +730,7 @@ define nofpclass(snan) half @unknown__fsub__nzero(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @unknown__fsub__nzero(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call half @returns_nzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[NZERO]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd half [[UNKNOWN]], 0xH0000
; CHECK-NEXT: ret half [[ADD]]
;
%nzero = call half @returns_nzero()
@@ -751,7 +742,7 @@ define nofpclass(snan) half @nzero__fsub__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @nzero__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call half @returns_nzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[ADD:%.*]] = fneg half [[UNKNOWN]]
; CHECK-NEXT: ret half [[ADD]]
;
%nzero = call half @returns_nzero()
@@ -787,7 +778,7 @@ define nofpclass(nan) half @ret_nonan__unknown__fsub__nzero(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__unknown__fsub__nzero(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call half @returns_nzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[UNKNOWN]], [[NZERO]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd nnan half [[UNKNOWN]], 0xH0000
; CHECK-NEXT: ret half [[ADD]]
;
%nzero = call half @returns_nzero()
@@ -799,7 +790,7 @@ define nofpclass(nan) half @ret_nonan__nzero__fsub__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__nzero__fsub__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call half @returns_nzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[ADD:%.*]] = fneg half [[UNKNOWN]]
; CHECK-NEXT: ret half [[ADD]]
;
%nzero = call half @returns_nzero()
@@ -835,8 +826,7 @@ define nofpclass(snan) half @not_nzero__fsub__pzero(half nofpclass(nzero) %not.n
; CHECK-LABEL: define nofpclass(snan) half @not_nzero__fsub__pzero(
; CHECK-SAME: half nofpclass(nzero) [[NOT_NZERO:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NOT_NZERO]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[NOT_NZERO]]
;
%pzero = call half @returns_pzero()
%add = fsub half %not.nzero, %pzero
@@ -847,7 +837,7 @@ define nofpclass(snan) half @pzero__fsub__not_nzero(half nofpclass(nzero) %not.n
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub__not_nzero(
; CHECK-SAME: half nofpclass(nzero) [[NOT_NZERO:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[NOT_NZERO]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub half 0xH0000, [[NOT_NZERO]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -907,8 +897,7 @@ define nofpclass(snan) half @unknown__fsub_nsz__pzero(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @unknown__fsub_nsz__pzero(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub nsz half [[UNKNOWN]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[UNKNOWN]]
;
%pzero = call half @returns_pzero()
%add = fsub nsz half %unknown, %pzero
@@ -919,7 +908,7 @@ define nofpclass(snan) half @pzero__fsub_nsz__unknown(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub_nsz__unknown(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub nsz half [[PZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[ADD:%.*]] = fneg nsz half [[UNKNOWN]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -931,8 +920,7 @@ define nofpclass(snan) half @unknown__fsub_nsz__pzero_or_nan(half %unknown) {
; CHECK-LABEL: define nofpclass(snan) half @unknown__fsub_nsz__pzero_or_nan(
; CHECK-SAME: half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO_OR_NAN:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub nsz half [[UNKNOWN]], [[PZERO_OR_NAN]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[UNKNOWN]]
;
%pzero.or.nan = call half @returns_pzero()
%add = fsub nsz half %unknown, %pzero.or.nan
@@ -1031,8 +1019,7 @@ define nofpclass(snan) half @not_nzero__fsub__pzero__daz(half nofpclass(nzero) %
; CHECK-LABEL: define nofpclass(snan) half @not_nzero__fsub__pzero__daz(
; CHECK-SAME: half nofpclass(nzero) [[NOT_NZERO:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NOT_NZERO]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[NOT_NZERO]]
;
%pzero = call half @returns_pzero()
%add = fsub half %not.nzero, %pzero
@@ -1043,7 +1030,7 @@ define nofpclass(snan) half @pzero__fsub__not_nzero__daz(half nofpclass(nzero) %
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub__not_nzero__daz(
; CHECK-SAME: half nofpclass(nzero) [[NOT_NZERO:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[NOT_NZERO]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub half 0xH0000, [[NOT_NZERO]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -1055,8 +1042,7 @@ define nofpclass(snan) half @not_nzero__fsub__pzero__dynamic(half nofpclass(nzer
; CHECK-LABEL: define nofpclass(snan) half @not_nzero__fsub__pzero__dynamic(
; CHECK-SAME: half nofpclass(nzero) [[NOT_NZERO:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NOT_NZERO]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[NOT_NZERO]]
;
%pzero = call half @returns_pzero()
%add = fsub half %not.nzero, %pzero
@@ -1067,7 +1053,7 @@ define nofpclass(snan) half @pzero__fsub__not_nzero__dynamic(half nofpclass(nzer
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub__not_nzero__dynamic(
; CHECK-SAME: half nofpclass(nzero) [[NOT_NZERO:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[NOT_NZERO]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub half 0xH0000, [[NOT_NZERO]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -1079,8 +1065,7 @@ define nofpclass(snan) half @not_nzero_nsub__fsub__pzero__daz(half nofpclass(nze
; CHECK-LABEL: define nofpclass(snan) half @not_nzero_nsub__fsub__pzero__daz(
; CHECK-SAME: half nofpclass(nzero nsub) [[NOT_NZERO_NSUB:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NOT_NZERO_NSUB]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[NOT_NZERO_NSUB]]
;
%pzero = call half @returns_pzero()
%add = fsub half %not.nzero.nsub, %pzero
@@ -1091,7 +1076,7 @@ define nofpclass(snan) half @pzero__fsub__not_nzero_nsub__daz(half nofpclass(nze
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub__not_nzero_nsub__daz(
; CHECK-SAME: half nofpclass(nzero nsub) [[NOT_NZERO_NSUB:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[NOT_NZERO_NSUB]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub half 0xH0000, [[NOT_NZERO_NSUB]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -1103,8 +1088,7 @@ define nofpclass(snan) half @not_nzero_nsub__fsub__pzero__dynamic(half nofpclass
; CHECK-LABEL: define nofpclass(snan) half @not_nzero_nsub__fsub__pzero__dynamic(
; CHECK-SAME: half nofpclass(nzero nsub) [[NOT_NZERO_NSUB:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[NOT_NZERO_NSUB]], [[PZERO]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half [[NOT_NZERO_NSUB]]
;
%pzero = call half @returns_pzero()
%add = fsub half %not.nzero.nsub, %pzero
@@ -1115,7 +1099,7 @@ define nofpclass(snan) half @pzero__fsub__not_nzero_nsub__dynamic(half nofpclass
; CHECK-LABEL: define nofpclass(snan) half @pzero__fsub__not_nzero_nsub__dynamic(
; CHECK-SAME: half nofpclass(nzero nsub) [[NOT_NZERO_NSUB:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero()
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[PZERO]], [[NOT_NZERO_NSUB]]
+; CHECK-NEXT: [[ADD:%.*]] = fsub half 0xH0000, [[NOT_NZERO_NSUB]]
; CHECK-NEXT: ret half [[ADD]]
;
%pzero = call half @returns_pzero()
@@ -1127,9 +1111,7 @@ define nofpclass(nan) half @ret_nonan__fsub_self__nonan(i1 %cond, half noundef %
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan__fsub_self__nonan(
; CHECK-SAME: i1 [[COND:%.*]], half noundef [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NAN:%.*]] = call noundef half @returns_nan()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[NAN]], half [[UNKNOWN]]
-; CHECK-NEXT: [[ADD:%.*]] = fsub half [[SELECT]], [[SELECT]]
-; CHECK-NEXT: ret half [[ADD]]
+; CHECK-NEXT: ret half 0xH0000
;
%nan = call noundef half @returns_nan()
%select = select i1 %cond, half %nan, half %unknown
@@ -1141,7 +1123,7 @@ define nofpclass(nan) half @ret_nonan_fneg_fabs_fsub_known_negative_or_nan_sourc
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan_fneg_fabs_fsub_known_negative_or_nan_sources() {
; CHECK-NEXT: [[NEGATIVE_OR_NAN0:%.*]] = call half @returns_negative_or_nan()
; CHECK-NEXT: [[NEGATIVE_OR_NAN1:%.*]] = call half @returns_negative_or_nan()
-; CHECK-NEXT: [[KNOWN_NEGATIVE_SUB:%.*]] = fsub half [[NEGATIVE_OR_NAN0]], [[NEGATIVE_OR_NAN1]]
+; CHECK-NEXT: [[KNOWN_NEGATIVE_SUB:%.*]] = fsub nnan half [[NEGATIVE_OR_NAN0]], [[NEGATIVE_OR_NAN1]]
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[KNOWN_NEGATIVE_SUB]])
; CHECK-NEXT: [[NEG_FABS:%.*]] = fneg half [[FABS]]
; CHECK-NEXT: ret half [[NEG_FABS]]
@@ -1158,7 +1140,7 @@ define nofpclass(nan) half @ret_nonan_fneg_fabs_fsub_known_negative_sources() {
; CHECK-LABEL: define nofpclass(nan) half @ret_nonan_fneg_fabs_fsub_known_negative_sources() {
; CHECK-NEXT: [[NEGATIVE0:%.*]] = call half @returns_negative()
; CHECK-NEXT: [[NEGATIVE1:%.*]] = call half @returns_negative()
-; CHECK-NEXT: [[KNOWN_NEGATIVE_OP:%.*]] = fsub half [[NEGATIVE0]], [[NEGATIVE1]]
+; CHECK-NEXT: [[KNOWN_NEGATIVE_OP:%.*]] = fsub nnan half [[NEGATIVE0]], [[NEGATIVE1]]
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[KNOWN_NEGATIVE_OP]])
; CHECK-NEXT: [[NEG_FABS:%.*]] = fneg half [[FABS]]
; CHECK-NEXT: ret half [[NEG_FABS]]
>From d670efc4765cfd7746c6fa1cec41f3b19c554c17 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 14 Jan 2026 17:02:20 +0100
Subject: [PATCH 2/2] Implement as fadd+fneg
---
llvm/include/llvm/Support/KnownFPClass.h | 6 ++++++
llvm/lib/Support/KnownFPClass.cpp | 17 +----------------
2 files changed, 7 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 010ca6a3e84ec..358804c932891 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -176,6 +176,12 @@ struct KnownFPClass {
SignBit = !*SignBit;
}
+ static KnownFPClass fneg(const KnownFPClass &Src) {
+ KnownFPClass Known = Src;
+ Known.fneg();
+ return Known;
+ }
+
void fabs() {
if (KnownFPClasses & fcNegZero)
KnownFPClasses |= fcPosZero;
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index dbd5707873f5d..2946c597aa286 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -282,22 +282,7 @@ KnownFPClass KnownFPClass::fadd_self(const KnownFPClass &KnownSrc,
KnownFPClass KnownFPClass::fsub(const KnownFPClass &KnownLHS,
const KnownFPClass &KnownRHS,
DenormalMode Mode) {
- KnownFPClass Known;
- // Adding positive and negative infinity produces NaN.
- // TODO: Check sign of infinities.
- if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
- (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
- Known.knownNot(fcNan);
-
- // Only fsub -0, +0 can return -0
- if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
- KnownRHS.isKnownNeverLogicalPosZero(Mode)) &&
- // Make sure output negative denormal can't flush to -0
- (Mode.Output == DenormalMode::IEEE ||
- Mode.Output == DenormalMode::PositiveZero))
- Known.knownNot(fcNegZero);
-
- return Known;
+ return fadd(KnownLHS, fneg(KnownRHS), Mode);
}
KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
More information about the llvm-branch-commits
mailing list