diff options
author | Matt Arsenault <Matthew.Arsenault@amd.com> | 2024-11-13 07:43:50 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-13 07:43:50 -0800 |
commit | cd88bfcb5906049e1387b856fc7256e5fae22e5f (patch) | |
tree | b70098a1343ac14da8a86e46ca12a3c885120f9d /llvm/lib/Analysis/ConstantFolding.cpp | |
parent | 1e5bfac933ea90ec4361446398551dd6b967c67f (diff) | |
download | llvm-cd88bfcb5906049e1387b856fc7256e5fae22e5f.zip llvm-cd88bfcb5906049e1387b856fc7256e5fae22e5f.tar.gz llvm-cd88bfcb5906049e1387b856fc7256e5fae22e5f.tar.bz2 |
ConstantFolding: Do not fold fcmp of denormal without known mode (#115407)
Fixes #114947
Diffstat (limited to 'llvm/lib/Analysis/ConstantFolding.cpp')
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 145 |
1 files changed, 105 insertions, 40 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 88db315..1971c28f 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1266,14 +1266,16 @@ Constant *llvm::ConstantFoldCompareInstOperands( return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI); } - // Flush any denormal constant float input according to denormal handling - // mode. - Ops0 = FlushFPConstant(Ops0, I, /* IsOutput */ false); - if (!Ops0) - return nullptr; - Ops1 = FlushFPConstant(Ops1, I, /* IsOutput */ false); - if (!Ops1) - return nullptr; + if (CmpInst::isFPPredicate(Predicate)) { + // Flush any denormal constant float input according to denormal handling + // mode. + Ops0 = FlushFPConstant(Ops0, I, /*IsOutput=*/false); + if (!Ops0) + return nullptr; + Ops1 = FlushFPConstant(Ops1, I, /*IsOutput=*/false); + if (!Ops1) + return nullptr; + } return ConstantFoldCompareInstruction(Predicate, Ops0, Ops1); } @@ -1298,47 +1300,110 @@ Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS, return ConstantFoldBinaryInstruction(Opcode, LHS, RHS); } -Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I, - bool IsOutput) { - if (!I || !I->getParent() || !I->getFunction()) - return Operand; +static ConstantFP *flushDenormalConstant(Type *Ty, const APFloat &APF, + DenormalMode::DenormalModeKind Mode) { + switch (Mode) { + case DenormalMode::Dynamic: + return nullptr; + case DenormalMode::IEEE: + return ConstantFP::get(Ty->getContext(), APF); + case DenormalMode::PreserveSign: + return ConstantFP::get( + Ty->getContext(), + APFloat::getZero(APF.getSemantics(), APF.isNegative())); + case DenormalMode::PositiveZero: + return ConstantFP::get(Ty->getContext(), + APFloat::getZero(APF.getSemantics(), false)); + default: + break; + } - ConstantFP *CFP = dyn_cast<ConstantFP>(Operand); - if (!CFP) - return Operand; + llvm_unreachable("unknown denormal mode"); +} + +/// Return the denormal mode that can be assumed when executing a floating point +/// operation at \p CtxI. +static DenormalMode getInstrDenormalMode(const Instruction *CtxI, Type *Ty) { + if (!CtxI || !CtxI->getParent() || !CtxI->getFunction()) + return DenormalMode::getDynamic(); + return CtxI->getFunction()->getDenormalMode(Ty->getFltSemantics()); +} +static ConstantFP *flushDenormalConstantFP(ConstantFP *CFP, + const Instruction *Inst, + bool IsOutput) { const APFloat &APF = CFP->getValueAPF(); - // TODO: Should this canonicalize nans? if (!APF.isDenormal()) - return Operand; + return CFP; - Type *Ty = CFP->getType(); - DenormalMode DenormMode = - I->getFunction()->getDenormalMode(Ty->getFltSemantics()); - DenormalMode::DenormalModeKind Mode = - IsOutput ? DenormMode.Output : DenormMode.Input; - switch (Mode) { - default: - llvm_unreachable("unknown denormal mode"); - case DenormalMode::Dynamic: - return nullptr; - case DenormalMode::IEEE: + DenormalMode Mode = getInstrDenormalMode(Inst, CFP->getType()); + return flushDenormalConstant(CFP->getType(), APF, + IsOutput ? Mode.Output : Mode.Input); +} + +Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *Inst, + bool IsOutput) { + if (ConstantFP *CFP = dyn_cast<ConstantFP>(Operand)) + return flushDenormalConstantFP(CFP, Inst, IsOutput); + + if (isa<ConstantAggregateZero, UndefValue, ConstantExpr>(Operand)) return Operand; - case DenormalMode::PreserveSign: - if (APF.isDenormal()) { - return ConstantFP::get( - Ty->getContext(), - APFloat::getZero(Ty->getFltSemantics(), APF.isNegative())); + + Type *Ty = Operand->getType(); + VectorType *VecTy = dyn_cast<VectorType>(Ty); + if (VecTy) { + if (auto *Splat = dyn_cast_or_null<ConstantFP>(Operand->getSplatValue())) { + ConstantFP *Folded = flushDenormalConstantFP(Splat, Inst, IsOutput); + if (!Folded) + return nullptr; + return ConstantVector::getSplat(VecTy->getElementCount(), Folded); } - return Operand; - case DenormalMode::PositiveZero: - if (APF.isDenormal()) { - return ConstantFP::get(Ty->getContext(), - APFloat::getZero(Ty->getFltSemantics(), false)); + + Ty = VecTy->getElementType(); + } + + if (const auto *CV = dyn_cast<ConstantVector>(Operand)) { + SmallVector<Constant *, 16> NewElts; + for (unsigned i = 0, e = CV->getNumOperands(); i != e; ++i) { + Constant *Element = CV->getAggregateElement(i); + if (isa<UndefValue>(Element)) { + NewElts.push_back(Element); + continue; + } + + ConstantFP *CFP = dyn_cast<ConstantFP>(Element); + if (!CFP) + return nullptr; + + ConstantFP *Folded = flushDenormalConstantFP(CFP, Inst, IsOutput); + if (!Folded) + return nullptr; + NewElts.push_back(Folded); } - return Operand; + + return ConstantVector::get(NewElts); + } + + if (const auto *CDV = dyn_cast<ConstantDataVector>(Operand)) { + SmallVector<Constant *, 16> NewElts; + for (unsigned I = 0, E = CDV->getNumElements(); I < E; ++I) { + const APFloat &Elt = CDV->getElementAsAPFloat(I); + if (!Elt.isDenormal()) { + NewElts.push_back(ConstantFP::get(Ty, Elt)); + } else { + DenormalMode Mode = getInstrDenormalMode(Inst, Ty); + ConstantFP *Folded = + flushDenormalConstant(Ty, Elt, IsOutput ? Mode.Output : Mode.Input); + if (!Folded) + return nullptr; + NewElts.push_back(Folded); + } + } + + return ConstantVector::get(NewElts); } - return Operand; + + return nullptr; } Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS, |