86 #define DEBUG_TYPE "global-merge"
91 cl::desc(
"Enable the global merge pass"),
96 cl::desc(
"Set maximum offset for global merge pass"),
105 cl::desc(
"Improve global merge pass to ignore globals only used alone"),
110 cl::desc(
"Enable global merge pass on constants"),
117 cl::desc(
"Enable global merge pass on external linkage"));
119 STATISTIC(NumMerged,
"Number of globals merged");
133 bool OnlyOptimizeForSize;
136 bool MergeExternalGlobals;
141 Module &M,
bool isConst,
unsigned AddrSpace)
const;
146 unsigned AddrSpace)
const;
152 return MustKeepGlobalVariables.count(GV);
157 void setMustKeepGlobalVariables(
Module &M);
167 explicit GlobalMerge()
169 OnlyOptimizeForSize(
false), MergeExternalGlobals(
false) {
174 bool OnlyOptimizeForSize,
bool MergeExternalGlobals)
176 OnlyOptimizeForSize(OnlyOptimizeForSize),
177 MergeExternalGlobals(MergeExternalGlobals) {
181 bool doInitialization(
Module &M)
override;
182 bool runOnFunction(
Function &
F)
override;
183 bool doFinalization(
Module &M)
override;
185 StringRef getPassName()
const override {
return "Merge internal globals"; }
201 Module &M,
bool isConst,
unsigned AddrSpace)
const {
202 auto &DL = M.getDataLayout();
204 std::stable_sort(Globals.begin(), Globals.end(),
207 DL.getTypeAllocSize(GV2->getValueType());
214 return doMerge(Globals, AllGlobals, M, isConst, AddrSpace);
236 struct UsedGlobalSet {
237 UsedGlobalSet(
size_t Size) : Globals(Size), UsageCount(1) {}
243 std::vector<UsedGlobalSet> UsedGlobalSets;
246 auto CreateGlobalSet = [&]() -> UsedGlobalSet & {
247 UsedGlobalSets.emplace_back(Globals.size());
248 return UsedGlobalSets.back();
252 CreateGlobalSet().UsageCount = 0;
273 std::vector<size_t> EncounteredUGS;
275 for (
size_t GI = 0,
GE = Globals.size(); GI !=
GE; ++GI) {
279 std::fill(EncounteredUGS.begin(), EncounteredUGS.end(), 0);
281 EncounteredUGS.resize(UsedGlobalSets.size());
285 size_t CurGVOnlySetIdx = 0;
288 for (
auto &U : GV->
uses()) {
292 if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser())) {
295 UI = &*CE->use_begin();
297 }
else if (isa<Instruction>(U.getUser())) {
306 for (; UI != UE; UI = UI->getNext()) {
317 size_t UGSIdx = GlobalUsesByFunction[ParentFn];
323 if (!CurGVOnlySetIdx) {
324 CurGVOnlySetIdx = UsedGlobalSets.
size();
325 CreateGlobalSet().Globals.set(GI);
327 ++UsedGlobalSets[CurGVOnlySetIdx].UsageCount;
330 GlobalUsesByFunction[ParentFn] = CurGVOnlySetIdx;
335 if (UsedGlobalSets[UGSIdx].Globals.test(GI)) {
336 ++UsedGlobalSets[UGSIdx].UsageCount;
341 --UsedGlobalSets[UGSIdx].UsageCount;
345 if (
size_t ExpandedIdx = EncounteredUGS[UGSIdx]) {
346 ++UsedGlobalSets[ExpandedIdx].UsageCount;
347 GlobalUsesByFunction[ParentFn] = ExpandedIdx;
353 GlobalUsesByFunction[ParentFn] = EncounteredUGS[UGSIdx] =
354 UsedGlobalSets.size();
356 UsedGlobalSet &NewUGS = CreateGlobalSet();
357 NewUGS.Globals.set(GI);
358 NewUGS.Globals |= UsedGlobalSets[UGSIdx].Globals;
369 std::sort(UsedGlobalSets.begin(), UsedGlobalSets.end(),
370 [](
const UsedGlobalSet &UGS1,
const UsedGlobalSet &UGS2) {
371 return UGS1.Globals.count() * UGS1.UsageCount <
372 UGS2.Globals.count() * UGS2.UsageCount;
380 for (
size_t i = 0, e = UsedGlobalSets.size();
i != e; ++
i) {
381 const UsedGlobalSet &UGS = UsedGlobalSets[e -
i - 1];
382 if (UGS.UsageCount == 0)
384 if (UGS.Globals.count() > 1)
385 AllGlobals |= UGS.Globals;
387 return doMerge(Globals, AllGlobals, M, isConst, AddrSpace);
397 bool Changed =
false;
399 for (
size_t i = 0, e = UsedGlobalSets.size();
i != e; ++
i) {
400 const UsedGlobalSet &UGS = UsedGlobalSets[e -
i - 1];
401 if (UGS.UsageCount == 0)
403 if (PickedGlobals.anyCommon(UGS.Globals))
405 PickedGlobals |= UGS.Globals;
409 if (UGS.Globals.count() < 2)
411 Changed |= doMerge(Globals, UGS.Globals, M, isConst, AddrSpace);
419 unsigned AddrSpace)
const {
425 DEBUG(
dbgs() <<
" Trying to merge set, starts with #"
431 uint64_t MergedSize = 0;
432 std::vector<Type*> Tys;
433 std::vector<Constant*> Inits;
435 bool HasExternal =
false;
437 for (j = i; j != -1; j = GlobalSet.
find_next(j)) {
438 Type *Ty = Globals[j]->getValueType();
439 MergedSize += DL.getTypeAllocSize(Ty);
440 if (MergedSize > MaxOffset) {
444 Inits.push_back(Globals[j]->getInitializer());
446 if (Globals[j]->hasExternalLinkage() && !HasExternal) {
448 FirstExternalName = Globals[j]->getName();
467 (IsMachO && HasExternal)
468 ?
"_MergedGlobals_" + FirstExternalName
472 M, MergedTy, isConst, MergedLinkage, MergedInit, MergedName,
nullptr,
475 const StructLayout *MergedLayout = DL.getStructLayout(MergedTy);
477 for (ssize_t k = i, idx = 0; k != j; k = GlobalSet.
find_next(k), ++idx) {
479 std::string
Name = Globals[k]->getName();
491 Globals[k]->replaceAllUsesWith(GEP);
492 Globals[k]->eraseFromParent();
522 MustKeepGlobalVariables.insert(
G);
525 void GlobalMerge::setMustKeepGlobalVariables(
Module &M) {
537 dyn_cast<GlobalVariable>(U->stripPointerCasts()))
538 MustKeepGlobalVariables.insert(GV);
544 bool GlobalMerge::doInitialization(
Module &M) {
553 bool Changed =
false;
554 setMustKeepGlobalVariables(M);
567 assert(PT &&
"Global variable is not a pointer!");
572 unsigned Alignment = DL.getPreferredAlignment(&GV);
574 if (Alignment > DL.getABITypeAlignment(Ty))
583 if (isMustKeepGlobalVariable(&GV))
586 if (DL.getTypeAllocSize(Ty) < MaxOffset) {
589 BSSGlobals[AddressSpace].push_back(&GV);
591 ConstGlobals[AddressSpace].push_back(&GV);
597 for (
auto &
P : Globals)
598 if (
P.second.size() > 1)
599 Changed |= doMerge(
P.second, M,
false,
P.first);
601 for (
auto &
P : BSSGlobals)
602 if (
P.second.size() > 1)
603 Changed |= doMerge(
P.second, M,
false,
P.first);
606 for (
auto &
P : ConstGlobals)
607 if (
P.second.size() > 1)
608 Changed |= doMerge(
P.second, M,
true,
P.first);
613 bool GlobalMerge::runOnFunction(
Function &F) {
617 bool GlobalMerge::doFinalization(
Module &M) {
618 MustKeepGlobalVariables.clear();
623 bool OnlyOptimizeForSize,
624 bool MergeExternalByDefault) {
627 return new GlobalMerge(TM, Offset, OnlyOptimizeForSize, MergeExternal);
Pass interface - Implemented by all 'passes'.
void push_back(const T &Elt)
int find_first() const
find_first - Returns the index of the first set bit, -1 if none of the bits are set.
iterator_range< use_iterator > uses()
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
STATISTIC(NumFunctions,"Total number of functions")
GlobalVariable * collectUsedGlobalVariables(const Module &M, SmallPtrSetImpl< GlobalValue * > &Set, bool CompilerUsed)
Given "llvm.used" or "llvm.compiler.used" as a global name, collect the initializer elements of that ...
A Module instance is used to store all the information related to an LLVM module. ...
static cl::opt< bool > GlobalMergeGroupByUse("global-merge-group-by-use", cl::Hidden, cl::desc("Improve global merge pass to look at uses"), cl::init(true))
unsigned getNumOperands() const
int find_next(unsigned Prev) const
find_next - Returns the index of the next set bit following the "Prev" bit.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Type * getValueType() const
Like Internal, but omit from symbol table.
INITIALIZE_PASS_BEGIN(GlobalMerge,"global-merge","Merge global variables", false, false) INITIALIZE_PASS_END(GlobalMerge
Externally visible function.
Pass * createGlobalMergePass(const TargetMachine *TM, unsigned MaximalOffset, bool OnlyOptimizeForSize=false, bool MergeExternalByDefault=false)
GlobalMerge - This pass merges internal (by default) globals into structs to enable reuse of a base p...
const Function * getParent() const
Return the enclosing method, or null if none.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
bool optForMinSize() const
Optimize this function for minimum size (-Oz).
StringRef getName() const
Return a constant reference to the value's name.
global Merge global variables
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Class to represent struct types.
A Use represents the edge between a Value definition and its users.
bool hasInternalLinkage() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This file contains the simple types necessary to represent the attributes associated with functions a...
static cl::opt< bool > EnableGlobalMerge("enable-global-merge", cl::Hidden, cl::desc("Enable the global merge pass"), cl::init(true))
A constant value that is initialized with an expression using other constant values.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Class to represent pointers.
uint64_t getElementOffset(unsigned Idx) const
bool hasSection() const
Check if this global has a custom object file section.
initializer< Ty > init(const Ty &Val)
static Constant * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)
Create an "inbounds" getelementptr.
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
This is an important base class in LLVM.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Represent the analysis usage information of a pass.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
FunctionPass class - This class is used to implement most global optimizations.
Value * getOperand(unsigned i) const
static Constant * get(StructType *T, ArrayRef< Constant * > V)
global Merge global false
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
Triple - Helper class for working with autoconf configuration names.
bool hasExternalLinkage() const
static void Merge(const std::string &Input, const std::vector< std::string > Result, size_t NumNewFeatures)
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Module.h This file contains the declarations for the Module class.
static cl::opt< bool > GlobalMergeIgnoreSingleUse("global-merge-ignore-single-use", cl::Hidden, cl::desc("Improve global merge pass to ignore globals only used alone"), cl::init(true))
Value * stripPointerCasts()
Strip off pointer casts, all-zero GEPs, and aliases.
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
static cl::opt< cl::boolOrDefault > EnableGlobalMergeOnExternal("global-merge-on-external", cl::Hidden, cl::desc("Enable global merge pass on external linkage"))
ConstantArray - Constant Array Declarations.
bool hasInitializer() const
Definitions have initializers, declarations don't.
LinkageTypes
An enumeration for the kinds of linkage for global values.
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
bool isEHPad() const
Return true if the instruction is a variety of EH-block.
PointerType * getType() const
Global values are always pointers.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
static IntegerType * getInt32Ty(LLVMContext &C)
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Rename collisions when linking (static functions).
static cl::opt< unsigned > GlobalMergeMaxOffset("global-merge-max-offset", cl::Hidden, cl::desc("Set maximum offset for global merge pass"), cl::init(0))
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static cl::opt< bool > EnableGlobalMergeOnConst("global-merge-on-const", cl::Hidden, cl::desc("Enable global merge pass on constants"), cl::init(false))
void initializeGlobalMergePass(PassRegistry &)
Primary interface to the complete machine description for the target machine.
iterator_range< global_iterator > globals()
StringRef - Represent a constant reference to a string, i.e.
static SectionKind getKindForGlobal(const GlobalObject *GO, const TargetMachine &TM)
Classify the specified global variable into a set of target independent categories embodied in Sectio...
const BasicBlock * getParent() const
static GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
GlobalVariable * getGlobalVariable(StringRef Name) const
Look up the specified global variable in the module symbol table.
LLVMContext & getContext() const
Get the global data context.
This file describes how to lower LLVM code to machine code.