Skip to content

Commit c43c07f

Browse files
authored
Support recursive struct in llvm-remove-addrspaces (#38573)
1 parent 4b739e7 commit c43c07f

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

src/llvm-remove-addrspaces.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,37 @@ class AddrspaceRemoveTypeRemapper : public ValueMapTypeRemapper {
5555
remapType(Ty->getReturnType()), Params, Ty->isVarArg());
5656
}
5757
else if (auto Ty = dyn_cast<StructType>(SrcTy)) {
58-
if (!Ty->isOpaque()) {
59-
auto Els = Ty->getNumElements();
60-
SmallVector<Type *, 4> NewElTys(Els);
61-
for (unsigned i = 0; i < Els; ++i)
62-
NewElTys[i] = remapType(Ty->getElementType(i));
58+
if (Ty->isLiteral()) {
59+
// Since a literal type has to have the body when it is created,
60+
// we need to remap the element types first. This is safe only
61+
// for literal types (i.e., no self-reference) and thus treated
62+
// separately.
63+
assert(!Ty->hasName()); // literal type has no name.
64+
SmallVector<Type *, 4> NewElTys;
65+
NewElTys.reserve(Ty->getNumElements());
66+
for (auto E: Ty->elements())
67+
NewElTys.push_back(remapType(E));
68+
DstTy = StructType::get(Ty->getContext(), NewElTys, Ty->isPacked());
69+
} else if (!Ty->isOpaque()) {
70+
// If the struct type is not literal and not opaque, it can have
71+
// self-referential fields (i.e., pointer type of itself as a
72+
// field).
73+
StructType *DstTy_ = StructType::create(Ty->getContext());
6374
if (Ty->hasName()) {
6475
auto Name = std::string(Ty->getName());
6576
Ty->setName(Name + ".bad");
66-
DstTy = StructType::create(
67-
Ty->getContext(), NewElTys, Name, Ty->isPacked());
77+
DstTy_->setName(Name);
6878
}
69-
else
70-
DstTy = StructType::get(
71-
Ty->getContext(), NewElTys, Ty->isPacked());
79+
// To avoid infinite recursion, shove the placeholder of the DstTy before
80+
// recursing into the element types:
81+
MappedTypes[SrcTy] = DstTy_;
82+
83+
auto Els = Ty->getNumElements();
84+
SmallVector<Type *, 4> NewElTys(Els);
85+
for (unsigned i = 0; i < Els; ++i)
86+
NewElTys[i] = remapType(Ty->getElementType(i));
87+
DstTy_->setBody(NewElTys, Ty->isPacked());
88+
DstTy = DstTy_;
7289
}
7390
}
7491
else if (auto Ty = dyn_cast<ArrayType>(SrcTy))

test/llvmpasses/remove-addrspaces.ll

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,63 @@ top:
4141
store i64 %0, i64 addrspace(13)* %4, align 8
4242
ret {} addrspace(10)* %1
4343
}
44+
45+
; COM: A type used for testing that remove-addrspaces can handle recursive types.
46+
%list = type { i64, %list* }
47+
48+
; COM: There's nothing to remove in this function; but remove-addrspaces shouldn't crash.
49+
define i64 @sum.linked.list() #0 {
50+
; CHECK-LABEL: @sum.linked.list
51+
top:
52+
%a = alloca %list
53+
%b = alloca %list
54+
%c = alloca %list
55+
%a.car = getelementptr %list, %list* %a, i32 0, i32 0
56+
%a.cdr = getelementptr %list, %list* %a, i32 0, i32 1
57+
%b.car = getelementptr %list, %list* %b, i32 0, i32 0
58+
%b.cdr = getelementptr %list, %list* %b, i32 0, i32 1
59+
%c.car = getelementptr %list, %list* %c, i32 0, i32 0
60+
%c.cdr = getelementptr %list, %list* %c, i32 0, i32 1
61+
; COM: Allow remove-addrspaces to rename the type but expect it to use the same prefix.
62+
; CHECK: getelementptr %list
63+
; CHECK-SAME: %list
64+
; CHECK-SAME: * %a
65+
; CHECK: getelementptr %list
66+
; CHECK-SAME: %list
67+
; CHECK-SAME: * %a
68+
; CHECK: getelementptr %list
69+
; CHECK-SAME: %list
70+
; CHECK-SAME: * %b
71+
; CHECK: getelementptr %list
72+
; CHECK-SAME: %list
73+
; CHECK-SAME: * %b
74+
; CHECK: getelementptr %list
75+
; CHECK-SAME: %list
76+
; CHECK-SAME: * %c
77+
; CHECK: getelementptr %list
78+
; CHECK-SAME: %list
79+
; CHECK-SAME: * %c
80+
store i64 111, i64* %a.car
81+
store i64 222, i64* %b.car
82+
store i64 333, i64* %c.car
83+
store %list* %b, %list** %a.cdr
84+
store %list* %c, %list** %b.cdr
85+
store %list* null, %list** %c.cdr
86+
br label %loop
87+
88+
loop:
89+
%x = phi %list* [ %a, %top ], [ %x.cdr.value, %loop ]
90+
%sum.prev = phi i64 [ 0, %top ], [ %sum, %loop ]
91+
%x.car = getelementptr %list, %list* %x, i32 0, i32 0
92+
%x.cdr = getelementptr %list, %list* %x, i32 0, i32 1
93+
%x.car.value = load i64, i64* %x.car
94+
%x.cdr.value = load %list*, %list** %x.cdr
95+
%sum = add i64 %sum.prev, %x.car.value
96+
%null.int = ptrtoint %list* null to i64
97+
%x.cdr.value.int = ptrtoint %list* %x.cdr.value to i64
98+
%cond = icmp eq i64 %x.cdr.value.int, %null.int
99+
br i1 %cond, label %exit, label %loop
100+
101+
exit:
102+
ret i64 %sum
103+
}

0 commit comments

Comments
 (0)