Skip to content

Commit aaf6755

Browse files
committed
[GlobalISel] Refactor Combiner API
Remove CodeGen leftovers from the old combiner backend and adapt the API to fit the new backend better. It's now quite a bit closer to how InstructionSelector works. - `CombinerInfo` is now a simple "options" struct. - `Combiner` is now the base class of all TableGen'd combiner implementation. - Many fields have been moved from derived classes into that class. - It has been refactored to create & own the Observer and Builder. - `tryCombineAll` TableGen'd method can now be renamed, which allows targets to implement the actual `tryCombineAll` call manually and do whatever they want to do before/after it. Note: `CombinerHelper` needs to be mutable because none of its methods are const. This can be revisited later. Depends on D158710 Reviewed By: aemerson, dsanders Differential Revision: https://reviews.llvm.org/D158713
1 parent 538f135 commit aaf6755

17 files changed

+424
-520
lines changed

llvm/include/llvm/CodeGen/GlobalISel/Combiner.h

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,70 @@
66
//
77
//===----------------------------------------------------------------------===//
88
/// \file
9-
/// This contains common code to drive combines. Combiner Passes will need to
10-
/// setup a CombinerInfo and call combineMachineFunction.
9+
/// This contains the base class for all Combiners generated by TableGen.
10+
/// Backends need to create class that inherits from "Combiner" and put all of
11+
/// the TableGen-erated code in there, as it implements the virtual functions.
1112
///
1213
//===----------------------------------------------------------------------===//
1314

1415
#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINER_H
1516
#define LLVM_CODEGEN_GLOBALISEL_COMBINER_H
1617

18+
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
19+
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
1720
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
1821

1922
namespace llvm {
2023
class MachineRegisterInfo;
21-
class CombinerInfo;
24+
struct CombinerInfo;
2225
class GISelCSEInfo;
2326
class TargetPassConfig;
2427
class MachineFunction;
28+
class MachineIRBuilder;
29+
30+
/// Combiner implementation. This is per-function, so passes need to recreate
31+
/// one of these each time they enter a new function.
32+
///
33+
/// TODO: Is it worth making this module-wide?
34+
class Combiner : public GIMatchTableExecutor {
35+
private:
36+
class WorkListMaintainer;
37+
GISelWorkList<512> WorkList;
38+
39+
// We have a little hack here where keep the owned pointers private, and only
40+
// expose a reference. This has two purposes:
41+
// - Avoid derived classes messing with those pointers.
42+
// - Keep the API consistent. CInfo, MF, MRI, etc. are all accessed as
43+
// references. Accessing Observer/B as pointers unnecessarily leaks
44+
// implementation details into derived classes.
45+
std::unique_ptr<MachineIRBuilder> Builder;
46+
std::unique_ptr<WorkListMaintainer> WLObserver;
47+
std::unique_ptr<GISelObserverWrapper> ObserverWrapper;
48+
49+
bool HasSetupMF = false;
2550

26-
class Combiner {
2751
public:
28-
Combiner(CombinerInfo &CombinerInfo, const TargetPassConfig *TPC);
52+
/// If CSEInfo is not null, then the Combiner will use CSEInfo as the observer
53+
/// and also create a CSEMIRBuilder. Pass nullptr if CSE is not needed.
54+
Combiner(MachineFunction &MF, CombinerInfo &CInfo,
55+
const TargetPassConfig *TPC, GISelKnownBits *KB,
56+
GISelCSEInfo *CSEInfo = nullptr);
57+
virtual ~Combiner();
58+
59+
virtual bool tryCombineAll(MachineInstr &I) const = 0;
2960

30-
/// If CSEInfo is not null, then the Combiner will setup observer for
31-
/// CSEInfo and instantiate a CSEMIRBuilder. Pass nullptr if CSE is not
32-
/// needed.
33-
bool combineMachineInstrs(MachineFunction &MF, GISelCSEInfo *CSEInfo);
61+
bool combineMachineInstrs();
3462

3563
protected:
3664
CombinerInfo &CInfo;
65+
GISelChangeObserver &Observer;
66+
MachineIRBuilder &B;
67+
MachineFunction &MF;
68+
MachineRegisterInfo &MRI;
69+
GISelKnownBits *KB;
3770

38-
MachineRegisterInfo *MRI = nullptr;
3971
const TargetPassConfig *TPC;
40-
std::unique_ptr<MachineIRBuilder> Builder;
72+
GISelCSEInfo *CSEInfo;
4173
};
4274

4375
} // End namespace llvm.

llvm/include/llvm/CodeGen/GlobalISel/CombinerInfo.h

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
//
77
//===----------------------------------------------------------------------===//
88
/// \file
9-
/// Interface for Targets to specify which operations are combined how and when.
9+
/// Option class for Targets to specify which operations are combined how and
10+
/// when.
1011
///
1112
//===----------------------------------------------------------------------===//
1213

@@ -16,15 +17,11 @@
1617
#include <cassert>
1718
namespace llvm {
1819

19-
class GISelChangeObserver;
2020
class LegalizerInfo;
21-
class MachineInstr;
22-
class MachineIRBuilder;
2321

2422
// Contains information relevant to enabling/disabling various combines for a
2523
// pass.
26-
class CombinerInfo {
27-
public:
24+
struct CombinerInfo {
2825
CombinerInfo(bool AllowIllegalOps, bool ShouldLegalizeIllegal,
2926
const LegalizerInfo *LInfo, bool OptEnabled, bool OptSize,
3027
bool MinSize)
@@ -52,19 +49,6 @@ class CombinerInfo {
5249
bool EnableOptSize;
5350
/// Whether we're optimizing for minsize (-Oz).
5451
bool EnableMinSize;
55-
56-
/// Attempt to combine instructions using MI as the root.
57-
///
58-
/// Use Observer to report the creation, modification, and erasure of
59-
/// instructions. GISelChangeObserver will automatically report certain
60-
/// kinds of operations. These operations are:
61-
/// * Instructions that are newly inserted into the MachineFunction
62-
/// * Instructions that are erased from the MachineFunction.
63-
///
64-
/// However, it is important to report instruction modification and this is
65-
/// not automatic.
66-
virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
67-
MachineIRBuilder &B) const = 0;
6852
};
6953
} // namespace llvm
7054

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,7 @@ class GIMatchTableExecutor {
463463
// For some predicates, we need to track the current MBB.
464464
MachineBasicBlock *CurMBB = nullptr;
465465

466-
virtual void setupGeneratedPerFunctionState(MachineFunction &MF) {
467-
llvm_unreachable("TableGen should have emitted implementation");
468-
}
466+
virtual void setupGeneratedPerFunctionState(MachineFunction &MF) = 0;
469467

470468
/// Setup per-MF executor state.
471469
virtual void setupMF(MachineFunction &mf, GISelKnownBits *kb,

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class GICombinerHelper<string classname, list<GICombine> rules>
3737
: GICombineGroup<rules> {
3838
// The class name to use in the generated output.
3939
string Classname = classname;
40+
// Combiners can use this so they're free to define tryCombineAll themselves
41+
// and do extra work before/after calling the TableGen-erated code.
42+
string CombineAllMethodName = "tryCombineAll";
4043
// The name of a run-time compiler option that will be generated to disable
4144
// specific rules within this combiner.
4245
string DisableRuleOption = ?;

llvm/lib/CodeGen/GlobalISel/Combiner.cpp

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ cl::OptionCategory GICombinerOptionCategory(
3939
);
4040
} // end namespace llvm
4141

42-
namespace {
4342
/// This class acts as the glue the joins the CombinerHelper to the overall
4443
/// Combine algorithm. The CombinerHelper is intended to report the
4544
/// modifications it makes to the MIR to the GISelChangeObserver and the
@@ -48,7 +47,7 @@ namespace {
4847
/// instruction creation will schedule that instruction for a future visit.
4948
/// Other Combiner implementations may require more complex behaviour from
5049
/// their GISelChangeObserver subclass.
51-
class WorkListMaintainer : public GISelChangeObserver {
50+
class Combiner::WorkListMaintainer : public GISelChangeObserver {
5251
using WorkListTy = GISelWorkList<512>;
5352
WorkListTy &WorkList;
5453
/// The instructions that have been created but we want to report once they
@@ -88,54 +87,70 @@ class WorkListMaintainer : public GISelChangeObserver {
8887
LLVM_DEBUG(CreatedInstrs.clear());
8988
}
9089
};
91-
}
9290

93-
Combiner::Combiner(CombinerInfo &Info, const TargetPassConfig *TPC)
94-
: CInfo(Info), TPC(TPC) {
91+
Combiner::Combiner(MachineFunction &MF, CombinerInfo &CInfo,
92+
const TargetPassConfig *TPC, GISelKnownBits *KB,
93+
GISelCSEInfo *CSEInfo)
94+
: Builder(CSEInfo ? std::make_unique<CSEMIRBuilder>()
95+
: std::make_unique<MachineIRBuilder>()),
96+
WLObserver(std::make_unique<WorkListMaintainer>(WorkList)),
97+
ObserverWrapper(std::make_unique<GISelObserverWrapper>()), CInfo(CInfo),
98+
Observer(*ObserverWrapper), B(*Builder), MF(MF), MRI(MF.getRegInfo()),
99+
KB(KB), TPC(TPC), CSEInfo(CSEInfo) {
95100
(void)this->TPC; // FIXME: Remove when used.
101+
102+
// Setup builder.
103+
B.setMF(MF);
104+
if (CSEInfo)
105+
B.setCSEInfo(CSEInfo);
106+
107+
// Setup observer.
108+
ObserverWrapper->addObserver(WLObserver.get());
109+
if (CSEInfo)
110+
ObserverWrapper->addObserver(CSEInfo);
111+
112+
B.setChangeObserver(*ObserverWrapper);
96113
}
97114

98-
bool Combiner::combineMachineInstrs(MachineFunction &MF,
99-
GISelCSEInfo *CSEInfo) {
115+
Combiner::~Combiner() = default;
116+
117+
bool Combiner::combineMachineInstrs() {
100118
// If the ISel pipeline failed, do not bother running this pass.
101119
// FIXME: Should this be here or in individual combiner passes.
102120
if (MF.getProperties().hasProperty(
103121
MachineFunctionProperties::Property::FailedISel))
104122
return false;
105123

106-
Builder =
107-
CSEInfo ? std::make_unique<CSEMIRBuilder>() : std::make_unique<MachineIRBuilder>();
108-
MRI = &MF.getRegInfo();
109-
Builder->setMF(MF);
110-
if (CSEInfo)
111-
Builder->setCSEInfo(CSEInfo);
124+
// We can't call this in the constructor because the derived class is
125+
// uninitialized at that time.
126+
if (!HasSetupMF) {
127+
HasSetupMF = true;
128+
setupMF(MF, KB);
129+
}
112130

113131
LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n');
114132

115133
MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
116134

117135
bool MFChanged = false;
118136
bool Changed;
119-
MachineIRBuilder &B = *Builder;
120137

121138
do {
139+
WorkList.clear();
140+
122141
// Collect all instructions. Do a post order traversal for basic blocks and
123142
// insert with list bottom up, so while we pop_back_val, we'll traverse top
124143
// down RPOT.
125144
Changed = false;
126-
GISelWorkList<512> WorkList;
127-
WorkListMaintainer Observer(WorkList);
128-
GISelObserverWrapper WrapperObserver(&Observer);
129-
if (CSEInfo)
130-
WrapperObserver.addObserver(CSEInfo);
131-
RAIIDelegateInstaller DelInstall(MF, &WrapperObserver);
145+
146+
RAIIDelegateInstaller DelInstall(MF, ObserverWrapper.get());
132147
for (MachineBasicBlock *MBB : post_order(&MF)) {
133148
for (MachineInstr &CurMI :
134149
llvm::make_early_inc_range(llvm::reverse(*MBB))) {
135150
// Erase dead insts before even adding to the list.
136-
if (isTriviallyDead(CurMI, *MRI)) {
151+
if (isTriviallyDead(CurMI, MRI)) {
137152
LLVM_DEBUG(dbgs() << CurMI << "Is dead; erasing.\n");
138-
llvm::salvageDebugInfo(*MRI, CurMI);
153+
llvm::salvageDebugInfo(MRI, CurMI);
139154
CurMI.eraseFromParent();
140155
continue;
141156
}
@@ -147,8 +162,8 @@ bool Combiner::combineMachineInstrs(MachineFunction &MF,
147162
while (!WorkList.empty()) {
148163
MachineInstr *CurrInst = WorkList.pop_back_val();
149164
LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;);
150-
Changed |= CInfo.combine(WrapperObserver, *CurrInst, B);
151-
Observer.reportFullyCreatedInstrs();
165+
Changed |= tryCombineAll(*CurrInst);
166+
WLObserver->reportFullyCreatedInstrs();
152167
}
153168
MFChanged |= Changed;
154169
} while (Changed);

llvm/lib/Target/AArch64/AArch64Combine.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ def AArch64PreLegalizerCombiner: GICombinerHelper<
3838
fconstant_to_constant,
3939
icmp_redundant_trunc,
4040
fold_global_offset]> {
41+
let CombineAllMethodName = "tryCombineAllImpl";
4142
}
4243

4344
def AArch64O0PreLegalizerCombiner: GICombinerHelper<
4445
"AArch64O0PreLegalizerCombinerImpl", [optnone_combines]> {
46+
let CombineAllMethodName = "tryCombineAllImpl";
4547
}
4648

4749
// Matchdata for combines which replace a G_SHUFFLE_VECTOR with a

0 commit comments

Comments
 (0)