Skip to content

Commit

Permalink
InstCombine: Introduce SimplifyDemandedUseFPClass
Browse files Browse the repository at this point in the history
This is the floating-point analog of SimplifyDemandedBits. If we know
the edge cases are assumed impossible in uses, it's possible to prune
upstream edge case handling.

Start by only using this on returns in functions with nofpclass
returns (where I'm surprised there are no other combines), but this
can be extended to include any other nofpclass use or FPMathOperator
with flags.

Partially addresses issue #64870

https://reviews.llvm.org/D158648
  • Loading branch information
arsenm committed Oct 5, 2023
1 parent bbdbcd8 commit 59c6e2e
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 111 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ struct KnownFPClass {
/// definitely set or false if the sign bit is definitely unset.
std::optional<bool> SignBit;

bool operator==(KnownFPClass Other) const {
return KnownFPClasses == Other.KnownFPClasses && SignBit == Other.SignBit;
}

/// Return true if it's known this can never be one of the mask entries.
bool isKnownNever(FPClassTest Mask) const {
return (KnownFPClasses & Mask) == fcNone;
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,15 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
APInt &UndefElts, unsigned Depth = 0,
bool AllowMultipleUsers = false) override;

/// Attempts to replace V with a simpler value based on the demanded
/// floating-point classes
Value *SimplifyDemandedUseFPClass(Value *V, FPClassTest DemandedMask,
KnownFPClass &Known, unsigned Depth,
Instruction *CxtI);
bool SimplifyDemandedFPClass(Instruction *I, unsigned Op,
FPClassTest DemandedMask, KnownFPClass &Known,
unsigned Depth = 0);

/// Canonicalize the position of binops relative to shufflevector.
Instruction *foldVectorBinop(BinaryOperator &Inst);
Instruction *foldVectorSelect(SelectInst &Sel);
Expand Down
113 changes: 113 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1781,3 +1781,116 @@ Value *InstCombinerImpl::SimplifyDemandedVectorElts(Value *V,

return MadeChange ? I : nullptr;
}

/// For floating-point classes that resolve to a single bit pattern, return that
/// value.
static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask) {
switch (Mask) {
case fcPosZero:
return ConstantFP::getZero(Ty);
case fcNegZero:
return ConstantFP::getZero(Ty, true);
case fcPosInf:
return ConstantFP::getInfinity(Ty);
case fcNegInf:
return ConstantFP::getInfinity(Ty, true);
case fcNone:
return PoisonValue::get(Ty);
default:
return nullptr;
}
}

Value *InstCombinerImpl::SimplifyDemandedUseFPClass(
Value *V, const FPClassTest DemandedMask, KnownFPClass &Known,
unsigned Depth, Instruction *CxtI) {
assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
Type *VTy = V->getType();

assert(Known == KnownFPClass() && "expected uninitialized state");

if (DemandedMask == fcNone)
return isa<UndefValue>(V) ? nullptr : PoisonValue::get(VTy);

if (Depth == MaxAnalysisRecursionDepth)
return nullptr;

Instruction *I = dyn_cast<Instruction>(V);
if (!I) {
// Handle constants and arguments
Known = computeKnownFPClass(V, fcAllFlags, CxtI, Depth + 1);
Value *FoldedToConst =
getFPClassConstant(VTy, DemandedMask & Known.KnownFPClasses);
return FoldedToConst == V ? nullptr : FoldedToConst;
}

if (!I->hasOneUse())
return nullptr;

// TODO: Should account for nofpclass/FastMathFlags on current instruction
switch (I->getOpcode()) {
case Instruction::FNeg: {
if (SimplifyDemandedFPClass(I, 0, llvm::fneg(DemandedMask), Known,
Depth + 1))
return I;
Known.fneg();
break;
}
case Instruction::Call: {
CallInst *CI = cast<CallInst>(I);
switch (CI->getIntrinsicID()) {
case Intrinsic::fabs:
if (SimplifyDemandedFPClass(I, 0, llvm::inverse_fabs(DemandedMask), Known,
Depth + 1))
return I;
Known.fabs();
break;
case Intrinsic::arithmetic_fence:
if (SimplifyDemandedFPClass(I, 0, DemandedMask, Known, Depth + 1))
return I;
break;
default:
Known = computeKnownFPClass(I, ~DemandedMask, CxtI, Depth + 1);
break;
}

break;
}
case Instruction::Select: {
KnownFPClass KnownLHS, KnownRHS;
if (SimplifyDemandedFPClass(I, 2, DemandedMask, KnownRHS, Depth + 1) ||
SimplifyDemandedFPClass(I, 1, DemandedMask, KnownLHS, Depth + 1))
return I;

if (KnownLHS.isKnownNever(DemandedMask))
return I->getOperand(2);
if (KnownRHS.isKnownNever(DemandedMask))
return I->getOperand(1);

// TODO: Recognize clamping patterns
Known = KnownLHS | KnownRHS;
break;
}
default:
Known = computeKnownFPClass(I, ~DemandedMask, CxtI, Depth + 1);
break;
}

return getFPClassConstant(VTy, DemandedMask & Known.KnownFPClasses);
}

bool InstCombinerImpl::SimplifyDemandedFPClass(Instruction *I, unsigned OpNo,
FPClassTest DemandedMask,
KnownFPClass &Known,
unsigned Depth) {
Use &U = I->getOperandUse(OpNo);
Value *NewVal =
SimplifyDemandedUseFPClass(U.get(), DemandedMask, Known, Depth, I);
if (!NewVal)
return false;
if (Instruction *OpInst = dyn_cast<Instruction>(U))
salvageDebugInfo(*OpInst);

replaceUse(U, NewVal);
return true;
}
18 changes: 16 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2732,8 +2732,22 @@ Instruction *InstCombinerImpl::visitFree(CallInst &FI, Value *Op) {
}

Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) {
// Nothing for now.
return nullptr;
Value *RetVal = RI.getReturnValue();
if (!RetVal || !AttributeFuncs::isNoFPClassCompatibleType(RetVal->getType()))
return nullptr;

Function *F = RI.getFunction();
FPClassTest ReturnClass = F->getAttributes().getRetNoFPClass();
if (ReturnClass == fcNone)
return nullptr;

KnownFPClass KnownClass;
Value *Simplified =
SimplifyDemandedUseFPClass(RetVal, ~ReturnClass, KnownClass, 0, &RI);
if (!Simplified)
return nullptr;

return ReturnInst::Create(RI.getContext(), Simplified);
}

// WARNING: keep in sync with SimplifyCFGOpt::simplifyUnreachable()!
Expand Down
Loading

2 comments on commit 59c6e2e

@hahnjo
Copy link
Member

@hahnjo hahnjo commented on 59c6e2e Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @arsenm, it appears this commit breaks clang/test/Headers/__clang_hip_math.hip: https://lab.llvm.org/buildbot/#/builders/109/builds/75022 Could you maybe have a look?

@hahnjo
Copy link
Member

@hahnjo hahnjo commented on 59c6e2e Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted in commit 26bb22b for now

Please sign in to comment.