Skip to content

Commit bd9e145

Browse files
authored
[CodeGen] Port GlobalMerge to new pass manager (llvm#77474)
1 parent d06fb0b commit bd9e145

File tree

12 files changed

+182
-83
lines changed

12 files changed

+182
-83
lines changed

llvm/include/llvm/CodeGen/CodeGenPassBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/CodeGen/ExpandMemCmp.h"
3131
#include "llvm/CodeGen/ExpandReductions.h"
3232
#include "llvm/CodeGen/GCMetadata.h"
33+
#include "llvm/CodeGen/GlobalMerge.h"
3334
#include "llvm/CodeGen/IndirectBrExpand.h"
3435
#include "llvm/CodeGen/InterleavedAccess.h"
3536
#include "llvm/CodeGen/InterleavedLoadCombine.h"
@@ -280,6 +281,9 @@ template <typename DerivedT> class CodeGenPassBuilder {
280281
inconvertibleErrorCode());
281282
}
282283

284+
/// Target can override this to add GlobalMergePass before all IR passes.
285+
void addGlobalMergePass(AddIRPass &) const {}
286+
283287
/// Add passes that optimize instruction level parallelism for out-of-order
284288
/// targets. These passes are run while the machine code is still in SSA
285289
/// form, so they can use MachineTraceMetrics to control their heuristics.
@@ -593,6 +597,7 @@ CodeGenPassBuilder<Derived>::getPassNameFromLegacyName(StringRef Name) const {
593597

594598
template <typename Derived>
595599
void CodeGenPassBuilder<Derived>::addISelPasses(AddIRPass &addPass) const {
600+
derived().addGlobalMergePass(addPass);
596601
if (TM.useEmulatedTLS())
597602
addPass(LowerEmuTLSPass());
598603

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===- llvm/CodeGen/GlobalMerge.h -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CODEGEN_GLOBALMERGE_H
10+
#define LLVM_CODEGEN_GLOBALMERGE_H
11+
12+
#include "llvm/IR/PassManager.h"
13+
14+
namespace llvm {
15+
16+
class TargetMachine;
17+
18+
struct GlobalMergeOptions {
19+
// FIXME: Infer the maximum possible offset depending on the actual users
20+
// (these max offsets are different for the users inside Thumb or ARM
21+
// functions), see the code that passes in the offset in the ARM backend
22+
// for more information.
23+
unsigned MaxOffset = 0;
24+
bool GroupByUse = true;
25+
bool IgnoreSingleUse = true;
26+
bool MergeConst = false;
27+
/// Whether we should merge global variables that have external linkage.
28+
bool MergeExternal = true;
29+
/// Whether we should try to optimize for size only.
30+
/// Currently, this applies a dead simple heuristic: only consider globals
31+
/// used in minsize functions for merging.
32+
/// FIXME: This could learn about optsize, and be used in the cost model.
33+
bool SizeOnly = false;
34+
};
35+
36+
// FIXME: This pass must run before AsmPrinterPass::doInitialization!
37+
class GlobalMergePass : public PassInfoMixin<GlobalMergePass> {
38+
const TargetMachine *TM;
39+
GlobalMergeOptions Options;
40+
41+
public:
42+
GlobalMergePass(const TargetMachine *TM, GlobalMergeOptions Options)
43+
: TM(TM), Options(Options) {}
44+
45+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
46+
};
47+
48+
} // namespace llvm
49+
50+
#endif // LLVM_CODEGEN_GLOBALMERGE_H

llvm/include/llvm/CodeGen/MachinePassRegistry.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis, (PIC))
2323
#ifndef MODULE_PASS
2424
#define MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR)
2525
#endif
26-
MODULE_PASS("pre-isel-intrinsic-lowering", PreISelIntrinsicLoweringPass, ())
26+
MODULE_PASS("global-merge", GlobalMergePass, (TM, GlobalMergeOptions()))
2727
MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass, ())
2828
MODULE_PASS("lower-emutls", LowerEmuTLSPass, ())
29+
MODULE_PASS("pre-isel-intrinsic-lowering", PreISelIntrinsicLoweringPass, ())
2930
MODULE_PASS("shadow-stack-gc-lowering", ShadowStackGCLoweringPass, ())
3031
#undef MODULE_PASS
3132

llvm/lib/CodeGen/GlobalMerge.cpp

Lines changed: 85 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
//
6161
// ===---------------------------------------------------------------------===//
6262

63+
#include "llvm/CodeGen/GlobalMerge.h"
6364
#include "llvm/ADT/BitVector.h"
6465
#include "llvm/ADT/DenseMap.h"
6566
#include "llvm/ADT/SetVector.h"
@@ -137,88 +138,99 @@ STATISTIC(NumMerged, "Number of globals merged");
137138

138139
namespace {
139140

140-
class GlobalMerge : public FunctionPass {
141-
const TargetMachine *TM = nullptr;
142-
143-
// FIXME: Infer the maximum possible offset depending on the actual users
144-
// (these max offsets are different for the users inside Thumb or ARM
145-
// functions), see the code that passes in the offset in the ARM backend
146-
// for more information.
147-
unsigned MaxOffset;
148-
149-
/// Whether we should try to optimize for size only.
150-
/// Currently, this applies a dead simple heuristic: only consider globals
151-
/// used in minsize functions for merging.
152-
/// FIXME: This could learn about optsize, and be used in the cost model.
153-
bool OnlyOptimizeForSize = false;
154-
155-
/// Whether we should merge global variables that have external linkage.
156-
bool MergeExternalGlobals = false;
141+
class GlobalMergeImpl {
142+
const TargetMachine *TM = nullptr;
143+
GlobalMergeOptions Opt;
144+
bool IsMachO = false;
145+
146+
private:
147+
bool doMerge(SmallVectorImpl<GlobalVariable *> &Globals, Module &M,
148+
bool isConst, unsigned AddrSpace) const;
149+
150+
/// Merge everything in \p Globals for which the corresponding bit
151+
/// in \p GlobalSet is set.
152+
bool doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
153+
const BitVector &GlobalSet, Module &M, bool isConst,
154+
unsigned AddrSpace) const;
155+
156+
/// Check if the given variable has been identified as must keep
157+
/// \pre setMustKeepGlobalVariables must have been called on the Module that
158+
/// contains GV
159+
bool isMustKeepGlobalVariable(const GlobalVariable *GV) const {
160+
return MustKeepGlobalVariables.count(GV);
161+
}
157162

158-
bool IsMachO = false;
163+
/// Collect every variables marked as "used" or used in a landing pad
164+
/// instruction for this Module.
165+
void setMustKeepGlobalVariables(Module &M);
159166

160-
bool doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
161-
Module &M, bool isConst, unsigned AddrSpace) const;
167+
/// Collect every variables marked as "used"
168+
void collectUsedGlobalVariables(Module &M, StringRef Name);
162169

163-
/// Merge everything in \p Globals for which the corresponding bit
164-
/// in \p GlobalSet is set.
165-
bool doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
166-
const BitVector &GlobalSet, Module &M, bool isConst,
167-
unsigned AddrSpace) const;
170+
/// Keep track of the GlobalVariable that must not be merged away
171+
SmallSetVector<const GlobalVariable *, 16> MustKeepGlobalVariables;
168172

169-
/// Check if the given variable has been identified as must keep
170-
/// \pre setMustKeepGlobalVariables must have been called on the Module that
171-
/// contains GV
172-
bool isMustKeepGlobalVariable(const GlobalVariable *GV) const {
173-
return MustKeepGlobalVariables.count(GV);
174-
}
173+
public:
174+
GlobalMergeImpl(const TargetMachine *TM, GlobalMergeOptions Opt)
175+
: TM(TM), Opt(Opt) {}
176+
bool run(Module &M);
177+
};
175178

176-
/// Collect every variables marked as "used" or used in a landing pad
177-
/// instruction for this Module.
178-
void setMustKeepGlobalVariables(Module &M);
179+
class GlobalMerge : public FunctionPass {
180+
const TargetMachine *TM = nullptr;
181+
GlobalMergeOptions Opt;
179182

180-
/// Collect every variables marked as "used"
181-
void collectUsedGlobalVariables(Module &M, StringRef Name);
183+
public:
184+
static char ID; // Pass identification, replacement for typeid.
182185

183-
/// Keep track of the GlobalVariable that must not be merged away
184-
SmallSetVector<const GlobalVariable *, 16> MustKeepGlobalVariables;
186+
explicit GlobalMerge() : FunctionPass(ID) {
187+
Opt.MaxOffset = GlobalMergeMaxOffset;
188+
initializeGlobalMergePass(*PassRegistry::getPassRegistry());
189+
}
185190

186-
public:
187-
static char ID; // Pass identification, replacement for typeid.
191+
explicit GlobalMerge(const TargetMachine *TM, unsigned MaximalOffset,
192+
bool OnlyOptimizeForSize, bool MergeExternalGlobals)
193+
: FunctionPass(ID), TM(TM) {
194+
Opt.MaxOffset = MaximalOffset;
195+
Opt.SizeOnly = OnlyOptimizeForSize;
196+
Opt.MergeExternal = MergeExternalGlobals;
197+
initializeGlobalMergePass(*PassRegistry::getPassRegistry());
198+
}
188199

189-
explicit GlobalMerge()
190-
: FunctionPass(ID), MaxOffset(GlobalMergeMaxOffset) {
191-
initializeGlobalMergePass(*PassRegistry::getPassRegistry());
192-
}
200+
bool doInitialization(Module &M) override {
201+
GlobalMergeImpl P(TM, Opt);
202+
return P.run(M);
203+
}
204+
bool runOnFunction(Function &F) override { return false; }
193205

194-
explicit GlobalMerge(const TargetMachine *TM, unsigned MaximalOffset,
195-
bool OnlyOptimizeForSize, bool MergeExternalGlobals)
196-
: FunctionPass(ID), TM(TM), MaxOffset(MaximalOffset),
197-
OnlyOptimizeForSize(OnlyOptimizeForSize),
198-
MergeExternalGlobals(MergeExternalGlobals) {
199-
initializeGlobalMergePass(*PassRegistry::getPassRegistry());
200-
}
206+
StringRef getPassName() const override { return "Merge internal globals"; }
201207

202-
bool doInitialization(Module &M) override;
203-
bool runOnFunction(Function &F) override;
204-
bool doFinalization(Module &M) override;
208+
void getAnalysisUsage(AnalysisUsage &AU) const override {
209+
AU.setPreservesCFG();
210+
FunctionPass::getAnalysisUsage(AU);
211+
}
212+
};
205213

206-
StringRef getPassName() const override { return "Merge internal globals"; }
214+
} // end anonymous namespace
207215

208-
void getAnalysisUsage(AnalysisUsage &AU) const override {
209-
AU.setPreservesCFG();
210-
FunctionPass::getAnalysisUsage(AU);
211-
}
212-
};
216+
PreservedAnalyses GlobalMergePass::run(Module &M, ModuleAnalysisManager &) {
217+
GlobalMergeImpl P(TM, Options);
218+
bool Changed = P.run(M);
219+
if (!Changed)
220+
return PreservedAnalyses::all();
213221

214-
} // end anonymous namespace
222+
PreservedAnalyses PA;
223+
PA.preserveSet<CFGAnalyses>();
224+
return PA;
225+
}
215226

216227
char GlobalMerge::ID = 0;
217228

218229
INITIALIZE_PASS(GlobalMerge, DEBUG_TYPE, "Merge global variables", false, false)
219230

220-
bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
221-
Module &M, bool isConst, unsigned AddrSpace) const {
231+
bool GlobalMergeImpl::doMerge(SmallVectorImpl<GlobalVariable *> &Globals,
232+
Module &M, bool isConst,
233+
unsigned AddrSpace) const {
222234
auto &DL = M.getDataLayout();
223235
// FIXME: Find better heuristics
224236
llvm::stable_sort(
@@ -333,7 +345,7 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
333345
Function *ParentFn = I->getParent()->getParent();
334346

335347
// If we're only optimizing for size, ignore non-minsize functions.
336-
if (OnlyOptimizeForSize && !ParentFn->hasMinSize())
348+
if (Opt.SizeOnly && !ParentFn->hasMinSize())
337349
continue;
338350

339351
size_t UGSIdx = GlobalUsesByFunction[ParentFn];
@@ -434,9 +446,9 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
434446
return Changed;
435447
}
436448

437-
bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
438-
const BitVector &GlobalSet, Module &M, bool isConst,
439-
unsigned AddrSpace) const {
449+
bool GlobalMergeImpl::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
450+
const BitVector &GlobalSet, Module &M,
451+
bool isConst, unsigned AddrSpace) const {
440452
assert(Globals.size() > 1);
441453

442454
Type *Int32Ty = Type::getInt32Ty(M.getContext());
@@ -467,7 +479,7 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
467479
unsigned Padding = alignTo(MergedSize, Alignment) - MergedSize;
468480
MergedSize += Padding;
469481
MergedSize += DL.getTypeAllocSize(Ty);
470-
if (MergedSize > MaxOffset) {
482+
if (MergedSize > Opt.MaxOffset) {
471483
break;
472484
}
473485
if (Padding) {
@@ -563,7 +575,7 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
563575
return Changed;
564576
}
565577

566-
void GlobalMerge::collectUsedGlobalVariables(Module &M, StringRef Name) {
578+
void GlobalMergeImpl::collectUsedGlobalVariables(Module &M, StringRef Name) {
567579
// Extract global variables from llvm.used array
568580
const GlobalVariable *GV = M.getGlobalVariable(Name);
569581
if (!GV || !GV->hasInitializer()) return;
@@ -577,7 +589,7 @@ void GlobalMerge::collectUsedGlobalVariables(Module &M, StringRef Name) {
577589
MustKeepGlobalVariables.insert(G);
578590
}
579591

580-
void GlobalMerge::setMustKeepGlobalVariables(Module &M) {
592+
void GlobalMergeImpl::setMustKeepGlobalVariables(Module &M) {
581593
collectUsedGlobalVariables(M, "llvm.used");
582594
collectUsedGlobalVariables(M, "llvm.compiler.used");
583595

@@ -604,7 +616,7 @@ void GlobalMerge::setMustKeepGlobalVariables(Module &M) {
604616
}
605617
}
606618

607-
bool GlobalMerge::doInitialization(Module &M) {
619+
bool GlobalMergeImpl::run(Module &M) {
608620
if (!EnableGlobalMerge)
609621
return false;
610622

@@ -632,7 +644,7 @@ bool GlobalMerge::doInitialization(Module &M) {
632644
if (TM && !TM->shouldAssumeDSOLocal(M, &GV))
633645
continue;
634646

635-
if (!(MergeExternalGlobals && GV.hasExternalLinkage()) &&
647+
if (!(Opt.MergeExternal && GV.hasExternalLinkage()) &&
636648
!GV.hasInternalLinkage())
637649
continue;
638650

@@ -659,7 +671,7 @@ bool GlobalMerge::doInitialization(Module &M) {
659671
continue;
660672

661673
Type *Ty = GV.getValueType();
662-
if (DL.getTypeAllocSize(Ty) < MaxOffset) {
674+
if (DL.getTypeAllocSize(Ty) < Opt.MaxOffset) {
663675
if (TM &&
664676
TargetLoweringObjectFile::getKindForGlobal(&GV, *TM).isBSS())
665677
BSSGlobals[{AddressSpace, Section}].push_back(&GV);
@@ -686,15 +698,6 @@ bool GlobalMerge::doInitialization(Module &M) {
686698
return Changed;
687699
}
688700

689-
bool GlobalMerge::runOnFunction(Function &F) {
690-
return false;
691-
}
692-
693-
bool GlobalMerge::doFinalization(Module &M) {
694-
MustKeepGlobalVariables.clear();
695-
return false;
696-
}
697-
698701
Pass *llvm::createGlobalMergePass(const TargetMachine *TM, unsigned Offset,
699702
bool OnlyOptimizeForSize,
700703
bool MergeExternalByDefault) {

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#include "llvm/CodeGen/ExpandLargeFpConvert.h"
8282
#include "llvm/CodeGen/ExpandMemCmp.h"
8383
#include "llvm/CodeGen/GCMetadata.h"
84+
#include "llvm/CodeGen/GlobalMerge.h"
8485
#include "llvm/CodeGen/HardwareLoops.h"
8586
#include "llvm/CodeGen/IndirectBrExpand.h"
8687
#include "llvm/CodeGen/InterleavedAccess.h"
@@ -1082,6 +1083,32 @@ Expected<bool> parseWinEHPrepareOptions(StringRef Params) {
10821083
"WinEHPreparePass");
10831084
}
10841085

1086+
Expected<GlobalMergeOptions> parseGlobalMergeOptions(StringRef Params) {
1087+
GlobalMergeOptions Result;
1088+
while (!Params.empty()) {
1089+
StringRef ParamName;
1090+
std::tie(ParamName, Params) = Params.split(';');
1091+
1092+
bool Enable = !ParamName.consume_front("no-");
1093+
if (ParamName == "group-by-use")
1094+
Result.GroupByUse = Enable;
1095+
else if (ParamName == "ignore-single-use")
1096+
Result.IgnoreSingleUse = Enable;
1097+
else if (ParamName == "merge-const")
1098+
Result.MergeConst = Enable;
1099+
else if (ParamName == "merge-external")
1100+
Result.MergeExternal = Enable;
1101+
else if (ParamName.consume_front("max-offset=")) {
1102+
if (ParamName.getAsInteger(0, Result.MaxOffset))
1103+
return make_error<StringError>(
1104+
formatv("invalid GlobalMergePass parameter '{0}' ", ParamName)
1105+
.str(),
1106+
inconvertibleErrorCode());
1107+
}
1108+
}
1109+
return Result;
1110+
}
1111+
10851112
} // namespace
10861113

10871114
/// Tests whether a pass name starts with a valid prefix for a default pipeline

0 commit comments

Comments
 (0)