forked from OSchip/llvm-project
[InstCombine] refactor fabs+fcmp fold; NFC
Also, remove/replace/minimize/enhance the tests for this fold. The code drops FMF, so it needs more tests and at least 1 fix. llvm-svn: 345734
This commit is contained in:
parent
0f46e34f74
commit
1c254c6716
|
@ -5288,6 +5288,46 @@ static Instruction *foldFCmpReciprocalAndZero(FCmpInst &I, Instruction *LHSI,
|
|||
return NewFCI;
|
||||
}
|
||||
|
||||
/// Optimize fabs(X) compared with zero.
|
||||
static Instruction *foldFabsWithFcmpZero(FCmpInst &I) {
|
||||
Value *X;
|
||||
if (!match(I.getOperand(0), m_Intrinsic<Intrinsic::fabs>(m_Value(X))) ||
|
||||
!match(I.getOperand(1), m_PosZeroFP()))
|
||||
return nullptr;
|
||||
|
||||
switch (I.getPredicate()) {
|
||||
case FCmpInst::FCMP_UGE:
|
||||
case FCmpInst::FCMP_OLT:
|
||||
// fabs(X) >= 0.0 --> true
|
||||
// fabs(X) < 0.0 --> false
|
||||
llvm_unreachable("fcmp should have simplified");
|
||||
|
||||
case FCmpInst::FCMP_OGT:
|
||||
// fabs(X) > 0.0 --> X != 0.0
|
||||
return new FCmpInst(FCmpInst::FCMP_ONE, X, I.getOperand(1));
|
||||
|
||||
case FCmpInst::FCMP_OLE:
|
||||
// fabs(X) <= 0.0 --> X == 0.0
|
||||
return new FCmpInst(FCmpInst::FCMP_OEQ, X, I.getOperand(1));
|
||||
|
||||
case FCmpInst::FCMP_OGE:
|
||||
// fabs(X) >= 0.0 --> !isnan(X)
|
||||
assert(!I.hasNoNaNs() && "fcmp should have simplified");
|
||||
return new FCmpInst(FCmpInst::FCMP_ORD, X, I.getOperand(1));
|
||||
|
||||
case FCmpInst::FCMP_OEQ:
|
||||
case FCmpInst::FCMP_UEQ:
|
||||
case FCmpInst::FCMP_ONE:
|
||||
case FCmpInst::FCMP_UNE:
|
||||
// fabs(X) == 0.0 --> X == 0.0
|
||||
// fabs(X) != 0.0 --> X != 0.0
|
||||
return new FCmpInst(I.getPredicate(), X, I.getOperand(1));
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) {
|
||||
bool Changed = false;
|
||||
|
||||
|
@ -5418,45 +5458,11 @@ Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) {
|
|||
if (Instruction *Res = foldCmpLoadFromIndexedGlobal(GEP, GV, I))
|
||||
return Res;
|
||||
break;
|
||||
case Instruction::Call: {
|
||||
if (!RHSC->isNullValue())
|
||||
break;
|
||||
|
||||
CallInst *CI = cast<CallInst>(LHSI);
|
||||
Intrinsic::ID IID = getIntrinsicForCallSite(CI, &TLI);
|
||||
if (IID != Intrinsic::fabs)
|
||||
break;
|
||||
|
||||
// Various optimization for fabs compared with zero.
|
||||
switch (Pred) {
|
||||
default:
|
||||
break;
|
||||
case FCmpInst::FCMP_UGE:
|
||||
case FCmpInst::FCMP_OLT:
|
||||
// fabs(x) >= 0.0 --> true
|
||||
// fabs(x) < 0.0 --> false
|
||||
llvm_unreachable("fcmp should have simplified");
|
||||
|
||||
// fabs(x) > 0 --> x != 0
|
||||
case FCmpInst::FCMP_OGT:
|
||||
return new FCmpInst(FCmpInst::FCMP_ONE, CI->getArgOperand(0), RHSC);
|
||||
// fabs(x) <= 0 --> x == 0
|
||||
case FCmpInst::FCMP_OLE:
|
||||
return new FCmpInst(FCmpInst::FCMP_OEQ, CI->getArgOperand(0), RHSC);
|
||||
// fabs(x) >= 0 --> !isnan(x)
|
||||
case FCmpInst::FCMP_OGE:
|
||||
assert(!I.hasNoNaNs() && "fcmp should have simplified");
|
||||
return new FCmpInst(FCmpInst::FCMP_ORD, CI->getArgOperand(0), RHSC);
|
||||
// fabs(x) == 0 --> x == 0
|
||||
// fabs(x) != 0 --> x != 0
|
||||
case FCmpInst::FCMP_OEQ:
|
||||
case FCmpInst::FCMP_UEQ:
|
||||
case FCmpInst::FCMP_ONE:
|
||||
case FCmpInst::FCMP_UNE:
|
||||
return new FCmpInst(Pred, CI->getArgOperand(0), RHSC);
|
||||
}
|
||||
}
|
||||
}
|
||||
case Instruction::Call:
|
||||
if (Instruction *X = foldFabsWithFcmpZero(I))
|
||||
return X;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fcmp pred (fneg x), (fneg y) -> fcmp swap(pred) x, y
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -instcombine < %s | FileCheck %s
|
||||
|
||||
declare double @llvm.fabs.f64(double) readnone
|
||||
declare half @llvm.fabs.f16(half)
|
||||
declare double @llvm.fabs.f64(double)
|
||||
declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
|
||||
|
||||
define i1 @test1(float %x, float %y) {
|
||||
; CHECK-LABEL: @test1(
|
||||
|
@ -133,194 +135,92 @@ define float @test8(float %x) {
|
|||
; Float comparison to zero shouldn't cast to double.
|
||||
}
|
||||
|
||||
declare double @fabs(double) readnone
|
||||
|
||||
define i32 @test9(double %a) {
|
||||
; CHECK-LABEL: @test9(
|
||||
; CHECK-NEXT: ret i32 0
|
||||
define i1 @fabs_uge(double %a) {
|
||||
; CHECK-LABEL: @fabs_uge(
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp olt double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp uge double %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test9_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test9_intrinsic(
|
||||
; CHECK-NEXT: ret i32 0
|
||||
define i1 @fabs_olt(half %a) {
|
||||
; CHECK-LABEL: @fabs_olt(
|
||||
; CHECK-NEXT: ret i1 false
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp olt double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call half @llvm.fabs.f16(half %a)
|
||||
%cmp = fcmp olt half %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test10(double %a) {
|
||||
; CHECK-LABEL: @test10(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
define <2 x i1> @fabs_ole(<2 x float> %a) {
|
||||
; CHECK-LABEL: @fabs_ole(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq <2 x float> [[A:%.*]], zeroinitializer
|
||||
; CHECK-NEXT: ret <2 x i1> [[CMP]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp ole double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
|
||||
%cmp = fcmp ole <2 x float> %call, zeroinitializer
|
||||
ret <2 x i1> %cmp
|
||||
}
|
||||
|
||||
define i32 @test10_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test10_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp ole double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test11(double %a) {
|
||||
; CHECK-LABEL: @test11(
|
||||
define i1 @fabs_ogt(double %a) {
|
||||
; CHECK-LABEL: @fabs_ogt(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp ogt double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp ogt double %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test11_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test11_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp ogt double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test12(double %a) {
|
||||
; CHECK-LABEL: @test12(
|
||||
define i1 @fabs_oge(double %a) {
|
||||
; CHECK-LABEL: @fabs_oge(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp ord double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp oge double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp oge double %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test12_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test12_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp ord double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
define i1 @fabs_une(half %a) {
|
||||
; CHECK-LABEL: @fabs_une(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp une half [[A:%.*]], 0xH0000
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp oge double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call half @llvm.fabs.f16(half %a)
|
||||
%cmp = fcmp une half %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test13(double %a) {
|
||||
; CHECK-LABEL: @test13(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp une double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test13_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test13_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp une double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test14(double %a) {
|
||||
; CHECK-LABEL: @test14(
|
||||
define i1 @fabs_oeq(double %a) {
|
||||
; CHECK-LABEL: @fabs_oeq(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp oeq double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp oeq double %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test14_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test14_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp oeq double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test15(double %a) {
|
||||
; CHECK-LABEL: @test15(
|
||||
define i1 @fabs_one(double %a) {
|
||||
; CHECK-LABEL: @fabs_one(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp one double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp one double %call, 0.0
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i32 @test15_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test15_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
define <2 x i1> @fabs_ueq(<2 x float> %a) {
|
||||
; CHECK-LABEL: @fabs_ueq(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq <2 x float> [[A:%.*]], zeroinitializer
|
||||
; CHECK-NEXT: ret <2 x i1> [[CMP]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp one double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test16(double %a) {
|
||||
; CHECK-LABEL: @test16(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @fabs(double %a)
|
||||
%cmp = fcmp ueq double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define i32 @test16_intrinsic(double %a) {
|
||||
; CHECK-LABEL: @test16_intrinsic(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq double [[A:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
|
||||
; CHECK-NEXT: ret i32 [[CONV]]
|
||||
;
|
||||
%call = tail call double @llvm.fabs.f64(double %a)
|
||||
%cmp = fcmp ueq double %call, 0.000000e+00
|
||||
%conv = zext i1 %cmp to i32
|
||||
ret i32 %conv
|
||||
%call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
|
||||
%cmp = fcmp ueq <2 x float> %call, zeroinitializer
|
||||
ret <2 x i1> %cmp
|
||||
}
|
||||
|
||||
; Don't crash.
|
||||
|
|
Loading…
Reference in New Issue