Skip to content

Commit

Permalink
Reapply "InstCombine: Introduce SimplifyDemandedUseFPClass"" (#74056)
Browse files Browse the repository at this point in the history
This reverts commit ef38833.

The referenced issue violates the spec for finite-only math only by
using a return value for a constant infinity. If the interpretation
is results and arguments cannot violate nofpclass, then any
std::numeric_limits<T>::infinity() result is invalid under
-ffinite-math-only. Without this interpretation the utility of
nofpclass is slashed.
  • Loading branch information
arsenm committed Feb 8, 2024
1 parent a24b0c3 commit decbd29
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 134 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 @@ -248,6 +248,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 @@ -566,6 +566,15 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
APInt &PoisonElts, 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
136 changes: 136 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1877,3 +1877,139 @@ 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;
case Intrinsic::copysign: {
// Flip on more potentially demanded classes
const FPClassTest DemandedMaskAnySign = llvm::unknown_sign(DemandedMask);
if (SimplifyDemandedFPClass(I, 0, DemandedMaskAnySign, Known, Depth + 1))
return I;

if ((DemandedMask & fcPositive) == fcNone) {
// Roundabout way of replacing with fneg(fabs)
I->setOperand(1, ConstantFP::get(VTy, -1.0));
return I;
}

if ((DemandedMask & fcNegative) == fcNone) {
// Roundabout way of replacing with fabs
I->setOperand(1, ConstantFP::getZero(VTy));
return I;
}

KnownFPClass KnownSign =
computeKnownFPClass(I->getOperand(1), fcAllFlags, CxtI, Depth + 1);
Known.copysign(KnownSign);
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;
}
27 changes: 25 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ static cl::opt<unsigned>
MaxArraySize("instcombine-maxarray-size", cl::init(1024),
cl::desc("Maximum array size considered when doing a combine"));

// TODO: Remove this option
static cl::opt<bool> EnableSimplifyDemandedUseFPClass(
"instcombine-simplify-demanded-fp-class",
cl::desc("Enable demanded floating-point class optimizations"),
cl::init(false));

// FIXME: Remove this flag when it is no longer necessary to convert
// llvm.dbg.declare to avoid inaccurate debug info. Setting this to false
// increases variable availability at the cost of accuracy. Variables that
Expand Down Expand Up @@ -3105,8 +3111,25 @@ Instruction *InstCombinerImpl::visitFree(CallInst &FI, Value *Op) {
}

Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) {
// Nothing for now.
return nullptr;
if (!EnableSimplifyDemandedUseFPClass)
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

0 comments on commit decbd29

Please sign in to comment.