Extend RemapInstruction and friends to take an optional new parameter, a ValueMaterializer.

Extend LinkModules to pass a ValueMaterializer to RemapInstruction and friends to lazily create Functions for lazily linked globals. This is a big win when linking small modules with large (mostly unused) library modules.

llvm-svn: 182776
This commit is contained in:
James Molloy
2013-05-28 15:17:05 +00:00
parent 40d7ed5d1e
commit f6f121e277
6 changed files with 142 additions and 70 deletions

View File

@@ -353,12 +353,32 @@ Type *TypeMapTy::getImpl(Type *Ty) {
//===----------------------------------------------------------------------===//
namespace {
class ModuleLinker;
/// ValueMaterializerTy - Creates prototypes for functions that are lazily
/// linked on the fly. This speeds up linking for modules with many
/// lazily linked functions of which few get used.
class ValueMaterializerTy : public ValueMaterializer {
TypeMapTy &TypeMap;
Module *DstM;
std::vector<Function*> &LazilyLinkFunctions;
public:
ValueMaterializerTy(TypeMapTy &TypeMap, Module *DstM,
std::vector<Function*> &LazilyLinkFunctions) :
ValueMaterializer(), TypeMap(TypeMap), DstM(DstM),
LazilyLinkFunctions(LazilyLinkFunctions) {
}
virtual Value *materializeValueFor(Value *V);
};
/// ModuleLinker - This is an implementation class for the LinkModules
/// function, which is the entrypoint for this file.
class ModuleLinker {
Module *DstM, *SrcM;
TypeMapTy TypeMap;
ValueMaterializerTy ValMaterializer;
/// ValueMap - Mapping of values from what they used to be in Src, to what
/// they are now in DstM. ValueToValueMapTy is a ValueMap, which involves
@@ -386,7 +406,9 @@ namespace {
std::string ErrorMsg;
ModuleLinker(Module *dstM, TypeSet &Set, Module *srcM, unsigned mode)
: DstM(dstM), SrcM(srcM), TypeMap(Set), Mode(mode) { }
: DstM(dstM), SrcM(srcM), TypeMap(Set),
ValMaterializer(TypeMap, DstM, LazilyLinkFunctions),
Mode(mode) { }
bool run();
@@ -487,6 +509,20 @@ static bool isLessConstraining(GlobalValue::VisibilityTypes a,
return false;
}
Value *ValueMaterializerTy::materializeValueFor(Value *V) {
Function *SF = dyn_cast<Function>(V);
if (!SF)
return NULL;
Function *DF = Function::Create(TypeMap.get(SF->getFunctionType()),
SF->getLinkage(), SF->getName(), DstM);
copyGVAttributes(DF, SF);
LazilyLinkFunctions.push_back(SF);
return DF;
}
/// getLinkageResult - This analyzes the two global values and determines what
/// the result will look like in the destination module. In particular, it
/// computes the resultant linkage type and visibility, computes whether the
@@ -802,6 +838,14 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
}
}
// If the function is to be lazily linked, don't create it just yet.
// The ValueMaterializerTy will deal with creating it if it's used.
if (!DGV && (SF->hasLocalLinkage() || SF->hasLinkOnceLinkage() ||
SF->hasAvailableExternallyLinkage())) {
DoNotLinkFromSource.insert(SF);
return false;
}
// If there is no linkage to be performed or we are linking from the source,
// bring SF over.
Function *NewDF = Function::Create(TypeMap.get(SF->getFunctionType()),
@@ -814,13 +858,6 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
// Any uses of DF need to change to NewDF, with cast.
DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDF, DGV->getType()));
DGV->eraseFromParent();
} else {
// Internal, LO_ODR, or LO linkage - stick in set to ignore and lazily link.
if (SF->hasLocalLinkage() || SF->hasLinkOnceLinkage() ||
SF->hasAvailableExternallyLinkage()) {
DoNotLinkFromSource.insert(SF);
LazilyLinkFunctions.push_back(SF);
}
}
ValueMap[SF] = NewDF;
@@ -887,7 +924,7 @@ void ModuleLinker::linkAppendingVarInit(const AppendingVarInfo &AVI) {
SmallVector<Constant*, 16> Elements;
getArrayElements(AVI.DstInit, Elements);
Constant *SrcInit = MapValue(AVI.SrcInit, ValueMap, RF_None, &TypeMap);
Constant *SrcInit = MapValue(AVI.SrcInit, ValueMap, RF_None, &TypeMap, &ValMaterializer);
getArrayElements(SrcInit, Elements);
ArrayType *NewType = cast<ArrayType>(AVI.NewGV->getType()->getElementType());
@@ -908,7 +945,7 @@ void ModuleLinker::linkGlobalInits() {
GlobalVariable *DGV = cast<GlobalVariable>(ValueMap[I]);
// Figure out what the initializer looks like in the dest module.
DGV->setInitializer(MapValue(I->getInitializer(), ValueMap,
RF_None, &TypeMap));
RF_None, &TypeMap, &ValMaterializer));
}
}
@@ -938,12 +975,14 @@ void ModuleLinker::linkFunctionBody(Function *Dst, Function *Src) {
// functions and patch them up to point to the local versions.
for (Function::iterator BB = Dst->begin(), BE = Dst->end(); BB != BE; ++BB)
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
RemapInstruction(I, ValueMap, RF_IgnoreMissingEntries, &TypeMap);
RemapInstruction(I, ValueMap, RF_IgnoreMissingEntries,
&TypeMap, &ValMaterializer);
} else {
// Clone the body of the function into the dest function.
SmallVector<ReturnInst*, 8> Returns; // Ignore returns.
CloneFunctionInto(Dst, Src, ValueMap, false, Returns, "", NULL, &TypeMap);
CloneFunctionInto(Dst, Src, ValueMap, false, Returns, "", NULL,
&TypeMap, &ValMaterializer);
}
// There is no need to map the arguments anymore.
@@ -961,7 +1000,8 @@ void ModuleLinker::linkAliasBodies() {
continue;
if (Constant *Aliasee = I->getAliasee()) {
GlobalAlias *DA = cast<GlobalAlias>(ValueMap[I]);
DA->setAliasee(MapValue(Aliasee, ValueMap, RF_None, &TypeMap));
DA->setAliasee(MapValue(Aliasee, ValueMap, RF_None,
&TypeMap, &ValMaterializer));
}
}
}
@@ -978,7 +1018,7 @@ void ModuleLinker::linkNamedMDNodes() {
// Add Src elements into Dest node.
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
DestNMD->addOperand(MapValue(I->getOperand(i), ValueMap,
RF_None, &TypeMap));
RF_None, &TypeMap, &ValMaterializer));
}
}
@@ -1238,49 +1278,36 @@ bool ModuleLinker::run() {
LinkedInAnyFunctions = false;
for(std::vector<Function*>::iterator I = LazilyLinkFunctions.begin(),
E = LazilyLinkFunctions.end(); I != E; ++I) {
if (!*I)
continue;
E = LazilyLinkFunctions.end(); I != E; ++I) {
Function *SF = *I;
Function *DF = cast<Function>(ValueMap[SF]);
if (!DF->use_empty()) {
// Materialize if necessary.
if (SF->isDeclaration()) {
if (!SF->isMaterializable())
continue;
if (SF->Materialize(&ErrorMsg))
return true;
}
// Link in function body.
linkFunctionBody(DF, SF);
SF->Dematerialize();
if (!SF)
continue;
// "Remove" from vector by setting the element to 0.
*I = 0;
// Set flag to indicate we may have more functions to lazily link in
// since we linked in a function.
LinkedInAnyFunctions = true;
Function *DF = cast<Function>(ValueMap[SF]);
// Materialize if necessary.
if (SF->isDeclaration()) {
if (!SF->isMaterializable())
continue;
if (SF->Materialize(&ErrorMsg))
return true;
}
// Erase from vector *before* the function body is linked - linkFunctionBody could
// invalidate I.
LazilyLinkFunctions.erase(I);
// Link in function body.
linkFunctionBody(DF, SF);
SF->Dematerialize();
// Set flag to indicate we may have more functions to lazily link in
// since we linked in a function.
LinkedInAnyFunctions = true;
break;
}
} while (LinkedInAnyFunctions);
// Remove any prototypes of functions that were not actually linked in.
for(std::vector<Function*>::iterator I = LazilyLinkFunctions.begin(),
E = LazilyLinkFunctions.end(); I != E; ++I) {
if (!*I)
continue;
Function *SF = *I;
Function *DF = cast<Function>(ValueMap[SF]);
if (DF->use_empty())
DF->eraseFromParent();
}
// Now that all of the types from the source are used, resolve any structs
// copied over to the dest that didn't exist there.
TypeMap.linkDefinedTypeBodies();