[llvm] 21d3871 - [InstCombine] fold not-shift of signbit to icmp+zext, part 2

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 8 09:04:16 PST 2023


Author: Sanjay Patel
Date: 2023-01-08T12:04:09-05:00
New Revision: 21d3871b7c90f85b3ae417724d7864369173bde0

URL: https://github.com/llvm/llvm-project/commit/21d3871b7c90f85b3ae417724d7864369173bde0
DIFF: https://github.com/llvm/llvm-project/commit/21d3871b7c90f85b3ae417724d7864369173bde0.diff

LOG: [InstCombine] fold not-shift of signbit to icmp+zext, part 2

Follow-up to:
6c39a3aae1dc

That converted a pattern with ashr directly to icmp+zext, and
this updates the pattern that we used to convert to.

This canonicalizes to icmp for better analysis in the minimum case
and shortens patterns where the source type is not the same as dest type:
https://alive2.llvm.org/ce/z/tpXJ64
https://alive2.llvm.org/ce/z/dQ405O

This requires an adjustment to an icmp transform to avoid infinite looping.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
    llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
    llvm/test/Transforms/InstCombine/and-xor-merge.ll
    llvm/test/Transforms/InstCombine/icmp-mul-zext.ll
    llvm/test/Transforms/InstCombine/lshr.ll
    llvm/test/Transforms/InstCombine/negated-bitmask.ll
    llvm/test/Transforms/InstCombine/xor.ll
    llvm/test/Transforms/InstCombine/zext.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 43d359acabc80..6c5918507b6e2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1027,8 +1027,11 @@ Instruction *InstCombinerImpl::transformZExtICmp(ICmpInst *Cmp, ZExtInst &Zext)
       // If Op1C some other power of two, convert:
       KnownBits Known = computeKnownBits(Cmp->getOperand(0), 0, &Zext);
 
+      // Exactly 1 possible 1? But not the high-bit because that is
+      // canonicalized to this form.
       APInt KnownZeroMask(~Known.Zero);
-      if (KnownZeroMask.isPowerOf2()) { // Exactly 1 possible 1?
+      if (KnownZeroMask.isPowerOf2() &&
+          (Zext.getType()->getScalarSizeInBits() != KnownZeroMask.logBase2() + 1)) {
         bool isNE = Cmp->getPredicate() == ICmpInst::ICMP_NE;
         uint32_t ShAmt = KnownZeroMask.logBase2();
         Value *In = Cmp->getOperand(0);

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 1fce5179af6a7..9ac1fd7731bf1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -1091,10 +1091,17 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
 
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
   Type *Ty = I.getType();
+  Value *X;
   const APInt *C;
+  unsigned BitWidth = Ty->getScalarSizeInBits();
+
+  // (iN (~X) u>> (N - 1)) --> zext (X > -1)
+  if (match(Op0, m_OneUse(m_Not(m_Value(X)))) &&
+      match(Op1, m_SpecificIntAllowUndef(BitWidth - 1)))
+    return new ZExtInst(Builder.CreateIsNotNeg(X, "isnotneg"), Ty);
+
   if (match(Op1, m_APInt(C))) {
     unsigned ShAmtC = C->getZExtValue();
-    unsigned BitWidth = Ty->getScalarSizeInBits();
     auto *II = dyn_cast<IntrinsicInst>(Op0);
     if (II && isPowerOf2_32(BitWidth) && Log2_32(BitWidth) == ShAmtC &&
         (II->getIntrinsicID() == Intrinsic::ctlz ||
@@ -1320,7 +1327,6 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
   }
 
   // Transform  (x << y) >> y  to  x & (-1 >> y)
-  Value *X;
   if (match(Op0, m_OneUse(m_Shl(m_Value(X), m_Specific(Op1))))) {
     Constant *AllOnes = ConstantInt::getAllOnesValue(Ty);
     Value *Mask = Builder.CreateLShr(AllOnes, Op1);

diff  --git a/llvm/test/Transforms/InstCombine/and-xor-merge.ll b/llvm/test/Transforms/InstCombine/and-xor-merge.ll
index 57d3f202c07a2..baf3248e29804 100644
--- a/llvm/test/Transforms/InstCombine/and-xor-merge.ll
+++ b/llvm/test/Transforms/InstCombine/and-xor-merge.ll
@@ -28,9 +28,9 @@ define i32 @test2(i32 %x, i32 %y, i32 %z) {
 
 define i32 @PR38781(i32 %a, i32 %b) {
 ; CHECK-LABEL: @PR38781(
-; CHECK-NEXT:    [[B_LOBIT_NOT1_DEMORGAN:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[B_LOBIT_NOT1:%.*]] = xor i32 [[B_LOBIT_NOT1_DEMORGAN]], -1
-; CHECK-NEXT:    [[AND:%.*]] = lshr i32 [[B_LOBIT_NOT1]], 31
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
+; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[TMP2]] to i32
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %a.lobit = lshr i32 %a, 31

diff  --git a/llvm/test/Transforms/InstCombine/icmp-mul-zext.ll b/llvm/test/Transforms/InstCombine/icmp-mul-zext.ll
index 27d812a25b2a6..581f9452929fc 100644
--- a/llvm/test/Transforms/InstCombine/icmp-mul-zext.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-mul-zext.ll
@@ -19,10 +19,10 @@ define i32 @sterix(i32, i8, i64) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i64 [[MUL3]], [[TMP2]]
 ; CHECK-NEXT:    [[CONV4:%.*]] = trunc i64 [[AND]] to i32
 ; CHECK-NEXT:    [[TOBOOL7_NOT:%.*]] = icmp eq i32 [[CONV4]], 0
-; CHECK-NEXT:    [[PHITMP:%.*]] = zext i1 [[TOBOOL7_NOT]] to i32
+; CHECK-NEXT:    [[PHI_CAST:%.*]] = zext i1 [[TOBOOL7_NOT]] to i32
 ; CHECK-NEXT:    br label [[LOR_END]]
 ; CHECK:       lor.end:
-; CHECK-NEXT:    [[TMP4:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[PHITMP]], [[LOR_RHS]] ]
+; CHECK-NEXT:    [[TMP4:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[PHI_CAST]], [[LOR_RHS]] ]
 ; CHECK-NEXT:    ret i32 [[TMP4]]
 ;
 entry:

diff  --git a/llvm/test/Transforms/InstCombine/lshr.ll b/llvm/test/Transforms/InstCombine/lshr.ll
index 715c58c3d8b63..2d58c53e108a0 100644
--- a/llvm/test/Transforms/InstCombine/lshr.ll
+++ b/llvm/test/Transforms/InstCombine/lshr.ll
@@ -947,8 +947,8 @@ define i32 @not_narrow_bswap(i24 %x) {
 
 define i8 @not_signbit(i8 %x) {
 ; CHECK-LABEL: @not_signbit(
-; CHECK-NEXT:    [[A:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT:    [[R:%.*]] = lshr i8 [[A]], 7
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[ISNOTNEG]] to i8
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a = xor i8 %x, -1
@@ -958,8 +958,8 @@ define i8 @not_signbit(i8 %x) {
 
 define <2 x i6> @not_signbit_vec(<2 x i6> %x) {
 ; CHECK-LABEL: @not_signbit_vec(
-; CHECK-NEXT:    [[A:%.*]] = xor <2 x i6> [[X:%.*]], <i6 -1, i6 poison>
-; CHECK-NEXT:    [[R:%.*]] = lshr <2 x i6> [[A]], <i6 5, i6 poison>
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt <2 x i6> [[X:%.*]], <i6 -1, i6 -1>
+; CHECK-NEXT:    [[R:%.*]] = zext <2 x i1> [[ISNOTNEG]] to <2 x i6>
 ; CHECK-NEXT:    ret <2 x i6> [[R]]
 ;
   %a = xor <2 x i6> %x, <i6 -1, i6 poison>
@@ -969,8 +969,8 @@ define <2 x i6> @not_signbit_vec(<2 x i6> %x) {
 
 define i8 @not_signbit_alt_xor(i8 %x) {
 ; CHECK-LABEL: @not_signbit_alt_xor(
-; CHECK-NEXT:    [[A:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT:    [[R:%.*]] = lshr i8 [[A]], 7
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[ISNOTNEG]] to i8
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a = xor i8 %x, -2
@@ -1004,9 +1004,8 @@ define i32 @not_signbit_use(i32 %x) {
 
 define i32 @not_signbit_zext(i16 %x) {
 ; CHECK-LABEL: @not_signbit_zext(
-; CHECK-NEXT:    [[A:%.*]] = xor i16 [[X:%.*]], -1
-; CHECK-NEXT:    [[R:%.*]] = lshr i16 [[A]], 15
-; CHECK-NEXT:    [[R2:%.*]] = zext i16 [[R]] to i32
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt i16 [[X:%.*]], -1
+; CHECK-NEXT:    [[R2:%.*]] = zext i1 [[ISNOTNEG]] to i32
 ; CHECK-NEXT:    ret i32 [[R2]]
 ;
   %a = xor i16 %x, -1
@@ -1017,9 +1016,8 @@ define i32 @not_signbit_zext(i16 %x) {
 
 define i8 @not_signbit_trunc(i16 %x) {
 ; CHECK-LABEL: @not_signbit_trunc(
-; CHECK-NEXT:    [[A:%.*]] = xor i16 [[X:%.*]], -1
-; CHECK-NEXT:    [[R:%.*]] = lshr i16 [[A]], 15
-; CHECK-NEXT:    [[R2:%.*]] = trunc i16 [[R]] to i8
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt i16 [[X:%.*]], -1
+; CHECK-NEXT:    [[R2:%.*]] = zext i1 [[ISNOTNEG]] to i8
 ; CHECK-NEXT:    ret i8 [[R2]]
 ;
   %a = xor i16 %x, -1

diff  --git a/llvm/test/Transforms/InstCombine/negated-bitmask.ll b/llvm/test/Transforms/InstCombine/negated-bitmask.ll
index fdd8e7e5b262a..e1d3a030297b2 100644
--- a/llvm/test/Transforms/InstCombine/negated-bitmask.ll
+++ b/llvm/test/Transforms/InstCombine/negated-bitmask.ll
@@ -233,9 +233,8 @@ define i8 @neg_signbit_use2(i5 %x) {
 
 define i32 @neg_not_signbit1(i8 %x) {
 ; CHECK-LABEL: @neg_not_signbit1(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT:    [[TMP2:%.*]] = lshr i8 [[TMP1]], 7
-; CHECK-NEXT:    [[R:%.*]] = zext i8 [[TMP2]] to i32
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[ISNOTNEG]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = lshr i8 %x, 7

diff  --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll
index 7ad8d79edd4ba..bb956c03c612e 100644
--- a/llvm/test/Transforms/InstCombine/xor.ll
+++ b/llvm/test/Transforms/InstCombine/xor.ll
@@ -1061,8 +1061,8 @@ define i8 @not_lshr(i8 %x) {
 
 define <2 x i8> @not_lshr_vec(<2 x i8> %x) {
 ; CHECK-LABEL: @not_lshr_vec(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[R:%.*]] = lshr <2 x i8> [[TMP1]], <i8 7, i8 7>
+; CHECK-NEXT:    [[ISNOTNEG:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT:    [[R:%.*]] = zext <2 x i1> [[ISNOTNEG]] to <2 x i8>
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %a = lshr <2 x i8> %x, <i8 7, i8 7>

diff  --git a/llvm/test/Transforms/InstCombine/zext.ll b/llvm/test/Transforms/InstCombine/zext.ll
index 43e50ed1ed15b..430685eb73ef5 100644
--- a/llvm/test/Transforms/InstCombine/zext.ll
+++ b/llvm/test/Transforms/InstCombine/zext.ll
@@ -501,10 +501,10 @@ define i8 @notneg_zext_narrower_use(i32 %x) {
 
 define i8 @disguised_signbit_clear_test(i64 %x) {
 ; CHECK-LABEL: @disguised_signbit_clear_test(
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i8
-; CHECK-NEXT:    [[TMP2:%.*]] = xor i8 [[TMP1]], -1
-; CHECK-NEXT:    [[TMP3:%.*]] = lshr i8 [[TMP2]], 7
-; CHECK-NEXT:    ret i8 [[TMP3]]
+; CHECK-NEXT:    [[A1:%.*]] = and i64 [[X:%.*]], 128
+; CHECK-NEXT:    [[T4:%.*]] = icmp eq i64 [[A1]], 0
+; CHECK-NEXT:    [[T6:%.*]] = zext i1 [[T4]] to i8
+; CHECK-NEXT:    ret i8 [[T6]]
 ;
   %a1 = and i64 %x, 128
   %t4 = icmp eq i64 %a1, 0


        


More information about the llvm-commits mailing list