diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 7 | ||||
-rw-r--r-- | lib/IR/Globals.cpp | 25 | ||||
-rw-r--r-- | lib/Target/AArch64/AArch64ISelLowering.cpp | 14 | ||||
-rw-r--r-- | lib/Target/AArch64/AArch64ISelLowering.h | 4 | ||||
-rw-r--r-- | lib/Target/ARM64/ARM64ISelLowering.cpp | 14 | ||||
-rw-r--r-- | lib/Target/ARM64/ARM64ISelLowering.h | 4 | ||||
-rw-r--r-- | lib/Transforms/Scalar/GlobalMerge.cpp | 85 | ||||
-rw-r--r-- | lib/Transforms/Scalar/Scalar.cpp | 1 |
8 files changed, 142 insertions, 12 deletions
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 37a2c3220c..0c4865f2f2 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -946,8 +946,11 @@ bool AsmPrinter::doFinalization(Module &M) { EmitVisibility(Name, Alias.getVisibility()); // Emit the directives as assignments aka .set: - OutStreamer.EmitAssignment(Name, - MCSymbolRefExpr::Create(Target, OutContext)); + const MCExpr *Expr = MCSymbolRefExpr::Create(Target, OutContext); + if (uint64_t Offset = Alias.calculateOffset(*TM.getDataLayout())) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(Offset, OutContext), OutContext); + OutStreamer.EmitAssignment(Name, Expr); } } diff --git a/lib/IR/Globals.cpp b/lib/IR/Globals.cpp index 0ec54fe3c0..d64046a7bf 100644 --- a/lib/IR/Globals.cpp +++ b/lib/IR/Globals.cpp @@ -15,6 +15,7 @@ #include "llvm/IR/GlobalValue.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" @@ -282,3 +283,27 @@ GlobalObject *GlobalAlias::getAliasedGlobal() { return cast<GlobalObject>(GV); } } + +uint64_t GlobalAlias::calculateOffset(const DataLayout &DL) const { + uint64_t Offset = 0; + const Constant *C = this; + while (C) { + if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(C)) { + C = GA->getAliasee(); + } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { + if (CE->getOpcode() == Instruction::GetElementPtr) { + std::vector<Value*> Args; + for (unsigned I = 1; I < CE->getNumOperands(); ++I) + Args.push_back(CE->getOperand(I)); + Offset += DL.getIndexedOffset(CE->getOperand(0)->getType(), Args); + } + C = CE->getOperand(0); + } else if (isa<GlobalValue>(C)) { + return Offset; + } else { + assert(0 && "Unexpected type in alias chain!"); + return 0; + } + } + return Offset; +} diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index 852d324476..a676600e5d 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -5560,3 +5560,17 @@ unsigned AArch64TargetLowering::getMaximalGlobalOffset() const { return 4095; } +/// getGlobalMergeAlignment - Set alignment to be the max size of merged +/// global variable data structure, and make it aligned up to power of 2. +/// This way, we could guarantee the merged global variable data structure +/// doesn't cross page boundary, because usually OS always allocates page at +/// 4096-byte aligned boundary. +unsigned AArch64TargetLowering::getGlobalMergeAlignment( + StructType *MergedTy) const { + unsigned Align = getDataLayout()->getTypeAllocSize(MergedTy); + if (Align & (Align - 1)) + Align = llvm::NextPowerOf2(Align); + + return Align; +} + diff --git a/lib/Target/AArch64/AArch64ISelLowering.h b/lib/Target/AArch64/AArch64ISelLowering.h index 070db94808..9818b7a2dc 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.h +++ b/lib/Target/AArch64/AArch64ISelLowering.h @@ -386,6 +386,10 @@ public: /// be used for loads / stores from the global. unsigned getMaximalGlobalOffset() const override; + /// getGlobalMergeAlignment - Set alignment to be the max size of merged + /// global variable data structure, and make it aligned up to power of 2. + unsigned getGlobalMergeAlignment(StructType *MergedTy) const override; + protected: std::pair<const TargetRegisterClass*, uint8_t> findRepresentativeClass(MVT VT) const override; diff --git a/lib/Target/ARM64/ARM64ISelLowering.cpp b/lib/Target/ARM64/ARM64ISelLowering.cpp index 118007fa70..880df0c1a8 100644 --- a/lib/Target/ARM64/ARM64ISelLowering.cpp +++ b/lib/Target/ARM64/ARM64ISelLowering.cpp @@ -630,6 +630,20 @@ unsigned ARM64TargetLowering::getMaximalGlobalOffset() const { return 4095; } +/// getGlobalMergeAlignment - Set alignment to be the max size of merged +/// global variable data structure, and make it aligned up to power of 2. +/// This way, we could guarantee the merged global variable data structure +/// doesn't cross page boundary, because usually OS always allocates page at +/// 4096-byte aligned boundary. +unsigned ARM64TargetLowering::getGlobalMergeAlignment( + StructType *MergedTy) const { + unsigned Align = getDataLayout()->getTypeAllocSize(MergedTy); + if (Align & (Align - 1)) + Align = llvm::NextPowerOf2(Align); + + return Align; +} + FastISel * ARM64TargetLowering::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) const { diff --git a/lib/Target/ARM64/ARM64ISelLowering.h b/lib/Target/ARM64/ARM64ISelLowering.h index 55792317db..00b2710a35 100644 --- a/lib/Target/ARM64/ARM64ISelLowering.h +++ b/lib/Target/ARM64/ARM64ISelLowering.h @@ -236,6 +236,10 @@ public: /// be used for loads / stores from the global. unsigned getMaximalGlobalOffset() const override; + /// getGlobalMergeAlignment - Set alignment to be the max size of merged + /// global variable data structure, and make it aligned up to power of 2. + unsigned getGlobalMergeAlignment(StructType *MergedTy) const override; + /// Returns true if a cast between SrcAS and DestAS is a noop. bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override { // Addrspacecasts are always noops. diff --git a/lib/Transforms/Scalar/GlobalMerge.cpp b/lib/Transforms/Scalar/GlobalMerge.cpp index dd9c3784cc..98061f5b9a 100644 --- a/lib/Transforms/Scalar/GlobalMerge.cpp +++ b/lib/Transforms/Scalar/GlobalMerge.cpp @@ -72,7 +72,7 @@ using namespace llvm; #define DEBUG_TYPE "global-merge" static cl::opt<bool> -EnableGlobalMerge("global-merge", cl::Hidden, +EnableGlobalMerge("enable-global-merge", cl::NotHidden, cl::desc("Enable global merge pass"), cl::init(true)); @@ -81,6 +81,16 @@ EnableGlobalMergeOnConst("global-merge-on-const", cl::Hidden, cl::desc("Enable global merge pass on constants"), cl::init(false)); +static cl::opt<bool> +EnableGlobalMergeOnExternal("global-merge-on-external", cl::Hidden, + cl::desc("Enable global merge pass on external linkage"), + cl::init(false)); + +static cl::opt<bool> +EnableGlobalMergeAligned("global-merge-aligned", cl::Hidden, + cl::desc("Set target specific alignment for global merge pass"), + cl::init(false)); + STATISTIC(NumMerged , "Number of globals merged"); namespace { class GlobalMerge : public FunctionPass { @@ -129,9 +139,21 @@ namespace { } // end anonymous namespace char GlobalMerge::ID = 0; -INITIALIZE_PASS(GlobalMerge, "global-merge", - "Global Merge", false, false) +static void *initializeGlobalMergePassOnce(PassRegistry &Registry) { + PassInfo *PI = new PassInfo( + "Merge global variables", + "global-merge", &GlobalMerge::ID, + PassInfo::NormalCtor_t(callDefaultCtor<GlobalMerge>), false, + false, PassInfo::TargetMachineCtor_t( + callTargetMachineCtor<GlobalMerge>)); + Registry.registerPass(*PI, true); + return PI; +} + +void llvm::initializeGlobalMergePass(PassRegistry &Registry) { + CALL_ONCE_INITIALIZATION(initializeGlobalMergePassOnce) +} bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals, Module &M, bool isConst, unsigned AddrSpace) const { @@ -154,11 +176,16 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals, Type *Int32Ty = Type::getInt32Ty(M.getContext()); + assert (Globals.size() > 1); + for (size_t i = 0, e = Globals.size(); i != e; ) { size_t j = 0; uint64_t MergedSize = 0; std::vector<Type*> Tys; std::vector<Constant*> Inits; + + bool HasExternal = false; + GlobalVariable *TheFirstExternal = 0; for (j = i; j != e; ++j) { Type *Ty = Globals[j]->getType()->getElementType(); MergedSize += DL->getTypeAllocSize(Ty); @@ -167,17 +194,45 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals, } Tys.push_back(Ty); Inits.push_back(Globals[j]->getInitializer()); + + if (Globals[j]->hasExternalLinkage() && !HasExternal) { + HasExternal = true; + TheFirstExternal = Globals[j]; + } } + // If merged variables doesn't have external linkage, we needn't to expose + // the symbol after merging. + GlobalValue::LinkageTypes Linkage = HasExternal ? + GlobalValue::ExternalLinkage : + GlobalValue::InternalLinkage ; + + // If merged variables have external linkage, we use symbol name of the + // first variable merged as the suffix of global symbol name. This would + // be able to avoid the link-time naming conflict for globalm symbols. + Twine MergedGVName = HasExternal ? + "_MergedGlobals_" + TheFirstExternal->getName() : + "_MergedGlobals" ; + StructType *MergedTy = StructType::get(M.getContext(), Tys); Constant *MergedInit = ConstantStruct::get(MergedTy, Inits); + GlobalVariable *MergedGV = new GlobalVariable(M, MergedTy, isConst, - GlobalValue::InternalLinkage, - MergedInit, "_MergedGlobals", - nullptr, - GlobalVariable::NotThreadLocal, - AddrSpace); + Linkage, MergedInit, MergedGVName, + nullptr, GlobalVariable::NotThreadLocal, + AddrSpace); + + if (EnableGlobalMergeAligned) { + unsigned Align = TLI->getGlobalMergeAlignment(MergedTy); + assert(((Align % DL->getABITypeAlignment(MergedTy)) == 0) && + "Specified alignment doesn't meet natural alignment requirement."); + MergedGV->setAlignment(Align); + } + for (size_t k = i; k < j; ++k) { + GlobalValue::LinkageTypes Linkage = Globals[k]->getLinkage(); + std::string Name = Globals[k]->getName(); + Constant *Idx[2] = { ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, k-i) @@ -185,6 +240,12 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals, Constant *GEP = ConstantExpr::getInBoundsGetElementPtr(MergedGV, Idx); Globals[k]->replaceAllUsesWith(GEP); Globals[k]->eraseFromParent(); + + if (Linkage != GlobalValue::InternalLinkage) { + // Generate a new alias... + new GlobalAlias(GEP->getType(), Linkage, Name, GEP, &M); + } + NumMerged++; } i = j; @@ -245,8 +306,12 @@ bool GlobalMerge::doInitialization(Module &M) { // Grab all non-const globals. for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) { - // Merge is safe for "normal" internal globals only - if (!I->hasLocalLinkage() || I->isThreadLocal() || I->hasSection()) + // Merge is safe for "normal" internal or external globals only + if (I->isDeclaration() || I->isThreadLocal() || I->hasSection()) + continue; + + if (!(EnableGlobalMergeOnExternal && I->hasExternalLinkage()) + && !I->hasInternalLinkage()) continue; PointerType *PT = dyn_cast<PointerType>(I->getType()); diff --git a/lib/Transforms/Scalar/Scalar.cpp b/lib/Transforms/Scalar/Scalar.cpp index f8f828c840..2cca725480 100644 --- a/lib/Transforms/Scalar/Scalar.cpp +++ b/lib/Transforms/Scalar/Scalar.cpp @@ -38,6 +38,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) { initializeDSEPass(Registry); initializeGVNPass(Registry); initializeEarlyCSEPass(Registry); + initializeGlobalMergePass(Registry); initializeIndVarSimplifyPass(Registry); initializeJumpThreadingPass(Registry); initializeLICMPass(Registry); |