[InstCombine] fold not-shift of signbit to icmp+zext, part 2
authorSanjay Patel <spatel@rotateright.com>
Sun, 8 Jan 2023 16:36:21 +0000 (11:36 -0500)
committerSanjay Patel <spatel@rotateright.com>
Sun, 8 Jan 2023 17:04:09 +0000 (12:04 -0500)
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.

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

index 43d359a..6c59185 100644 (file)
@@ -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);
index 1fce517..9ac1fd7 100644 (file)
@@ -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);
index 57d3f20..baf3248 100644 (file)
@@ -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
index 27d812a..581f945 100644 (file)
@@ -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:
index 715c58c..2d58c53 100644 (file)
@@ -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
index fdd8e7e..e1d3a03 100644 (file)
@@ -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
index 7ad8d79..bb956c0 100644 (file)
@@ -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>
index 43e50ed..430685e 100644 (file)
@@ -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