aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Linker
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2003-05-13 21:33:43 +0000
committerChris Lattner <sabre@nondot.org>2003-05-13 21:33:43 +0000
commit8166e6eef6518da6f1f805e0d5e2bb22c15dd49c (patch)
tree428a676cf9839d019124a1054e7de8142a4fca35 /lib/Linker
parentc49b27a7df46949ff64101e21fb694b228d13b80 (diff)
downloadexternal_llvm-8166e6eef6518da6f1f805e0d5e2bb22c15dd49c.zip
external_llvm-8166e6eef6518da6f1f805e0d5e2bb22c15dd49c.tar.gz
external_llvm-8166e6eef6518da6f1f805e0d5e2bb22c15dd49c.tar.bz2
Implement linkage of appending global variables!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6178 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Linker')
-rw-r--r--lib/Linker/LinkModules.cpp121
1 files changed, 115 insertions, 6 deletions
diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp
index 47aa548..13afe1f 100644
--- a/lib/Linker/LinkModules.cpp
+++ b/lib/Linker/LinkModules.cpp
@@ -19,7 +19,7 @@
// Error - Simple wrapper function to conditionally assign to E and return true.
// This just makes error return conditions a little bit simpler...
//
-static inline bool Error(std::string *E, std::string Message) {
+static inline bool Error(std::string *E, const std::string &Message) {
if (E) *E = Message;
return true;
}
@@ -176,10 +176,11 @@ static Value *RemapOperand(const Value *In,
// LinkGlobals - Loop through the global variables in the src module and merge
-// them into the dest module...
+// them into the dest module.
//
static bool LinkGlobals(Module *Dest, const Module *Src,
std::map<const Value*, Value*> &ValueMap,
+ std::multimap<std::string, GlobalVariable *> &AppendingVars,
std::string *Err) {
// We will need a module level symbol table if the src module has a module
// level symbol table...
@@ -230,6 +231,10 @@ static bool LinkGlobals(Module *Dest, const Module *Src,
// Make sure to remember this mapping...
ValueMap.insert(std::make_pair(SGV, NewDGV));
+ if (SGV->hasAppendingLinkage())
+ // Keep track that this is an appending variable...
+ AppendingVars.insert(std::make_pair(SGV->getName(), NewDGV));
+
} else if (SGV->isExternal()) {
// If SGV is external or if both SGV & DGV are external.. Just link the
// external globals, we aren't adding anything.
@@ -263,7 +268,20 @@ static bool LinkGlobals(Module *Dest, const Module *Src,
// Okay, everything is cool, remember the mapping...
ValueMap.insert(std::make_pair(SGV, DGV));
} else if (SGV->hasAppendingLinkage()) {
- assert(0 && "FIXME: Appending linkage unimplemented!");
+ // No linking is performed yet. Just insert a new copy of the global, and
+ // keep track of the fact that it is an appending variable in the
+ // AppendingVars map. The name is cleared out so that no linkage is
+ // performed.
+ GlobalVariable *NewDGV =
+ new GlobalVariable(SGV->getType()->getElementType(),
+ SGV->isConstant(), SGV->getLinkage(), /*init*/0,
+ "", Dest);
+
+ // Make sure to remember this mapping...
+ ValueMap.insert(std::make_pair(SGV, NewDGV));
+
+ // Keep track that this is an appending variable...
+ AppendingVars.insert(std::make_pair(SGV->getName(), NewDGV));
} else {
assert(0 && "Unknown linkage!");
}
@@ -470,6 +488,81 @@ static bool LinkFunctionBodies(Module *Dest, const Module *Src,
return false;
}
+// LinkAppendingVars - If there were any appending global variables, link them
+// together now. Return true on error.
+//
+static bool LinkAppendingVars(Module *M,
+ std::multimap<std::string, GlobalVariable *> &AppendingVars,
+ std::string *ErrorMsg) {
+ if (AppendingVars.empty()) return false; // Nothing to do.
+
+ // Loop over the multimap of appending vars, processing any variables with the
+ // same name, forming a new appending global variable with both of the
+ // initializers merged together, then rewrite references to the old variables
+ // and delete them.
+ //
+ std::vector<Constant*> Inits;
+ while (AppendingVars.size() > 1) {
+ // Get the first two elements in the map...
+ std::multimap<std::string,
+ GlobalVariable*>::iterator Second = AppendingVars.begin(), First=Second++;
+
+ // If the first two elements are for different names, there is no pair...
+ // Otherwise there is a pair, so link them together...
+ if (First->first == Second->first) {
+ GlobalVariable *G1 = First->second, *G2 = Second->second;
+ const ArrayType *T1 = cast<ArrayType>(G1->getType()->getElementType());
+ const ArrayType *T2 = cast<ArrayType>(G2->getType()->getElementType());
+
+ // Check to see that they two arrays agree on type...
+ if (T1->getElementType() != T2->getElementType())
+ return Error(ErrorMsg,
+ "Appending variables with different element types need to be linked!");
+ if (G1->isConstant() != G2->isConstant())
+ return Error(ErrorMsg,
+ "Appending variables linked with different const'ness!");
+
+ unsigned NewSize = T1->getNumElements() + T2->getNumElements();
+ ArrayType *NewType = ArrayType::get(T1->getElementType(), NewSize);
+
+ // Create the new global variable...
+ GlobalVariable *NG =
+ new GlobalVariable(NewType, G1->isConstant(), G1->getLinkage(),
+ /*init*/0, First->first, M);
+
+ // Merge the initializer...
+ Inits.reserve(NewSize);
+ ConstantArray *I = cast<ConstantArray>(G1->getInitializer());
+ for (unsigned i = 0, e = T1->getNumElements(); i != e; ++i)
+ Inits.push_back(cast<Constant>(I->getValues()[i]));
+ I = cast<ConstantArray>(G2->getInitializer());
+ for (unsigned i = 0, e = T2->getNumElements(); i != e; ++i)
+ Inits.push_back(cast<Constant>(I->getValues()[i]));
+ NG->setInitializer(ConstantArray::get(NewType, Inits));
+ Inits.clear();
+
+ // Replace any uses of the two global variables with uses of the new
+ // global...
+
+ // FIXME: This should rewrite simple/straight-forward uses such as
+ // getelementptr instructions to not use the Cast!
+ ConstantPointerRef *NGCP = ConstantPointerRef::get(NG);
+ G1->replaceAllUsesWith(ConstantExpr::getCast(NGCP, G1->getType()));
+ G2->replaceAllUsesWith(ConstantExpr::getCast(NGCP, G2->getType()));
+
+ // Remove the two globals from the module now...
+ M->getGlobalList().erase(G1);
+ M->getGlobalList().erase(G2);
+
+ // Put the new global into the AppendingVars map so that we can handle
+ // linking of more than two vars...
+ Second->second = NG;
+ }
+ AppendingVars.erase(First);
+ }
+
+ return false;
+}
// LinkModules - This function links two modules together, with the resulting
@@ -495,9 +588,21 @@ bool LinkModules(Module *Dest, const Module *Src, std::string *ErrorMsg) {
//
std::map<const Value*, Value*> ValueMap;
- // Insert all of the globals in src into the Dest module... without
- // initializers
- if (LinkGlobals(Dest, Src, ValueMap, ErrorMsg)) return true;
+ // AppendingVars - Keep track of global variables in the destination module
+ // with appending linkage. After the module is linked together, they are
+ // appended and the module is rewritten.
+ //
+ std::multimap<std::string, GlobalVariable *> AppendingVars;
+
+ // Add all of the appending globals already in the Dest module to
+ // AppendingVars.
+ for (Module::giterator I = Dest->gbegin(), E = Dest->gend(); I != E; ++I)
+ AppendingVars.insert(std::make_pair(I->getName(), I));
+
+ // Insert all of the globals in src into the Dest module... without linking
+ // initializers (which could refer to functions not yet mapped over).
+ //
+ if (LinkGlobals(Dest, Src, ValueMap, AppendingVars, ErrorMsg)) return true;
// Link the functions together between the two modules, without doing function
// bodies... this just adds external function prototypes to the Dest
@@ -518,6 +623,10 @@ bool LinkModules(Module *Dest, const Module *Src, std::string *ErrorMsg) {
//
if (LinkFunctionBodies(Dest, Src, ValueMap, ErrorMsg)) return true;
+ // If there were any appending global variables, link them together now.
+ //
+ if (LinkAppendingVars(Dest, AppendingVars, ErrorMsg)) return true;
+
return false;
}