Skip to content

[InstCombine] Handle a bitreverse idiom which ends with a bswap #77677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 11, 2024

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Jan 10, 2024

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

@llvmbot
Copy link
Member

llvmbot commented Jan 10, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

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 &amp; 0xaaaaaaaau) &gt;&gt; 1 | (bits &amp; 0x55555555u) &lt;&lt; 1;
  bits = (bits &amp; 0xccccccccu) &gt;&gt; 2 | (bits &amp; 0x33333333u) &lt;&lt; 2;
  bits = (bits &amp; 0xf0f0f0f0u) &gt;&gt; 4 | (bits &amp; 0x0f0f0f0fu) &lt;&lt; 4;
  return absl::gbswap_32(bits);
}

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


Full diff: https://github.com/llvm/llvm-project/pull/77677.diff

3 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+4)
  • (modified) llvm/lib/Transforms/Utils/Local.cpp (+2-1)
  • (modified) llvm/test/Transforms/InstCombine/bitreverse.ll (+26)
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 7d122297c11b2d..cbe9695c48690b 100644
--- a/llvm/test/Transforms/InstCombine/bitreverse.ll
+++ b/llvm/test/Transforms/InstCombine/bitreverse.ll
@@ -106,6 +106,30 @@ entry:
   ret i32 %or.4
 }
 
+define i32 @rev32_bswap(i32 %v) {
+; CHECK-LABEL: @rev32_bswap(
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.bitreverse.i32(i32 [[V:%.*]])
+; 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 +532,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)

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Jan 10, 2024
Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dtcxzyw dtcxzyw merged commit 3d795bd into llvm:main Jan 11, 2024
@dtcxzyw dtcxzyw deleted the fold-bitreverse-bswap branch January 11, 2024 07:15
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…#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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants