Skip to content

Commit fc9898c

Browse files
authored
[CIR] Add support for recursive record layouts (#140811)
While processing members of a record, we try to create new record types as we encounter them, but if this would result in recursion (either because the type points to itself or because it points to a type that points back to the original type) we need to add it to a list for deferred processing. Previously, we issued an error saying this wasn't handled. This change adds the necessary handling.
1 parent 09c266b commit fc9898c

File tree

4 files changed

+114
-3
lines changed

4 files changed

+114
-3
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ struct MissingFeatures {
127127
static bool shouldReverseUnaryCondOnBoolExpr() { return false; }
128128

129129
// RecordType
130-
static bool recursiveRecordLayout() { return false; }
131130
static bool skippedLayout() { return false; }
132131
static bool astRecordDeclAttr() { return false; }
133132
static bool cxxSupport() { return false; }

clang/lib/CIR/CodeGen/CIRGenTypes.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) {
226226

227227
// If converting this type would cause us to infinitely loop, don't do it!
228228
if (!isSafeToConvert(rd, *this)) {
229-
cgm.errorNYI(rd->getSourceRange(), "recursive record layout");
229+
deferredRecords.push_back(rd);
230230
return entry;
231231
}
232232

@@ -259,7 +259,9 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) {
259259

260260
// If we're done converting the outer-most record, then convert any deferred
261261
// records as well.
262-
assert(!cir::MissingFeatures::recursiveRecordLayout());
262+
if (recordsBeingLaidOut.empty())
263+
while (!deferredRecords.empty())
264+
convertRecordDeclType(deferredRecords.pop_back_val());
263265

264266
return entry;
265267
}

clang/lib/CIR/CodeGen/CIRGenTypes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class CIRGenTypes {
6868
/// types will be in this set.
6969
llvm::SmallPtrSet<const clang::Type *, 4> recordsBeingLaidOut;
7070

71+
llvm::SmallVector<const clang::RecordDecl *, 8> deferredRecords;
72+
7173
/// Heper for convertType.
7274
mlir::Type convertFunctionTypeInternal(clang::QualType ft);
7375

clang/test/CIR/CodeGen/struct.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,34 @@
1313
// CIR-DAG: !rec_InnerS = !cir.record<struct "InnerS" {!s32i, !s8i}>
1414
// CIR-DAG: !rec_PackedS = !cir.record<struct "PackedS" packed {!s32i, !s8i}>
1515
// CIR-DAG: !rec_PackedAndPaddedS = !cir.record<struct "PackedAndPaddedS" packed padded {!s32i, !s8i, !u8i}>
16+
// CIR-DAG: !rec_NodeS = !cir.record<struct "NodeS" {!cir.ptr<!cir.record<struct "NodeS">>}>
17+
// CIR-DAG: !rec_RightS = !cir.record<struct "RightS" {!cir.ptr<!cir.record<struct "LeftS" {!cir.ptr<!cir.record<struct "RightS">>}>>}>
18+
// CIR-DAG: !rec_LeftS = !cir.record<struct "LeftS" {!cir.ptr<!rec_RightS>}>
19+
// CIR-DAG: !rec_CycleEnd = !cir.record<struct "CycleEnd" {!cir.ptr<!cir.record<struct "CycleStart" {!cir.ptr<!cir.record<struct "CycleMiddle" {!cir.ptr<!cir.record<struct "CycleEnd">>}>>}>>}>
20+
// CIR-DAG: !rec_CycleMiddle = !cir.record<struct "CycleMiddle" {!cir.ptr<!rec_CycleEnd>}>
21+
// CIR-DAG: !rec_CycleStart = !cir.record<struct "CycleStart" {!cir.ptr<!rec_CycleMiddle>}>
1622
// LLVM-DAG: %struct.CompleteS = type { i32, i8 }
1723
// LLVM-DAG: %struct.OuterS = type { %struct.InnerS, i32 }
1824
// LLVM-DAG: %struct.InnerS = type { i32, i8 }
1925
// LLVM-DAG: %struct.PackedS = type <{ i32, i8 }>
2026
// LLVM-DAG: %struct.PackedAndPaddedS = type <{ i32, i8, i8 }>
27+
// LLVM-DAG: %struct.NodeS = type { ptr }
28+
// LLVM-DAG: %struct.LeftS = type { ptr }
29+
// LLVM-DAG: %struct.RightS = type { ptr }
30+
// LLVM-DAG: %struct.CycleStart = type { ptr }
31+
// LLVM-DAG: %struct.CycleMiddle = type { ptr }
32+
// LLVM-DAG: %struct.CycleEnd = type { ptr }
2133
// OGCG-DAG: %struct.CompleteS = type { i32, i8 }
2234
// OGCG-DAG: %struct.OuterS = type { %struct.InnerS, i32 }
2335
// OGCG-DAG: %struct.InnerS = type { i32, i8 }
2436
// OGCG-DAG: %struct.PackedS = type <{ i32, i8 }>
2537
// OGCG-DAG: %struct.PackedAndPaddedS = type <{ i32, i8, i8 }>
38+
// OGCG-DAG: %struct.NodeS = type { ptr }
39+
// OGCG-DAG: %struct.LeftS = type { ptr }
40+
// OGCG-DAG: %struct.RightS = type { ptr }
41+
// OGCG-DAG: %struct.CycleStart = type { ptr }
42+
// OGCG-DAG: %struct.CycleMiddle = type { ptr }
43+
// OGCG-DAG: %struct.CycleEnd = type { ptr }
2644

2745
struct IncompleteS *p;
2846

@@ -78,6 +96,59 @@ struct PackedAndPaddedS {
7896

7997
#pragma pack(pop)
8098

99+
// Recursive type
100+
struct NodeS {
101+
struct NodeS* next;
102+
} node;
103+
104+
// CIR: cir.global{{.*}} @node = #cir.zero : !rec_NodeS
105+
// LLVM-DAG: @node = dso_local global %struct.NodeS zeroinitializer
106+
// OGCG-DAG: @node = global %struct.NodeS zeroinitializer
107+
108+
// Mutually dependent types
109+
struct RightS;
110+
struct LeftS {
111+
struct RightS* right;
112+
} ls;
113+
114+
// CIR: cir.global{{.*}} @ls = #cir.zero : !rec_LeftS
115+
// LLVM-DAG: @ls = dso_local global %struct.LeftS zeroinitializer
116+
// OGCG-DAG: @ls = global %struct.LeftS zeroinitializer
117+
118+
struct RightS {
119+
struct LeftS* left;
120+
} rs;
121+
122+
// CIR: cir.global{{.*}} @rs = #cir.zero : !rec_RightS
123+
// LLVM-DAG: @rs = dso_local global %struct.RightS zeroinitializer
124+
// OGCG-DAG: @rs = global %struct.RightS zeroinitializer
125+
126+
struct CycleMiddle;
127+
struct CycleEnd;
128+
struct CycleStart {
129+
struct CycleMiddle* middle;
130+
} start;
131+
132+
// CIR: cir.global{{.*}} @start = #cir.zero : !rec_CycleStart
133+
// LLVM-DAG: @start = dso_local global %struct.CycleStart zeroinitializer
134+
// OGCG-DAG: @start = global %struct.CycleStart zeroinitializer
135+
136+
struct CycleMiddle {
137+
struct CycleEnd* end;
138+
} middle;
139+
140+
// CIR: cir.global{{.*}} @middle = #cir.zero : !rec_CycleMiddle
141+
// LLVM-DAG: @middle = dso_local global %struct.CycleMiddle zeroinitializer
142+
// OGCG-DAG: @middle = global %struct.CycleMiddle zeroinitializer
143+
144+
struct CycleEnd {
145+
struct CycleStart* start;
146+
} end;
147+
148+
// CIR: cir.global{{.*}} @end = #cir.zero : !rec_CycleEnd
149+
// LLVM-DAG: @end = dso_local global %struct.CycleEnd zeroinitializer
150+
// OGCG-DAG: @end = global %struct.CycleEnd zeroinitializer
151+
81152
void f(void) {
82153
struct IncompleteS *p;
83154
}
@@ -205,3 +276,40 @@ char f4(int a, struct CompleteS *p) {
205276
// OGCG-NEXT: %[[P_B:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[P2]], i32 0, i32 1
206277
// OGCG-NEXT: %[[P_B_VAL:.*]] = load i8, ptr %[[P_B]], align 4
207278
// OGCG-NEXT: ret i8 %[[P_B_VAL]]
279+
280+
void f5(struct NodeS* a) {
281+
a->next = 0;
282+
}
283+
284+
// CIR: cir.func @f5
285+
// CIR: %[[NEXT:.*]] = cir.get_member {{%.}}[0] {name = "next"} : !cir.ptr<!rec_NodeS> -> !cir.ptr<!cir.ptr<!rec_NodeS>>
286+
// CIR: cir.store {{.*}}, %[[NEXT]]
287+
288+
// LLVM: define{{.*}} void @f5
289+
// LLVM: %[[NEXT:.*]] = getelementptr %struct.NodeS, ptr %{{.*}}, i32 0, i32 0
290+
// LLVM: store ptr null, ptr %[[NEXT]]
291+
292+
// OGCG: define{{.*}} void @f5
293+
// OGCG: %[[NEXT:.*]] = getelementptr inbounds nuw %struct.NodeS, ptr %{{.*}}, i32 0, i32 0
294+
// OGCG: store ptr null, ptr %[[NEXT]]
295+
296+
void f6(struct CycleStart *start) {
297+
struct CycleMiddle *middle = start->middle;
298+
struct CycleEnd *end = middle->end;
299+
struct CycleStart *start2 = end->start;
300+
}
301+
302+
// CIR: cir.func @f6
303+
// CIR: %[[MIDDLE:.*]] = cir.get_member {{.*}}[0] {name = "middle"} : !cir.ptr<!rec_CycleStart> -> !cir.ptr<!cir.ptr<!rec_CycleMiddle>>
304+
// CIR: %[[END:.*]] = cir.get_member %{{.*}}[0] {name = "end"} : !cir.ptr<!rec_CycleMiddle> -> !cir.ptr<!cir.ptr<!rec_CycleEnd>>
305+
// CIR: %[[START2:.*]] = cir.get_member %{{.*}}[0] {name = "start"} : !cir.ptr<!rec_CycleEnd> -> !cir.ptr<!cir.ptr<!rec_CycleStart>>
306+
307+
// LLVM: define{{.*}} void @f6
308+
// LLVM: %[[MIDDLE:.*]] = getelementptr %struct.CycleStart, ptr %{{.*}}, i32 0, i32 0
309+
// LLVM: %[[END:.*]] = getelementptr %struct.CycleMiddle, ptr %{{.*}}, i32 0, i32 0
310+
// LLVM: %[[START2:.*]] = getelementptr %struct.CycleEnd, ptr %{{.*}}, i32 0, i32 0
311+
312+
// OGCG: define{{.*}} void @f6
313+
// OGCG: %[[MIDDLE:.*]] = getelementptr inbounds nuw %struct.CycleStart, ptr %{{.*}}, i32 0, i32 0
314+
// OGCG: %[[END:.*]] = getelementptr inbounds nuw %struct.CycleMiddle, ptr %{{.*}}, i32 0, i32 0
315+
// OGCG: %[[START2:.*]] = getelementptr inbounds nuw %struct.CycleEnd, ptr %{{.*}}, i32 0, i32 0

0 commit comments

Comments
 (0)