Skip to content

[ValueTracking][InstCombine] Generalize ignoreSignBitOfZero/NaN to handle more cases #141015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 28, 2025
11 changes: 6 additions & 5 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,13 @@ bool isKnownNeverNaN(const Value *V, unsigned Depth, const SimplifyQuery &SQ);
std::optional<bool> computeKnownFPSignBit(const Value *V, unsigned Depth,
const SimplifyQuery &SQ);

/// Return true if the sign bit of result can be ignored when the result is
/// zero.
bool ignoreSignBitOfZero(Instruction &I);
/// Return true if the sign bit of result can be ignored by the user when the
/// result is zero.
bool ignoreSignBitOfZero(const Use &U);

/// Return true if the sign bit of result can be ignored when the result is NaN.
bool ignoreSignBitOfNaN(Instruction &I);
/// Return true if the sign bit of result can be ignored by the user when the
/// result is NaN.
bool ignoreSignBitOfNaN(const Use &U);

/// If the specified value can be set by repeating the same byte in memory,
/// return the i8 value that it is represented with. This is true for all i8
Expand Down
38 changes: 13 additions & 25 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6357,17 +6357,10 @@ std::optional<bool> llvm::computeKnownFPSignBit(const Value *V, unsigned Depth,
return Known.SignBit;
}

/// Return true if the sign bit of result can be ignored when the result is
/// zero.
bool llvm::ignoreSignBitOfZero(Instruction &I) {
if (auto *FPOp = dyn_cast<FPMathOperator>(&I))
if (FPOp->hasNoSignedZeros())
return true;

// Check if the sign bit is ignored by the only user.
if (!I.hasOneUse())
return false;
Instruction *User = I.user_back();
/// Return true if the sign bit of result can be ignored by the user when the
/// result is zero.
bool llvm::ignoreSignBitOfZero(const Use &U) {
auto *User = cast<Instruction>(U.getUser());
if (auto *FPOp = dyn_cast<FPMathOperator>(User)) {
if (FPOp->hasNoSignedZeros())
return true;
Expand All @@ -6386,7 +6379,7 @@ bool llvm::ignoreSignBitOfZero(Instruction &I) {
case Intrinsic::fabs:
return true;
case Intrinsic::copysign:
return II->getArgOperand(0) == &I;
return U.getOperandNo() == 0;
case Intrinsic::is_fpclass:
case Intrinsic::vp_is_fpclass: {
auto Test =
Expand All @@ -6405,15 +6398,10 @@ bool llvm::ignoreSignBitOfZero(Instruction &I) {
}
}

bool llvm::ignoreSignBitOfNaN(Instruction &I) {
if (auto *FPOp = dyn_cast<FPMathOperator>(&I))
if (FPOp->hasNoNaNs())
return true;

// Check if the sign bit is ignored by the only user.
if (!I.hasOneUse())
return false;
Instruction *User = I.user_back();
/// Return true if the sign bit of result can be ignored by the user when the
/// result is NaN.
bool llvm::ignoreSignBitOfNaN(const Use &U) {
auto *User = cast<Instruction>(U.getUser());
if (auto *FPOp = dyn_cast<FPMathOperator>(User)) {
if (FPOp->hasNoNaNs())
return true;
Expand All @@ -6439,7 +6427,7 @@ bool llvm::ignoreSignBitOfNaN(Instruction &I) {
case Instruction::PHI:
return false;
case Instruction::Ret:
return I.getFunction()->getAttributes().getRetNoFPClass() &
return User->getFunction()->getAttributes().getRetNoFPClass() &
FPClassTest::fcNan;
case Instruction::Call:
case Instruction::Invoke: {
Expand All @@ -6448,7 +6436,7 @@ bool llvm::ignoreSignBitOfNaN(Instruction &I) {
case Intrinsic::fabs:
return true;
case Intrinsic::copysign:
return II->getArgOperand(0) == &I;
return U.getOperandNo() == 0;
// Other proper FP math intrinsics ignore the sign bit of NaN.
case Intrinsic::maxnum:
case Intrinsic::minnum:
Expand All @@ -6472,8 +6460,8 @@ bool llvm::ignoreSignBitOfNaN(Instruction &I) {
}
}

FPClassTest NoFPClass = cast<CallBase>(User)->getParamNoFPClass(
I.uses().begin()->getOperandNo());
FPClassTest NoFPClass =
cast<CallBase>(User)->getParamNoFPClass(U.getOperandNo());
return NoFPClass & FPClassTest::fcNan;
}
default:
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2797,7 +2797,8 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
// of NAN, but IEEE-754 specifies the signbit of NAN values with
// fneg/fabs operations.
if (match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(X))) &&
(cast<FPMathOperator>(CondVal)->hasNoNaNs() || ignoreSignBitOfNaN(SI) ||
(cast<FPMathOperator>(CondVal)->hasNoNaNs() || SI.hasNoNaNs() ||
(SI.hasOneUse() && ignoreSignBitOfNaN(*SI.use_begin())) ||
isKnownNeverNaN(X, /*Depth=*/0,
IC.getSimplifyQuery().getWithInstruction(
cast<Instruction>(CondVal))))) {
Expand Down Expand Up @@ -2844,7 +2845,11 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
// Note: We require "nnan" for this fold because fcmp ignores the signbit
// of NAN, but IEEE-754 specifies the signbit of NAN values with
// fneg/fabs operations.
if (!ignoreSignBitOfZero(SI) || !ignoreSignBitOfNaN(SI))
if (!SI.hasNoSignedZeros() &&
!(SI.hasOneUse() && ignoreSignBitOfZero(*SI.use_begin())))
return nullptr;
if (!SI.hasNoNaNs() &&
!(SI.hasOneUse() && ignoreSignBitOfNaN(*SI.use_begin())))
return nullptr;

if (Swap)
Expand Down