Skip to content

Commit

Permalink
[InstructionSimplify] handle denormal input for fcmp
Browse files Browse the repository at this point in the history
Handle denormal constant input for fcmp instructions based on the
denormal handling mode.

Reviewed By: spatel, dcandler

Differential Revision: https://reviews.llvm.org/D128647
  • Loading branch information
chenzheng1030 committed Jul 1, 2022
1 parent 573c7e6 commit 758de0e
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 69 deletions.
23 changes: 15 additions & 8 deletions llvm/include/llvm/Analysis/ConstantFolding.h
Expand Up @@ -67,14 +67,13 @@ Constant *ConstantFoldInstOperands(Instruction *I, ArrayRef<Constant *> Ops,
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
Expand All @@ -95,6 +94,14 @@ Constant *ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
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.
Expand Down
104 changes: 55 additions & 49 deletions llvm/lib/Analysis/ConstantFolding.cpp
Expand Up @@ -1071,9 +1071,11 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
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:
Expand Down Expand Up @@ -1210,10 +1212,9 @@ Constant *llvm::ConstantFoldInstOperands(Instruction *I,
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
Expand Down Expand Up @@ -1315,6 +1316,11 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned IntPredicate,
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);
}

Expand All @@ -1336,57 +1342,57 @@ Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
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).
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Analysis/InstructionSimplify.cpp
Expand Up @@ -3900,7 +3900,8 @@ static Value *simplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,

if (Constant *CLHS = dyn_cast<Constant>(LHS)) {
if (Constant *CRHS = dyn_cast<Constant>(RHS))
return ConstantFoldCompareInstOperands(Pred, CLHS, CRHS, Q.DL, Q.TLI);
return ConstantFoldCompareInstOperands(Pred, CLHS, CRHS, Q.DL, Q.TLI,
Q.CxtI);

// If we have a constant, make sure it is on the RHS.
std::swap(LHS, RHS);
Expand Down
22 changes: 11 additions & 11 deletions llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll
Expand Up @@ -763,7 +763,7 @@ entry:
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
Expand All @@ -773,7 +773,7 @@ entry:
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
Expand All @@ -783,7 +783,7 @@ entry:
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
Expand All @@ -793,7 +793,7 @@ entry:
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
Expand Down Expand Up @@ -823,7 +823,7 @@ entry:
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
Expand All @@ -833,7 +833,7 @@ entry:
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
Expand All @@ -853,7 +853,7 @@ entry:
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
Expand Down Expand Up @@ -903,7 +903,7 @@ entry:
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
Expand All @@ -923,7 +923,7 @@ entry:
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
Expand Down Expand Up @@ -983,7 +983,7 @@ entry:
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
Expand Down Expand Up @@ -1043,7 +1043,7 @@ entry:
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
Expand Down

0 comments on commit 758de0e

Please sign in to comment.