diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -9738,9 +9738,19 @@ // fold (bitreverse c1) -> c2 if (DAG.isConstantIntBuildVectorOrConstantInt(N0)) return DAG.getNode(ISD::BITREVERSE, SDLoc(N), VT, N0); + // fold (bitreverse (bitreverse x)) -> x if (N0.getOpcode() == ISD::BITREVERSE) return N0.getOperand(0); + + // fold (bitreverse(srl (bitreverse c), x)) -> (shl c, x) + if (N0->getOpcode() == ISD::SRL && N0.hasOneUse()) { + SDValue BITREVERSE = N0->getOperand(0); + if (BITREVERSE->getOpcode() == ISD::BITREVERSE && BITREVERSE.hasOneUse()) + return DAG.getNode(ISD::SHL, SDLoc(N), VT, BITREVERSE->getOperand(0), + N0->getOperand(1)); + } + return SDValue(); } diff --git a/llvm/test/CodeGen/RISCV/bitreverse-srli-bitreverse.ll b/llvm/test/CodeGen/RISCV/bitreverse-srli-bitreverse.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/bitreverse-srli-bitreverse.ll @@ -0,0 +1,124 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv32 -mattr=+zbb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV32ZB,RV32ZBB +; RUN: llc -mtriple=riscv64 -mattr=+zbb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64ZB,RV64ZBB +; RUN: llc -mtriple=riscv32 -mattr=+zbkb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV32ZB,RV32ZBKB +; RUN: llc -mtriple=riscv64 -mattr=+zbkb -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64ZB,RV64ZBKB + +declare i8 @llvm.bitreverse.i8(i8) +declare i16 @llvm.bitreverse.i16(i16) +declare i32 @llvm.bitreverse.i32(i32) +declare i64 @llvm.bitreverse.i64(i64) + +define i8 @test_bitreverse_srli_bitreverse_i8(i8 %a) nounwind { +; RV32I-LABEL: test_bitreverse_srli_bitreverse_i8: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 3 +; RV32I-NEXT: ret +; +; RV64I-LABEL: test_bitreverse_srli_bitreverse_i8: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 3 +; RV64I-NEXT: ret +; +; RV32ZB-LABEL: test_bitreverse_srli_bitreverse_i8: +; RV32ZB: # %bb.0: +; RV32ZB-NEXT: slli a0, a0, 3 +; RV32ZB-NEXT: ret +; +; RV64ZB-LABEL: test_bitreverse_srli_bitreverse_i8: +; RV64ZB: # %bb.0: +; RV64ZB-NEXT: slli a0, a0, 3 +; RV64ZB-NEXT: ret + %1 = call i8 @llvm.bitreverse.i8(i8 %a) + %2 = lshr i8 %1, 3 + %3 = call i8 @llvm.bitreverse.i8(i8 %2) + ret i8 %3 +} + +define i16 @test_bitreverse_srli_bitreverse_i16(i16 %a) nounwind { +; RV32I-LABEL: test_bitreverse_srli_bitreverse_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 7 +; RV32I-NEXT: ret +; +; RV64I-LABEL: test_bitreverse_srli_bitreverse_i16: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 7 +; RV64I-NEXT: ret +; +; RV32ZB-LABEL: test_bitreverse_srli_bitreverse_i16: +; RV32ZB: # %bb.0: +; RV32ZB-NEXT: slli a0, a0, 7 +; RV32ZB-NEXT: ret +; +; RV64ZB-LABEL: test_bitreverse_srli_bitreverse_i16: +; RV64ZB: # %bb.0: +; RV64ZB-NEXT: slli a0, a0, 7 +; RV64ZB-NEXT: ret + %1 = call i16 @llvm.bitreverse.i16(i16 %a) + %2 = lshr i16 %1, 7 + %3 = call i16 @llvm.bitreverse.i16(i16 %2) + ret i16 %3 +} + +define i32 @test_bitreverse_srli_bitreverse_i32(i32 %a) nounwind { +; RV32I-LABEL: test_bitreverse_srli_bitreverse_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 15 +; RV32I-NEXT: ret +; +; RV64I-LABEL: test_bitreverse_srli_bitreverse_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: slliw a0, a0, 15 +; RV64I-NEXT: ret +; +; RV32ZB-LABEL: test_bitreverse_srli_bitreverse_i32: +; RV32ZB: # %bb.0: +; RV32ZB-NEXT: slli a0, a0, 15 +; RV32ZB-NEXT: ret +; +; RV64ZB-LABEL: test_bitreverse_srli_bitreverse_i32: +; RV64ZB: # %bb.0: +; RV64ZB-NEXT: slliw a0, a0, 15 +; RV64ZB-NEXT: ret + %1 = call i32 @llvm.bitreverse.i32(i32 %a) + %2 = lshr i32 %1, 15 + %3 = call i32 @llvm.bitreverse.i32(i32 %2) + ret i32 %3 +} + +define i64 @test_bitreverse_srli_bitreverse_i64(i64 %a) nounwind { +; RV32I-LABEL: test_bitreverse_srli_bitreverse_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a1, a0, 1 +; RV32I-NEXT: li a0, 0 +; RV32I-NEXT: ret +; +; RV64I-LABEL: test_bitreverse_srli_bitreverse_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 33 +; RV64I-NEXT: ret +; +; RV32ZB-LABEL: test_bitreverse_srli_bitreverse_i64: +; RV32ZB: # %bb.0: +; RV32ZB-NEXT: slli a1, a0, 1 +; RV32ZB-NEXT: li a0, 0 +; RV32ZB-NEXT: ret +; +; RV64ZB-LABEL: test_bitreverse_srli_bitreverse_i64: +; RV64ZB: # %bb.0: +; RV64ZB-NEXT: slli a0, a0, 33 +; RV64ZB-NEXT: ret + %1 = call i64 @llvm.bitreverse.i64(i64 %a) + %2 = lshr i64 %1, 33 + %3 = call i64 @llvm.bitreverse.i64(i64 %2) + ret i64 %3 +} diff --git a/llvm/test/CodeGen/X86/combine-bitreverse.ll b/llvm/test/CodeGen/X86/combine-bitreverse.ll --- a/llvm/test/CodeGen/X86/combine-bitreverse.ll +++ b/llvm/test/CodeGen/X86/combine-bitreverse.ll @@ -37,6 +37,25 @@ ret i32 %c } +; fold (bitreverse(srl (bitreverse c), x)) -> (shl c, x) +define i32 @test_bitreverse_srl_bitreverse(i32 %a0) nounwind { +; X86-LABEL: test_bitreverse_srl_bitreverse: +; X86: # %bb.0: +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: shll $7, %eax +; X86-NEXT: retl +; +; X64-LABEL: test_bitreverse_srl_bitreverse: +; X64: # %bb.0: +; X64-NEXT: movl %edi, %eax +; X64-NEXT: shll $7, %eax +; X64-NEXT: retq + %b = call i32 @llvm.bitreverse.i32(i32 %a0) + %c = lshr i32 %b, 7 + %d = call i32 @llvm.bitreverse.i32(i32 %c) + ret i32 %d +} + define <4 x i32> @test_demandedbits_bitreverse(<4 x i32> %a0) nounwind { ; X86-LABEL: test_demandedbits_bitreverse: ; X86: # %bb.0: