summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Linker/IRMover.h28
-rw-r--r--llvm/lib/Linker/IRMover.cpp21
-rw-r--r--llvm/test/Linker/Inputs/struct-mapping.ll4
-rw-r--r--llvm/test/Linker/struct-mapping.ll12
-rw-r--r--llvm/tools/llvm-link/llvm-link.cpp9
5 files changed, 55 insertions, 19 deletions
diff --git a/llvm/include/llvm/Linker/IRMover.h b/llvm/include/llvm/Linker/IRMover.h
index 235ada47cef..7b483cb53f0 100644
--- a/llvm/include/llvm/Linker/IRMover.h
+++ b/llvm/include/llvm/Linker/IRMover.h
@@ -49,17 +49,23 @@ public:
// The set of opaque types is the composite module.
DenseSet<StructType *> OpaqueStructTypes;
- // The set of identified but non opaque structures in the composite module.
- DenseSet<StructType *, StructTypeKeyInfo> NonOpaqueStructTypes;
-
- public:
- void addNonOpaque(StructType *Ty);
- void switchToNonOpaque(StructType *Ty);
- void addOpaque(StructType *Ty);
- StructType *findNonOpaque(ArrayRef<Type *> ETypes, bool IsPacked);
- bool hasType(StructType *Ty);
- };
-
+ // The set of identified but non opaque structures in the composite module.
+ DenseSet<StructType *, StructTypeKeyInfo> NonOpaqueStructTypes;
+
+ // Map between structure type name and instance. Used in findNonOpaque
+ // to correctly map imported global variable type during ThinLTO import
+ // phase.
+ DenseMap<StringRef, StructType *> NonOpaqueStructNameMap;
+
+ public:
+ void addNonOpaque(StructType *Ty);
+ void switchToNonOpaque(StructType *Ty);
+ void addOpaque(StructType *Ty);
+ StructType *findNonOpaque(ArrayRef<Type *> ETypes, bool IsPacked,
+ StringRef Name);
+ bool hasType(StructType *Ty);
+ };
+
IRMover(Module &M);
typedef std::function<void(GlobalValue &)> ValueAdder;
diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp
index 42081442db7..03539f393cb 100644
--- a/llvm/lib/Linker/IRMover.cpp
+++ b/llvm/lib/Linker/IRMover.cpp
@@ -318,8 +318,8 @@ Type *TypeMapTy::get(Type *Ty, SmallPtrSet<StructType *, 8> &Visited) {
return *Entry = Ty;
}
- if (StructType *OldT =
- DstStructTypesSet.findNonOpaque(ElementTypes, IsPacked)) {
+ if (StructType *OldT = DstStructTypesSet.findNonOpaque(
+ ElementTypes, IsPacked, STy->getName())) {
STy->setName("");
return *Entry = OldT;
}
@@ -906,7 +906,6 @@ bool IRLinker::shouldLink(GlobalValue *DGV, GlobalValue &SGV) {
Expected<Constant *> IRLinker::linkGlobalValueProto(GlobalValue *SGV,
bool ForAlias) {
GlobalValue *DGV = getLinkedToGlobal(SGV);
-
bool ShouldLink = shouldLink(DGV, *SGV);
// just missing from map
@@ -1410,12 +1409,14 @@ bool IRMover::StructTypeKeyInfo::isEqual(const StructType *LHS,
void IRMover::IdentifiedStructTypeSet::addNonOpaque(StructType *Ty) {
assert(!Ty->isOpaque());
+ if (Ty->hasName())
+ NonOpaqueStructNameMap.insert({getTypeNamePrefix(Ty->getName()), Ty});
+
NonOpaqueStructTypes.insert(Ty);
}
void IRMover::IdentifiedStructTypeSet::switchToNonOpaque(StructType *Ty) {
- assert(!Ty->isOpaque());
- NonOpaqueStructTypes.insert(Ty);
+ addNonOpaque(Ty);
bool Removed = OpaqueStructTypes.erase(Ty);
(void)Removed;
assert(Removed);
@@ -1428,10 +1429,16 @@ void IRMover::IdentifiedStructTypeSet::addOpaque(StructType *Ty) {
StructType *
IRMover::IdentifiedStructTypeSet::findNonOpaque(ArrayRef<Type *> ETypes,
- bool IsPacked) {
+ bool IsPacked, StringRef Name) {
IRMover::StructTypeKeyInfo::KeyTy Key(ETypes, IsPacked);
auto I = NonOpaqueStructTypes.find_as(Key);
- return I == NonOpaqueStructTypes.end() ? nullptr : *I;
+ if (I == NonOpaqueStructTypes.end())
+ return nullptr;
+ auto NI = NonOpaqueStructNameMap.find(getTypeNamePrefix(Name));
+ if (NI != NonOpaqueStructNameMap.end() &&
+ IRMover::StructTypeKeyInfo::KeyTy((*NI).second) == Key)
+ return (*NI).second;
+ return *I;
}
bool IRMover::IdentifiedStructTypeSet::hasType(StructType *Ty) {
diff --git a/llvm/test/Linker/Inputs/struct-mapping.ll b/llvm/test/Linker/Inputs/struct-mapping.ll
new file mode 100644
index 00000000000..d4fa07313c6
--- /dev/null
+++ b/llvm/test/Linker/Inputs/struct-mapping.ll
@@ -0,0 +1,4 @@
+%struct.Baz = type { i64, i64, %struct.Foo }
+%struct.Foo = type { i64, i64 }
+
+@baz = global %struct.Baz zeroinitializer
diff --git a/llvm/test/Linker/struct-mapping.ll b/llvm/test/Linker/struct-mapping.ll
new file mode 100644
index 00000000000..732ef8c50cd
--- /dev/null
+++ b/llvm/test/Linker/struct-mapping.ll
@@ -0,0 +1,12 @@
+; RUN: llvm-link --initial-module=%s %p/Inputs/struct-mapping.ll -S -o - | FileCheck %s
+
+; Here we check that new type mapping algorithm correctly mapped type of internal
+; member of struct.Baz to struct.Foo. Without it we'd map that type to struct.Bar, because
+; it is recursively isomorphic to struct.Foo and is defined first in source file.
+; CHECK: %struct.Baz = type { i64, i64, %struct.Foo }
+
+%struct.Bar = type { i64, i64 }
+%struct.Foo = type { i64, i64 }
+
+@bar = global %struct.Bar zeroinitializer
+@foo = global %struct.Foo zeroinitializer
diff --git a/llvm/tools/llvm-link/llvm-link.cpp b/llvm/tools/llvm-link/llvm-link.cpp
index 1ada60ee5f2..8d29caf47bf 100644
--- a/llvm/tools/llvm-link/llvm-link.cpp
+++ b/llvm/tools/llvm-link/llvm-link.cpp
@@ -70,6 +70,11 @@ static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
cl::value_desc("filename"));
+static cl::opt<std::string>
+ InitialModule("initial-module",
+ cl::desc("Link to existing destination module"), cl::init(""),
+ cl::value_desc("filename"));
+
static cl::opt<bool>
Internalize("internalize", cl::desc("Internalize linked symbols"));
@@ -360,7 +365,9 @@ int main(int argc, char **argv) {
if (!DisableDITypeMap)
Context.enableDebugTypeODRUniquing();
- auto Composite = make_unique<Module>("llvm-link", Context);
+ auto Composite = InitialModule.empty()
+ ? make_unique<Module>("llvm-link", Context)
+ : loadFile(argv[0], InitialModule, Context);
Linker L(*Composite);
unsigned Flags = Linker::Flags::None;
OpenPOWER on IntegriCloud