Fix overly aggressive type merging.
authorRafael Espindola <rafael.espindola@gmail.com>
Tue, 25 Nov 2014 05:59:24 +0000 (05:59 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Tue, 25 Nov 2014 05:59:24 +0000 (05:59 +0000)
If we find out that two types are *not* isomorphic, we learn nothing about
opaque sub types in both the source and destination.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222727 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Linker/LinkModules.cpp
test/Linker/Inputs/type-unique-opaque.ll [new file with mode: 0644]
test/Linker/type-unique-opaque.ll [new file with mode: 0644]

index a8dc324daa215878ea2f52366bceca7c07c187c0..e57a37fb4a0d863b841923feacbdde2a2d011c10 100644 (file)
@@ -107,12 +107,23 @@ void TypeMapTy::addTypeMapping(Type *DstTy, Type *SrcTy) {
 
   // Check to see if these types are recursively isomorphic and establish a
   // mapping between them if so.
-  if (!areTypesIsomorphic(DstTy, SrcTy)) {
-    // Oops, they aren't isomorphic.  Just discard this request by rolling out
-    // any speculative mappings we've established.
-    for (unsigned i = 0, e = SpeculativeTypes.size(); i != e; ++i)
-      MappedTypes.erase(SpeculativeTypes[i]);
+  if (areTypesIsomorphic(DstTy, SrcTy)) {
+    SpeculativeTypes.clear();
+    return;
+  }
+
+  // Oops, they aren't isomorphic. Just discard this request by rolling out
+  // any speculative mappings we've established.
+  unsigned Removed = 0;
+  for (unsigned I = 0, E = SpeculativeTypes.size(); I != E; ++I) {
+    Type *SrcTy = SpeculativeTypes[I];
+    auto Iter = MappedTypes.find(SrcTy);
+    auto *DstTy = dyn_cast<StructType>(Iter->second);
+    if (DstTy && DstResolvedOpaqueTypes.erase(DstTy))
+      Removed++;
+    MappedTypes.erase(Iter);
   }
+  SrcDefinitionsToResolve.resize(SrcDefinitionsToResolve.size() - Removed);
   SpeculativeTypes.clear();
 }
 
@@ -147,14 +158,14 @@ bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
 
     // Mapping a non-opaque source type to an opaque dest.  If this is the first
     // type that we're mapping onto this destination type then we succeed.  Keep
-    // the dest, but fill it in later.  This doesn't need to be speculative.  If
-    // this is the second (different) type that we're trying to map onto the
-    // same opaque type then we fail.
+    // the dest, but fill it in later. If this is the second (different) type
+    // that we're trying to map onto the same opaque type then we fail.
     if (cast<StructType>(DstTy)->isOpaque()) {
       // We can only map one source type onto the opaque destination type.
       if (!DstResolvedOpaqueTypes.insert(cast<StructType>(DstTy)).second)
         return false;
       SrcDefinitionsToResolve.push_back(SSTy);
+      SpeculativeTypes.push_back(SrcTy);
       Entry = DstTy;
       return true;
     }
diff --git a/test/Linker/Inputs/type-unique-opaque.ll b/test/Linker/Inputs/type-unique-opaque.ll
new file mode 100644 (file)
index 0000000..872b601
--- /dev/null
@@ -0,0 +1,6 @@
+%t = type { i8 }
+%t2 = type { %t*, i16 }
+
+define %t2* @f() {
+  ret %t2* null
+}
diff --git a/test/Linker/type-unique-opaque.ll b/test/Linker/type-unique-opaque.ll
new file mode 100644 (file)
index 0000000..b4f6966
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llvm-link -S %s %p/Inputs/type-unique-opaque.ll | FileCheck %s
+
+; Test that a failed attempt at merging %u2 and %t2 (for the other file) will
+; not cause %u and %t to get merged.
+
+; CHECK: %u = type opaque
+; CHECK: define %u* @g() {
+
+%u = type opaque
+%u2 = type { %u*, i8 }
+
+declare %u2* @f()
+
+define %u* @g() {
+  ret %u* null
+}