summaryrefslogtreecommitdiff
path: root/lib/Transforms/Scalar
diff options
context:
space:
mode:
authorJiangning Liu <jiangning.liu@arm.com>2014-05-15 23:45:42 +0000
committerJiangning Liu <jiangning.liu@arm.com>2014-05-15 23:45:42 +0000
commitd5db8765d61ca77a55867cf1f39aecb8cae3a6cd (patch)
treefd12d05d5eac5450fa954c2aee66443a36a82df2 /lib/Transforms/Scalar
parent01a02d91dcb47cdc31fe6570f59eac3740d3da0e (diff)
downloadllvm-d5db8765d61ca77a55867cf1f39aecb8cae3a6cd.tar.gz
llvm-d5db8765d61ca77a55867cf1f39aecb8cae3a6cd.tar.bz2
llvm-d5db8765d61ca77a55867cf1f39aecb8cae3a6cd.tar.xz
Implement global merge optimization for global variables.
This commit implements two command line switches -global-merge-on-external and -global-merge-aligned, and both of them are false by default, so this optimization is disabled by default for all targets. For ARM64, some back-end behaviors need to be tuned to get this optimization further enabled. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208934 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Scalar')
-rw-r--r--lib/Transforms/Scalar/GlobalMerge.cpp85
-rw-r--r--lib/Transforms/Scalar/Scalar.cpp1
2 files changed, 76 insertions, 10 deletions
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);