const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr);
-/// 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);
+/// 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.
+/// Denormal inputs may be flushed based on the denormal handling mode.
+Constant *ConstantFoldCompareInstOperands(
+ unsigned Predicate, Constant *LHS, Constant *RHS, const DataLayout &DL,
+ const TargetLibraryInfo *TLI = nullptr, const Instruction *I = nullptr);
/// Attempt to constant fold a unary operation with the specified
/// operand. If it fails, it returns a constant expression of the specified
Constant *RHS, const DataLayout &DL,
const Instruction *I);
+/// Attempt to flush float point constant according to denormal mode set in the
+/// instruction's parent 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 Instruction *I,
+ bool IsOutput);
+
/// Attempt to constant fold a select instruction with the specified
/// operands. The constant result is returned if successful; if not, null is
/// returned.
switch (Opcode) {
default: return nullptr;
case Instruction::ICmp:
- case Instruction::FCmp:
- return ConstantFoldCompareInstOperands(
- cast<CmpInst>(InstOrCE)->getPredicate(), Ops[0], Ops[1], DL, TLI);
+ case Instruction::FCmp: {
+ auto *C = cast<CmpInst>(InstOrCE);
+ return ConstantFoldCompareInstOperands(C->getPredicate(), Ops[0], Ops[1],
+ DL, TLI, C);
+ }
case Instruction::Freeze:
return isGuaranteedNotToBeUndefOrPoison(Ops[0]) ? Ops[0] : nullptr;
case Instruction::Call:
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, const Instruction *I) {
CmpInst::Predicate Predicate = (CmpInst::Predicate)IntPredicate;
// fold: icmp (inttoptr x), null -> icmp x, 0
// fold: icmp null, (inttoptr x) -> icmp 0, x
return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI);
}
+ // Flush any denormal constant float input according to denormal handling
+ // mode.
+ Ops0 = FlushFPConstant(Ops0, I, /* IsOutput */ false);
+ Ops1 = FlushFPConstant(Ops1, I, /* IsOutput */ false);
+
return ConstantExpr::getCompare(Predicate, Ops0, Ops1);
}
return ConstantExpr::get(Opcode, LHS, RHS);
}
-// 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)
+Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I,
+ bool IsOutput) {
+ if (!I || !I->getParent() || !I->getFunction())
return Operand;
- if (auto *CFP = dyn_cast<ConstantFP>(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;
+
+ ConstantFP *CFP = dyn_cast<ConstantFP>(Operand);
+ if (!CFP)
+ return Operand;
+
+ const APFloat &APF = CFP->getValueAPF();
+ 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");
+ 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;
}
Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
Constant *RHS, const DataLayout &DL,
const Instruction *I) {
- 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 *C = ConstantFoldBinaryOpOperands(Opcode, Op0, Op1, DL);
- return FlushFPConstant(C, F, true);
- }
- }
+ if (Instruction::isBinaryOp(Opcode)) {
+ // Flush denormal inputs if needed.
+ Constant *Op0 = FlushFPConstant(LHS, I, /* IsOutput */ false);
+ Constant *Op1 = FlushFPConstant(RHS, I, /* IsOutput */ false);
+
+ // Calculate constant result.
+ Constant *C = ConstantFoldBinaryOpOperands(Opcode, Op0, Op1, DL);
+
+ // Flush denormal output if needed.
+ return FlushFPConstant(C, I, /* IsOutput */ true);
}
// If instruction lacks a parent/function and the denormal mode cannot be
// determined, use the default (IEEE).
define i1 @fcmp_double_pz_in_pz_out() #6 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une double 0x0008000000000000, 0x0
define i1 @fcmp_float_pz_in_pz_out() #6 {
; CHECK-LABEL: @fcmp_float_pz_in_pz_out(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une float 0x3800000000000000, 0x0
define i1 @fcmp_double_ps_in_ps_out() #7 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une double 0x0008000000000000, 0x0
define i1 @fcmp_float_ps_in_ps_out() #7 {
; CHECK-LABEL: @fcmp_float_ps_in_ps_out(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une float 0x3800000000000000, 0x0
define i1 @fcmp_double_ieee_out_pz_in() #3 {
; CHECK-LABEL: @fcmp_double_ieee_out_pz_in(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une double 0x0008000000000000, 0x0
define i1 @fcmp_double_ieee_out_ps_in() #4 {
; CHECK-LABEL: @fcmp_double_ieee_out_ps_in(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une double 0x0008000000000000, 0x0
define i1 @fcmp_double_two_denormal_ins() #6 {
; CHECK-LABEL: @fcmp_double_two_denormal_ins(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp une double 0x0008100000000000, 0x0008000000000000
define i1 @fcmp_double_ps_in_ps_out_oeq() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_oeq(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT: ret i1 true
;
entry:
%cmp = fcmp oeq double 0x0008100000000000, 0x0008000000000000
define i1 @fcmp_double_ps_in_ps_out_one() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_one(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp one double 0x0008100000000000, 0x0008000000000000
define i1 @fcmp_double_pz_in_pz_out_ugt() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_ugt(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: ret i1 false
;
entry:
%cmp = fcmp ugt double 0x0008000000000000, 0x0
define i1 @fcmp_double_pz_in_pz_out_ule() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_ule(
; CHECK-NEXT: entry:
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT: ret i1 true
;
entry:
%cmp = fcmp ule double 0x0008000000000000, 0x0