[llvm] [InstCombine] Fold ((cst << x) & 1) --> x == 0 when cst is odd (PR #79772)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 31 10:20:15 PST 2024


https://github.com/elhewaty updated https://github.com/llvm/llvm-project/pull/79772

>From ad9850124b45ae2b556c0511019878d3cfe65525 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Mon, 29 Jan 2024 00:15:17 +0200
Subject: [PATCH 1/2] [InstCombine] Add test coverage ((cst << x) & 1) --> x ==
 0 when cst is odd (NFC)

---
 llvm/test/Transforms/InstCombine/and.ll | 86 +++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll
index 2e37fee07cc47..73364e6e0f7e8 100644
--- a/llvm/test/Transforms/InstCombine/and.ll
+++ b/llvm/test/Transforms/InstCombine/and.ll
@@ -7,6 +7,92 @@ declare void @use32(i32)
 
 ; There should be no 'and' instructions left in any test.
 
+define i32 @test_with_1(i32 %x) {
+; CHECK-LABEL: @test_with_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %shl = shl i32 1, %x
+  %and = and i32 %shl, 1
+  ret i32 %and
+}
+
+define i32 @test_with_3(i32 %x) {
+; CHECK-LABEL: @test_with_3(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 3, [[X:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %shl = shl i32 3, %x
+  %and = and i32 %shl, 1
+  ret i32 %and
+}
+
+define i32 @test_with_5(i32 %x) {
+; CHECK-LABEL: @test_with_5(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 5, [[X:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %shl = shl i32 5, %x
+  %and = and i32 %shl, 1
+  ret i32 %and
+}
+
+define i32 @test_with_neg_5(i32 %x) {
+; CHECK-LABEL: @test_with_neg_5(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 -5, [[X:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %shl = shl i32 -5, %x
+  %and = and i32 %shl, 1
+  ret i32 %and
+}
+
+define i32 @test_with_even(i32 %x) {
+; CHECK-LABEL: @test_with_even(
+; CHECK-NEXT:    ret i32 0
+;
+  %shl = shl i32 4, %x
+  %and = and i32 %shl, 1
+  ret i32 %and
+}
+
+define <2 x i32> @test_vec(<2 x i32> %x) {
+; CHECK-LABEL: @test_vec(
+; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> <i32 5, i32 5>, [[X:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[SHL]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[AND]]
+;
+  %shl = shl <2 x i32> <i32 5, i32 5>, %x
+  %and = and <2 x i32> %shl, <i32 1, i32 1>
+  ret <2 x i32> %and
+}
+
+define i32 @test_with_neg_even(i32 %x) {
+; CHECK-LABEL: @test_with_neg_even(
+; CHECK-NEXT:    ret i32 0
+;
+  %shl = shl i32 -4, %x
+  %and = and i32 %shl, 1
+  ret i32 %and
+}
+
+define i32 @test_with_more_one_use(i32 %x) {
+; CHECK-LABEL: @test_with_more_one_use(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 7, [[X:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    call void @use32(i32 [[SHL]])
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %shl = shl i32 7, %x
+  %and = and i32 %shl, 1
+  call void @use32(i32 %shl)
+  ret i32 %and
+}
+
 define i32 @test1(i32 %A) {
 ; CHECK-LABEL: @test1(
 ; CHECK-NEXT:    ret i32 0

>From 51fd29137fa1a91929b2c28c296fcf5ffb8d9827 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Wed, 31 Jan 2024 20:17:40 +0200
Subject: [PATCH 2/2] [InstCombine] Fold ((cst << x) & 1) to x == 0 when cst is
 odd

---
 .../InstCombine/InstCombineAndOrXor.cpp          |  7 ++++---
 llvm/test/Transforms/InstCombine/and.ll          | 16 ++++++++--------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 0620752e32139..f31261abb812c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2220,10 +2220,12 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
 
   Value *X, *Y;
-  if (match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) &&
+  const APInt *C;
+  if ((match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) ||
+       (match(Op0, m_OneUse(m_Shl(m_APInt(C), m_Value(X)))) && (*C)[0])) &&
       match(Op1, m_One())) {
-    // (1 << X) & 1 --> zext(X == 0)
     // (1 >> X) & 1 --> zext(X == 0)
+    // (C << X) & 1 --> zext(X == 0), when C is odd
     Value *IsZero = Builder.CreateICmpEQ(X, ConstantInt::get(Ty, 0));
     return new ZExtInst(IsZero, Ty);
   }
@@ -2246,7 +2248,6 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
       isKnownToBeAPowerOfTwo(Y, /*OrZero*/ true, /*Depth*/ 0, &I))
     return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y);
 
-  const APInt *C;
   if (match(Op1, m_APInt(C))) {
     const APInt *XorC;
     if (match(Op0, m_OneUse(m_Xor(m_Value(X), m_APInt(XorC))))) {
diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll
index 73364e6e0f7e8..c5d8b578b4dc9 100644
--- a/llvm/test/Transforms/InstCombine/and.ll
+++ b/llvm/test/Transforms/InstCombine/and.ll
@@ -20,8 +20,8 @@ define i32 @test_with_1(i32 %x) {
 
 define i32 @test_with_3(i32 %x) {
 ; CHECK-LABEL: @test_with_3(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 3, [[X:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[TMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %shl = shl i32 3, %x
@@ -31,8 +31,8 @@ define i32 @test_with_3(i32 %x) {
 
 define i32 @test_with_5(i32 %x) {
 ; CHECK-LABEL: @test_with_5(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 5, [[X:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[TMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %shl = shl i32 5, %x
@@ -42,8 +42,8 @@ define i32 @test_with_5(i32 %x) {
 
 define i32 @test_with_neg_5(i32 %x) {
 ; CHECK-LABEL: @test_with_neg_5(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 -5, [[X:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[TMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %shl = shl i32 -5, %x
@@ -62,8 +62,8 @@ define i32 @test_with_even(i32 %x) {
 
 define <2 x i32> @test_vec(<2 x i32> %x) {
 ; CHECK-LABEL: @test_vec(
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> <i32 5, i32 5>, [[X:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[SHL]], <i32 1, i32 1>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[AND:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
 ; CHECK-NEXT:    ret <2 x i32> [[AND]]
 ;
   %shl = shl <2 x i32> <i32 5, i32 5>, %x



More information about the llvm-commits mailing list