From 98b5e22e78973acfd4f5c6c0fbec323d7851cb69 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Fri, 4 Oct 2019 22:16:22 +0000 Subject: [PATCH] [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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@373802 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineCompares.cpp | 28 +++++++++++++++++++ test/Transforms/InstCombine/shift.ll | 4 +-- ...-test-via-right-shifting-all-other-bits.ll | 18 +++++------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index ddc7de39d8d..f07f64e3f02 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1384,6 +1384,29 @@ Instruction *InstCombiner::foldIRemByPowerOfTwoToBitTest(ICmpInst &I) { 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 Instruction *InstCombiner::foldICmpWithZero(ICmpInst &Cmp) { CmpInst::Predicate Pred = Cmp.getPredicate(); @@ -5449,6 +5472,11 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { if (Instruction *Res = foldICmpInstWithConstant(I)) 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)) return Res; diff --git a/test/Transforms/InstCombine/shift.ll b/test/Transforms/InstCombine/shift.ll index 501f015ed73..9ded69ad7b9 100644 --- a/test/Transforms/InstCombine/shift.ll +++ b/test/Transforms/InstCombine/shift.ll @@ -428,8 +428,8 @@ define i8 @test28a(i8 %x, i8 %y) { ; CHECK-LABEL: @test28a( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[X:%.*]], 7 -; CHECK-NEXT: [[COND1:%.*]] = icmp eq i8 [[TMP1]], 0 -; CHECK-NEXT: br i1 [[COND1]], label [[BB2:%.*]], label [[BB1:%.*]] +; CHECK-NEXT: [[COND1:%.*]] = icmp slt i8 [[X]], 0 +; CHECK-NEXT: br i1 [[COND1]], label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: ret i8 [[TMP1]] ; CHECK: bb2: diff --git a/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll b/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll index fa5cc4349cf..c6507afab1f 100644 --- a/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll +++ b/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll @@ -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) { ; CHECK-LABEL: @highest_bit_test_via_ashr_with_truncation( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i64 [[DATA:%.*]], 63 -; CHECK-NEXT: [[SIGNBIT:%.*]] = trunc i64 [[TMP1]] to i32 -; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNBIT]], 0 +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[DATA:%.*]], 0 ; CHECK-NEXT: ret i1 [[ISNEG]] ; %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-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[X:%.*]], 31 ; 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]] ; %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-NEXT: [[SIGNBIT:%.*]] = lshr i32 [[X:%.*]], 31 ; 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]] ; %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-NEXT: [[SIGNSMEAR:%.*]] = ashr i32 [[X:%.*]], 31 ; 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]] ; %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: [[SIGNBIT_NARROW:%.*]] = trunc i64 [[SIGNBIT]] to i32 ; 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]] ; %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) { ; CHECK-LABEL: @signed_sign_bit_extract_trunc( -; CHECK-NEXT: [[SIGNSMEAR:%.*]] = ashr i64 [[X:%.*]], 63 -; CHECK-NEXT: [[SIGNSMEAR_NARROW:%.*]] = trunc i64 [[SIGNSMEAR]] to i32 -; CHECK-NEXT: [[ISNEG:%.*]] = icmp ne i32 [[SIGNSMEAR_NARROW]], 0 +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i64 [[X:%.*]], 0 ; CHECK-NEXT: ret i1 [[ISNEG]] ; %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: [[SIGNSMEAR_NARROW:%.*]] = trunc i64 [[SIGNSMEAR]] to i32 ; 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]] ; %signsmear = ashr i64 %x, 63 -- 2.40.0