[IRMover] Implement name based structure type mapping
authorEugene Leviant <eleviant@accesssoftek.com>
Wed, 21 Feb 2018 15:13:48 +0000 (15:13 +0000)
committerEugene Leviant <eleviant@accesssoftek.com>
Wed, 21 Feb 2018 15:13:48 +0000 (15:13 +0000)
Differential revision: https://reviews.llvm.org/D43199

llvm-svn: 325686

llvm/include/llvm/Linker/IRMover.h
llvm/lib/Linker/IRMover.cpp
llvm/test/Linker/Inputs/struct-mapping.ll [new file with mode: 0644]
llvm/test/Linker/struct-mapping.ll [new file with mode: 0644]
llvm/tools/llvm-link/llvm-link.cpp

index 235ada4..7b483cb 100644 (file)
@@ -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.\r
+    DenseSet<StructType *, StructTypeKeyInfo> NonOpaqueStructTypes;\r
+\r
+    // Map between structure type name and instance. Used in findNonOpaque\r
+    // to correctly map imported global variable type during ThinLTO import\r
+    // phase.\r
+    DenseMap<StringRef, StructType *> NonOpaqueStructNameMap;\r
+\r
+  public:\r
+    void addNonOpaque(StructType *Ty);\r
+    void switchToNonOpaque(StructType *Ty);\r
+    void addOpaque(StructType *Ty);\r
+    StructType *findNonOpaque(ArrayRef<Type *> ETypes, bool IsPacked,\r
+                              StringRef Name);\r
+    bool hasType(StructType *Ty);\r
+  };\r
+\r
   IRMover(Module &M);
 
   typedef std::function<void(GlobalValue &)> ValueAdder;
index 4208144..03539f3 100644 (file)
@@ -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 (file)
index 0000000..d4fa073
--- /dev/null
@@ -0,0 +1,4 @@
+%struct.Baz = type { i64, i64, %struct.Foo }\r
+%struct.Foo = type { i64, i64 }\r
+\r
+@baz = global %struct.Baz zeroinitializer\r
diff --git a/llvm/test/Linker/struct-mapping.ll b/llvm/test/Linker/struct-mapping.ll
new file mode 100644 (file)
index 0000000..732ef8c
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llvm-link --initial-module=%s %p/Inputs/struct-mapping.ll -S -o - | FileCheck %s\r
+\r
+; Here we check that new type mapping algorithm correctly mapped type of internal\r
+; member of struct.Baz to struct.Foo. Without it we'd map that type to struct.Bar, because\r
+; it is recursively isomorphic to struct.Foo and is defined first in source file.\r
+; CHECK: %struct.Baz = type { i64, i64, %struct.Foo }\r
+\r
+%struct.Bar = type { i64, i64 }\r
+%struct.Foo = type { i64, i64 }\r
+\r
+@bar = global %struct.Bar zeroinitializer\r
+@foo = global %struct.Foo zeroinitializer\r
index 1ada60e..8d29caf 100644 (file)
@@ -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;