diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -19,6 +19,7 @@ #ifndef LLVM_ANALYSIS_CONSTANTFOLDING_H #define LLVM_ANALYSIS_CONSTANTFOLDING_H +#include "llvm/ADT/APFloat.h" #include namespace llvm { @@ -26,6 +27,7 @@ template class ArrayRef; class CallBase; class Constant; +class ConstantFP; class DSOLocalEquivalent; class DataLayout; class Function; @@ -70,11 +72,12 @@ /// ConstantFoldCompareInstOperands - Attempt to constant fold a compare /// instruction (icmp/fcmp) with the specified operands. If it fails, it /// returns a constant expression of the specified operands. -/// -Constant * -ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS, - Constant *RHS, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); +/// For fcmp, denormal constant input will be folded further according to the +/// denormal handling mode. +Constant *ConstantFoldCompareInstOperands( + unsigned Predicate, Constant *LHS, Constant *RHS, const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr, + DenormalMode::DenormalModeKind Mode = DenormalMode::IEEE); /// Attempt to constant fold a unary operation with the specified /// operand. If it fails, it returns a constant expression of the specified @@ -95,6 +98,10 @@ Constant *RHS, const DataLayout &DL, const Instruction *I); +/// Attempt to flush float point constant according to denormal mode. +ConstantFP *FlushFPConstant(ConstantFP *Operand, + DenormalMode::DenormalModeKind Mode); + /// Attempt to constant fold a select instruction with the specified /// operands. The constant result is returned if successful; if not, null is /// returned. diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -16,7 +16,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/ConstantFolding.h" -#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" @@ -1184,9 +1183,16 @@ Ops.push_back(Op); } - if (const auto *CI = dyn_cast(I)) + if (const auto *CI = dyn_cast(I)) { + DenormalMode::DenormalModeKind Mode = DenormalMode::IEEE; + if (isa(I->getOperand(0)) && I->getParent()) + Mode = + I->getFunction() + ->getDenormalMode(I->getOperand(0)->getType()->getFltSemantics()) + .Input; return ConstantFoldCompareInstOperands(CI->getPredicate(), Ops[0], Ops[1], - DL, TLI); + DL, TLI, Mode); + } if (const auto *LI = dyn_cast(I)) { if (LI->isVolatile()) @@ -1216,10 +1222,9 @@ return ConstantFoldInstOperandsImpl(I, I->getOpcode(), Ops, DL, TLI); } -Constant *llvm::ConstantFoldCompareInstOperands(unsigned IntPredicate, - Constant *Ops0, Constant *Ops1, - const DataLayout &DL, - const TargetLibraryInfo *TLI) { +Constant *llvm::ConstantFoldCompareInstOperands( + unsigned IntPredicate, Constant *Ops0, Constant *Ops1, const DataLayout &DL, + const TargetLibraryInfo *TLI, DenormalMode::DenormalModeKind Mode) { CmpInst::Predicate Predicate = (CmpInst::Predicate)IntPredicate; // fold: icmp (inttoptr x), null -> icmp x, 0 // fold: icmp null, (inttoptr x) -> icmp 0, x @@ -1321,6 +1326,13 @@ return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI); } + // Flush any denormal constant float input according to denormal handling + // mode. + if (isa(Ops0)) + Ops0 = FlushFPConstant(cast(Ops0), Mode); + if (isa(Ops1)) + Ops1 = FlushFPConstant(cast(Ops1), Mode); + return ConstantExpr::getCompare(Predicate, Ops0, Ops1); } @@ -1343,40 +1355,31 @@ } // Check whether a constant is a floating point denormal that should be flushed -// to zero according to the denormal handling mode set in the function -// attributes. If so, return a zero with the correct sign, otherwise return the -// original constant. Inputs and outputs to floating point instructions can have -// their mode set separately, so the direction is also needed. -Constant *FlushFPConstant(Constant *Operand, const llvm::Function *F, - bool IsOutput) { - if (F == nullptr) +// to zero according to the denormal handling mode. If so, return a zero with +// the correct sign, otherwise return the original constant. +ConstantFP *llvm::FlushFPConstant(ConstantFP *Operand, + DenormalMode::DenormalModeKind Mode) { + const APFloat &APF = Operand->getValueAPF(); + Type *Ty = Operand->getType(); + switch (Mode) { + default: + llvm_unreachable("unknown denormal mode"); return Operand; - if (auto *CFP = dyn_cast(Operand)) { - const APFloat &APF = CFP->getValueAPF(); - Type *Ty = CFP->getType(); - DenormalMode DenormMode = F->getDenormalMode(Ty->getFltSemantics()); - DenormalMode::DenormalModeKind Mode = - IsOutput ? DenormMode.Output : DenormMode.Input; - switch (Mode) { - default: - llvm_unreachable("unknown denormal mode"); - return Operand; - case DenormalMode::IEEE: - return Operand; - case DenormalMode::PreserveSign: - if (APF.isDenormal()) { - return ConstantFP::get( - Ty->getContext(), - APFloat::getZero(Ty->getFltSemantics(), APF.isNegative())); - } - return Operand; - case DenormalMode::PositiveZero: - if (APF.isDenormal()) { - return ConstantFP::get(Ty->getContext(), - APFloat::getZero(Ty->getFltSemantics(), false)); - } - return Operand; + case DenormalMode::IEEE: + return Operand; + case DenormalMode::PreserveSign: + if (APF.isDenormal()) { + return ConstantFP::get( + Ty->getContext(), + APFloat::getZero(Ty->getFltSemantics(), APF.isNegative())); } + return Operand; + case DenormalMode::PositiveZero: + if (APF.isDenormal()) { + return ConstantFP::get(Ty->getContext(), + APFloat::getZero(Ty->getFltSemantics(), false)); + } + return Operand; } return Operand; } @@ -1387,10 +1390,27 @@ if (auto *BB = I->getParent()) { if (auto *F = BB->getParent()) { if (Instruction::isBinaryOp(Opcode)) { - Constant *Op0 = FlushFPConstant(LHS, F, false); - Constant *Op1 = FlushFPConstant(RHS, F, false); + Constant *Op0 = + isa(LHS) + ? FlushFPConstant( + cast(LHS), + F->getDenormalMode(LHS->getType()->getFltSemantics()) + .Input) + : LHS; + Constant *Op1 = + isa(RHS) + ? FlushFPConstant( + cast(RHS), + F->getDenormalMode(RHS->getType()->getFltSemantics()) + .Input) + : RHS; Constant *C = ConstantFoldBinaryOpOperands(Opcode, Op0, Op1, DL); - return FlushFPConstant(C, F, true); + return isa(C) + ? FlushFPConstant( + cast(C), + F->getDenormalMode(C->getType()->getFltSemantics()) + .Output) + : C; } } } diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3899,8 +3899,14 @@ assert(CmpInst::isFPPredicate(Pred) && "Not an FP compare!"); if (Constant *CLHS = dyn_cast(LHS)) { - if (Constant *CRHS = dyn_cast(RHS)) - return ConstantFoldCompareInstOperands(Pred, CLHS, CRHS, Q.DL, Q.TLI); + if (Constant *CRHS = dyn_cast(RHS)) { + DenormalMode::DenormalModeKind Mode = DenormalMode::IEEE; + if (isa(LHS) && Q.CxtI && Q.CxtI->getParent()) + Mode = Q.CxtI->getFunction()->getDenormalMode( + LHS->getType()->getFltSemantics()).Input; + return ConstantFoldCompareInstOperands(Pred, CLHS, CRHS, Q.DL, Q.TLI, + Mode); + } // If we have a constant, make sure it is on the RHS. std::swap(LHS, RHS); @@ -4209,9 +4215,15 @@ if (!AllowRefinement && canCreatePoison(cast(I))) return nullptr; - if (CmpInst *C = dyn_cast(I)) + if (CmpInst *C = dyn_cast(I)) { + DenormalMode::DenormalModeKind Mode = DenormalMode::IEEE; + if (isa(ConstOps[0]) && C->getParent()) + Mode = C->getFunction() + ->getDenormalMode(ConstOps[0]->getType()->getFltSemantics()) + .Input; return ConstantFoldCompareInstOperands(C->getPredicate(), ConstOps[0], - ConstOps[1], Q.DL, Q.TLI); + ConstOps[1], Q.DL, Q.TLI, Mode); + } if (LoadInst *LI = dyn_cast(I)) if (!LI->isVolatile()) diff --git a/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll b/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll --- a/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll +++ b/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll @@ -763,7 +763,7 @@ define i1 @fcmp_double_positive_zero() #6 { ; CHECK-LABEL: @fcmp_double_positive_zero( ; CHECK-NEXT: entry: -; CHECK-NEXT: ret i1 true +; CHECK-NEXT: ret i1 false ; entry: %cmp = fcmp une double 0x0, 0x8000000000000 @@ -773,7 +773,7 @@ define i1 @fcmp_float_positive_zero() #6 { ; CHECK-LABEL: @fcmp_float_positive_zero( ; CHECK-NEXT: entry: -; CHECK-NEXT: ret i1 true +; CHECK-NEXT: ret i1 false ; entry: %cmp = fcmp une double 0x0, 0x8000000000000