[llvm] r373802 - [InstCombine] Fold 'icmp eq/ne (?trunc (lshr/ashr %x, bitwidth(x)-1)), 0' -> 'icmp sge/slt %x, 0'

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 4 15:16:22 PDT 2019


Author: lebedevri
Date: Fri Oct  4 15:16:22 2019
New Revision: 373802

URL: http://llvm.org/viewvc/llvm-project?rev=373802&view=rev
Log:
[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

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/trunk/test/Transforms/InstCombine/shift.ll
    llvm/trunk/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=373802&r1=373801&r2=373802&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp Fri Oct  4 15:16:22 2019
@@ -1384,6 +1384,29 @@ Instruction *InstCombiner::foldIRemByPow
   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
   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;
 

Modified: llvm/trunk/test/Transforms/InstCombine/shift.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/shift.ll?rev=373802&r1=373801&r2=373802&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/shift.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/shift.ll Fri Oct  4 15:16:22 2019
@@ -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:

Modified: llvm/trunk/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll?rev=373802&r1=373801&r2=373802&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/sign-bit-test-via-right-shifting-all-other-bits.ll Fri Oct  4 15:16:22 2019
@@ -44,9 +44,7 @@ define i1 @highest_bit_test_via_ashr(i32
 
 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_ext
 ; 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_ext
 ; 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_extra
 ; 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_wit
 ; 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_wit
 }
 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
 ; 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




More information about the llvm-commits mailing list