forked from OSchip/llvm-project
[InstCombine] Fold 'icmp eq/ne (?trunc (lshr/ashr %x, bitwidth(x)-1)), 0' -> 'icmp sge/slt %x, 0'
We do indeed already get it right in some cases, but only transitively, with one-use restrictions. Since we only need to produce a single comparison, it makes sense to match the pattern directly: https://rise4fun.com/Alive/kPg llvm-svn: 373802
This commit is contained in:
parent
f304d4d185
commit
fb5af8b9b9
|
@ -1384,6 +1384,29 @@ Instruction *InstCombiner::foldIRemByPowerOfTwoToBitTest(ICmpInst &I) {
|
||||||
return ICmpInst::Create(Instruction::ICmp, Pred, Masked, Zero);
|
return ICmpInst::Create(Instruction::ICmp, Pred, Masked, Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fold equality-comparison between zero and any (maybe truncated) right-shift
|
||||||
|
/// by one-less-than-bitwidth into a sign test on the original value.
|
||||||
|
Instruction *foldSignBitTest(ICmpInst &I) {
|
||||||
|
ICmpInst::Predicate Pred;
|
||||||
|
Value *X;
|
||||||
|
Constant *C;
|
||||||
|
if (!I.isEquality() ||
|
||||||
|
!match(&I, m_ICmp(Pred, m_TruncOrSelf(m_Shr(m_Value(X), m_Constant(C))),
|
||||||
|
m_Zero())))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Type *XTy = X->getType();
|
||||||
|
unsigned XBitWidth = XTy->getScalarSizeInBits();
|
||||||
|
if (!match(C, m_SpecificInt_ICMP(ICmpInst::Predicate::ICMP_EQ,
|
||||||
|
APInt(XBitWidth, XBitWidth - 1))))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return ICmpInst::Create(Instruction::ICmp,
|
||||||
|
Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_SGE
|
||||||
|
: ICmpInst::ICMP_SLT,
|
||||||
|
X, ConstantInt::getNullValue(XTy));
|
||||||
|
}
|
||||||
|
|
||||||
// Handle icmp pred X, 0
|
// Handle icmp pred X, 0
|
||||||
Instruction *InstCombiner::foldICmpWithZero(ICmpInst &Cmp) {
|
Instruction *InstCombiner::foldICmpWithZero(ICmpInst &Cmp) {
|
||||||
CmpInst::Predicate Pred = Cmp.getPredicate();
|
CmpInst::Predicate Pred = Cmp.getPredicate();
|
||||||
|
@ -5449,6 +5472,11 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) {
|
||||||
if (Instruction *Res = foldICmpInstWithConstant(I))
|
if (Instruction *Res = foldICmpInstWithConstant(I))
|
||||||
return Res;
|
return Res;
|
||||||
|
|
||||||
|
// Try to match comparison as a sign bit test. Intentionally do this after
|
||||||
|
// foldICmpInstWithConstant() to potentially let other folds to happen first.
|
||||||
|
if (Instruction *New = foldSignBitTest(I))
|
||||||
|
return New;
|
||||||
|
|
||||||
if (Instruction *Res = foldICmpInstWithConstantNotInt(I))
|
if (Instruction *Res = foldICmpInstWithConstantNotInt(I))
|
||||||
return Res;
|
return Res;
|
||||||
|
|
||||||
|
|
|
@ -428,8 +428,8 @@ define i8 @test28a(i8 %x, i8 %y) {
|
||||||
; CHECK-LABEL: @test28a(
|
; CHECK-LABEL: @test28a(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[X:%.*]], 7
|
; CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[X:%.*]], 7
|
||||||
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i8 [[TMP1]], 0
|
; CHECK-NEXT: [[COND1:%.*]] = icmp slt i8 [[X]], 0
|
||||||
; CHECK-NEXT: br i1 [[COND1]], label [[BB2:%.*]], label [[BB1:%.*]]
|
; CHECK-NEXT: br i1 [[COND1]], label [[BB1:%.*]], label [[BB2:%.*]]
|
||||||
; CHECK: bb1:
|
; CHECK: bb1:
|
||||||
; CHECK-NEXT: ret i8 [[TMP1]]
|
; CHECK-NEXT: ret i8 [[TMP1]]
|
||||||
; CHECK: bb2:
|
; CHECK: bb2:
|
||||||
|
|
|
@ -44,9 +44,7 @@ define i1 @highest_bit_test_via_ashr(i32 %data, i32 %nbits) {
|
||||||
|
|
||||||
define i1 @highest_bit_test_via_ashr_with_truncation(i64 %data, i32 %nbits) {
|
define i1 @highest_bit_test_via_ashr_with_truncation(i64 %data, i32 %nbits) {
|
||||||
; CHECK-LABEL: @highest_bit_test_via_ashr_with_truncation(
|
; CHECK-LABEL: @highest_bit_test_via_ashr_with_truncation(
|
||||||
; CHECK-NEXT: [[TMP1:%.*]] = ashr i64 [[DATA:%.*]], 63
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[DATA:%.*]], 0
|
||||||
; CHECK-NEXT: [[SIGNBIT:%.*]] = trunc i64 [[TMP1]] to i32
|
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0
|
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%num_low_bits_to_skip = sub i32 64, %nbits
|
%num_low_bits_to_skip = sub i32 64, %nbits
|
||||||
|
@ -75,7 +73,7 @@ define i1 @unsigned_sign_bit_extract_extrause(i32 %x) {
|
||||||
; CHECK-LABEL: @unsigned_sign_bit_extract_extrause(
|
; CHECK-LABEL: @unsigned_sign_bit_extract_extrause(
|
||||||
; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[X:%.*]], 31
|
; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[X:%.*]], 31
|
||||||
; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]])
|
; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]])
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[X]], 0
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%signbit = lshr i32 %x, 31
|
%signbit = lshr i32 %x, 31
|
||||||
|
@ -87,7 +85,7 @@ define i1 @unsigned_sign_bit_extract_extrause__ispositive(i32 %x) {
|
||||||
; CHECK-LABEL: @unsigned_sign_bit_extract_extrause__ispositive(
|
; CHECK-LABEL: @unsigned_sign_bit_extract_extrause__ispositive(
|
||||||
; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[X:%.*]], 31
|
; CHECK-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[X:%.*]], 31
|
||||||
; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]])
|
; CHECK-NEXT: call void @use32(i32 [[SIGNBIT]])
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp eq i32 [[SIGNBIT]], 0
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp sgt i32 [[X]], -1
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%signbit = lshr i32 %x, 31
|
%signbit = lshr i32 %x, 31
|
||||||
|
@ -108,7 +106,7 @@ define i1 @signed_sign_bit_extract_extrause(i32 %x) {
|
||||||
; CHECK-LABEL: @signed_sign_bit_extract_extrause(
|
; CHECK-LABEL: @signed_sign_bit_extract_extrause(
|
||||||
; CHECK-NEXT: [[SIGNSMEAR:%.*]] = ashr i32 [[X:%.*]], 31
|
; CHECK-NEXT: [[SIGNSMEAR:%.*]] = ashr i32 [[X:%.*]], 31
|
||||||
; CHECK-NEXT: call void @use32(i32 [[SIGNSMEAR]])
|
; CHECK-NEXT: call void @use32(i32 [[SIGNSMEAR]])
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNSMEAR]], 0
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[X]], 0
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%signsmear = ashr i32 %x, 31
|
%signsmear = ashr i32 %x, 31
|
||||||
|
@ -132,7 +130,7 @@ define i1 @unsigned_sign_bit_extract_with_trunc_extrause(i64 %x) {
|
||||||
; CHECK-NEXT: call void @use64(i64 [[SIGNBIT]])
|
; CHECK-NEXT: call void @use64(i64 [[SIGNBIT]])
|
||||||
; CHECK-NEXT: [[SIGNBIT_NARROW:%.*]] = trunc i64 [[SIGNBIT]] to i32
|
; CHECK-NEXT: [[SIGNBIT_NARROW:%.*]] = trunc i64 [[SIGNBIT]] to i32
|
||||||
; CHECK-NEXT: call void @use32(i32 [[SIGNBIT_NARROW]])
|
; CHECK-NEXT: call void @use32(i32 [[SIGNBIT_NARROW]])
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT_NARROW]], 0
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[X]], 0
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%signbit = lshr i64 %x, 63
|
%signbit = lshr i64 %x, 63
|
||||||
|
@ -144,9 +142,7 @@ define i1 @unsigned_sign_bit_extract_with_trunc_extrause(i64 %x) {
|
||||||
}
|
}
|
||||||
define i1 @signed_sign_bit_extract_trunc(i64 %x) {
|
define i1 @signed_sign_bit_extract_trunc(i64 %x) {
|
||||||
; CHECK-LABEL: @signed_sign_bit_extract_trunc(
|
; CHECK-LABEL: @signed_sign_bit_extract_trunc(
|
||||||
; CHECK-NEXT: [[SIGNSMEAR:%.*]] = ashr i64 [[X:%.*]], 63
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[X:%.*]], 0
|
||||||
; CHECK-NEXT: [[SIGNSMEAR_NARROW:%.*]] = trunc i64 [[SIGNSMEAR]] to i32
|
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNSMEAR_NARROW]], 0
|
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%signsmear = ashr i64 %x, 63
|
%signsmear = ashr i64 %x, 63
|
||||||
|
@ -160,7 +156,7 @@ define i1 @signed_sign_bit_extract_trunc_extrause(i64 %x) {
|
||||||
; CHECK-NEXT: call void @use64(i64 [[SIGNSMEAR]])
|
; CHECK-NEXT: call void @use64(i64 [[SIGNSMEAR]])
|
||||||
; CHECK-NEXT: [[SIGNSMEAR_NARROW:%.*]] = trunc i64 [[SIGNSMEAR]] to i32
|
; CHECK-NEXT: [[SIGNSMEAR_NARROW:%.*]] = trunc i64 [[SIGNSMEAR]] to i32
|
||||||
; CHECK-NEXT: call void @use32(i32 [[SIGNSMEAR_NARROW]])
|
; CHECK-NEXT: call void @use32(i32 [[SIGNSMEAR_NARROW]])
|
||||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNSMEAR_NARROW]], 0
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[X]], 0
|
||||||
; CHECK-NEXT: ret i1 [[ISNEG]]
|
; CHECK-NEXT: ret i1 [[ISNEG]]
|
||||||
;
|
;
|
||||||
%signsmear = ashr i64 %x, 63
|
%signsmear = ashr i64 %x, 63
|
||||||
|
|
Loading…
Reference in New Issue