Skip to content

Commit a9346e0

Browse files
committed
GlobalISel: Make MachineCSE runnable in the middle of the GlobalISel
Right now, it is not possible to run MachineCSE in the middle of the GlobalISel pipeline. Being able to run generic optimizations between the core passes of GlobalISel was one of the goals of the new ISel framework. This is the first attempt to do it. The problem is that MachineCSE pass assumes all register operands have a register class, which, in GlobalISel context, won't be true until after the InstructionSelect pass. The reason for this behaviour is that before replacing one virtual register with another, MachineCSE pass (and most of the other optimization machine passes) must check if the virtual registers' constraints have a (sufficiently large) intersection, and constrain the resulting register appropriately if such intersection exists. GlobalISel extends the representation of such constraints from just a register class to a triple (low-level type, register bank, register class). This commit adds MachineRegisterInfo::constrainRegAttrs method that extends MachineRegisterInfo::constrainRegClass to such a triple. The idea is that going forward we should use: - RegisterBankInfo::constrainGenericRegister within GlobalISel's InstructionSelect pass - MachineRegisterInfo::constrainRegClass within SelectionDAG ISel - MachineRegisterInfo::constrainRegAttrs everywhere else regardless the target and instruction selector it uses. Patch by Roman Tereshin. Thanks! llvm-svn: 322805
1 parent 3feefe0 commit a9346e0

File tree

5 files changed

+266
-17
lines changed

5 files changed

+266
-17
lines changed

llvm/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,8 @@ class RegisterBankInfo {
622622
/// \pre \p Reg is a virtual register that either has a bank or a class.
623623
/// \returns The constrained register class, or nullptr if there is none.
624624
/// \note This is a generic variant of MachineRegisterInfo::constrainRegClass
625+
/// \note Use MachineRegisterInfo::constrainRegAttrs instead for any non-isel
626+
/// purpose, including non-select passes of GlobalISel
625627
static const TargetRegisterClass *
626628
constrainGenericRegister(unsigned Reg, const TargetRegisterClass &RC,
627629
MachineRegisterInfo &MRI);

llvm/include/llvm/CodeGen/MachineRegisterInfo.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,16 @@ class MachineRegisterInfo {
548548
/// except that it also changes any definitions of the register as well.
549549
///
550550
/// Note that it is usually necessary to first constrain ToReg's register
551-
/// class to match the FromReg constraints using:
551+
/// class and register bank to match the FromReg constraints using one of the
552+
/// methods:
552553
///
553554
/// constrainRegClass(ToReg, getRegClass(FromReg))
555+
/// constrainRegAttrs(ToReg, FromReg)
556+
/// RegisterBankInfo::constrainGenericRegister(ToReg,
557+
/// *MRI.getRegClass(FromReg), MRI)
554558
///
555-
/// That function will return NULL if the virtual registers have incompatible
556-
/// constraints.
559+
/// These functions will return a falsy result if the virtual registers have
560+
/// incompatible constraints.
557561
///
558562
/// Note that if ToReg is a physical register the function will replace and
559563
/// apply sub registers to ToReg in order to obtain a final/proper physical
@@ -653,10 +657,30 @@ class MachineRegisterInfo {
653657
/// new register class, or NULL if no such class exists.
654658
/// This should only be used when the constraint is known to be trivial, like
655659
/// GR32 -> GR32_NOSP. Beware of increasing register pressure.
660+
///
661+
/// \note Assumes that the register has a register class assigned.
662+
/// Use RegisterBankInfo::constrainGenericRegister in GlobalISel's
663+
/// InstructionSelect pass and constrainRegAttrs in every other pass,
664+
/// including non-select passes of GlobalISel, instead.
656665
const TargetRegisterClass *constrainRegClass(unsigned Reg,
657666
const TargetRegisterClass *RC,
658667
unsigned MinNumRegs = 0);
659668

669+
/// Constrain the register class or the register bank of the virtual register
670+
/// \p Reg to be a common subclass and a common bank of both registers
671+
/// provided respectively. Do nothing if any of the attributes (classes,
672+
/// banks, or low-level types) of the registers are deemed incompatible, or if
673+
/// the resulting register will have a class smaller than before and of size
674+
/// less than \p MinNumRegs. Return true if such register attributes exist,
675+
/// false otherwise.
676+
///
677+
/// \note Assumes that each register has either a low-level type or a class
678+
/// assigned, but not both. Use this method instead of constrainRegClass and
679+
/// RegisterBankInfo::constrainGenericRegister everywhere but SelectionDAG
680+
/// ISel / FastISel and GlobalISel's InstructionSelect pass respectively.
681+
bool constrainRegAttrs(unsigned Reg, unsigned ConstrainingReg,
682+
unsigned MinNumRegs = 0);
683+
660684
/// recomputeRegClass - Try to find a legal super-class of Reg's register
661685
/// class that still satisfies the constraints from the instructions using
662686
/// Reg. Returns true if Reg was upgraded.

llvm/lib/CodeGen/MachineCSE.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@ bool MachineCSE::PerformTrivialCopyPropagation(MachineInstr *MI,
176176
// class given a super-reg class and subreg index.
177177
if (DefMI->getOperand(1).getSubReg())
178178
continue;
179-
const TargetRegisterClass *RC = MRI->getRegClass(Reg);
180-
if (!MRI->constrainRegClass(SrcReg, RC))
179+
if (!MRI->constrainRegAttrs(SrcReg, Reg))
181180
continue;
182181
DEBUG(dbgs() << "Coalescing: " << *DefMI);
183182
DEBUG(dbgs() << "*** to: " << *MI);
@@ -588,11 +587,11 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) {
588587
break;
589588
}
590589

591-
// Don't perform CSE if the result of the old instruction cannot exist
592-
// within the register class of the new instruction.
593-
const TargetRegisterClass *OldRC = MRI->getRegClass(OldReg);
594-
if (!MRI->constrainRegClass(NewReg, OldRC)) {
595-
DEBUG(dbgs() << "*** Not the same register class, avoid CSE!\n");
590+
// Don't perform CSE if the result of the new instruction cannot exist
591+
// within the constraints (register class, bank, or low-level type) of
592+
// the old instruction.
593+
if (!MRI->constrainRegAttrs(NewReg, OldReg)) {
594+
DEBUG(dbgs() << "*** Not the same register constraints, avoid CSE!\n");
596595
DoCSE = false;
597596
break;
598597
}

llvm/lib/CodeGen/MachineRegisterInfo.cpp

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,66 @@ void MachineRegisterInfo::setRegBank(unsigned Reg,
6565
VRegInfo[Reg].first = &RegBank;
6666
}
6767

68-
const TargetRegisterClass *
69-
MachineRegisterInfo::constrainRegClass(unsigned Reg,
70-
const TargetRegisterClass *RC,
71-
unsigned MinNumRegs) {
72-
const TargetRegisterClass *OldRC = getRegClass(Reg);
68+
static const TargetRegisterClass *
69+
constrainRegClass(MachineRegisterInfo &MRI, unsigned Reg,
70+
const TargetRegisterClass *OldRC,
71+
const TargetRegisterClass *RC, unsigned MinNumRegs) {
7372
if (OldRC == RC)
7473
return RC;
7574
const TargetRegisterClass *NewRC =
76-
getTargetRegisterInfo()->getCommonSubClass(OldRC, RC);
75+
MRI.getTargetRegisterInfo()->getCommonSubClass(OldRC, RC);
7776
if (!NewRC || NewRC == OldRC)
7877
return NewRC;
7978
if (NewRC->getNumRegs() < MinNumRegs)
8079
return nullptr;
81-
setRegClass(Reg, NewRC);
80+
MRI.setRegClass(Reg, NewRC);
8281
return NewRC;
8382
}
8483

84+
const TargetRegisterClass *
85+
MachineRegisterInfo::constrainRegClass(unsigned Reg,
86+
const TargetRegisterClass *RC,
87+
unsigned MinNumRegs) {
88+
return ::constrainRegClass(*this, Reg, getRegClass(Reg), RC, MinNumRegs);
89+
}
90+
91+
bool
92+
MachineRegisterInfo::constrainRegAttrs(unsigned Reg,
93+
unsigned ConstrainingReg,
94+
unsigned MinNumRegs) {
95+
auto const *OldRC = getRegClassOrNull(Reg);
96+
auto const *RC = getRegClassOrNull(ConstrainingReg);
97+
// A virtual register at any point must have either a low-level type
98+
// or a class assigned, but not both. The only exception is the internals of
99+
// GlobalISel's instruction selection pass, which is allowed to temporarily
100+
// introduce registers with types and classes both.
101+
assert((OldRC || getType(Reg).isValid()) && "Reg has neither class nor type");
102+
assert((!OldRC || !getType(Reg).isValid()) && "Reg has class and type both");
103+
assert((RC || getType(ConstrainingReg).isValid()) &&
104+
"ConstrainingReg has neither class nor type");
105+
assert((!RC || !getType(ConstrainingReg).isValid()) &&
106+
"ConstrainingReg has class and type both");
107+
if (OldRC && RC)
108+
return ::constrainRegClass(*this, Reg, OldRC, RC, MinNumRegs);
109+
// If one of the virtual registers is generic (used in generic machine
110+
// instructions, has a low-level type, doesn't have a class), and the other is
111+
// concrete (used in target specific instructions, doesn't have a low-level
112+
// type, has a class), we can not unify them.
113+
if (OldRC || RC)
114+
return false;
115+
// At this point, both registers are guaranteed to have a valid low-level
116+
// type, and they must agree.
117+
if (getType(Reg) != getType(ConstrainingReg))
118+
return false;
119+
auto const *OldRB = getRegBankOrNull(Reg);
120+
auto const *RB = getRegBankOrNull(ConstrainingReg);
121+
if (OldRB)
122+
return !RB || RB == OldRB;
123+
if (RB)
124+
setRegBank(Reg, *RB);
125+
return true;
126+
}
127+
85128
bool
86129
MachineRegisterInfo::recomputeRegClass(unsigned Reg) {
87130
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# RUN: llc -run-pass machine-cse -global-isel -verify-machineinstrs -mtriple aarch64-apple-ios %s -o - | FileCheck %s
2+
---
3+
name: irtranslated
4+
legalized: false
5+
regBankSelected: false
6+
selected: false
7+
body: |
8+
; CHECK-LABEL: name: irtranslated
9+
; CHECK: %[[ONE:[0-9]+]]:_(s32) = G_CONSTANT i32 1
10+
; CHECK-NEXT: %[[TWO:[0-9]+]]:_(s32) = G_ADD %[[ONE]], %[[ONE]]
11+
; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s32) = G_ADD %[[TWO]], %[[TWO]]
12+
; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
13+
; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
14+
bb.0:
15+
%0:_(s32) = G_CONSTANT i32 1
16+
%1:_(s32) = G_ADD %0, %0
17+
%2:_(s32) = G_ADD %0, %0
18+
%3:_(s32) = G_ADD %1, %2
19+
%w0 = COPY %3(s32)
20+
RET_ReallyLR implicit %w0
21+
...
22+
---
23+
name: regbankselected
24+
legalized: true
25+
regBankSelected: true
26+
selected: false
27+
body: |
28+
; CHECK-LABEL: name: regbankselected
29+
; CHECK: %[[ONE:[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
30+
; CHECK-NEXT: %[[TWO:[0-9]+]]:gpr(s32) = G_ADD %[[ONE]], %[[ONE]]
31+
; CHECK-NEXT: %[[SUM:[0-9]+]]:gpr(s32) = G_ADD %[[TWO]], %[[TWO]]
32+
; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
33+
; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
34+
bb.0:
35+
%0:gpr(s32) = G_CONSTANT i32 1
36+
%1:gpr(s32) = G_ADD %0, %0
37+
%2:gpr(s32) = G_ADD %0, %0
38+
%3:gpr(s32) = G_ADD %1, %2
39+
%w0 = COPY %3(s32)
40+
RET_ReallyLR implicit %w0
41+
...
42+
---
43+
name: legalized
44+
legalized: true
45+
regBankSelected: false
46+
selected: false
47+
body: |
48+
; CHECK-LABEL: name: legalized
49+
; CHECK: %[[ONE:[0-9]+]]:_(s32) = G_CONSTANT i32 1
50+
; CHECK-NEXT: %[[TWO:[0-9]+]]:gpr(s32) = G_ADD %[[ONE]], %[[ONE]]
51+
; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s32) = G_ADD %[[TWO]], %[[TWO]]
52+
; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
53+
; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
54+
bb.0:
55+
%0:_(s32) = G_CONSTANT i32 1
56+
%1:_(s32) = G_ADD %0, %0
57+
%2:gpr(s32) = G_ADD %0, %0
58+
%3:_(s32) = G_ADD %1, %2
59+
%w0 = COPY %3(s32)
60+
RET_ReallyLR implicit %w0
61+
...
62+
---
63+
name: legalized_sym
64+
legalized: true
65+
regBankSelected: false
66+
selected: false
67+
body: |
68+
; CHECK-LABEL: name: legalized_sym
69+
; CHECK: %[[ONE:[0-9]+]]:_(s32) = G_CONSTANT i32 1
70+
; CHECK-NEXT: %[[TWO:[0-9]+]]:gpr(s32) = G_ADD %[[ONE]], %[[ONE]]
71+
; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s32) = G_ADD %[[TWO]], %[[TWO]]
72+
; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
73+
; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
74+
bb.0:
75+
%0:_(s32) = G_CONSTANT i32 1
76+
%1:gpr(s32) = G_ADD %0, %0
77+
%2:_(s32) = G_ADD %0, %0
78+
%3:_(s32) = G_ADD %1, %2
79+
%w0 = COPY %3(s32)
80+
RET_ReallyLR implicit %w0
81+
...
82+
---
83+
name: int_extensions
84+
alignment: 2
85+
legalized: false
86+
regBankSelected: false
87+
selected: false
88+
body: |
89+
; CHECK-LABEL: name: int_extensions
90+
; CHECK: %[[ONE:[0-9]+]]:_(s8) = G_CONSTANT i8 1
91+
; CHECK-NEXT: %[[S16:[0-9]+]]:_(s16) = G_SEXT %[[ONE]](s8)
92+
; CHECK-NEXT: %[[S32:[0-9]+]]:_(s32) = G_SEXT %[[ONE]](s8)
93+
; CHECK-NEXT: %[[S16_Z64:[0-9]+]]:_(s64) = G_ZEXT %[[S16]](s16)
94+
; CHECK-NEXT: %[[S32_Z64:[0-9]+]]:_(s64) = G_ZEXT %[[S32]](s32)
95+
; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s64) = G_ADD %[[S16_Z64]], %[[S32_Z64]]
96+
; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s64)
97+
; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
98+
bb.0.entry:
99+
%0:_(s8) = G_CONSTANT i8 1
100+
%1:_(s16) = G_SEXT %0(s8)
101+
%2:_(s32) = G_SEXT %0(s8)
102+
%3:_(s64) = G_ZEXT %1(s16)
103+
%4:_(s64) = G_ZEXT %2(s32)
104+
%5:_(s64) = G_ADD %3, %4
105+
%x0 = COPY %5(s64)
106+
RET_ReallyLR implicit %x0
107+
...
108+
---
109+
name: generic
110+
legalized: true
111+
regBankSelected: false
112+
selected: false
113+
body: |
114+
; CHECK-LABEL: name: generic
115+
; CHECK: %[[SG:[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, %{{[0-9]+}}
116+
; CHECK-NEXT: %{{[0-9]+}}:_(s32) = G_ADD %[[SG]], %[[SG]]
117+
bb.0:
118+
%0:_(s32) = COPY %w0
119+
%1:_(s32) = COPY %w1
120+
%2:_(s32) = G_ADD %0, %1
121+
%3:_(s32) = COPY %2(s32)
122+
%4:_(s32) = G_ADD %3, %3
123+
%w0 = COPY %4(s32)
124+
RET_ReallyLR implicit %w0
125+
...
126+
---
127+
name: generic_to_concrete_copy
128+
legalized: true
129+
regBankSelected: false
130+
selected: false
131+
body: |
132+
; CHECK-LABEL: name: generic_to_concrete_copy
133+
; CHECK: %[[S1:[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, %{{[0-9]+}}
134+
; CHECK-NEXT: %[[S2:[0-9]+]]:gpr32 = COPY %[[S1]](s32)
135+
; CHECK-NEXT: %{{[0-9]+}}:gpr32 = ADDWrr %[[S2]], %[[S2]]
136+
bb.0:
137+
%0:_(s32) = COPY %w0
138+
%1:_(s32) = COPY %w1
139+
%2:_(s32) = G_ADD %0, %1
140+
%3:gpr32 = COPY %2(s32)
141+
%4:gpr32 = ADDWrr %3, %3
142+
%w0 = COPY %4
143+
RET_ReallyLR implicit %w0
144+
...
145+
---
146+
name: concrete_to_generic_copy
147+
legalized: true
148+
regBankSelected: false
149+
selected: false
150+
body: |
151+
; CHECK-LABEL: name: concrete_to_generic_copy
152+
; CHECK: %[[S1:[0-9]+]]:gpr32 = ADDWrr %{{[0-9]+}}, %{{[0-9]+}}
153+
; CHECK-NEXT: %[[S2:[0-9]+]]:_(s32) = COPY %[[S1]]
154+
; CHECK-NEXT: %{{[0-9]+}}:_(s32) = G_ADD %[[S2]], %[[S2]]
155+
bb.0:
156+
%0:gpr32 = COPY %w0
157+
%1:gpr32 = COPY %w1
158+
%2:gpr32 = ADDWrr %0, %1
159+
%3:_(s32) = COPY %2
160+
%4:_(s32) = G_ADD %3, %3
161+
%w0 = COPY %4(s32)
162+
RET_ReallyLR implicit %w0
163+
...
164+
---
165+
name: concrete
166+
legalized: true
167+
regBankSelected: false
168+
selected: false
169+
body: |
170+
; CHECK-LABEL: name: concrete
171+
; CHECK: %[[SC:[0-9]+]]:gpr32 = ADDWrr %{{[0-9]+}}, %{{[0-9]+}}
172+
; CHECK-NEXT: %{{[0-9]+}}:gpr32 = ADDWrr %[[SC]], %[[SC]]
173+
bb.0:
174+
%0:gpr32 = COPY %w0
175+
%1:gpr32 = COPY %w1
176+
%2:gpr32 = ADDWrr %0, %1
177+
%3:gpr32 = COPY %2
178+
%4:gpr32 = ADDWrr %3, %3
179+
%w0 = COPY %4
180+
RET_ReallyLR implicit %w0
181+
...

0 commit comments

Comments
 (0)