summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Linker/LinkModules.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Linker/LinkModules.cpp')
-rw-r--r--llvm/lib/Linker/LinkModules.cpp54
1 files changed, 54 insertions, 0 deletions
diff --git a/llvm/lib/Linker/LinkModules.cpp b/llvm/lib/Linker/LinkModules.cpp
index 0e144157af4..7f3e5b3bd2a 100644
--- a/llvm/lib/Linker/LinkModules.cpp
+++ b/llvm/lib/Linker/LinkModules.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
@@ -416,6 +417,9 @@ class ModuleLinker {
// Vector of GlobalValues to lazily link in.
std::vector<GlobalValue *> LazilyLinkGlobalValues;
+ /// Functions that have replaced other functions.
+ SmallPtrSet<const Function *, 16> OverridingFunctions;
+
Linker::DiagnosticHandlerFunction DiagnosticHandler;
public:
@@ -494,6 +498,7 @@ private:
bool linkGlobalValueBody(GlobalValue &Src);
void linkNamedMDNodes();
+ void stripReplacedSubprograms();
};
}
@@ -1078,6 +1083,10 @@ bool ModuleLinker::linkGlobalValueProto(GlobalValue *SGV) {
}
NewGV = copyGlobalValueProto(TypeMap, *DstM, SGV);
+
+ if (DGV && isa<Function>(DGV))
+ if (auto *NewF = dyn_cast<Function>(NewGV))
+ OverridingFunctions.insert(NewF);
}
NewGV->setUnnamedAddr(HasUnnamedAddr);
@@ -1244,6 +1253,48 @@ void ModuleLinker::linkNamedMDNodes() {
}
}
+/// Drop DISubprograms that have been superseded.
+///
+/// FIXME: this creates an asymmetric result: we strip losing subprograms from
+/// DstM, but leave losing subprograms in SrcM. Instead we should also strip
+/// losers from SrcM, but this requires extra plumbing in MapValue.
+void ModuleLinker::stripReplacedSubprograms() {
+ // Avoid quadratic runtime by returning early when there's nothing to do.
+ if (OverridingFunctions.empty())
+ return;
+
+ // Move the functions now, so the set gets cleared even on early returns.
+ auto Functions = std::move(OverridingFunctions);
+ OverridingFunctions.clear();
+
+ // Drop subprograms whose functions have been overridden by the new compile
+ // unit.
+ NamedMDNode *CompileUnits = DstM->getNamedMetadata("llvm.dbg.cu");
+ if (!CompileUnits)
+ return;
+ for (unsigned I = 0, E = CompileUnits->getNumOperands(); I != E; ++I) {
+ DICompileUnit CU(CompileUnits->getOperand(I));
+ assert(CU && "Expected valid compile unit");
+
+ DITypedArray<DISubprogram> SPs(CU.getSubprograms());
+ assert(SPs && "Expected valid subprogram array");
+
+ SmallVector<Metadata *, 16> NewSPs;
+ NewSPs.reserve(SPs.getNumElements());
+ for (unsigned S = 0, SE = SPs.getNumElements(); S != SE; ++S) {
+ DISubprogram SP = SPs.getElement(S);
+ if (SP && SP.getFunction() && Functions.count(SP.getFunction()))
+ continue;
+
+ NewSPs.push_back(SP);
+ }
+
+ // Redirect operand to the overriding subprogram.
+ if (NewSPs.size() != SPs.getNumElements())
+ CU.replaceSubprograms(DIArray(MDNode::get(DstM->getContext(), NewSPs)));
+ }
+}
+
/// Merge the linker flags in Src into the Dest module.
bool ModuleLinker::linkModuleFlagsMetadata() {
// If the source module has no module flags, we are done.
@@ -1509,6 +1560,9 @@ bool ModuleLinker::run() {
linkGlobalValueBody(Src);
}
+ // Strip replaced subprograms before linking together compile units.
+ stripReplacedSubprograms();
+
// Remap all of the named MDNodes in Src into the DstM module. We do this
// after linking GlobalValues so that MDNodes that reference GlobalValues
// are properly remapped.
OpenPOWER on IntegriCloud