101 #define DEBUG_TYPE "global-merge" 106 cl::desc(
"Enable the global merge pass"),
111 cl::desc(
"Set maximum offset for global merge pass"),
120 cl::desc(
"Improve global merge pass to ignore globals only used alone"),
125 cl::desc(
"Enable global merge pass on constants"),
132 cl::desc(
"Enable global merge pass on external linkage"));
134 STATISTIC(NumMerged,
"Number of globals merged");
151 bool OnlyOptimizeForSize =
false;
154 bool MergeExternalGlobals =
false;
159 Module &M,
bool isConst,
unsigned AddrSpace)
const;
165 unsigned AddrSpace)
const;
171 return MustKeepGlobalVariables.count(GV);
176 void setMustKeepGlobalVariables(
Module &M);
187 explicit GlobalMerge()
192 explicit GlobalMerge(
const TargetMachine *TM,
unsigned MaximalOffset,
193 bool OnlyOptimizeForSize,
bool MergeExternalGlobals)
195 OnlyOptimizeForSize(OnlyOptimizeForSize),
196 MergeExternalGlobals(MergeExternalGlobals) {
200 bool doInitialization(
Module &M)
override;
202 bool doFinalization(
Module &M)
override;
204 StringRef getPassName()
const override {
return "Merge internal globals"; }
219 Module &M,
bool isConst,
unsigned AddrSpace)
const {
220 auto &DL = M.getDataLayout();
232 return doMerge(Globals, AllGlobals, M, isConst, AddrSpace);
254 struct UsedGlobalSet {
256 unsigned UsageCount = 1;
258 UsedGlobalSet(
size_t Size) : Globals(Size) {}
262 std::vector<UsedGlobalSet> UsedGlobalSets;
265 auto CreateGlobalSet = [&]() -> UsedGlobalSet & {
266 UsedGlobalSets.emplace_back(Globals.size());
267 return UsedGlobalSets.back();
271 CreateGlobalSet().UsageCount = 0;
292 std::vector<size_t> EncounteredUGS;
294 for (
size_t GI = 0,
GE = Globals.size(); GI !=
GE; ++GI) {
298 std::fill(EncounteredUGS.begin(), EncounteredUGS.end(), 0);
300 EncounteredUGS.resize(UsedGlobalSets.size());
304 size_t CurGVOnlySetIdx = 0;
307 for (
auto &U : GV->
uses()) {
311 if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser())) {
314 UI = &*CE->use_begin();
316 }
else if (isa<Instruction>(U.getUser())) {
325 for (; UI != UE; UI = UI->getNext()) {
333 if (OnlyOptimizeForSize && !ParentFn->
hasMinSize())
336 size_t UGSIdx = GlobalUsesByFunction[ParentFn];
342 if (!CurGVOnlySetIdx) {
343 CurGVOnlySetIdx = UsedGlobalSets.
size();
344 CreateGlobalSet().Globals.set(GI);
346 ++UsedGlobalSets[CurGVOnlySetIdx].UsageCount;
349 GlobalUsesByFunction[ParentFn] = CurGVOnlySetIdx;
354 if (UsedGlobalSets[UGSIdx].Globals.test(GI)) {
355 ++UsedGlobalSets[UGSIdx].UsageCount;
360 --UsedGlobalSets[UGSIdx].UsageCount;
364 if (
size_t ExpandedIdx = EncounteredUGS[UGSIdx]) {
365 ++UsedGlobalSets[ExpandedIdx].UsageCount;
366 GlobalUsesByFunction[ParentFn] = ExpandedIdx;
372 GlobalUsesByFunction[ParentFn] = EncounteredUGS[UGSIdx] =
373 UsedGlobalSets.size();
375 UsedGlobalSet &NewUGS = CreateGlobalSet();
376 NewUGS.Globals.set(GI);
377 NewUGS.Globals |= UsedGlobalSets[UGSIdx].Globals;
389 [](
const UsedGlobalSet &UGS1,
const UsedGlobalSet &UGS2) {
390 return UGS1.Globals.count() * UGS1.UsageCount <
391 UGS2.Globals.count() * UGS2.UsageCount;
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 (UGS.Globals.count() > 1)
404 AllGlobals |= UGS.Globals;
406 return doMerge(Globals, AllGlobals, M, isConst, AddrSpace);
416 bool Changed =
false;
418 for (
size_t i = 0,
e = UsedGlobalSets.size(); i !=
e; ++i) {
419 const UsedGlobalSet &UGS = UsedGlobalSets[
e - i - 1];
420 if (UGS.UsageCount == 0)
422 if (PickedGlobals.anyCommon(UGS.Globals))
424 PickedGlobals |= UGS.Globals;
428 if (UGS.Globals.count() < 2)
430 Changed |= doMerge(Globals, UGS.Globals, M, isConst, AddrSpace);
438 unsigned AddrSpace)
const {
448 bool Changed =
false;
452 uint64_t MergedSize = 0;
453 std::vector<Type*> Tys;
454 std::vector<Constant*> Inits;
455 std::vector<unsigned> StructIdxs;
457 bool HasExternal =
false;
461 for (j = i; j != -1; j = GlobalSet.
find_next(j)) {
462 Type *Ty = Globals[j]->getValueType();
465 Align Alignment(DL.getPreferredAlignment(Globals[j]));
466 unsigned Padding =
alignTo(MergedSize, Alignment) - MergedSize;
467 MergedSize += Padding;
468 MergedSize += DL.getTypeAllocSize(Ty);
469 if (MergedSize > MaxOffset) {
479 StructIdxs.push_back(CurIdx++);
481 MaxAlign =
std::max(MaxAlign, Alignment);
483 if (Globals[j]->hasExternalLinkage() && !HasExternal) {
485 FirstExternalName = Globals[j]->getName();
490 if (Tys.size() < 2) {
511 (IsMachO && HasExternal)
512 ?
"_MergedGlobals_" + FirstExternalName
516 M, MergedTy, isConst, MergedLinkage, MergedInit, MergedName,
nullptr,
519 MergedGV->setAlignment(MaxAlign);
520 MergedGV->setSection(Globals[i]->
getSection());
522 const StructLayout *MergedLayout = DL.getStructLayout(MergedTy);
523 for (ssize_t k = i, idx = 0; k != j; k = GlobalSet.
find_next(k), ++idx) {
525 std::string
Name = Globals[k]->getName();
527 Globals[k]->getDLLStorageClass();
531 MergedGV->copyMetadata(Globals[k],
540 Globals[k]->replaceAllUsesWith(GEP);
541 Globals[k]->eraseFromParent();
550 Linkage, Name, GEP, &M);
574 MustKeepGlobalVariables.
insert(
G);
577 void GlobalMerge::setMustKeepGlobalVariables(
Module &M) {
581 for (Function &
F : M) {
590 dyn_cast<GlobalVariable>(U->stripPointerCasts()))
591 MustKeepGlobalVariables.
insert(GV);
597 bool GlobalMerge::doInitialization(
Module &M) {
605 Globals, ConstGlobals, BSSGlobals;
606 bool Changed =
false;
607 setMustKeepGlobalVariables(M);
624 assert(PT &&
"Global variable is not a pointer!");
635 if (isMustKeepGlobalVariable(&GV))
639 if (DL.getTypeAllocSize(Ty) < MaxOffset) {
650 for (
auto &
P : Globals)
651 if (
P.second.size() > 1)
652 Changed |= doMerge(
P.second, M,
false,
P.first.first);
654 for (
auto &
P : BSSGlobals)
655 if (
P.second.size() > 1)
656 Changed |= doMerge(
P.second, M,
false,
P.first.first);
659 for (
auto &
P : ConstGlobals)
660 if (
P.second.size() > 1)
661 Changed |= doMerge(
P.second, M,
true,
P.first.first);
670 bool GlobalMerge::doFinalization(
Module &M) {
671 MustKeepGlobalVariables.
clear();
676 bool OnlyOptimizeForSize,
677 bool MergeExternalByDefault) {
680 return new GlobalMerge(TM, Offset, OnlyOptimizeForSize, MergeExternal);
Pass interface - Implemented by all 'passes'.
StringRef getSection() const
Get the custom section of this global if it has one.
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
iterator_range< use_iterator > uses()
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This class represents lattice values for constants.
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))
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
static ConstantAggregateZero * get(Type *Ty)
Like Internal, but omit from symbol table.
Externally visible function.
GlobalVariable * getGlobalVariable(StringRef Name) const
Look up the specified global variable in the module symbol table.
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...
STATISTIC(NumFunctions, "Total number of functions")
This defines the Use class.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
int find_first() const
find_first - Returns the index of the first set bit, -1 if none of the bits are set.
Class to represent struct types.
LLVMContext & getContext() const
Get the global data context.
A Use represents the edge between a Value definition and its users.
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
int find_next(unsigned Prev) const
find_next - Returns the index of the next set bit following the "Prev" bit.
static cl::opt< bool > EnableGlobalMerge("enable-global-merge", cl::Hidden, cl::desc("Enable the global merge pass"), cl::init(true))
void setDLLStorageClass(DLLStorageClassTypes C)
static StructType * get(LLVMContext &Context, ArrayRef< Type *> Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Expected< const typename ELFT::Shdr * > getSection(typename ELFT::ShdrRange Sections, uint32_t Index)
bool hasExternalLinkage() const
A constant value that is initialized with an expression using other constant values.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
bool hasImplicitSection() const
Check if section name is present.
Value * getOperand(unsigned i) const
Class to represent pointers.
static bool runOnFunction(Function &F, bool PostInlining)
initializer< Ty > init(const Ty &Val)
bool shouldAssumeDSOLocal(const Module &M, const GlobalValue *GV) const
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...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Represent the analysis usage information of a pass.
bool hasInternalLinkage() const
FunctionPass class - This class is used to implement most global optimizations.
DLLStorageClassTypes
Storage classes of global values for PE targets.
static Constant * get(StructType *T, ArrayRef< Constant *> V)
unsigned getAddressSpace() const
Return the address space of the Pointer type.
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Triple - Helper class for working with autoconf configuration names.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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 ...
unsigned getNumOperands() const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
Align max(MaybeAlign Lhs, Align Rhs)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
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))
static Constant * getInitializer(Constant *C)
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.
LinkageTypes
An enumeration for the kinds of linkage for global values.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
uint64_t getElementOffset(unsigned Idx) const
static IntegerType * getInt32Ty(LLVMContext &C)
Linkage
Describes symbol linkage.
StringRef getName() const
Return a constant reference to the value's name.
static Constant * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant *> IdxList)
Create an "inbounds" getelementptr.
const Function * getParent() const
Return the enclosing method, or null if none.
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Type * getValueType() const
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))
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void stable_sort(R &&Range)
static cl::opt< bool > EnableGlobalMergeOnConst("global-merge-on-const", cl::Hidden, cl::desc("Enable global merge pass on constants"), cl::init(false))
bool hasInitializer() const
Definitions have initializers, declarations don't.
void initializeGlobalMergePass(PassRegistry &)
Primary interface to the complete machine description for the target machine.
bool isEHPad() const
Return true if the instruction is a variety of EH-block.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
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...
static IntegerType * getInt8Ty(LLVMContext &C)
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...
PointerType * getType() const
Global values are always pointers.
const BasicBlock * getParent() const