100 using namespace llvm;
102 #define DEBUG_TYPE "global-merge" 107 cl::desc(
"Enable the global merge pass"),
112 cl::desc(
"Set maximum offset for global merge pass"),
121 cl::desc(
"Improve global merge pass to ignore globals only used alone"),
126 cl::desc(
"Enable global merge pass on constants"),
133 cl::desc(
"Enable global merge pass on external linkage"));
135 STATISTIC(NumMerged,
"Number of globals merged");
152 bool OnlyOptimizeForSize =
false;
155 bool MergeExternalGlobals =
false;
160 Module &M,
bool isConst,
unsigned AddrSpace)
const;
166 unsigned AddrSpace)
const;
172 return MustKeepGlobalVariables.count(GV);
177 void setMustKeepGlobalVariables(
Module &M);
188 explicit GlobalMerge()
193 explicit GlobalMerge(
const TargetMachine *TM,
unsigned MaximalOffset,
194 bool OnlyOptimizeForSize,
bool MergeExternalGlobals)
196 OnlyOptimizeForSize(OnlyOptimizeForSize),
197 MergeExternalGlobals(MergeExternalGlobals) {
201 bool doInitialization(
Module &M)
override;
203 bool doFinalization(
Module &M)
override;
205 StringRef getPassName()
const override {
return "Merge internal globals"; }
220 Module &M,
bool isConst,
unsigned AddrSpace)
const {
221 auto &DL = M.getDataLayout();
223 std::stable_sort(Globals.begin(), Globals.end(),
226 DL.getTypeAllocSize(GV2->getValueType());
233 return doMerge(Globals, AllGlobals, M, isConst, AddrSpace);
255 struct UsedGlobalSet {
257 unsigned UsageCount = 1;
259 UsedGlobalSet(
size_t Size) : Globals(Size) {}
263 std::vector<UsedGlobalSet> UsedGlobalSets;
266 auto CreateGlobalSet = [&]() -> UsedGlobalSet & {
267 UsedGlobalSets.emplace_back(Globals.size());
268 return UsedGlobalSets.back();
272 CreateGlobalSet().UsageCount = 0;
293 std::vector<size_t> EncounteredUGS;
295 for (
size_t GI = 0,
GE = Globals.size(); GI !=
GE; ++GI) {
299 std::fill(EncounteredUGS.begin(), EncounteredUGS.end(), 0);
301 EncounteredUGS.resize(UsedGlobalSets.size());
305 size_t CurGVOnlySetIdx = 0;
308 for (
auto &U : GV->
uses()) {
312 if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser())) {
315 UI = &*CE->use_begin();
317 }
else if (isa<Instruction>(U.getUser())) {
326 for (; UI != UE; UI = UI->getNext()) {
337 size_t UGSIdx = GlobalUsesByFunction[ParentFn];
343 if (!CurGVOnlySetIdx) {
344 CurGVOnlySetIdx = UsedGlobalSets.
size();
345 CreateGlobalSet().Globals.set(GI);
347 ++UsedGlobalSets[CurGVOnlySetIdx].UsageCount;
350 GlobalUsesByFunction[ParentFn] = CurGVOnlySetIdx;
355 if (UsedGlobalSets[UGSIdx].Globals.test(GI)) {
356 ++UsedGlobalSets[UGSIdx].UsageCount;
361 --UsedGlobalSets[UGSIdx].UsageCount;
365 if (
size_t ExpandedIdx = EncounteredUGS[UGSIdx]) {
366 ++UsedGlobalSets[ExpandedIdx].UsageCount;
367 GlobalUsesByFunction[ParentFn] = ExpandedIdx;
373 GlobalUsesByFunction[ParentFn] = EncounteredUGS[UGSIdx] =
374 UsedGlobalSets.size();
376 UsedGlobalSet &NewUGS = CreateGlobalSet();
377 NewUGS.Globals.set(GI);
378 NewUGS.Globals |= UsedGlobalSets[UGSIdx].Globals;
389 std::stable_sort(UsedGlobalSets.begin(), UsedGlobalSets.end(),
390 [](
const UsedGlobalSet &UGS1,
const UsedGlobalSet &UGS2) {
391 return UGS1.Globals.count() * UGS1.UsageCount <
392 UGS2.Globals.count() * UGS2.UsageCount;
400 for (
size_t i = 0, e = UsedGlobalSets.size(); i != e; ++i) {
401 const UsedGlobalSet &UGS = UsedGlobalSets[e - i - 1];
402 if (UGS.UsageCount == 0)
404 if (UGS.Globals.count() > 1)
405 AllGlobals |= UGS.Globals;
407 return doMerge(Globals, AllGlobals, M, isConst, AddrSpace);
417 bool Changed =
false;
419 for (
size_t i = 0, e = UsedGlobalSets.size(); i != e; ++i) {
420 const UsedGlobalSet &UGS = UsedGlobalSets[e - i - 1];
421 if (UGS.UsageCount == 0)
423 if (PickedGlobals.anyCommon(UGS.Globals))
425 PickedGlobals |= UGS.Globals;
429 if (UGS.Globals.count() < 2)
431 Changed |= doMerge(Globals, UGS.Globals, M, isConst, AddrSpace);
439 unsigned AddrSpace)
const {
449 bool Changed =
false;
453 uint64_t MergedSize = 0;
454 std::vector<Type*> Tys;
455 std::vector<Constant*> Inits;
456 std::vector<unsigned> StructIdxs;
458 bool HasExternal =
false;
460 unsigned MaxAlign = 1;
462 for (j = i; j != -1; j = GlobalSet.
find_next(j)) {
463 Type *Ty = Globals[j]->getValueType();
466 unsigned Align = DL.getPreferredAlignment(Globals[j]);
467 unsigned Padding =
alignTo(MergedSize, Align) - MergedSize;
468 MergedSize += Padding;
469 MergedSize += DL.getTypeAllocSize(Ty);
470 if (MergedSize > MaxOffset) {
480 StructIdxs.push_back(CurIdx++);
482 MaxAlign =
std::max(MaxAlign, Align);
484 if (Globals[j]->hasExternalLinkage() && !HasExternal) {
486 FirstExternalName = Globals[j]->getName();
491 if (Tys.size() < 2) {
512 (IsMachO && HasExternal)
513 ?
"_MergedGlobals_" + FirstExternalName
517 M, MergedTy, isConst, MergedLinkage, MergedInit, MergedName,
nullptr,
520 MergedGV->setAlignment(MaxAlign);
521 MergedGV->setSection(Globals[i]->
getSection());
523 const StructLayout *MergedLayout = DL.getStructLayout(MergedTy);
524 for (ssize_t k = i, idx = 0; k != j; k = GlobalSet.
find_next(k), ++idx) {
526 std::string
Name = Globals[k]->getName();
528 Globals[k]->getDLLStorageClass();
532 MergedGV->copyMetadata(Globals[k],
541 Globals[k]->replaceAllUsesWith(GEP);
542 Globals[k]->eraseFromParent();
551 Linkage, Name, GEP, &M);
575 MustKeepGlobalVariables.
insert(
G);
578 void GlobalMerge::setMustKeepGlobalVariables(
Module &M) {
582 for (Function &
F : M) {
591 dyn_cast<GlobalVariable>(U->stripPointerCasts()))
592 MustKeepGlobalVariables.
insert(GV);
598 bool GlobalMerge::doInitialization(
Module &M) {
606 Globals, ConstGlobals, BSSGlobals;
607 bool Changed =
false;
608 setMustKeepGlobalVariables(M);
625 assert(PT &&
"Global variable is not a pointer!");
636 if (isMustKeepGlobalVariable(&GV))
640 if (DL.getTypeAllocSize(Ty) < MaxOffset) {
651 for (
auto &
P : Globals)
652 if (
P.second.size() > 1)
653 Changed |= doMerge(
P.second, M,
false,
P.first.first);
655 for (
auto &
P : BSSGlobals)
656 if (
P.second.size() > 1)
657 Changed |= doMerge(
P.second, M,
false,
P.first.first);
660 for (
auto &
P : ConstGlobals)
661 if (
P.second.size() > 1)
662 Changed |= doMerge(
P.second, M,
true,
P.first.first);
671 bool GlobalMerge::doFinalization(
Module &M) {
672 MustKeepGlobalVariables.
clear();
677 bool OnlyOptimizeForSize,
678 bool MergeExternalByDefault) {
681 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.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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...
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
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))
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")
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
This defines the Use class.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
amdgpu Simplify well known AMD library false Value Value const Twine & Name
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
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
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 aliases.
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...
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 getElementOffset(unsigned Idx) const
static IntegerType * getInt32Ty(LLVMContext &C)
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 optForMinSize() 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())
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