[llvm] [InstCombine] fold nested bitreverse and bswap (PR #202236)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 7 15:19:54 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Kenny Lau (lauk20)
<details>
<summary>Changes</summary>
Addresses #<!-- -->201756
---
Full diff: https://github.com/llvm/llvm-project/pull/202236.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+44)
- (added) llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll (+63)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 7bcaa930511ee..4952f1a80c21c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1643,6 +1643,41 @@ static Instruction *foldBitOrderCrossLogicOp(Value *V,
return nullptr;
}
+/// Fold the following cases into a single byte-level bit-reverse operation
+/// and accepts bswap and bitreverse intrinsics:
+/// bswap(bitreverse(x)) --> bitcast(bitreverse(bitcast(x)))
+/// bitreverse(bswap(x)) --> bitcast(bitreverse(bitcast(x)))
+template <Intrinsic::ID IntrID>
+static Value *foldBitOrderReverseAndSwap(IntrinsicInst *II,
+ InstCombiner::BuilderTy &Builder) {
+ static_assert(IntrID == Intrinsic::bswap || IntrID == Intrinsic::bitreverse,
+ "This helper only supports BSWAP and BITREVERSE intrinsics");
+
+ Value *Arg = II->getArgOperand(0);
+ Type *Ty = II->getType();
+
+ if (Ty->getScalarSizeInBits() <= 8)
+ return nullptr;
+
+ constexpr Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse)
+ ? Intrinsic::bswap
+ : Intrinsic::bitreverse;
+
+ Value *X;
+ if (match(Arg, m_OneUse(m_Intrinsic<ComplementID>(m_Value(X))))) {
+ unsigned TotalBits = Ty->getPrimitiveSizeInBits();
+ Type *I8Ty = Builder.getInt8Ty();
+ Type *NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
+
+ // Cast to <N x i8>, perform a bitreverse, and cast back
+ Value *CastIn = Builder.CreateBitCast(X, NewVecTy);
+ Value *NewCall = Builder.CreateUnaryIntrinsic(Intrinsic::bitreverse, CastIn);
+ return Builder.CreateBitCast(NewCall, Ty);
+ }
+
+ return nullptr;
+}
+
/// Helper to match idempotent binary intrinsics, namely, intrinsics where
/// `f(f(x, y), y) == f(x, y)` holds.
static bool isIdempotentBinaryIntrinsic(Intrinsic::ID IID) {
@@ -2420,6 +2455,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Instruction *crossLogicOpFold =
foldBitOrderCrossLogicOp<Intrinsic::bitreverse>(IIOperand, Builder))
return crossLogicOpFold;
+
+ if (Value *swapReverseSwapFold =
+ foldBitOrderReverseAndSwap<Intrinsic::bitreverse>(II, Builder))
+ return replaceInstUsesWith(*II, swapReverseSwapFold);
break;
}
@@ -2476,6 +2515,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Instruction *BitOp = matchBSwapOrBitReverse(*II, /*MatchBSwaps*/ false,
/*MatchBitReversals*/ true))
return BitOp;
+
+ if (Value *swapReverseSwapFold =
+ foldBitOrderReverseAndSwap<Intrinsic::bswap>(II, Builder))
+ return replaceInstUsesWith(*II, swapReverseSwapFold);
+
break;
}
case Intrinsic::masked_load:
diff --git a/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll b/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
new file mode 100644
index 0000000000000..6c75a2a62c91d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define i64 @fold_scalar_i64(i64 %0) {
+; CHECK-LABEL: define i64 @fold_scalar_i64(
+; CHECK-SAME: i64 [[TMP0:%.*]]) {
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64 [[TMP0]] to <8 x i8>
+; CHECK-NEXT: [[TMP3:%.*]] = call <8 x i8> @llvm.bitreverse.v8i8(<8 x i8> [[TMP2]])
+; CHECK-NEXT: [[T2:%.*]] = bitcast <8 x i8> [[TMP3]] to i64
+; CHECK-NEXT: ret i64 [[T2]]
+;
+ %t1 = tail call i64 @llvm.bswap.i64(i64 %0)
+ %t2 = tail call i64 @llvm.bitreverse.i64(i64 %t1)
+ ret i64 %t2
+}
+
+define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
+; CHECK-LABEL: define <2 x i64> @fold_vector_v2i64(
+; CHECK-SAME: <2 x i64> [[TMP0:%.*]]) {
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
+; CHECK-NEXT: [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; CHECK-NEXT: [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[T2]]
+;
+ %t1 = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %0)
+ %t2 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %t1)
+ ret <2 x i64> %t2
+}
+
+define i32 @fold_scalar_i32(i32 %0) {
+; CHECK-LABEL: define i32 @fold_scalar_i32(
+; CHECK-SAME: i32 [[TMP0:%.*]]) {
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP0]] to <4 x i8>
+; CHECK-NEXT: [[TMP3:%.*]] = call <4 x i8> @llvm.bitreverse.v4i8(<4 x i8> [[TMP2]])
+; CHECK-NEXT: [[T2:%.*]] = bitcast <4 x i8> [[TMP3]] to i32
+; CHECK-NEXT: ret i32 [[T2]]
+;
+ %t1 = tail call i32 @llvm.bswap.i32(i32 %0)
+ %t2 = tail call i32 @llvm.bitreverse.i32(i32 %t1)
+ ret i32 %t2
+}
+
+define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
+; CHECK-LABEL: define <4 x i32> @fold_vector_v4i32(
+; CHECK-SAME: <4 x i32> [[TMP0:%.*]]) {
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8>
+; CHECK-NEXT: [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; CHECK-NEXT: [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32>
+; CHECK-NEXT: ret <4 x i32> [[T2]]
+;
+ %t1 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %0)
+ %t2 = tail call <4 x i32> @llvm.bitreverse.v4i32(<4 x i32> %t1)
+ ret <4 x i32> %t2
+}
+
+declare i64 @llvm.bswap.i64(i64)
+declare i64 @llvm.bitreverse.i64(i64)
+declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
+declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
+declare i32 @llvm.bswap.i32(i32)
+declare i32 @llvm.bitreverse.i32(i32)
+declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
+declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>)
``````````
</details>
https://github.com/llvm/llvm-project/pull/202236
More information about the llvm-commits
mailing list