[llvm] [InstCombine] Handle a bitreverse idiom which ends with a bswap (PR #77677)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 10 11:52:12 PST 2024


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/77677

This patch handles the following `bitreverse` idiom, which is found in https://github.com/abseil/abseil-cpp/blob/8bd6445acc4bd0d123da2a44448b7218dfc70939/absl/crc/internal/crc.cc#L75-L80:

```
uint32_t ReverseBits(uint32_t bits) {
  bits = (bits & 0xaaaaaaaau) >> 1 | (bits & 0x55555555u) << 1;
  bits = (bits & 0xccccccccu) >> 2 | (bits & 0x33333333u) << 2;
  bits = (bits & 0xf0f0f0f0u) >> 4 | (bits & 0x0f0f0f0fu) << 4;
  return absl::gbswap_32(bits);
}
```

Alive2: https://alive2.llvm.org/ce/z/ZYXNmj

>From fb91a75cf24530078417940733a24c0a5d48577a Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 11 Jan 2024 03:21:30 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.

---
 .../test/Transforms/InstCombine/bitreverse.ll | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/bitreverse.ll b/llvm/test/Transforms/InstCombine/bitreverse.ll
index 7d122297c11b2d..f8744aacf60359 100644
--- a/llvm/test/Transforms/InstCombine/bitreverse.ll
+++ b/llvm/test/Transforms/InstCombine/bitreverse.ll
@@ -106,6 +106,45 @@ entry:
   ret i32 %or.4
 }
 
+define i32 @rev32_bswap(i32 %v) {
+; CHECK-LABEL: @rev32_bswap(
+; CHECK-NEXT:    [[AND_I:%.*]] = lshr i32 [[V:%.*]], 1
+; CHECK-NEXT:    [[SHR_I:%.*]] = and i32 [[AND_I]], 1431655765
+; CHECK-NEXT:    [[AND1_I:%.*]] = shl i32 [[V]], 1
+; CHECK-NEXT:    [[SHL_I:%.*]] = and i32 [[AND1_I]], -1431655766
+; CHECK-NEXT:    [[OR_I:%.*]] = or disjoint i32 [[SHR_I]], [[SHL_I]]
+; CHECK-NEXT:    [[AND2_I:%.*]] = lshr i32 [[OR_I]], 2
+; CHECK-NEXT:    [[SHR3_I:%.*]] = and i32 [[AND2_I]], 858993459
+; CHECK-NEXT:    [[AND4_I:%.*]] = shl i32 [[OR_I]], 2
+; CHECK-NEXT:    [[SHL5_I:%.*]] = and i32 [[AND4_I]], -858993460
+; CHECK-NEXT:    [[OR6_I:%.*]] = or disjoint i32 [[SHR3_I]], [[SHL5_I]]
+; CHECK-NEXT:    [[AND7_I:%.*]] = lshr i32 [[OR6_I]], 4
+; CHECK-NEXT:    [[SHR8_I:%.*]] = and i32 [[AND7_I]], 252645135
+; CHECK-NEXT:    [[AND9_I:%.*]] = shl i32 [[OR6_I]], 4
+; CHECK-NEXT:    [[SHL10_I:%.*]] = and i32 [[AND9_I]], -252645136
+; CHECK-NEXT:    [[OR11_I:%.*]] = or disjoint i32 [[SHR8_I]], [[SHL10_I]]
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.bswap.i32(i32 [[OR11_I]])
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %and.i = lshr i32 %v, 1
+  %shr.i = and i32 %and.i, 1431655765
+  %and1.i = shl i32 %v, 1
+  %shl.i = and i32 %and1.i, -1431655766
+  %or.i = or disjoint i32 %shr.i, %shl.i
+  %and2.i = lshr i32 %or.i, 2
+  %shr3.i = and i32 %and2.i, 858993459
+  %and4.i = shl i32 %or.i, 2
+  %shl5.i = and i32 %and4.i, -858993460
+  %or6.i = or disjoint i32 %shr3.i, %shl5.i
+  %and7.i = lshr i32 %or6.i, 4
+  %shr8.i = and i32 %and7.i, 252645135
+  %and9.i = shl i32 %or6.i, 4
+  %shl10.i = and i32 %and9.i, -252645136
+  %or11.i = or disjoint i32 %shr8.i, %shl10.i
+  %ret = call i32 @llvm.bswap.i32(i32 %or11.i)
+  ret i32 %ret
+}
+
 define i64 @rev64(i64 %v) {
 ; CHECK-LABEL: @rev64(
 ; CHECK-NEXT:  entry:
@@ -508,3 +547,5 @@ define i64 @rev_all_operand64_multiuse_both(i64 %a, i64 %b) #0 {
   call void @use_i64(i64 %2)
   ret i64 %4
 }
+
+declare i32 @llvm.bswap.i32(i32 %or11.i)

>From 0b4083ddb503b361fff1745e54f9bfecba8200ae Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 11 Jan 2024 03:32:15 +0800
Subject: [PATCH 2/2] [InstCombine] Handle a bitreverse idiom which ends with a
 bswap

---
 .../Transforms/InstCombine/InstCombineCalls.cpp |  4 ++++
 llvm/lib/Transforms/Utils/Local.cpp             |  3 ++-
 llvm/test/Transforms/InstCombine/bitreverse.ll  | 17 +----------------
 3 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 40b48699f75851..64fbd5543a9e20 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1884,6 +1884,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       return crossLogicOpFold;
     }
 
+    // Try to fold into bitreverse if bswap is the root of the expression tree.
+    if (Instruction *BitOp = matchBSwapOrBitReverse(*II, /*MatchBSwaps*/ false,
+                                                    /*MatchBitReversals*/ true))
+      return BitOp;
     break;
   }
   case Intrinsic::masked_load:
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index c76cc9db16d7e7..b9cad764aaef8b 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3905,7 +3905,8 @@ bool llvm::recognizeBSwapOrBitReverseIdiom(
     SmallVectorImpl<Instruction *> &InsertedInsts) {
   if (!match(I, m_Or(m_Value(), m_Value())) &&
       !match(I, m_FShl(m_Value(), m_Value(), m_Value())) &&
-      !match(I, m_FShr(m_Value(), m_Value(), m_Value())))
+      !match(I, m_FShr(m_Value(), m_Value(), m_Value())) &&
+      !match(I, m_BSwap(m_Value())))
     return false;
   if (!MatchBSwaps && !MatchBitReversals)
     return false;
diff --git a/llvm/test/Transforms/InstCombine/bitreverse.ll b/llvm/test/Transforms/InstCombine/bitreverse.ll
index f8744aacf60359..cbe9695c48690b 100644
--- a/llvm/test/Transforms/InstCombine/bitreverse.ll
+++ b/llvm/test/Transforms/InstCombine/bitreverse.ll
@@ -108,22 +108,7 @@ entry:
 
 define i32 @rev32_bswap(i32 %v) {
 ; CHECK-LABEL: @rev32_bswap(
-; CHECK-NEXT:    [[AND_I:%.*]] = lshr i32 [[V:%.*]], 1
-; CHECK-NEXT:    [[SHR_I:%.*]] = and i32 [[AND_I]], 1431655765
-; CHECK-NEXT:    [[AND1_I:%.*]] = shl i32 [[V]], 1
-; CHECK-NEXT:    [[SHL_I:%.*]] = and i32 [[AND1_I]], -1431655766
-; CHECK-NEXT:    [[OR_I:%.*]] = or disjoint i32 [[SHR_I]], [[SHL_I]]
-; CHECK-NEXT:    [[AND2_I:%.*]] = lshr i32 [[OR_I]], 2
-; CHECK-NEXT:    [[SHR3_I:%.*]] = and i32 [[AND2_I]], 858993459
-; CHECK-NEXT:    [[AND4_I:%.*]] = shl i32 [[OR_I]], 2
-; CHECK-NEXT:    [[SHL5_I:%.*]] = and i32 [[AND4_I]], -858993460
-; CHECK-NEXT:    [[OR6_I:%.*]] = or disjoint i32 [[SHR3_I]], [[SHL5_I]]
-; CHECK-NEXT:    [[AND7_I:%.*]] = lshr i32 [[OR6_I]], 4
-; CHECK-NEXT:    [[SHR8_I:%.*]] = and i32 [[AND7_I]], 252645135
-; CHECK-NEXT:    [[AND9_I:%.*]] = shl i32 [[OR6_I]], 4
-; CHECK-NEXT:    [[SHL10_I:%.*]] = and i32 [[AND9_I]], -252645136
-; CHECK-NEXT:    [[OR11_I:%.*]] = or disjoint i32 [[SHR8_I]], [[SHL10_I]]
-; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.bswap.i32(i32 [[OR11_I]])
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.bitreverse.i32(i32 [[V:%.*]])
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %and.i = lshr i32 %v, 1



More information about the llvm-commits mailing list