Index: llvm/trunk/include/llvm/Linker/IRMover.h =================================================================== --- llvm/trunk/include/llvm/Linker/IRMover.h +++ llvm/trunk/include/llvm/Linker/IRMover.h @@ -49,17 +49,23 @@ // The set of opaque types is the composite module. DenseSet OpaqueStructTypes; - // The set of identified but non opaque structures in the composite module. - DenseSet NonOpaqueStructTypes; - - public: - void addNonOpaque(StructType *Ty); - void switchToNonOpaque(StructType *Ty); - void addOpaque(StructType *Ty); - StructType *findNonOpaque(ArrayRef ETypes, bool IsPacked); - bool hasType(StructType *Ty); - }; - + // The set of identified but non opaque structures in the composite module. + DenseSet NonOpaqueStructTypes; + + // Map between structure type name and instance. Used in findNonOpaque + // to correctly map imported global variable type during ThinLTO import + // phase. + DenseMap NonOpaqueStructNameMap; + + public: + void addNonOpaque(StructType *Ty); + void switchToNonOpaque(StructType *Ty); + void addOpaque(StructType *Ty); + StructType *findNonOpaque(ArrayRef ETypes, bool IsPacked, + StringRef Name); + bool hasType(StructType *Ty); + }; + IRMover(Module &M); typedef std::function ValueAdder; Index: llvm/trunk/lib/Linker/IRMover.cpp =================================================================== --- llvm/trunk/lib/Linker/IRMover.cpp +++ llvm/trunk/lib/Linker/IRMover.cpp @@ -318,8 +318,8 @@ 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 @@ Expected IRLinker::linkGlobalValueProto(GlobalValue *SGV, bool ForAlias) { GlobalValue *DGV = getLinkedToGlobal(SGV); - bool ShouldLink = shouldLink(DGV, *SGV); // just missing from map @@ -1410,12 +1409,14 @@ 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 @@ StructType * IRMover::IdentifiedStructTypeSet::findNonOpaque(ArrayRef 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) { Index: llvm/trunk/test/Linker/Inputs/struct-mapping.ll =================================================================== --- llvm/trunk/test/Linker/Inputs/struct-mapping.ll +++ llvm/trunk/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 Index: llvm/trunk/test/Linker/struct-mapping.ll =================================================================== --- llvm/trunk/test/Linker/struct-mapping.ll +++ llvm/trunk/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 Index: llvm/trunk/tools/llvm-link/llvm-link.cpp =================================================================== --- llvm/trunk/tools/llvm-link/llvm-link.cpp +++ llvm/trunk/tools/llvm-link/llvm-link.cpp @@ -70,6 +70,11 @@ OutputFilename("o", cl::desc("Override output filename"), cl::init("-"), cl::value_desc("filename")); +static cl::opt + InitialModule("initial-module", + cl::desc("Link to existing destination module"), cl::init(""), + cl::value_desc("filename")); + static cl::opt Internalize("internalize", cl::desc("Internalize linked symbols")); @@ -360,7 +365,9 @@ if (!DisableDITypeMap) Context.enableDebugTypeODRUniquing(); - auto Composite = make_unique("llvm-link", Context); + auto Composite = InitialModule.empty() + ? make_unique("llvm-link", Context) + : loadFile(argv[0], InitialModule, Context); Linker L(*Composite); unsigned Flags = Linker::Flags::None;