Skip to content

Commit bb75f65

Browse files
authored
[IRMover] Don't consider opaque types isomorphic to other types (#138241)
The type mapping in IRMover currently has a decent amount of complexity related to establishing isomorphism between opaque struct types and non-opaque struct types. I believe that this is both largely useless at this point (after some recent clarifications, essentially the only place where opaque types can still appear are external gobals) and has never been entirely correct in the first place (because it does this in part purely based on name rather than use, which means that we effectively end up assigning semantics to the type name, which is illegal). As such, I'd like to remove this functionality entirely.
1 parent aac1f85 commit bb75f65

File tree

4 files changed

+36
-116
lines changed

4 files changed

+36
-116
lines changed

llvm/lib/Linker/IRMover.cpp

Lines changed: 24 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,6 @@ class TypeMapTy : public ValueMapTypeRemapper {
4949
/// This is a mapping from a source type to a destination type to use.
5050
DenseMap<Type *, Type *> MappedTypes;
5151

52-
/// When checking to see if two subgraphs are isomorphic, we speculatively
53-
/// add types to MappedTypes, but keep track of them here in case we need to
54-
/// roll back.
55-
SmallVector<Type *, 16> SpeculativeTypes;
56-
57-
SmallVector<StructType *, 16> SpeculativeDstOpaqueTypes;
58-
59-
/// This is a list of non-opaque structs in the source module that are mapped
60-
/// to an opaque struct in the destination module.
61-
SmallVector<StructType *, 16> SrcDefinitionsToResolve;
62-
63-
/// This is the set of opaque types in the destination modules who are
64-
/// getting a body from the source module.
65-
SmallPtrSet<StructType *, 16> DstResolvedOpaqueTypes;
66-
6752
public:
6853
TypeMapTy(IRMover::IdentifiedStructTypeSet &DstStructTypesSet)
6954
: DstStructTypesSet(DstStructTypesSet) {}
@@ -73,10 +58,6 @@ class TypeMapTy : public ValueMapTypeRemapper {
7358
/// equivalent to the specified type in the source module.
7459
void addTypeMapping(Type *DstTy, Type *SrcTy);
7560

76-
/// Produce a body for an opaque type in the dest module from a type
77-
/// definition in the source module.
78-
Error linkDefinedTypeBodies();
79-
8061
/// Return the mapped type to use for the specified input type from the
8162
/// source module.
8263
Type *get(Type *SrcTy);
@@ -88,45 +69,19 @@ class TypeMapTy : public ValueMapTypeRemapper {
8869
private:
8970
Type *remapType(Type *SrcTy) override { return get(SrcTy); }
9071

91-
bool areTypesIsomorphic(Type *DstTy, Type *SrcTy);
72+
bool recursivelyAddMappingIfTypesAreIsomorphic(Type *DstTy, Type *SrcTy);
9273
};
9374
}
9475

9576
void TypeMapTy::addTypeMapping(Type *DstTy, Type *SrcTy) {
96-
assert(SpeculativeTypes.empty());
97-
assert(SpeculativeDstOpaqueTypes.empty());
98-
99-
// Check to see if these types are recursively isomorphic and establish a
100-
// mapping between them if so.
101-
if (!areTypesIsomorphic(DstTy, SrcTy)) {
102-
// Oops, they aren't isomorphic. Just discard this request by rolling out
103-
// any speculative mappings we've established.
104-
for (Type *Ty : SpeculativeTypes)
105-
MappedTypes.erase(Ty);
106-
107-
SrcDefinitionsToResolve.resize(SrcDefinitionsToResolve.size() -
108-
SpeculativeDstOpaqueTypes.size());
109-
for (StructType *Ty : SpeculativeDstOpaqueTypes)
110-
DstResolvedOpaqueTypes.erase(Ty);
111-
} else {
112-
// SrcTy and DstTy are recursively ismorphic. We clear names of SrcTy
113-
// and all its descendants to lower amount of renaming in LLVM context
114-
// Renaming occurs because we load all source modules to the same context
115-
// and declaration with existing name gets renamed (i.e Foo -> Foo.42).
116-
// As a result we may get several different types in the destination
117-
// module, which are in fact the same.
118-
for (Type *Ty : SpeculativeTypes)
119-
if (auto *STy = dyn_cast<StructType>(Ty))
120-
if (STy->hasName())
121-
STy->setName("");
122-
}
123-
SpeculativeTypes.clear();
124-
SpeculativeDstOpaqueTypes.clear();
77+
recursivelyAddMappingIfTypesAreIsomorphic(DstTy, SrcTy);
12578
}
12679

12780
/// Recursively walk this pair of types, returning true if they are isomorphic,
128-
/// false if they are not.
129-
bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
81+
/// false if they are not. Types that were determined to be isomorphic are
82+
/// added to MappedTypes.
83+
bool TypeMapTy::recursivelyAddMappingIfTypesAreIsomorphic(Type *DstTy,
84+
Type *SrcTy) {
13085
// Two types with differing kinds are clearly not isomorphic.
13186
if (DstTy->getTypeID() != SrcTy->getTypeID())
13287
return false;
@@ -145,29 +100,10 @@ bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
145100

146101
// Okay, we have two types with identical kinds that we haven't seen before.
147102

148-
// If this is an opaque struct type, special case it.
103+
// Always consider opaque struct types non-isomorphic.
149104
if (StructType *SSTy = dyn_cast<StructType>(SrcTy)) {
150-
// Mapping an opaque type to any struct, just keep the dest struct.
151-
if (SSTy->isOpaque()) {
152-
Entry = DstTy;
153-
SpeculativeTypes.push_back(SrcTy);
154-
return true;
155-
}
156-
157-
// Mapping a non-opaque source type to an opaque dest. If this is the first
158-
// type that we're mapping onto this destination type then we succeed. Keep
159-
// the dest, but fill it in later. If this is the second (different) type
160-
// that we're trying to map onto the same opaque type then we fail.
161-
if (cast<StructType>(DstTy)->isOpaque()) {
162-
// We can only map one source type onto the opaque destination type.
163-
if (!DstResolvedOpaqueTypes.insert(cast<StructType>(DstTy)).second)
164-
return false;
165-
SrcDefinitionsToResolve.push_back(SSTy);
166-
SpeculativeTypes.push_back(SrcTy);
167-
SpeculativeDstOpaqueTypes.push_back(cast<StructType>(DstTy));
168-
Entry = DstTy;
169-
return true;
170-
}
105+
if (SSTy->isOpaque() || cast<StructType>(DstTy)->isOpaque())
106+
return false;
171107
}
172108

173109
// If the number of subtypes disagree between the two types, then we fail.
@@ -196,38 +132,27 @@ bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
196132
return false;
197133
}
198134

199-
// Otherwise, we speculate that these two types will line up and recursively
200-
// check the subelements.
201-
Entry = DstTy;
202-
SpeculativeTypes.push_back(SrcTy);
203-
135+
// Recursively check the subelements.
204136
for (unsigned I = 0, E = SrcTy->getNumContainedTypes(); I != E; ++I)
205-
if (!areTypesIsomorphic(DstTy->getContainedType(I),
206-
SrcTy->getContainedType(I)))
137+
if (!recursivelyAddMappingIfTypesAreIsomorphic(DstTy->getContainedType(I),
138+
SrcTy->getContainedType(I)))
207139
return false;
208140

209141
// If everything seems to have lined up, then everything is great.
210-
return true;
211-
}
142+
[[maybe_unused]] auto Res = MappedTypes.insert({SrcTy, DstTy});
143+
assert(!Res.second && "Recursive type?");
212144

213-
Error TypeMapTy::linkDefinedTypeBodies() {
214-
SmallVector<Type *, 16> Elements;
215-
for (StructType *SrcSTy : SrcDefinitionsToResolve) {
216-
StructType *DstSTy = cast<StructType>(MappedTypes[SrcSTy]);
217-
assert(DstSTy->isOpaque());
218-
219-
// Map the body of the source type over to a new body for the dest type.
220-
Elements.resize(SrcSTy->getNumElements());
221-
for (unsigned I = 0, E = Elements.size(); I != E; ++I)
222-
Elements[I] = get(SrcSTy->getElementType(I));
223-
224-
if (auto E = DstSTy->setBodyOrError(Elements, SrcSTy->isPacked()))
225-
return E;
226-
DstStructTypesSet.switchToNonOpaque(DstSTy);
145+
if (auto *STy = dyn_cast<StructType>(SrcTy)) {
146+
// We clear name of SrcTy to lower amount of renaming in LLVM context.
147+
// Renaming occurs because we load all source modules to the same context
148+
// and declaration with existing name gets renamed (i.e Foo -> Foo.42).
149+
// As a result we may get several different types in the destination
150+
// module, which are in fact the same.
151+
if (STy->hasName())
152+
STy->setName("");
227153
}
228-
SrcDefinitionsToResolve.clear();
229-
DstResolvedOpaqueTypes.clear();
230-
return Error::success();
154+
155+
return true;
231156
}
232157

233158
Type *TypeMapTy::get(Type *Ty) {
@@ -845,10 +770,6 @@ void IRLinker::computeTypeMapping() {
845770
if (TypeMap.DstStructTypesSet.hasType(DST))
846771
TypeMap.addTypeMapping(DST, ST);
847772
}
848-
849-
// Now that we have discovered all of the type equivalences, get a body for
850-
// any 'opaque' types in the dest module that are now resolved.
851-
setError(TypeMap.linkDefinedTypeBodies());
852773
}
853774

854775
static void getArrayElements(const Constant *C,

llvm/test/Linker/opaque.ll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
; RUN: llvm-link %p/opaque.ll %p/Inputs/opaque.ll -S -o - | FileCheck %s
22

3-
; CHECK-DAG: %A = type {}
3+
; CHECK-DAG: %A = type opaque
4+
; CHECK-DAG: %A.0 = type {}
45
; CHECK-DAG: %B = type { %C, %C, ptr }
56
; CHECK-DAG: %B.1 = type { %D, %E, ptr }
67
; CHECK-DAG: %C = type { %A }
78
; CHECK-DAG: %D = type { %E }
89
; CHECK-DAG: %E = type opaque
910

1011
; CHECK-DAG: @g1 = external global %B
11-
; CHECK-DAG: @g2 = external global %A
12+
; CHECK-DAG: @g2 = external global %A.0
1213
; CHECK-DAG: @g3 = external global %B.1
1314

14-
; CHECK-DAG: getelementptr %A, ptr null, i32 0
15+
; CHECK-DAG: getelementptr %A.0, ptr null, i32 0
1516

1617
%A = type opaque
1718
%B = type { %C, %C, ptr }

llvm/test/Linker/pr22807.ll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
; RUN: not llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807.ll 2>&1 | FileCheck %s
1+
; RUN: llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807.ll 2>&1 | FileCheck %s
22

3-
; CHECK: error: identified structure type 'struct.A' is recursive
3+
; CHECK: %struct.B = type { %struct.A }
4+
; CHECK: %struct.A = type opaque
5+
; CHECK: @g = external global %struct.B
46

57
%struct.B = type { %struct.A }
68
%struct.A = type opaque

llvm/test/Linker/type-unique-dst-types.ll

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,17 @@
22
; RUN: %p/Inputs/type-unique-dst-types2.ll \
33
; RUN: %p/Inputs/type-unique-dst-types3.ll -S -o %t1.ll
44
; RUN: cat %t1.ll | FileCheck %s
5-
; RUN: cat %t1.ll | FileCheck --check-prefix=RENAMED %s
65

7-
; This tests the importance of keeping track of which types are part of the
8-
; destination module.
9-
; When the second input is merged in, the context gets an unused A.11. When
10-
; the third module is then merged, we should pretend it doesn't exist.
6+
; The types of @g1 and @g3 can be deduplicated, but @g2 should retain its
7+
; opaque type, even if it has the same name as a type from a different module.
118

129
; CHECK: %A = type { %B }
1310
; CHECK-NEXT: %B = type { i8 }
11+
; CHECK-NEXT: %A.11 = type opaque
1412

1513
; CHECK: @g3 = external global %A
1614
; CHECK: @g1 = external global %A
17-
; CHECK: @g2 = external global %A
18-
19-
; RENAMED-NOT: A.11
15+
; CHECK: @g2 = external global %A.11
2016

2117
%A = type { %B }
2218
%B = type { i8 }

0 commit comments

Comments
 (0)