Skip to content

Commit 40204df

Browse files
Jessica Paquettememfrob
authored andcommitted
[GlobalISel][AArch64] Combine G_SEXT_INREG + right shift -> G_SBFX
Basically a port of isBitfieldExtractOpFromSExtInReg in AArch64ISelDAGToDAG. This is only done post-legalization for now. Once the legalizer knows how to decompose these back into shifts, this requirement can probably be removed. Differential Revision: https://reviews.llvm.org/D99230
1 parent 71a2050 commit 40204df

File tree

6 files changed

+202
-8
lines changed

6 files changed

+202
-8
lines changed

llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,6 @@ class CombinerHelper {
491491
/// bswap.
492492
bool matchLoadOrCombine(MachineInstr &MI,
493493
std::function<void(MachineIRBuilder &)> &MatchInfo);
494-
bool applyLoadOrCombine(MachineInstr &MI,
495-
std::function<void(MachineIRBuilder &)> &MatchInfo);
496494

497495
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI);
498496
bool applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI);
@@ -507,6 +505,10 @@ class CombinerHelper {
507505
MachineInstr &MI,
508506
SmallVectorImpl<std::pair<Register, MachineInstr *>> &MatchInfo);
509507

508+
/// Use a function which takes in a MachineIRBuilder to perform a combine.
509+
bool applyBuildFn(MachineInstr &MI,
510+
std::function<void(MachineIRBuilder &)> &MatchInfo);
511+
510512
/// Try to transform \p MI by using all of the above
511513
/// combine functions. Returns true if changed.
512514
bool tryCombine(MachineInstr &MI);

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ class GIApplyKind;
114114
class GIApplyKindWithArgs;
115115

116116
def register_matchinfo: GIDefMatchData<"Register">;
117+
def build_fn_matchinfo :
118+
GIDefMatchData<"std::function<void(MachineIRBuilder &)>">;
117119

118120
def copy_prop : GICombineRule<
119121
(defs root:$d),
@@ -560,13 +562,11 @@ def combine_insert_vec_elts_build_vector : GICombineRule<
560562
[{ return Helper.matchCombineInsertVecElts(*${root}, ${info}); }]),
561563
(apply [{ return Helper.applyCombineInsertVecElts(*${root}, ${info}); }])>;
562564

563-
def load_or_combine_matchdata :
564-
GIDefMatchData<"std::function<void(MachineIRBuilder &)>">;
565565
def load_or_combine : GICombineRule<
566-
(defs root:$root, load_or_combine_matchdata:$info),
566+
(defs root:$root, build_fn_matchinfo:$info),
567567
(match (wip_match_opcode G_OR):$root,
568568
[{ return Helper.matchLoadOrCombine(*${root}, ${info}); }]),
569-
(apply [{ return Helper.applyLoadOrCombine(*${root}, ${info}); }])>;
569+
(apply [{ return Helper.applyBuildFn(*${root}, ${info}); }])>;
570570

571571
def extend_through_phis_matchdata: GIDefMatchData<"MachineInstr*">;
572572
def extend_through_phis : GICombineRule<

llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3862,7 +3862,7 @@ void CombinerHelper::applyExtractAllEltsFromBuildVector(
38623862
MI.eraseFromParent();
38633863
}
38643864

3865-
bool CombinerHelper::applyLoadOrCombine(
3865+
bool CombinerHelper::applyBuildFn(
38663866
MachineInstr &MI, std::function<void(MachineIRBuilder &)> &MatchInfo) {
38673867
Builder.setInstrAndDebugLoc(MI);
38683868
MatchInfo(Builder);

llvm/lib/Target/AArch64/AArch64Combine.td

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@ def build_vector_to_dup : GICombineRule<
154154

155155
def build_vector_lowering : GICombineGroup<[build_vector_to_dup]>;
156156

157+
def bitfield_extract_from_sext_inreg : GICombineRule<
158+
(defs root:$root, build_fn_matchinfo:$info),
159+
(match (wip_match_opcode G_SEXT_INREG):$root,
160+
[{ return matchBitfieldExtractFromSExtInReg(*${root}, MRI, ${info}); }]),
161+
(apply [{ return Helper.applyBuildFn(*${root}, ${info}); }])>;
162+
163+
def form_bitfield_extract : GICombineGroup<[bitfield_extract_from_sext_inreg]>;
164+
157165
// Post-legalization combines which should happen at all optimization levels.
158166
// (E.g. ones that facilitate matching for the selector) For example, matching
159167
// pseudos.
@@ -172,6 +180,7 @@ def AArch64PostLegalizerCombinerHelper
172180
hoist_logic_op_with_same_opcode_hands,
173181
redundant_and, xor_of_and_with_same_reg,
174182
extractvecelt_pairwise_add, redundant_or,
175-
mul_const, redundant_sext_inreg]> {
183+
mul_const, redundant_sext_inreg,
184+
form_bitfield_extract]> {
176185
let DisableRuleOption = "aarch64postlegalizercombiner-disable-rule";
177186
}

llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
2525
#include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
2626
#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
27+
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
2728
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
2829
#include "llvm/CodeGen/GlobalISel/Utils.h"
2930
#include "llvm/CodeGen/MachineDominators.h"
@@ -36,6 +37,7 @@
3637
#define DEBUG_TYPE "aarch64-postlegalizer-combiner"
3738

3839
using namespace llvm;
40+
using namespace MIPatternMatch;
3941

4042
/// This combine tries do what performExtractVectorEltCombine does in SDAG.
4143
/// Rewrite for pairwise fadd pattern
@@ -238,6 +240,34 @@ bool applyAArch64MulConstCombine(
238240
return true;
239241
}
240242

243+
/// Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
244+
static bool matchBitfieldExtractFromSExtInReg(
245+
MachineInstr &MI, MachineRegisterInfo &MRI,
246+
std::function<void(MachineIRBuilder &)> &MatchInfo) {
247+
assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
248+
Register Dst = MI.getOperand(0).getReg();
249+
Register Src = MI.getOperand(1).getReg();
250+
int64_t Width = MI.getOperand(2).getImm();
251+
LLT Ty = MRI.getType(Src);
252+
assert((Ty == LLT::scalar(32) || Ty == LLT::scalar(64)) &&
253+
"Unexpected type for G_SEXT_INREG?");
254+
Register ShiftSrc;
255+
int64_t ShiftImm;
256+
if (!mi_match(
257+
Src, MRI,
258+
m_OneNonDBGUse(m_any_of(m_GAShr(m_Reg(ShiftSrc), m_ICst(ShiftImm)),
259+
m_GLShr(m_Reg(ShiftSrc), m_ICst(ShiftImm))))))
260+
return false;
261+
if (ShiftImm < 0 || ShiftImm + Width > Ty.getSizeInBits())
262+
return false;
263+
MatchInfo = [=](MachineIRBuilder &B) {
264+
auto Cst1 = B.buildConstant(Ty, ShiftImm);
265+
auto Cst2 = B.buildConstant(Ty, ShiftImm + Width - 1);
266+
B.buildInstr(TargetOpcode::G_SBFX, {Dst}, {ShiftSrc, Cst1, Cst2});
267+
};
268+
return true;
269+
}
270+
241271
#define AARCH64POSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
242272
#include "AArch64GenPostLegalizeGICombiner.inc"
243273
#undef AARCH64POSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s
3+
4+
# Check that we can fold a G_SEXT_INREG fed by a G_ASHR/G_LSHR into a G_SBFX.
5+
6+
...
7+
---
8+
name: sextinreg_ashr_to_sbfx
9+
tracksRegLiveness: true
10+
legalized: true
11+
body: |
12+
bb.0:
13+
liveins: $w0
14+
; CHECK-LABEL: name: sextinreg_ashr_to_sbfx
15+
; CHECK: liveins: $w0
16+
; CHECK: %x:_(s32) = COPY $w0
17+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
18+
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 14
19+
; CHECK: %sext_inreg:_(s32) = G_SBFX %x, [[C]], [[C1]]
20+
; CHECK: $w0 = COPY %sext_inreg(s32)
21+
; CHECK: RET_ReallyLR implicit $w0
22+
%x:_(s32) = COPY $w0
23+
%lsb:_(s32) = G_CONSTANT i32 5
24+
%shift:_(s32) = G_ASHR %x, %lsb
25+
%sext_inreg:_(s32) = G_SEXT_INREG %shift, 10
26+
$w0 = COPY %sext_inreg
27+
RET_ReallyLR implicit $w0
28+
29+
...
30+
---
31+
name: sextinreg_lshr_to_sbfx
32+
tracksRegLiveness: true
33+
legalized: true
34+
body: |
35+
bb.0:
36+
liveins: $w0
37+
; CHECK-LABEL: name: sextinreg_lshr_to_sbfx
38+
; CHECK: liveins: $w0
39+
; CHECK: %x:_(s32) = COPY $w0
40+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
41+
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 14
42+
; CHECK: %sext_inreg:_(s32) = G_SBFX %x, [[C]], [[C1]]
43+
; CHECK: $w0 = COPY %sext_inreg(s32)
44+
; CHECK: RET_ReallyLR implicit $w0
45+
%x:_(s32) = COPY $w0
46+
%lsb:_(s32) = G_CONSTANT i32 5
47+
%shift:_(s32) = G_LSHR %x, %lsb
48+
%sext_inreg:_(s32) = G_SEXT_INREG %shift, 10
49+
$w0 = COPY %sext_inreg
50+
RET_ReallyLR implicit $w0
51+
52+
53+
...
54+
---
55+
name: dont_apply_no_constant
56+
tracksRegLiveness: true
57+
legalized: true
58+
body: |
59+
bb.0:
60+
liveins: $w0
61+
; AArch64 needs a constant on the shift for this combine.
62+
63+
; CHECK-LABEL: name: dont_apply_no_constant
64+
; CHECK: liveins: $w0
65+
; CHECK: %x:_(s32) = COPY $w0
66+
; CHECK: %y:_(s32) = COPY $w0
67+
; CHECK: %shift:_(s32) = G_LSHR %x, %y(s32)
68+
; CHECK: %sext_inreg:_(s32) = G_SEXT_INREG %shift, 10
69+
; CHECK: $w0 = COPY %sext_inreg(s32)
70+
; CHECK: RET_ReallyLR implicit $w0
71+
%x:_(s32) = COPY $w0
72+
%y:_(s32) = COPY $w0
73+
%shift:_(s32) = G_LSHR %x, %y
74+
%sext_inreg:_(s32) = G_SEXT_INREG %shift, 10
75+
$w0 = COPY %sext_inreg
76+
RET_ReallyLR implicit $w0
77+
78+
...
79+
---
80+
name: dont_apply_shift_imm_too_large
81+
tracksRegLiveness: true
82+
legalized: true
83+
body: |
84+
bb.0:
85+
liveins: $w0
86+
87+
; LSB must be in 0-31.
88+
89+
; CHECK-LABEL: name: dont_apply_shift_imm_too_large
90+
; CHECK: liveins: $w0
91+
; CHECK: %x:_(s32) = COPY $w0
92+
; CHECK: %lsb:_(s32) = G_CONSTANT i32 32
93+
; CHECK: %shift:_(s32) = G_ASHR %x, %lsb(s32)
94+
; CHECK: %sext_inreg:_(s32) = G_SEXT_INREG %shift, 1
95+
; CHECK: $w0 = COPY %sext_inreg(s32)
96+
; CHECK: RET_ReallyLR implicit $w0
97+
%x:_(s32) = COPY $w0
98+
%lsb:_(s32) = G_CONSTANT i32 32
99+
%shift:_(s32) = G_ASHR %x, %lsb
100+
%sext_inreg:_(s32) = G_SEXT_INREG %shift, 1
101+
$w0 = COPY %sext_inreg
102+
RET_ReallyLR implicit $w0
103+
104+
...
105+
---
106+
name: dont_apply_negative_shift_imm
107+
tracksRegLiveness: true
108+
legalized: true
109+
body: |
110+
bb.0:
111+
liveins: $w0
112+
113+
; LSB must be in 0-31.
114+
115+
; CHECK-LABEL: name: dont_apply_negative_shift_imm
116+
; CHECK: liveins: $w0
117+
; CHECK: %x:_(s32) = COPY $w0
118+
; CHECK: %lsb:_(s32) = G_CONSTANT i32 -1
119+
; CHECK: %shift:_(s32) = G_ASHR %x, %lsb(s32)
120+
; CHECK: %sext_inreg:_(s32) = G_SEXT_INREG %shift, 1
121+
; CHECK: $w0 = COPY %sext_inreg(s32)
122+
; CHECK: RET_ReallyLR implicit $w0
123+
%x:_(s32) = COPY $w0
124+
%lsb:_(s32) = G_CONSTANT i32 -1
125+
%shift:_(s32) = G_ASHR %x, %lsb
126+
%sext_inreg:_(s32) = G_SEXT_INREG %shift, 1
127+
$w0 = COPY %sext_inreg
128+
RET_ReallyLR implicit $w0
129+
130+
...
131+
---
132+
name: dont_apply_more_than_one_use
133+
tracksRegLiveness: true
134+
legalized: true
135+
body: |
136+
bb.0:
137+
liveins: $w0
138+
; CHECK-LABEL: name: dont_apply_more_than_one_use
139+
; CHECK: liveins: $w0
140+
; CHECK: %x:_(s32) = COPY $w0
141+
; CHECK: %lsb:_(s32) = G_CONSTANT i32 1
142+
; CHECK: %shift:_(s32) = G_ASHR %x, %lsb(s32)
143+
; CHECK: %sext_inreg:_(s32) = G_SEXT_INREG %shift, 1
144+
; CHECK: %mul:_(s32) = G_MUL %shift, %sext_inreg
145+
; CHECK: $w0 = COPY %mul(s32)
146+
; CHECK: RET_ReallyLR implicit $w0
147+
%x:_(s32) = COPY $w0
148+
%lsb:_(s32) = G_CONSTANT i32 1
149+
%shift:_(s32) = G_ASHR %x, %lsb
150+
%sext_inreg:_(s32) = G_SEXT_INREG %shift, 1
151+
%mul:_(s32) = G_MUL %shift, %sext_inreg
152+
$w0 = COPY %mul
153+
RET_ReallyLR implicit $w0

0 commit comments

Comments
 (0)