[llvm] InstCombine: Add baseline test for SimplifyDemandedFPClass log handling (PR #173880)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 7 09:07:05 PST 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/173880
>From 672c8be1333f5656ca9d6d0079710bec6ff9a90d Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 21 Dec 2025 16:11:38 +0100
Subject: [PATCH 1/6] InstCombine: Handle fmul in SimplifyDemandedFPClass
---
llvm/include/llvm/Support/KnownFPClass.h | 37 ++++-
llvm/lib/Analysis/ValueTracking.cpp | 81 +++--------
llvm/lib/Support/KnownFPClass.cpp | 58 ++++++++
.../InstCombineSimplifyDemanded.cpp | 131 +++++++++++++++++-
.../simplify-demanded-fpclass-fmul.ll | 82 +++++------
.../InstCombine/simplify-demanded-fpclass.ll | 3 +-
6 files changed, 279 insertions(+), 113 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index bf70ddb272e29..f151a21914d26 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -54,6 +54,9 @@ struct KnownFPClass {
/// Return true if it's known this can never be an infinity.
bool isKnownNeverInfinity() const { return isKnownNever(fcInf); }
+ /// Return true if it's known this can never be an infinity or nan
+ bool isKnownNeverInfOrNaN() const { return isKnownNever(fcInf | fcNan); }
+
/// Return true if it's known this can never be +infinity.
bool isKnownNeverPosInfinity() const { return isKnownNever(fcPosInf); }
@@ -80,15 +83,17 @@ struct KnownFPClass {
/// literal -0 and does not include denormal inputs implicitly treated as -0.
bool isKnownNeverNegZero() const { return isKnownNever(fcNegZero); }
- /// Return true if it's know this can never be interpreted as a zero. This
+ /// Return true if it's known this can never be interpreted as a zero. This
/// extends isKnownNeverZero to cover the case where the assumed
/// floating-point mode for the function interprets denormals as zero.
LLVM_ABI bool isKnownNeverLogicalZero(DenormalMode Mode) const;
- /// Return true if it's know this can never be interpreted as a negative zero.
+ /// Return true if it's known this can never be interpreted as a negative
+ /// zero.
LLVM_ABI bool isKnownNeverLogicalNegZero(DenormalMode Mode) const;
- /// Return true if it's know this can never be interpreted as a positive zero.
+ /// Return true if it's known this can never be interpreted as a positive
+ /// zero.
LLVM_ABI bool isKnownNeverLogicalPosZero(DenormalMode Mode) const;
static constexpr FPClassTest OrderedLessThanZeroMask =
@@ -119,6 +124,17 @@ struct KnownFPClass {
return isKnownNever(OrderedGreaterThanZeroMask);
}
+ /// Return true if it's know this can never be a negative value or a logical
+ /// 0.
+ ///
+ /// NaN --> true
+ /// x >= -0 --> false
+ /// nsub --> true if mode is ieee, false otherwise.
+ /// x < -0 --> true
+ bool cannotBeOrderedGreaterEqZero(DenormalMode Mode) const {
+ return isKnownNever(fcPositive) && isKnownNeverLogicalNegZero(Mode);
+ }
+
KnownFPClass &operator|=(const KnownFPClass &RHS) {
KnownFPClasses = KnownFPClasses | RHS.KnownFPClasses;
@@ -165,6 +181,21 @@ struct KnownFPClass {
canonicalize(const KnownFPClass &Src,
DenormalMode DenormMode = DenormalMode::getDynamic());
+ /// Report known values for fmul
+ LLVM_ABI static KnownFPClass
+ fmul(const KnownFPClass &LHS, const KnownFPClass &RHS,
+ DenormalMode Mode = DenormalMode::getDynamic());
+
+ // Special case of fmul x, x.
+ static KnownFPClass square(const KnownFPClass &Src,
+ DenormalMode Mode = DenormalMode::getDynamic()) {
+ KnownFPClass Known = fmul(Src, Src, Mode);
+
+ // X * X is always non-negative or a NaN.
+ Known.knownNot(fcNegative);
+ return Known;
+ }
+
/// 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 350998a25e9ec..ce80025f45e3d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5690,12 +5690,24 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
break;
}
case Instruction::FMul: {
+ const Function *F = cast<Instruction>(Op)->getFunction();
+ DenormalMode Mode =
+ F ? F->getDenormalMode(
+ Op->getType()->getScalarType()->getFltSemantics())
+ : DenormalMode::getDynamic();
+
// X * X is always non-negative or a NaN.
- if (Op->getOperand(0) == Op->getOperand(1))
- Known.knownNot(fcNegative);
+ if (Op->getOperand(0) == Op->getOperand(1)) {
+ KnownFPClass KnownSrc;
+ computeKnownFPClass(Op->getOperand(0), DemandedElts, fcAllFlags, KnownSrc,
+ Q, Depth + 1);
+ Known = KnownFPClass::square(KnownSrc, Mode);
+ break;
+ }
KnownFPClass KnownLHS, KnownRHS;
+ bool CannotBeSubnormal = false;
const APFloat *CRHS;
if (match(Op->getOperand(1), m_APFloat(CRHS))) {
// Match denormal scaling pattern, similar to the case in ldexp. If the
@@ -5710,7 +5722,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
int MinKnownExponent = ilogb(*CRHS);
if (MinKnownExponent >= MantissaBits)
- Known.knownNot(fcSubnormal);
+ CannotBeSubnormal = true;
KnownRHS = KnownFPClass(*CRHS);
} else {
@@ -5721,66 +5733,9 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
computeKnownFPClass(Op->getOperand(0), DemandedElts, fcAllFlags, KnownLHS,
Q, Depth + 1);
- // xor sign bit.
- if ((KnownLHS.isKnownNever(fcNegative) &&
- KnownRHS.isKnownNever(fcNegative)) ||
- (KnownLHS.isKnownNever(fcPositive) &&
- KnownRHS.isKnownNever(fcPositive)))
- Known.knownNot(fcNegative);
-
- if ((KnownLHS.isKnownNever(fcPositive) &&
- KnownRHS.isKnownNever(fcNegative)) ||
- (KnownLHS.isKnownNever(fcNegative) &&
- KnownRHS.isKnownNever(fcPositive)))
- Known.knownNot(fcPositive);
-
- // inf * anything => inf or nan
- if (KnownLHS.isKnownAlways(fcInf | fcNan) ||
- KnownRHS.isKnownAlways(fcInf | fcNan))
- Known.knownNot(fcNormal | fcSubnormal | fcZero);
-
- // 0 * anything => 0 or nan
- if (KnownRHS.isKnownAlways(fcZero | fcNan) ||
- KnownLHS.isKnownAlways(fcZero | fcNan))
- Known.knownNot(fcNormal | fcSubnormal | fcInf);
-
- // +/-0 * +/-inf = nan
- if ((KnownLHS.isKnownAlways(fcZero | fcNan) &&
- KnownRHS.isKnownAlways(fcInf | fcNan)) ||
- (KnownLHS.isKnownAlways(fcInf | fcNan) &&
- KnownRHS.isKnownAlways(fcZero | fcNan)))
- Known.knownNot(~fcNan);
-
- if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
- break;
-
- if (KnownLHS.SignBit && KnownRHS.SignBit) {
- if (*KnownLHS.SignBit == *KnownRHS.SignBit)
- Known.signBitMustBeZero();
- else
- Known.signBitMustBeOne();
- }
-
- // If 0 * +/-inf produces NaN.
- if (KnownLHS.isKnownNeverInfinity() && KnownRHS.isKnownNeverInfinity()) {
- Known.knownNot(fcNan);
- break;
- }
-
- const Function *F = cast<Instruction>(Op)->getFunction();
- if (!F)
- break;
-
- Type *OpTy = Op->getType()->getScalarType();
- const fltSemantics &FltSem = OpTy->getFltSemantics();
- DenormalMode Mode = F->getDenormalMode(FltSem);
-
- if ((KnownRHS.isKnownNeverInfinity() ||
- KnownLHS.isKnownNeverLogicalZero(Mode)) &&
- (KnownLHS.isKnownNeverInfinity() ||
- KnownRHS.isKnownNeverLogicalZero(Mode)))
- Known.knownNot(fcNan);
-
+ Known = KnownFPClass::fmul(KnownLHS, KnownRHS, Mode);
+ if (CannotBeSubnormal)
+ Known.knownNot(fcSubnormal);
break;
}
case Instruction::FDiv:
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 9ca040366b611..a0f22d67c49ab 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -141,6 +141,64 @@ KnownFPClass KnownFPClass::canonicalize(const KnownFPClass &KnownSrc,
return Known;
}
+KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS,
+ DenormalMode Mode) {
+ KnownFPClass Known;
+
+ // xor sign bit.
+ if ((KnownLHS.isKnownNever(fcNegative) &&
+ KnownRHS.isKnownNever(fcNegative)) ||
+ (KnownLHS.isKnownNever(fcPositive) && KnownRHS.isKnownNever(fcPositive)))
+ Known.knownNot(fcNegative);
+
+ if ((KnownLHS.isKnownNever(fcPositive) &&
+ KnownRHS.isKnownNever(fcNegative)) ||
+ (KnownLHS.isKnownNever(fcNegative) && KnownRHS.isKnownNever(fcPositive)))
+ Known.knownNot(fcPositive);
+
+ // inf * anything => inf or nan
+ if (KnownLHS.isKnownAlways(fcInf | fcNan) ||
+ KnownRHS.isKnownAlways(fcInf | fcNan))
+ Known.knownNot(fcNormal | fcSubnormal | fcZero);
+
+ // 0 * anything => 0 or nan
+ if (KnownRHS.isKnownAlways(fcZero | fcNan) ||
+ KnownLHS.isKnownAlways(fcZero | fcNan))
+ Known.knownNot(fcNormal | fcSubnormal | fcInf);
+
+ // +/-0 * +/-inf = nan
+ if ((KnownLHS.isKnownAlways(fcZero | fcNan) &&
+ KnownRHS.isKnownAlways(fcInf | fcNan)) ||
+ (KnownLHS.isKnownAlways(fcInf | fcNan) &&
+ KnownRHS.isKnownAlways(fcZero | fcNan)))
+ Known.knownNot(~fcNan);
+
+ if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
+ return Known;
+
+ if (KnownLHS.SignBit && KnownRHS.SignBit) {
+ if (*KnownLHS.SignBit == *KnownRHS.SignBit)
+ Known.signBitMustBeZero();
+ else
+ Known.signBitMustBeOne();
+ }
+
+ // If 0 * +/-inf produces NaN.
+ if (KnownLHS.isKnownNeverInfinity() && KnownRHS.isKnownNeverInfinity()) {
+ Known.knownNot(fcNan);
+ return Known;
+ }
+
+ if ((KnownRHS.isKnownNeverInfinity() ||
+ KnownLHS.isKnownNeverLogicalZero(Mode)) &&
+ (KnownLHS.isKnownNeverInfinity() ||
+ KnownRHS.isKnownNeverLogicalZero(Mode)))
+ Known.knownNot(fcNan);
+
+ return Known;
+}
+
KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) {
KnownFPClass Known;
Known.knownNot(fcNegative);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index fe910ee32b56a..4c106e0d05a3c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2005,13 +2005,18 @@ Value *InstCombinerImpl::SimplifyDemandedVectorElts(Value *V,
/// For floating-point classes that resolve to a single bit pattern, return that
/// value.
-static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask) {
+static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask,
+ bool IsCanonicalizing = false) {
if (Mask == fcNone)
return PoisonValue::get(Ty);
if (Mask == fcPosZero)
return Constant::getNullValue(Ty);
+ // Turn any possible snans into quiet if we can.
+ if (Mask == fcNan && IsCanonicalizing)
+ return ConstantFP::getQNaN(Ty);
+
// TODO: Support aggregate types that are allowed by FPMathOperator.
if (Ty->isAggregateType())
return nullptr;
@@ -2086,6 +2091,130 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
Known.fneg();
break;
}
+ case Instruction::FMul: {
+ KnownFPClass KnownLHS, KnownRHS;
+
+ Value *X = I->getOperand(0);
+ Value *Y = I->getOperand(1);
+
+ FPClassTest SrcDemandedMask =
+ DemandedMask & (fcNan | fcZero | fcSubnormal | fcNormal);
+
+ if (DemandedMask & fcInf) {
+ // mul x, inf = inf
+ // mul large_x, large_y = inf
+ SrcDemandedMask |= fcSubnormal | fcNormal | fcInf;
+ }
+
+ if (DemandedMask & fcNan) {
+ // mul +/-inf, 0 => nan
+ SrcDemandedMask |= fcZero | fcInf;
+
+ // TODO: Mode check
+ // mul +/-inf, sub => nan if daz
+ SrcDemandedMask |= fcSubnormal;
+ }
+
+ const SimplifyQuery &SQ = getSimplifyQuery();
+ if (X == Y && isGuaranteedNotToBeUndef(X, SQ.AC, CxtI, SQ.DT, Depth + 1)) {
+ if (SimplifyDemandedFPClass(I, 0, SrcDemandedMask, KnownLHS, Depth + 1))
+ return I;
+ Type *EltTy = VTy->getScalarType();
+
+ DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics());
+ Known = KnownFPClass::square(KnownLHS, Mode);
+
+ // Propagate known result to simplify edge case checks.
+ if ((DemandedMask & fcNan) == fcNone)
+ Known.knownNot(fcNan);
+ if ((DemandedMask & fcPosInf) == fcNone)
+ Known.knownNot(fcInf);
+
+ FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
+ if (Constant *Folded =
+ getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true))
+ return Folded;
+
+ if (Known.isKnownAlways(fcPosZero | fcPosInf | fcNan)) {
+ assert(KnownLHS.isKnownNever(fcPosNormal));
+
+ // We can skip the fabs if the source was already known positive.
+ if (KnownLHS.isKnownAlways(fcPositive))
+ return X;
+
+ // => fabs(x), in case this was a -inf or -0.
+ // Note: Dropping canonicalize.
+ IRBuilderBase::InsertPointGuard Guard(Builder);
+ Builder.SetInsertPoint(I);
+ Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X, FMF);
+ Fabs->takeName(I);
+ return Fabs;
+ }
+
+ return nullptr;
+ }
+
+ if (SimplifyDemandedFPClass(I, 1, SrcDemandedMask, KnownRHS, Depth + 1) ||
+ SimplifyDemandedFPClass(I, 0, SrcDemandedMask, KnownLHS, Depth + 1))
+ return I;
+
+ // Propagate nnan-ness to sources to simplify source checks.
+ if ((DemandedMask & fcNan) == fcNone) {
+ KnownLHS.knownNot(fcNan);
+ KnownRHS.knownNot(fcNan);
+ }
+
+ // With no-nans/no-infs:
+ // X * 0.0 --> copysign(0.0, X)
+ // X * -0.0 --> copysign(0.0, -X)
+
+ // TODO: Apply knowledge of no-infinity returns to sources.
+
+ // TODO: Known -0, turn into copysign(y, fneg(x)) like visitFMul.
+ if (KnownLHS.isKnownNeverInfOrNaN() &&
+ KnownRHS.isKnownAlways(fcPosZero | fcNan)) {
+ // => copysign(+0, lhs)
+ // Note: Dropping canonicalize
+ Value *Copysign = Builder.CreateCopySign(Y, X, FMF);
+ Copysign->takeName(I);
+ return Copysign;
+ }
+
+ if (KnownLHS.isKnownAlways(fcPosZero | fcNan) &&
+ KnownRHS.isKnownNeverInfOrNaN()) {
+ // => copysign(+0, rhs)
+ // Note: Dropping canonicalize
+ Value *Copysign = Builder.CreateCopySign(X, Y, FMF);
+ Copysign->takeName(I);
+ return Copysign;
+ }
+
+ Type *EltTy = VTy->getScalarType();
+ DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics());
+
+ if (KnownLHS.isKnownAlways(fcInf | fcNan) &&
+ (KnownRHS.isKnownNeverNaN() &&
+ KnownRHS.cannotBeOrderedGreaterEqZero(Mode))) {
+ // Note: Dropping canonicalize
+ Value *Neg = Builder.CreateFNegFMF(X, FMF);
+ Neg->takeName(I);
+ return Neg;
+ }
+
+ if (KnownRHS.isKnownAlways(fcInf | fcNan) &&
+ (KnownLHS.isKnownNeverNaN() &&
+ KnownLHS.cannotBeOrderedGreaterEqZero(Mode))) {
+ // Note: Dropping canonicalize
+ Value *Neg = Builder.CreateFNegFMF(Y, FMF);
+ Neg->takeName(I);
+ return Neg;
+ }
+
+ Known = KnownFPClass::fmul(KnownLHS, KnownRHS, Mode);
+
+ FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
+ return getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true);
+ }
case Instruction::Call: {
CallInst *CI = cast<CallInst>(I);
switch (CI->getIntrinsicID()) {
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
index d9d68d277273e..98a365b0f4ef6 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -52,8 +52,7 @@ define nofpclass(inf) float @ret_nofpclass_inf__fmul_unknown_or_pinf(i1 %cond, f
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_results_or_nan_square(float noundef %x) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_results_or_nan_square(
; CHECK-SAME: float noundef [[X:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
-; CHECK-NEXT: ret float [[MUL]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%mul = fmul float %x, %x
ret float %mul
@@ -73,7 +72,8 @@ define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_squ
define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_square_maybe_undef(float %x) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative_results_square_maybe_undef(
; CHECK-SAME: float [[X:%.*]]) {
-; CHECK-NEXT: ret float poison
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %x, %x
ret float %mul
@@ -101,8 +101,7 @@ define nofpclass(inf norm sub nan) float @ret_only_zero_results_square(float nou
define nofpclass(inf norm sub zero) float @ret_only_nan_results_square(float noundef %x) {
; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan_results_square(
; CHECK-SAME: float noundef [[X:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
-; CHECK-NEXT: ret float [[MUL]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%mul = fmul float %x, %x
ret float %mul
@@ -206,7 +205,7 @@ define nofpclass(inf) float @ret_src_must_be_nzero(float noundef nofpclass(nan i
define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square(float noundef nofpclass(inf norm sub) %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square(
; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %x, %x
@@ -216,7 +215,7 @@ define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square(float noundef no
define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square__preserve_flags(float noundef nofpclass(inf norm sub) %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square__preserve_flags(
; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[X]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %x, %x
@@ -227,7 +226,7 @@ define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input0
; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input0(
; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) {
; CHECK-NEXT: call void @use(float [[X]])
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[MUL]]
;
call void @use(float %x)
@@ -238,7 +237,7 @@ define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input0
define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input1(float noundef nofpclass(inf norm sub) %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square_other_use_input1(
; CHECK-SAME: float noundef nofpclass(inf sub norm) [[X:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: call void @use(float [[X]])
; CHECK-NEXT: ret float [[MUL]]
;
@@ -305,8 +304,7 @@ define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_square_unknown_or_pinf__o
define nofpclass(nzero) float @ret_src_must_be_nan_square(float noundef nofpclass(inf norm sub zero) %x) {
; CHECK-LABEL: define nofpclass(nzero) float @ret_src_must_be_nan_square(
; CHECK-SAME: float noundef nofpclass(inf zero sub norm) [[X:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[X]]
-; CHECK-NEXT: ret float [[MUL]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%mul = fmul float %x, %x
ret float %mul
@@ -316,9 +314,7 @@ define nofpclass(nzero) float @ret_src_must_be_nan_square(float noundef nofpclas
define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_results_or_nan_fabs_xy(float %x, float nofpclass(ninf nnorm nsub nzero) %y.pos.or.nan) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_results_or_nan_fabs_xy(
; CHECK-SAME: float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[Y_POS_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_FABS]], [[Y_POS_OR_NAN]]
-; CHECK-NEXT: ret float [[MUL]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%x.fabs = call float @llvm.fabs.f32(float %x)
%mul = fmul float %x.fabs, %y.pos.or.nan
@@ -450,8 +446,7 @@ define nofpclass(pinf nan) float @ret_no_pinf_or_nan_results__lhs_known_non_inf(
define nofpclass(inf nan) float @ret_no_inf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_or_nan_results__lhs_known_non_inf(
; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[Y]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]]
; CHECK-NEXT: ret float [[MUL]]
;
%x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
@@ -463,8 +458,7 @@ define nofpclass(inf nan) float @ret_no_inf_or_nan_results__lhs_known_non_inf(i1
define nofpclass(inf nan) float @ret_no_inf_or_nan_results__rhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_or_nan_results__rhs_known_non_inf(
; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
-; CHECK-NEXT: [[Y_OR_PINF:%.*]] = select i1 [[COND]], float [[Y]], float 0x7FF0000000000000
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y_OR_PINF]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]]
; CHECK-NEXT: ret float [[MUL]]
;
%y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000
@@ -476,8 +470,7 @@ define nofpclass(inf nan) float @ret_no_inf_or_nan_results__rhs_known_non_inf(i1
define nofpclass(ninf nnorm nsub nzero) float @ret_only_positive_results_or_nan_known_negative_fmul(float nofpclass(ninf nnorm nsub nzero) %only.positive.or.nan, float nofpclass(pinf pnorm psub pzero) %only.negative.or.nan) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_only_positive_results_or_nan_known_negative_fmul(
; CHECK-SAME: float nofpclass(ninf nzero nsub nnorm) [[ONLY_POSITIVE_OR_NAN:%.*]], float nofpclass(pinf pzero psub pnorm) [[ONLY_NEGATIVE_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[ONLY_NEGATIVE_OR_NAN]], [[ONLY_POSITIVE_OR_NAN]]
-; CHECK-NEXT: ret float [[MUL]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%mul = fmul float %only.negative.or.nan, %only.positive.or.nan
ret float %mul
@@ -530,7 +523,7 @@ define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_zero_or_nan(float
define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %not.inf.or.nan
@@ -552,7 +545,7 @@ define nofpclass(nsub) float @ret__not_inf__fmul__known_pzero_or_nan(float nofpc
define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan(
; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_INF_OR_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %not.inf.or.nan, %pzero.or.nan
@@ -585,7 +578,7 @@ define nofpclass(nsub) float @ret__known_negative_non0_or_nan__fmul__known_inf_o
define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm psub) %negative.non0) {
; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0(
; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0]]
+; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %inf.or.nan, %negative.non0
@@ -596,7 +589,7 @@ define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0(f
define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan(float nofpclass(nan zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) {
; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan(
; CHECK-SAME: float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEGATIVE_NON0]], [[INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %negative.non0, %inf.or.nan
@@ -629,7 +622,7 @@ define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__
define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlogical0__daz(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm sub) %negative.nonlogical0) #1 {
; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlogical0__daz(
; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero sub pnorm) [[NEGATIVE_NONLOGICAL0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NONLOGICAL0]]
+; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %inf.or.nan, %negative.nonlogical0
@@ -640,7 +633,7 @@ define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlog
define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_or_nan__daz(float nofpclass(nan zero pinf pnorm sub) %negative.nonlogical0, float nofpclass(zero sub norm) %inf.or.nan) #1 {
; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_or_nan__daz(
; CHECK-SAME: float nofpclass(nan pinf zero sub pnorm) [[NEGATIVE_NONLOGICAL0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEGATIVE_NONLOGICAL0]], [[INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %negative.nonlogical0, %inf.or.nan
@@ -651,7 +644,7 @@ define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_o
define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NOT_INF_OR_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %not.inf.or.nan
@@ -662,7 +655,7 @@ define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf(float
define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzero_or_nan(
; CHECK-SAME: float nofpclass(inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_INF_OR_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NOT_INF_OR_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %not.inf.or.nan, %pzero.or.nan
@@ -673,7 +666,7 @@ define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzer
define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_negative_non0(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(zero pinf pnorm psub) %negative.non0) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_negative_non0(
; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0]]
+; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %inf.or.nan, %negative.non0
@@ -684,7 +677,7 @@ define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_ne
define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known_inf_or_nan(float nofpclass(zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known_inf_or_nan(
; CHECK-SAME: float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEGATIVE_NON0]], [[INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = fneg float [[INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %negative.non0, %inf.or.nan
@@ -695,7 +688,7 @@ define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known
define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[UNKNOWN]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -706,7 +699,7 @@ define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_
define nofpclass(inf nan) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[UNKNOWN]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -881,8 +874,7 @@ define nofpclass(ninf) float @ret_noninf__not_nan_neg__fmul__known_zero_or_pos_n
define nofpclass(inf norm sub zero) float @ret_only_nan_results_fmul(float %x, float %y) {
; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan_results_fmul(
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X]], [[Y]]
-; CHECK-NEXT: ret float [[MUL]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%mul = fmul float %x, %y
ret float %mul
@@ -956,7 +948,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[PZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -968,7 +960,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], [[PZERO]]
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -980,7 +972,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[NZERO]], [[UNKNOWN]]
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -992,7 +984,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], [[NZERO]]
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -1116,7 +1108,7 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NZERO_OR_NAN]], [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %nzero.or.nan, %not.nan
@@ -1127,7 +1119,7 @@ define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float
define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], [[NZERO_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %not.nan, %nzero.or.nan
@@ -1160,7 +1152,8 @@ define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(float
define nofpclass(snan) float @ret__nzero_or_nan__fmul_nnan__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(snan) float @ret__nzero_or_nan__fmul_nnan__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[NZERO_OR_NAN]], [[UNKNOWN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan float [[UNKNOWN]]
+; CHECK-NEXT: [[MUL:%.*]] = call nnan float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul nnan float %nzero.or.nan, %unknown
@@ -1171,7 +1164,8 @@ define nofpclass(snan) float @ret__nzero_or_nan__fmul_nnan__not_inf_or_nan(float
define nofpclass(snan) float @not_inf_or_nan__fmul_nnan__nzero_or_nan(float %unknown, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @not_inf_or_nan__fmul_nnan__nzero_or_nan(
; CHECK-SAME: float [[UNKNOWN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[UNKNOWN]], [[NZERO_OR_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan float [[UNKNOWN]]
+; CHECK-NEXT: [[MUL:%.*]] = call nnan float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul nnan float %unknown, %nzero.or.nan
@@ -1182,7 +1176,7 @@ define nofpclass(snan) float @not_inf_or_nan__fmul_nnan__nzero_or_nan(float %unk
define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %pzero.or.nan, %not.inf.or.nan
@@ -1193,7 +1187,7 @@ define nofpclass(snan) float @known__pzero_or_nan__fmul__not_inf_or_nan(float no
define nofpclass(snan) float @known__not_inf_or_nan__fmul__pzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @known__not_inf_or_nan__fmul__pzero_or_nan(
; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NOT_INF_OR_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_INF_OR_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %not.inf.or.nan, %pzero.or.nan
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index 6d4674c8c9b54..844769e960b98 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -970,8 +970,7 @@ define nofpclass(nan inf nzero nsub nnorm) float @test_powr_issue64870_2(float n
; CHECK-NEXT: [[I:%.*]] = fcmp olt float [[ARG]], 0.000000e+00
; CHECK-NEXT: [[I2:%.*]] = select i1 [[I]], float 0x7FF8000000000000, float [[ARG]]
; CHECK-NEXT: [[I3:%.*]] = tail call float @llvm.log2.f32(float noundef [[I2]])
-; CHECK-NEXT: [[I4:%.*]] = select i1 [[I]], float 0x7FF8000000000000, float [[ARG1]]
-; CHECK-NEXT: [[I5:%.*]] = fmul float [[I4]], [[I3]]
+; CHECK-NEXT: [[I5:%.*]] = fmul float [[ARG1]], [[I3]]
; CHECK-NEXT: [[I6:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float noundef [[I5]])
; CHECK-NEXT: [[I10:%.*]] = fcmp oeq float [[I2]], 0.000000e+00
; CHECK-NEXT: [[I12:%.*]] = select i1 [[I10]], float 0.000000e+00, float [[I6]]
>From 1e243637d55c195bfc43ad0f6024f081a3fbf843 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 6 Jan 2026 20:34:44 +0100
Subject: [PATCH 2/6] Add more tests
---
.../simplify-demanded-fpclass-fmul.ll | 80 +++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
index 98a365b0f4ef6..8a6224612cab8 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -5,6 +5,8 @@ declare nofpclass(nan inf sub norm) float @returns_zero()
declare nofpclass(nan inf nzero sub norm) float @returns_pzero()
declare nofpclass(nan inf pzero sub norm) float @returns_nzero()
declare nofpclass(nan inf zero sub nnorm) float @returns_pnorm()
+declare nofpclass(nan inf norm zero) float @returns_sub()
+declare nofpclass(nan inf sub zero) float @returns_norm()
declare void @use(float)
; No inf result implies no inf inputs.
@@ -1282,5 +1284,83 @@ define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(float
ret float %mul
}
+define nofpclass(nan inf norm sub) float @zero_result_demands_sub_source_lhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_sub_source_lhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub()
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN0]], [[UNKNOWN1]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %sub = call float @returns_sub()
+ %select = select i1 %cond, float %sub, float %unknown0
+ %mul = fmul float %select, %unknown1
+ ret float %mul
+}
+
+define nofpclass(nan inf norm sub) float @zero_result_demands_sub_source_rhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_sub_source_rhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub()
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[UNKNOWN0]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %sub = call float @returns_sub()
+ %select = select i1 %cond, float %sub, float %unknown0
+ %mul = fmul float %unknown1, %select
+ ret float %mul
+}
+
+define nofpclass(nan inf norm sub) float @zero_result_demands_norm_source_lhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_norm_source_lhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN0]], [[UNKNOWN1]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %norm = call float @returns_norm()
+ %select = select i1 %cond, float %norm, float %unknown0
+ %mul = fmul float %select, %unknown1
+ ret float %mul
+}
+
+define nofpclass(nan inf norm sub) float @zero_result_demands_norm_source_rhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_norm_source_rhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[UNKNOWN0]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %norm = call float @returns_norm()
+ %select = select i1 %cond, float %norm, float %unknown0
+ %mul = fmul float %unknown1, %select
+ ret float %mul
+}
+
+define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_lhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_demands_norm_source_lhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN0]], [[UNKNOWN1]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %norm = call float @returns_norm()
+ %select = select i1 %cond, float %norm, float %unknown0
+ %mul = fmul float %select, %unknown1
+ ret float %mul
+}
+
+define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_rhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_demands_norm_source_rhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[UNKNOWN0]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %norm = call float @returns_norm()
+ %select = select i1 %cond, float %norm, float %unknown0
+ %mul = fmul float %unknown1, %select
+ ret float %mul
+}
+
attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
attributes #1 = { "denormal-fp-math"="dynamic,dynamic" }
>From 04216a01e9383e7834188c21df6bc77b231b2503 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 6 Jan 2026 20:38:48 +0100
Subject: [PATCH 3/6] Fix normal inputs with zero or sub only results
---
.../InstCombineSimplifyDemanded.cpp | 7 +++++++
.../simplify-demanded-fpclass-fmul.ll | 18 ++++++++++++------
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 4c106e0d05a3c..993a729b4d8bf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2115,6 +2115,13 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
SrcDemandedMask |= fcSubnormal;
}
+ // Normal inputs may result in underflow.
+ if (DemandedMask & fcSubnormal)
+ SrcDemandedMask |= fcNormal;
+
+ if (DemandedMask & fcZero)
+ SrcDemandedMask |= fcNormal | fcSubnormal;
+
const SimplifyQuery &SQ = getSimplifyQuery();
if (X == Y && isGuaranteedNotToBeUndef(X, SQ.AC, CxtI, SQ.DT, Depth + 1)) {
if (SimplifyDemandedFPClass(I, 0, SrcDemandedMask, KnownLHS, Depth + 1))
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
index 8a6224612cab8..e0c5917854083 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -1288,7 +1288,8 @@ define nofpclass(nan inf norm sub) float @zero_result_demands_sub_source_lhs(i1
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_sub_source_lhs(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub()
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN0]], [[UNKNOWN1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[UNKNOWN1]]
; CHECK-NEXT: ret float [[MUL]]
;
%sub = call float @returns_sub()
@@ -1301,7 +1302,8 @@ define nofpclass(nan inf norm sub) float @zero_result_demands_sub_source_rhs(i1
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_sub_source_rhs(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub()
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[UNKNOWN0]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[SELECT]]
; CHECK-NEXT: ret float [[MUL]]
;
%sub = call float @returns_sub()
@@ -1314,7 +1316,8 @@ define nofpclass(nan inf norm sub) float @zero_result_demands_norm_source_lhs(i1
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_norm_source_lhs(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN0]], [[UNKNOWN1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[UNKNOWN1]]
; CHECK-NEXT: ret float [[MUL]]
;
%norm = call float @returns_norm()
@@ -1327,7 +1330,8 @@ define nofpclass(nan inf norm sub) float @zero_result_demands_norm_source_rhs(i1
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @zero_result_demands_norm_source_rhs(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[UNKNOWN0]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[SELECT]]
; CHECK-NEXT: ret float [[MUL]]
;
%norm = call float @returns_norm()
@@ -1340,7 +1344,8 @@ define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_lhs(i1
; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_demands_norm_source_lhs(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN0]], [[UNKNOWN1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[UNKNOWN1]]
; CHECK-NEXT: ret float [[MUL]]
;
%norm = call float @returns_norm()
@@ -1353,7 +1358,8 @@ define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_rhs(i1
; CHECK-LABEL: define nofpclass(nan inf zero norm) float @sub_result_demands_norm_source_rhs(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
; CHECK-NEXT: [[NORM:%.*]] = call float @returns_norm()
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[UNKNOWN0]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NORM]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[SELECT]]
; CHECK-NEXT: ret float [[MUL]]
;
%norm = call float @returns_norm()
>From befd4a2cdfeaa9b8473c2e9274e3c19c5d0af1f0 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 7 Jan 2026 11:34:46 +0100
Subject: [PATCH 4/6] Normal output may imply subnormal input
---
.../InstCombineSimplifyDemanded.cpp | 4 ++
.../simplify-demanded-fpclass-fmul.ll | 64 +++++++++++++++----
2 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 993a729b4d8bf..5e200560e83d1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2115,6 +2115,10 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
SrcDemandedMask |= fcSubnormal;
}
+ // mul normal, subnormal = normal
+ if (DemandedMask & fcNormal)
+ SrcDemandedMask |= fcSubnormal;
+
// Normal inputs may result in underflow.
if (DemandedMask & fcSubnormal)
SrcDemandedMask |= fcNormal;
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
index e0c5917854083..a0a3c8fe208bd 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -690,7 +690,7 @@ define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known
define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -701,7 +701,7 @@ define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_
define nofpclass(inf nan) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -950,7 +950,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -962,7 +962,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -974,7 +974,8 @@ define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]]
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -986,7 +987,8 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]]
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -1022,7 +1024,8 @@ define nofpclass(ninf) float @ret_ninf__fmul_nnan_unknown__zero(float %unknown)
define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %nzero.or.nan, %not.inf.or.nan
@@ -1033,7 +1036,8 @@ define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(float no
define nofpclass(snan) float @known__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @known__not_inf_or_nan__fmul__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NOT_INF_OR_NAN]], [[NZERO_OR_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %not.inf.or.nan, %nzero.or.nan
@@ -1110,7 +1114,8 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %nzero.or.nan, %not.nan
@@ -1121,7 +1126,8 @@ define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float
define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %not.nan, %nzero.or.nan
@@ -1132,7 +1138,8 @@ define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NZERO_OR_NAN]], [[NOT_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %nzero.or.nan, %not.nan
@@ -1143,7 +1150,8 @@ define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float
define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_NAN]], [[NZERO_OR_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %not.nan, %nzero.or.nan
@@ -1266,7 +1274,7 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__pzero_or_nan(float
define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[PZERO_OR_NAN]], [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %pzero.or.nan, %not.nan
@@ -1277,7 +1285,7 @@ define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float
define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %not.nan, %pzero.or.nan
@@ -1368,5 +1376,33 @@ define nofpclass(nan inf norm zero) float @sub_result_demands_norm_source_rhs(i1
ret float %mul
}
+define nofpclass(nan inf sub zero) float @norm_result_demands_sub_source_lhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub) float @norm_result_demands_sub_source_lhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub()
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SELECT]], [[UNKNOWN1]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %sub = call float @returns_sub()
+ %select = select i1 %cond, float %sub, float %unknown0
+ %mul = fmul float %select, %unknown1
+ ret float %mul
+}
+
+define nofpclass(nan inf sub zero) float @norm_result_demands_sub_source_rhs(i1 %cond, float %unknown0, float %unknown1) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub) float @norm_result_demands_sub_source_rhs(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN0:%.*]], float [[UNKNOWN1:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub()
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SUB]], float [[UNKNOWN0]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN1]], [[SELECT]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %sub = call float @returns_sub()
+ %select = select i1 %cond, float %sub, float %unknown0
+ %mul = fmul float %unknown1, %select
+ ret float %mul
+}
+
attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
attributes #1 = { "denormal-fp-math"="dynamic,dynamic" }
>From f3c995f4636bb95f2712254ec1cd3ecddd01917d Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 7 Jan 2026 13:13:59 +0100
Subject: [PATCH 5/6] Remove redundant nan output check
---
llvm/lib/Support/KnownFPClass.cpp | 5 ---
.../simplify-demanded-fpclass-fmul.ll | 36 ++++++++-----------
2 files changed, 14 insertions(+), 27 deletions(-)
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index a0f22d67c49ab..62e1bbabd6c8e 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -185,11 +185,6 @@ KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
}
// If 0 * +/-inf produces NaN.
- if (KnownLHS.isKnownNeverInfinity() && KnownRHS.isKnownNeverInfinity()) {
- Known.knownNot(fcNan);
- return Known;
- }
-
if ((KnownRHS.isKnownNeverInfinity() ||
KnownLHS.isKnownNeverLogicalZero(Mode)) &&
(KnownLHS.isKnownNeverInfinity() ||
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
index a0a3c8fe208bd..9f4d04bde725b 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -690,7 +690,7 @@ define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known
define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -701,7 +701,7 @@ define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_
define nofpclass(inf nan) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -950,7 +950,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -962,7 +962,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -974,8 +974,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]]
-; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -987,8 +986,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]]
-; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
+; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -1024,8 +1022,7 @@ define nofpclass(ninf) float @ret_ninf__fmul_nnan_unknown__zero(float %unknown)
define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]]
-; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %nzero.or.nan, %not.inf.or.nan
@@ -1036,8 +1033,7 @@ define nofpclass(snan) float @known__nzero_or_nan__fmul__not_inf_or_nan(float no
define nofpclass(snan) float @known__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @known__not_inf_or_nan__fmul__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[NOT_INF_OR_NAN]]
-; CHECK-NEXT: [[MUL:%.*]] = call contract float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul contract float [[NOT_INF_OR_NAN]], [[NZERO_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul contract float %not.inf.or.nan, %nzero.or.nan
@@ -1114,8 +1110,7 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]]
-; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %nzero.or.nan, %not.nan
@@ -1126,8 +1121,7 @@ define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float
define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]]
-; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %not.nan, %nzero.or.nan
@@ -1138,8 +1132,7 @@ define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]]
-; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NZERO_OR_NAN]], [[NOT_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %nzero.or.nan, %not.nan
@@ -1150,8 +1143,7 @@ define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float
define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]]
-; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_NAN]], [[NZERO_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %not.nan, %nzero.or.nan
@@ -1274,7 +1266,7 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__pzero_or_nan(float
define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[PZERO_OR_NAN]], [[NOT_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %pzero.or.nan, %not.nan
@@ -1285,7 +1277,7 @@ define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float
define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = call ninf float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]])
+; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_NAN]], [[PZERO_OR_NAN]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %not.nan, %pzero.or.nan
>From cc28d55b26d9af58c1acbb203cdcb185d27fdaef Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 22 Dec 2025 23:01:19 +0100
Subject: [PATCH 6/6] InstCombine: Add baseline test for
SimplifyDemandedFPClass log handling
---
.../simplify-demanded-fpclass-log.ll | 268 ++++++++++++++++++
1 file changed, 268 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll
new file mode 100644
index 0000000000000..2c6d11378e167
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll
@@ -0,0 +1,268 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; -> qnan, canonicalizing
+define nofpclass(inf norm sub zero) float @ret_nofpclass_only_nan__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_nofpclass_only_nan__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+; -> +0
+define nofpclass(nan inf norm sub) float @ret_nofpclass_only_zero__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan inf sub norm) float @ret_nofpclass_only_zero__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+; -> +0
+define nofpclass(nan inf norm sub nzero) float @ret_nofpclass_only_pzero__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @ret_nofpclass_only_pzero__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+; -> pinf
+define nofpclass(nan ninf norm sub zero) float @ret_nofpclass_only_pinf__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan ninf zero sub norm) float @ret_nofpclass_only_pinf__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: ret float 0x7FF0000000000000
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+; -> ninf
+define nofpclass(nan pinf norm sub zero) float @ret_nofpclass_only_ninf__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan pinf zero sub norm) float @ret_nofpclass_only_ninf__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: ret float 0xFFF0000000000000
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+; log cannot return -0, -> poison
+define nofpclass(nan inf norm sub pzero) float @ret_nofpclass_only_nzero__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan inf pzero sub norm) float @ret_nofpclass_only_nzero__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: ret float poison
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+define nofpclass(nan norm sub zero) float @ret_nofpclass_only_inf__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan zero sub norm) float @ret_nofpclass_only_inf__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+define nofpclass(norm sub zero) float @ret_nofpclass_only_inf_nan__log(float %unknown) {
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_nofpclass_only_inf_nan__log(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %result = call float @llvm.log.f32(float %unknown)
+ ret float %result
+}
+
+; Return implies argument cannot be 0, fold to just log
+define nofpclass(ninf) float @ret_nofpclass_ninf_log(i1 %cond, float %x, float nofpclass(inf norm sub) %zero) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf_log(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf sub norm) [[ZERO:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[ZERO]], float [[X]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %zero, float %x
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; -> only log
+define nofpclass(pinf) float @ret_nofpclass_pinf_log_select_inf_or_unknown(i1 %cond, float %unknown) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf_log_select_inf_or_unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[UNKNOWN]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float 0x7ff0000000000000, float %unknown
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Check log2 is handled, -> only log2
+define nofpclass(pinf) float @ret_nofpclass_pinf_log2_select_inf_or_unknown(i1 %cond, float %unknown) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf_log2_select_inf_or_unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[UNKNOWN]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log2.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float 0x7ff0000000000000, float %unknown
+ %result = call float @llvm.log2.f32(float %select)
+ ret float %result
+}
+
+; Check log10 is handled, -> only log10
+define nofpclass(pinf) float @ret_nofpclass_pinf_log10_select_inf_or_unknown(i1 %cond, float %unknown) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf_log10_select_inf_or_unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[UNKNOWN]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log10.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float 0x7ff0000000000000, float %unknown
+ %result = call float @llvm.log10.f32(float %select)
+ ret float %result
+}
+
+; -> only log
+define nofpclass(ninf norm zero) float @ret_nofpclass_nan_or_sub__log_select__finite_positive__unknown(i1 %cond, float nofpclass(inf nnorm nsub nan) %must.be.finite.positive, float %unknown) {
+; CHECK-LABEL: define nofpclass(ninf zero norm) float @ret_nofpclass_nan_or_sub__log_select__finite_positive__unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan inf nsub nnorm) [[MUST_BE_FINITE_POSITIVE:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_FINITE_POSITIVE]], float [[UNKNOWN]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %must.be.finite.positive, float %unknown
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Cannot fold out due to subnormal input on first argument
+define nofpclass(ninf norm zero) float @ret_nofpclass_nan_or_sub__log_select__finite_positive_or_sub__unknown(i1 %cond, float nofpclass(inf nnorm nan) %must.be.finite.positive.or.sub, float %unknown) {
+; CHECK-LABEL: define nofpclass(ninf zero norm) float @ret_nofpclass_nan_or_sub__log_select__finite_positive_or_sub__unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan inf nnorm) [[MUST_BE_FINITE_POSITIVE_OR_SUB:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_FINITE_POSITIVE_OR_SUB]], float [[UNKNOWN]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %must.be.finite.positive.or.sub, float %unknown
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Fold out select
+define nofpclass(pinf nan norm zero) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__ieee(i1 %cond, float nofpclass(ninf norm nan) %must.be.pinf.or.sub.or.zero, float nofpclass(zero) %not.zero) {
+; CHECK-LABEL: define nofpclass(nan pinf zero norm) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__ieee(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan ninf norm) [[MUST_BE_PINF_OR_SUB_OR_ZERO:%.*]], float nofpclass(zero) [[NOT_ZERO:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_PINF_OR_SUB_OR_ZERO]], float [[NOT_ZERO]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %must.be.pinf.or.sub.or.zero, float %not.zero
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Must keep select
+define nofpclass(pinf nan norm zero) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__daz(i1 %cond, float nofpclass(ninf norm nan) %must.be.pinf.or.sub.or.zero, float nofpclass(zero) %not.zero) #0 {
+; CHECK-LABEL: define nofpclass(nan pinf zero norm) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__daz(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan ninf norm) [[MUST_BE_PINF_OR_SUB_OR_ZERO:%.*]], float nofpclass(zero) [[NOT_ZERO:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_PINF_OR_SUB_OR_ZERO]], float [[NOT_ZERO]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %must.be.pinf.or.sub.or.zero, float %not.zero
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Must keep select
+define nofpclass(pinf nan norm zero) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__dynamic(i1 %cond, float nofpclass(ninf norm nan) %must.be.pinf.or.sub.or.zero, float nofpclass(zero) %not.zero) #1 {
+; CHECK-LABEL: define nofpclass(nan pinf zero norm) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__dynamic(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan ninf norm) [[MUST_BE_PINF_OR_SUB_OR_ZERO:%.*]], float nofpclass(zero) [[NOT_ZERO:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_PINF_OR_SUB_OR_ZERO]], float [[NOT_ZERO]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %must.be.pinf.or.sub.or.zero, float %not.zero
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Fold to select unknown
+define nofpclass(inf nan pnorm sub zero) float @ret_only_nnorm__log__select_unknown_or_infnan(i1 %cond, float %unknown, float nofpclass(norm sub zero) %b) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub pnorm) float @ret_only_nnorm__log__select_unknown_or_infnan(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(zero sub norm) [[B:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[UNKNOWN]], float [[B]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %unknown, float %b
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Fold to select unknown
+define nofpclass(inf nan nnorm sub zero) float @ret_only_pnorm__log__select_unknown_or_infnan(i1 %cond, float %unknown, float nofpclass(norm sub zero) %b) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @ret_only_pnorm__log__select_unknown_or_infnan(
+; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(zero sub norm) [[B:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[UNKNOWN]], float [[B]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %unknown, float %b
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Keep select
+define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_pnormnan_or_unknown(i1 %cond, float nofpclass(inf sub zero nnorm) %pnorm.or.nan, float %b) {
+; CHECK-LABEL: define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_pnormnan_or_unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub nnorm) [[PNORM_OR_NAN:%.*]], float [[B:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[PNORM_OR_NAN]], float [[B]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %pnorm.or.nan, float %b
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Keep select
+define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_nnormnan_or_unknown(i1 %cond, float nofpclass(inf sub zero pnorm) %nnorm.or.nan, float %b) {
+; CHECK-LABEL: define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_nnormnan_or_unknown(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub pnorm) [[NNORM_OR_NAN:%.*]], float [[B:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NNORM_OR_NAN]], float [[B]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %nnorm.or.nan, float %b
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+; Keep select, 0 result implies it could be 1
+define nofpclass(inf norm sub) float @ret_only_zero_nan__log__select_maybe_pnorm__else_negative_or_zero(i1 %cond, float nofpclass(nan inf sub zero nnorm) %maybe.pnorm, float nofpclass(nan pinf pnorm psub) %negative.or.zero) {
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_only_zero_nan__log__select_maybe_pnorm__else_negative_or_zero(
+; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan inf zero sub nnorm) [[MAYBE_PNORM:%.*]], float nofpclass(nan pinf psub pnorm) [[NEGATIVE_OR_ZERO:%.*]]) {
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MAYBE_PNORM]], float [[NEGATIVE_OR_ZERO]]
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: ret float [[RESULT]]
+;
+ %select = select i1 %cond, float %maybe.pnorm, float %negative.or.zero
+ %result = call float @llvm.log.f32(float %select)
+ ret float %result
+}
+
+attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
+attributes #1 = { "denormal-fp-math"="dynamic,dynamic" }
More information about the llvm-commits
mailing list