Skip to content

Commit 9402531

Browse files
committed
[DAG] Fold bitreverse(shl/srl(bitreverse(x),y)) -> srl/shl(x,y)
Noticed while investigating GFNI per-element vector shifts (we can form SHL but not SRL/SRA) Alive2: https://alive2.llvm.org/ce/z/fSH-rf
1 parent 01f8da9 commit 9402531

File tree

4 files changed

+57
-397
lines changed

4 files changed

+57
-397
lines changed

llvm/include/llvm/CodeGen/SDPatternMatch.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,11 @@ inline UnaryOpc_match<Opnd, true> m_ChainedUnaryOp(unsigned Opc,
616616
return UnaryOpc_match<Opnd, true>(Opc, Op);
617617
}
618618

619+
template <typename Opnd>
620+
inline UnaryOpc_match<Opnd> m_BitReverse(const Opnd &Op) {
621+
return UnaryOpc_match<Opnd>(ISD::BITREVERSE, Op);
622+
}
623+
619624
template <typename Opnd> inline UnaryOpc_match<Opnd> m_ZExt(const Opnd &Op) {
620625
return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op);
621626
}

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10950,9 +10950,23 @@ SDValue DAGCombiner::visitBITREVERSE(SDNode *N) {
1095010950
// fold (bitreverse c1) -> c2
1095110951
if (SDValue C = DAG.FoldConstantArithmetic(ISD::BITREVERSE, DL, VT, {N0}))
1095210952
return C;
10953+
1095310954
// fold (bitreverse (bitreverse x)) -> x
1095410955
if (N0.getOpcode() == ISD::BITREVERSE)
1095510956
return N0.getOperand(0);
10957+
10958+
SDValue X, Y;
10959+
10960+
// fold (bitreverse (lshr (bitreverse x), y)) -> (shl x, y)
10961+
if ((!LegalOperations || TLI.isOperationLegal(ISD::SHL, VT)) &&
10962+
sd_match(N, m_BitReverse(m_Srl(m_BitReverse(m_Value(X)), m_Value(Y)))))
10963+
return DAG.getNode(ISD::SHL, DL, VT, X, Y);
10964+
10965+
// fold (bitreverse (shl (bitreverse x), y)) -> (lshr x, y)
10966+
if ((!LegalOperations || TLI.isOperationLegal(ISD::SRL, VT)) &&
10967+
sd_match(N, m_BitReverse(m_Shl(m_BitReverse(m_Value(X)), m_Value(Y)))))
10968+
return DAG.getNode(ISD::SRL, DL, VT, X, Y);
10969+
1095610970
return SDValue();
1095710971
}
1095810972

llvm/test/CodeGen/RISCV/bitreverse-shift.ll

Lines changed: 27 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
22
; RUN: llc -mtriple=riscv32 -mattr=+zbkb -verify-machineinstrs < %s \
3-
; RUN: | FileCheck %s -check-prefixes=RV32ZBKB
3+
; RUN: | FileCheck %s -check-prefixes=CHECK,RV32ZBKB
44
; RUN: llc -mtriple=riscv64 -mattr=+zbkb -verify-machineinstrs < %s \
5-
; RUN: | FileCheck %s -check-prefixes=RV64ZBKB
5+
; RUN: | FileCheck %s -check-prefixes=CHECK,RV64ZBKB
66

7-
; TODO: These tests can be optimised
7+
; These tests can be optimised
88
; fold (bitreverse(srl (bitreverse c), x)) -> (shl c, x)
99
; fold (bitreverse(shl (bitreverse c), x)) -> (srl c, x)
1010

@@ -14,51 +14,21 @@ declare i32 @llvm.bitreverse.i32(i32)
1414
declare i64 @llvm.bitreverse.i64(i64)
1515

1616
define i8 @test_bitreverse_srli_bitreverse_i8(i8 %a) nounwind {
17-
; RV32ZBKB-LABEL: test_bitreverse_srli_bitreverse_i8:
18-
; RV32ZBKB: # %bb.0:
19-
; RV32ZBKB-NEXT: rev8 a0, a0
20-
; RV32ZBKB-NEXT: brev8 a0, a0
21-
; RV32ZBKB-NEXT: srli a0, a0, 27
22-
; RV32ZBKB-NEXT: rev8 a0, a0
23-
; RV32ZBKB-NEXT: brev8 a0, a0
24-
; RV32ZBKB-NEXT: srli a0, a0, 24
25-
; RV32ZBKB-NEXT: ret
26-
;
27-
; RV64ZBKB-LABEL: test_bitreverse_srli_bitreverse_i8:
28-
; RV64ZBKB: # %bb.0:
29-
; RV64ZBKB-NEXT: rev8 a0, a0
30-
; RV64ZBKB-NEXT: brev8 a0, a0
31-
; RV64ZBKB-NEXT: srli a0, a0, 59
32-
; RV64ZBKB-NEXT: rev8 a0, a0
33-
; RV64ZBKB-NEXT: brev8 a0, a0
34-
; RV64ZBKB-NEXT: srli a0, a0, 56
35-
; RV64ZBKB-NEXT: ret
17+
; CHECK-LABEL: test_bitreverse_srli_bitreverse_i8:
18+
; CHECK: # %bb.0:
19+
; CHECK-NEXT: slli a0, a0, 3
20+
; CHECK-NEXT: ret
3621
%1 = call i8 @llvm.bitreverse.i8(i8 %a)
3722
%2 = lshr i8 %1, 3
3823
%3 = call i8 @llvm.bitreverse.i8(i8 %2)
3924
ret i8 %3
4025
}
4126

4227
define i16 @test_bitreverse_srli_bitreverse_i16(i16 %a) nounwind {
43-
; RV32ZBKB-LABEL: test_bitreverse_srli_bitreverse_i16:
44-
; RV32ZBKB: # %bb.0:
45-
; RV32ZBKB-NEXT: rev8 a0, a0
46-
; RV32ZBKB-NEXT: brev8 a0, a0
47-
; RV32ZBKB-NEXT: srli a0, a0, 23
48-
; RV32ZBKB-NEXT: rev8 a0, a0
49-
; RV32ZBKB-NEXT: brev8 a0, a0
50-
; RV32ZBKB-NEXT: srli a0, a0, 16
51-
; RV32ZBKB-NEXT: ret
52-
;
53-
; RV64ZBKB-LABEL: test_bitreverse_srli_bitreverse_i16:
54-
; RV64ZBKB: # %bb.0:
55-
; RV64ZBKB-NEXT: rev8 a0, a0
56-
; RV64ZBKB-NEXT: brev8 a0, a0
57-
; RV64ZBKB-NEXT: srli a0, a0, 55
58-
; RV64ZBKB-NEXT: rev8 a0, a0
59-
; RV64ZBKB-NEXT: brev8 a0, a0
60-
; RV64ZBKB-NEXT: srli a0, a0, 48
61-
; RV64ZBKB-NEXT: ret
28+
; CHECK-LABEL: test_bitreverse_srli_bitreverse_i16:
29+
; CHECK: # %bb.0:
30+
; CHECK-NEXT: slli a0, a0, 7
31+
; CHECK-NEXT: ret
6232
%1 = call i16 @llvm.bitreverse.i16(i16 %a)
6333
%2 = lshr i16 %1, 7
6434
%3 = call i16 @llvm.bitreverse.i16(i16 %2)
@@ -68,21 +38,12 @@ define i16 @test_bitreverse_srli_bitreverse_i16(i16 %a) nounwind {
6838
define i32 @test_bitreverse_srli_bitreverse_i32(i32 %a) nounwind {
6939
; RV32ZBKB-LABEL: test_bitreverse_srli_bitreverse_i32:
7040
; RV32ZBKB: # %bb.0:
71-
; RV32ZBKB-NEXT: rev8 a0, a0
72-
; RV32ZBKB-NEXT: brev8 a0, a0
73-
; RV32ZBKB-NEXT: srli a0, a0, 15
74-
; RV32ZBKB-NEXT: rev8 a0, a0
75-
; RV32ZBKB-NEXT: brev8 a0, a0
41+
; RV32ZBKB-NEXT: slli a0, a0, 15
7642
; RV32ZBKB-NEXT: ret
7743
;
7844
; RV64ZBKB-LABEL: test_bitreverse_srli_bitreverse_i32:
7945
; RV64ZBKB: # %bb.0:
80-
; RV64ZBKB-NEXT: rev8 a0, a0
81-
; RV64ZBKB-NEXT: brev8 a0, a0
82-
; RV64ZBKB-NEXT: srli a0, a0, 47
83-
; RV64ZBKB-NEXT: rev8 a0, a0
84-
; RV64ZBKB-NEXT: brev8 a0, a0
85-
; RV64ZBKB-NEXT: srli a0, a0, 32
46+
; RV64ZBKB-NEXT: slliw a0, a0, 15
8647
; RV64ZBKB-NEXT: ret
8748
%1 = call i32 @llvm.bitreverse.i32(i32 %a)
8849
%2 = lshr i32 %1, 15
@@ -93,21 +54,13 @@ define i32 @test_bitreverse_srli_bitreverse_i32(i32 %a) nounwind {
9354
define i64 @test_bitreverse_srli_bitreverse_i64(i64 %a) nounwind {
9455
; RV32ZBKB-LABEL: test_bitreverse_srli_bitreverse_i64:
9556
; RV32ZBKB: # %bb.0:
96-
; RV32ZBKB-NEXT: rev8 a0, a0
97-
; RV32ZBKB-NEXT: brev8 a0, a0
98-
; RV32ZBKB-NEXT: srli a0, a0, 1
99-
; RV32ZBKB-NEXT: rev8 a0, a0
100-
; RV32ZBKB-NEXT: brev8 a1, a0
57+
; RV32ZBKB-NEXT: slli a1, a0, 1
10158
; RV32ZBKB-NEXT: li a0, 0
10259
; RV32ZBKB-NEXT: ret
10360
;
10461
; RV64ZBKB-LABEL: test_bitreverse_srli_bitreverse_i64:
10562
; RV64ZBKB: # %bb.0:
106-
; RV64ZBKB-NEXT: rev8 a0, a0
107-
; RV64ZBKB-NEXT: brev8 a0, a0
108-
; RV64ZBKB-NEXT: srli a0, a0, 33
109-
; RV64ZBKB-NEXT: rev8 a0, a0
110-
; RV64ZBKB-NEXT: brev8 a0, a0
63+
; RV64ZBKB-NEXT: slli a0, a0, 33
11164
; RV64ZBKB-NEXT: ret
11265
%1 = call i64 @llvm.bitreverse.i64(i64 %a)
11366
%2 = lshr i64 %1, 33
@@ -118,24 +71,14 @@ define i64 @test_bitreverse_srli_bitreverse_i64(i64 %a) nounwind {
11871
define i8 @test_bitreverse_shli_bitreverse_i8(i8 %a) nounwind {
11972
; RV32ZBKB-LABEL: test_bitreverse_shli_bitreverse_i8:
12073
; RV32ZBKB: # %bb.0:
121-
; RV32ZBKB-NEXT: rev8 a0, a0
122-
; RV32ZBKB-NEXT: brev8 a0, a0
123-
; RV32ZBKB-NEXT: srli a0, a0, 24
124-
; RV32ZBKB-NEXT: slli a0, a0, 3
125-
; RV32ZBKB-NEXT: rev8 a0, a0
126-
; RV32ZBKB-NEXT: brev8 a0, a0
127-
; RV32ZBKB-NEXT: srli a0, a0, 24
74+
; RV32ZBKB-NEXT: slli a0, a0, 24
75+
; RV32ZBKB-NEXT: srli a0, a0, 27
12876
; RV32ZBKB-NEXT: ret
12977
;
13078
; RV64ZBKB-LABEL: test_bitreverse_shli_bitreverse_i8:
13179
; RV64ZBKB: # %bb.0:
132-
; RV64ZBKB-NEXT: rev8 a0, a0
133-
; RV64ZBKB-NEXT: brev8 a0, a0
134-
; RV64ZBKB-NEXT: srli a0, a0, 56
135-
; RV64ZBKB-NEXT: slli a0, a0, 3
136-
; RV64ZBKB-NEXT: rev8 a0, a0
137-
; RV64ZBKB-NEXT: brev8 a0, a0
138-
; RV64ZBKB-NEXT: srli a0, a0, 56
80+
; RV64ZBKB-NEXT: slli a0, a0, 56
81+
; RV64ZBKB-NEXT: srli a0, a0, 59
13982
; RV64ZBKB-NEXT: ret
14083
%1 = call i8 @llvm.bitreverse.i8(i8 %a)
14184
%2 = shl i8 %1, 3
@@ -146,24 +89,14 @@ define i8 @test_bitreverse_shli_bitreverse_i8(i8 %a) nounwind {
14689
define i16 @test_bitreverse_shli_bitreverse_i16(i16 %a) nounwind {
14790
; RV32ZBKB-LABEL: test_bitreverse_shli_bitreverse_i16:
14891
; RV32ZBKB: # %bb.0:
149-
; RV32ZBKB-NEXT: rev8 a0, a0
150-
; RV32ZBKB-NEXT: brev8 a0, a0
151-
; RV32ZBKB-NEXT: srli a0, a0, 16
152-
; RV32ZBKB-NEXT: slli a0, a0, 7
153-
; RV32ZBKB-NEXT: rev8 a0, a0
154-
; RV32ZBKB-NEXT: brev8 a0, a0
155-
; RV32ZBKB-NEXT: srli a0, a0, 16
92+
; RV32ZBKB-NEXT: slli a0, a0, 16
93+
; RV32ZBKB-NEXT: srli a0, a0, 23
15694
; RV32ZBKB-NEXT: ret
15795
;
15896
; RV64ZBKB-LABEL: test_bitreverse_shli_bitreverse_i16:
15997
; RV64ZBKB: # %bb.0:
160-
; RV64ZBKB-NEXT: rev8 a0, a0
161-
; RV64ZBKB-NEXT: brev8 a0, a0
162-
; RV64ZBKB-NEXT: srli a0, a0, 48
163-
; RV64ZBKB-NEXT: slli a0, a0, 7
164-
; RV64ZBKB-NEXT: rev8 a0, a0
165-
; RV64ZBKB-NEXT: brev8 a0, a0
166-
; RV64ZBKB-NEXT: srli a0, a0, 48
98+
; RV64ZBKB-NEXT: slli a0, a0, 48
99+
; RV64ZBKB-NEXT: srli a0, a0, 55
167100
; RV64ZBKB-NEXT: ret
168101
%1 = call i16 @llvm.bitreverse.i16(i16 %a)
169102
%2 = shl i16 %1, 7
@@ -174,22 +107,12 @@ define i16 @test_bitreverse_shli_bitreverse_i16(i16 %a) nounwind {
174107
define i32 @test_bitreverse_shli_bitreverse_i32(i32 %a) nounwind {
175108
; RV32ZBKB-LABEL: test_bitreverse_shli_bitreverse_i32:
176109
; RV32ZBKB: # %bb.0:
177-
; RV32ZBKB-NEXT: rev8 a0, a0
178-
; RV32ZBKB-NEXT: brev8 a0, a0
179-
; RV32ZBKB-NEXT: slli a0, a0, 15
180-
; RV32ZBKB-NEXT: rev8 a0, a0
181-
; RV32ZBKB-NEXT: brev8 a0, a0
110+
; RV32ZBKB-NEXT: srli a0, a0, 15
182111
; RV32ZBKB-NEXT: ret
183112
;
184113
; RV64ZBKB-LABEL: test_bitreverse_shli_bitreverse_i32:
185114
; RV64ZBKB: # %bb.0:
186-
; RV64ZBKB-NEXT: rev8 a0, a0
187-
; RV64ZBKB-NEXT: brev8 a0, a0
188-
; RV64ZBKB-NEXT: srli a0, a0, 32
189-
; RV64ZBKB-NEXT: slli a0, a0, 15
190-
; RV64ZBKB-NEXT: rev8 a0, a0
191-
; RV64ZBKB-NEXT: brev8 a0, a0
192-
; RV64ZBKB-NEXT: srli a0, a0, 32
115+
; RV64ZBKB-NEXT: srliw a0, a0, 15
193116
; RV64ZBKB-NEXT: ret
194117
%1 = call i32 @llvm.bitreverse.i32(i32 %a)
195118
%2 = shl i32 %1, 15
@@ -200,21 +123,13 @@ define i32 @test_bitreverse_shli_bitreverse_i32(i32 %a) nounwind {
200123
define i64 @test_bitreverse_shli_bitreverse_i64(i64 %a) nounwind {
201124
; RV32ZBKB-LABEL: test_bitreverse_shli_bitreverse_i64:
202125
; RV32ZBKB: # %bb.0:
203-
; RV32ZBKB-NEXT: rev8 a0, a1
204-
; RV32ZBKB-NEXT: brev8 a0, a0
205-
; RV32ZBKB-NEXT: slli a0, a0, 1
206-
; RV32ZBKB-NEXT: rev8 a0, a0
207-
; RV32ZBKB-NEXT: brev8 a0, a0
126+
; RV32ZBKB-NEXT: srli a0, a1, 1
208127
; RV32ZBKB-NEXT: li a1, 0
209128
; RV32ZBKB-NEXT: ret
210129
;
211130
; RV64ZBKB-LABEL: test_bitreverse_shli_bitreverse_i64:
212131
; RV64ZBKB: # %bb.0:
213-
; RV64ZBKB-NEXT: rev8 a0, a0
214-
; RV64ZBKB-NEXT: brev8 a0, a0
215-
; RV64ZBKB-NEXT: slli a0, a0, 33
216-
; RV64ZBKB-NEXT: rev8 a0, a0
217-
; RV64ZBKB-NEXT: brev8 a0, a0
132+
; RV64ZBKB-NEXT: srli a0, a0, 33
218133
; RV64ZBKB-NEXT: ret
219134
%1 = call i64 @llvm.bitreverse.i64(i64 %a)
220135
%2 = shl i64 %1, 33

0 commit comments

Comments
 (0)