summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/AsmPrinter/AsmPrinter.cpp7
-rw-r--r--lib/IR/Globals.cpp25
-rw-r--r--lib/Target/AArch64/AArch64ISelLowering.cpp14
-rw-r--r--lib/Target/AArch64/AArch64ISelLowering.h4
-rw-r--r--lib/Target/ARM64/ARM64ISelLowering.cpp14
-rw-r--r--lib/Target/ARM64/ARM64ISelLowering.h4
-rw-r--r--lib/Transforms/Scalar/GlobalMerge.cpp85
-rw-r--r--lib/Transforms/Scalar/Scalar.cpp1
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);