#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/GVMaterializer.h"
#include "llvm/IR/TypeFinder.h"
void LinkDiagnosticInfo::print(DiagnosticPrinter &DP) const { DP << Msg; }
//===----------------------------------------------------------------------===//
-// ModuleLinker implementation.
+// IRLinker implementation.
//===----------------------------------------------------------------------===//
namespace {
/// speeds up linking for modules with many/ lazily linked functions of which
/// few get used.
class GlobalValueMaterializer final : public ValueMaterializer {
- IRLinker *ModLinker;
+ IRLinker *TheIRLinker;
public:
- GlobalValueMaterializer(IRLinker *ModLinker) : ModLinker(ModLinker) {}
+ GlobalValueMaterializer(IRLinker *TheIRLinker) : TheIRLinker(TheIRLinker) {}
Value *materializeDeclFor(Value *V) override;
void materializeInitFor(GlobalValue *New, GlobalValue *Old) override;
Metadata *mapTemporaryMetadata(Metadata *MD) override;
void replaceTemporaryMetadata(const Metadata *OrigMD,
Metadata *NewMD) override;
+ bool isMetadataNeeded(Metadata *MD) override;
};
class LocalValueMaterializer final : public ValueMaterializer {
- IRLinker *ModLinker;
+ IRLinker *TheIRLinker;
public:
- LocalValueMaterializer(IRLinker *ModLinker) : ModLinker(ModLinker) {}
+ LocalValueMaterializer(IRLinker *TheIRLinker) : TheIRLinker(TheIRLinker) {}
Value *materializeDeclFor(Value *V) override;
void materializeInitFor(GlobalValue *New, GlobalValue *Old) override;
Metadata *mapTemporaryMetadata(Metadata *MD) override;
void replaceTemporaryMetadata(const Metadata *OrigMD,
Metadata *NewMD) override;
+ bool isMetadataNeeded(Metadata *MD) override;
};
/// This is responsible for keeping track of the state used for moving data
/// the value id. Used to correlate temporary metadata created during
/// function importing with the final metadata parsed during the subsequent
/// metadata linking postpass.
- DenseMap<const Metadata *, unsigned> MDValueToValIDMap;
+ DenseMap<const Metadata *, unsigned> MetadataToIDs;
/// Association between metadata value id and temporary metadata that
/// remains unmapped after function importing. Saved during function
/// importing and consumed during the metadata linking postpass.
DenseMap<unsigned, MDNode *> *ValIDToTempMDMap;
+ /// Set of subprogram metadata that does not need to be linked into the
+ /// destination module, because the functions were not imported directly
+ /// or via an inlined body in an imported function.
+ SmallPtrSet<const Metadata *, 16> UnneededSubprograms;
+
/// Handles cloning of a global values from the source module into
/// the destination module, including setting the attributes and visibility.
GlobalValue *copyGlobalValueProto(const GlobalValue *SGV, bool ForDefinition);
void linkNamedMDNodes();
+ /// Populate the UnneededSubprograms set with the DISubprogram metadata
+ /// from the source module that we don't need to link into the dest module,
+ /// because the functions were not imported directly or via an inlined body
+ /// in an imported function.
+ void findNeededSubprograms(ValueToValueMapTy &ValueMap);
+
+ /// The value mapper leaves nulls in the list of subprograms for any
+ /// in the UnneededSubprograms map. Strip those out after metadata linking.
+ void stripNullSubprograms();
+
public:
IRLinker(Module &DstM, IRMover::IdentifiedStructTypeSet &Set, Module &SrcM,
ArrayRef<GlobalValue *> ValuesToLink,
/// the new non-temporary metadata. Used when metadata linking as a postpass
/// for function importing.
void replaceTemporaryMetadata(const Metadata *OrigMD, Metadata *NewMD);
+
+ /// Indicates whether we need to map the given metadata into the destination
+ /// module. Used to prevent linking of metadata only needed by functions not
+ /// linked into the dest module.
+ bool isMetadataNeeded(Metadata *MD);
};
}
}
Value *GlobalValueMaterializer::materializeDeclFor(Value *V) {
- return ModLinker->materializeDeclFor(V, false);
+ return TheIRLinker->materializeDeclFor(V, false);
}
void GlobalValueMaterializer::materializeInitFor(GlobalValue *New,
GlobalValue *Old) {
- ModLinker->materializeInitFor(New, Old, false);
+ TheIRLinker->materializeInitFor(New, Old, false);
}
Metadata *GlobalValueMaterializer::mapTemporaryMetadata(Metadata *MD) {
- return ModLinker->mapTemporaryMetadata(MD);
+ return TheIRLinker->mapTemporaryMetadata(MD);
}
void GlobalValueMaterializer::replaceTemporaryMetadata(const Metadata *OrigMD,
Metadata *NewMD) {
- ModLinker->replaceTemporaryMetadata(OrigMD, NewMD);
+ TheIRLinker->replaceTemporaryMetadata(OrigMD, NewMD);
+}
+
+bool GlobalValueMaterializer::isMetadataNeeded(Metadata *MD) {
+ return TheIRLinker->isMetadataNeeded(MD);
}
Value *LocalValueMaterializer::materializeDeclFor(Value *V) {
- return ModLinker->materializeDeclFor(V, true);
+ return TheIRLinker->materializeDeclFor(V, true);
}
void LocalValueMaterializer::materializeInitFor(GlobalValue *New,
GlobalValue *Old) {
- ModLinker->materializeInitFor(New, Old, true);
+ TheIRLinker->materializeInitFor(New, Old, true);
}
Metadata *LocalValueMaterializer::mapTemporaryMetadata(Metadata *MD) {
- return ModLinker->mapTemporaryMetadata(MD);
+ return TheIRLinker->mapTemporaryMetadata(MD);
}
void LocalValueMaterializer::replaceTemporaryMetadata(const Metadata *OrigMD,
Metadata *NewMD) {
- ModLinker->replaceTemporaryMetadata(OrigMD, NewMD);
+ TheIRLinker->replaceTemporaryMetadata(OrigMD, NewMD);
+}
+
+bool LocalValueMaterializer::isMetadataNeeded(Metadata *MD) {
+ return TheIRLinker->isMetadataNeeded(MD);
}
Value *IRLinker::materializeDeclFor(Value *V, bool ForAlias) {
return nullptr;
// If this temporary metadata has a value id recorded during function
// parsing, record that in the ValIDToTempMDMap if one was provided.
- if (MDValueToValIDMap.count(MD)) {
- unsigned Idx = MDValueToValIDMap[MD];
+ if (MetadataToIDs.count(MD)) {
+ unsigned Idx = MetadataToIDs[MD];
// Check if we created a temp MD when importing a different function from
// this module. If so, reuse it the same temporary metadata, otherwise
// add this temporary metadata to the map.
// created during function importing was provided, and the source
// metadata has a value id recorded during metadata parsing, replace
// the temporary metadata with the final mapped metadata now.
- if (MDValueToValIDMap.count(OrigMD)) {
- unsigned Idx = MDValueToValIDMap[OrigMD];
+ if (MetadataToIDs.count(OrigMD)) {
+ unsigned Idx = MetadataToIDs[OrigMD];
// Nothing to do if we didn't need to create a temporary metadata during
// function importing.
if (!ValIDToTempMDMap->count(Idx))
}
}
+bool IRLinker::isMetadataNeeded(Metadata *MD) {
+ // Currently only DISubprogram metadata is marked as being unneeded.
+ if (UnneededSubprograms.empty())
+ return true;
+ MDNode *Node = dyn_cast<MDNode>(MD);
+ if (!Node)
+ return true;
+ DISubprogram *SP = getDISubprogram(Node);
+ if (!SP)
+ return true;
+ return !UnneededSubprograms.count(SP);
+}
+
/// Loop through the global variables in the src module and merge them into the
/// dest module.
GlobalVariable *IRLinker::copyGlobalVariableProto(const GlobalVariable *SGVar) {
// a function and before remapping metadata on instructions below
// in RemapInstruction, as the saved mapping is used to handle
// the temporary metadata hanging off instructions.
- SrcM.getMaterializer()->saveMDValueList(MDValueToValIDMap, true);
+ SrcM.getMaterializer()->saveMetadataList(MetadataToIDs, true);
// Link in the prefix data.
if (Src.hasPrefixData())
for (Argument &Arg : Src.args())
ValueMap.erase(&Arg);
- Src.dematerialize();
return false;
}
return false;
}
+void IRLinker::findNeededSubprograms(ValueToValueMapTy &ValueMap) {
+ // Track unneeded nodes to make it simpler to handle the case
+ // where we are checking if an already-mapped SP is needed.
+ NamedMDNode *CompileUnits = SrcM.getNamedMetadata("llvm.dbg.cu");
+ if (!CompileUnits)
+ return;
+ for (unsigned I = 0, E = CompileUnits->getNumOperands(); I != E; ++I) {
+ auto *CU = cast<DICompileUnit>(CompileUnits->getOperand(I));
+ assert(CU && "Expected valid compile unit");
+ for (auto *Op : CU->getSubprograms()) {
+ // Unless we were doing function importing and deferred metadata linking,
+ // any needed SPs should have been mapped as they would be reached
+ // from the function linked in (either on the function itself for linked
+ // function bodies, or from DILocation on inlined instructions).
+ assert(!(ValueMap.MD()[Op] && IsMetadataLinkingPostpass) &&
+ "DISubprogram shouldn't be mapped yet");
+ if (!ValueMap.MD()[Op])
+ UnneededSubprograms.insert(Op);
+ }
+ }
+ if (!IsMetadataLinkingPostpass)
+ return;
+ // In the case of metadata linking as a postpass (e.g. for function
+ // importing), see which DISubprogram MD from the source has an associated
+ // temporary metadata node, which means the SP was needed by an imported
+ // function.
+ for (auto MDI : MetadataToIDs) {
+ const MDNode *Node = dyn_cast<MDNode>(MDI.first);
+ if (!Node)
+ continue;
+ DISubprogram *SP = getDISubprogram(Node);
+ if (!SP || !ValIDToTempMDMap->count(MDI.second))
+ continue;
+ UnneededSubprograms.erase(SP);
+ }
+}
+
+// Squash null subprograms from compile unit subprogram lists.
+void IRLinker::stripNullSubprograms() {
+ NamedMDNode *CompileUnits = DstM.getNamedMetadata("llvm.dbg.cu");
+ if (!CompileUnits)
+ return;
+ for (unsigned I = 0, E = CompileUnits->getNumOperands(); I != E; ++I) {
+ auto *CU = cast<DICompileUnit>(CompileUnits->getOperand(I));
+ assert(CU && "Expected valid compile unit");
+
+ SmallVector<Metadata *, 16> NewSPs;
+ NewSPs.reserve(CU->getSubprograms().size());
+ bool FoundNull = false;
+ for (DISubprogram *SP : CU->getSubprograms()) {
+ if (!SP) {
+ FoundNull = true;
+ continue;
+ }
+ NewSPs.push_back(SP);
+ }
+ if (FoundNull)
+ CU->replaceSubprograms(MDTuple::get(CU->getContext(), NewSPs));
+ }
+}
+
/// Insert all of the named MDNodes in Src into the Dest module.
void IRLinker::linkNamedMDNodes() {
+ findNeededSubprograms(ValueMap);
const NamedMDNode *SrcModFlags = SrcM.getModuleFlagsMetadata();
for (const NamedMDNode &NMD : SrcM.named_metadata()) {
// Don't link module flags here. Do them separately.
op, ValueMap, ValueMapperFlags | RF_NullMapMissingGlobalValues,
&TypeMap, &GValMaterializer));
}
+ stripNullSubprograms();
}
/// Merge the linker flags in Src into the Dest module.
// Ensure metadata materialized
if (SrcM.getMaterializer()->materializeMetadata())
return true;
- SrcM.getMaterializer()->saveMDValueList(MDValueToValIDMap, false);
+ SrcM.getMaterializer()->saveMetadataList(MetadataToIDs, false);
}
linkNamedMDNodes();
// Handle anything left in the ValIDToTempMDMap, such as metadata nodes
// not reached by the dbg.cu NamedMD (i.e. only reached from
// instructions).
- // Walk the MDValueToValIDMap once to find the set of new (imported) MD
+ // Walk the MetadataToIDs once to find the set of new (imported) MD
// that still has corresponding temporary metadata, and invoke metadata
// mapping on each one.
- for (auto MDI : MDValueToValIDMap) {
+ for (auto MDI : MetadataToIDs) {
if (!ValIDToTempMDMap->count(MDI.second))
continue;
MapMetadata(MDI.first, ValueMap, ValueMapperFlags, &TypeMap,
std::function<void(GlobalValue &, ValueAdder Add)> AddLazyFor,
DenseMap<unsigned, MDNode *> *ValIDToTempMDMap,
bool IsMetadataLinkingPostpass) {
- IRLinker TheLinker(Composite, IdentifiedStructTypes, Src, ValuesToLink,
- AddLazyFor, ValIDToTempMDMap, IsMetadataLinkingPostpass);
- bool RetCode = TheLinker.run();
+ IRLinker TheIRLinker(Composite, IdentifiedStructTypes, Src, ValuesToLink,
+ AddLazyFor, ValIDToTempMDMap, IsMetadataLinkingPostpass);
+ bool RetCode = TheIRLinker.run();
Composite.dropTriviallyDeadConstantArrays();
return RetCode;
}