Skip to content

Commit d09984e

Browse files
authored
[CIR] Add support for parsing complete records (#147403)
When complete record support was initially added, the parsing support was left incomplete. This change adds the necessary parsing.
1 parent 1762b30 commit d09984e

File tree

3 files changed

+98
-14
lines changed

3 files changed

+98
-14
lines changed

clang/include/clang/CIR/Dialect/IR/CIRTypes.td

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -509,9 +509,12 @@ def CIR_RecordType : CIR_Type<"Record", "record", [
509509
A few examples:
510510

511511
```mlir
512-
!complete = !cir.record<struct "complete" {!cir.int<u, 8>}>
513-
!incomplete = !cir.record<struct "incomplete" incomplete>
514-
!anonymous = !cir.record<struct {!cir.int<u, 8>}>
512+
!rec_complete = !cir.record<struct "complete" {!u8i}>
513+
!rec_incomplete = !cir.record<struct "incomplete" incomplete>
514+
!anonymous_struct = !cir.record<struct {!u8i}>
515+
!rec_p1 = !cir.record<struct "p1" packed {!u8i, !u8i}>
516+
!rec_p2 = !cir.record<struct "p2" padded {!u8i, !u8i}>
517+
!rec_p3 = !cir.record<struct "p3" packed padded {!s32i, !u8i, !u8i}>
515518
```
516519

517520
Incomplete records are mutable, meaning they can be later completed with a
@@ -552,7 +555,7 @@ def CIR_RecordType : CIR_Type<"Record", "record", [
552555
"bool":$padded,
553556
"RecordKind":$kind
554557
), [{
555-
return $_get($_ctxt, members, name, /*complete=*/true, packed, padded,
558+
return $_get($_ctxt, members, name, /*incomplete=*/false, packed, padded,
556559
kind);
557560
}]>,
558561

@@ -564,6 +567,17 @@ def CIR_RecordType : CIR_Type<"Record", "record", [
564567
return $_get($_ctxt, /*members=*/llvm::ArrayRef<Type>{}, name,
565568
/*incomplete=*/true, /*packed=*/false,
566569
/*padded=*/false, kind);
570+
}]>,
571+
572+
// Create an anonymous record type (always complete).
573+
TypeBuilder<(ins
574+
"llvm::ArrayRef<mlir::Type>":$members,
575+
"bool":$packed,
576+
"bool":$padded,
577+
"RecordKind":$kind
578+
), [{
579+
return $_get($_ctxt, members, mlir::StringAttr{}, /*incomplete=*/false,
580+
packed, padded, kind);
567581
}]>];
568582

569583
let extraClassDeclaration = [{

clang/lib/CIR/Dialect/IR/CIRTypes.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ Type RecordType::parse(mlir::AsmParser &parser) {
9696
FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard;
9797
const llvm::SMLoc loc = parser.getCurrentLocation();
9898
const mlir::Location eLoc = parser.getEncodedSourceLoc(loc);
99+
bool packed = false;
100+
bool padded = false;
99101
RecordKind kind;
100102
mlir::MLIRContext *context = parser.getContext();
101103

@@ -138,6 +140,12 @@ Type RecordType::parse(mlir::AsmParser &parser) {
138140
}
139141
}
140142

143+
if (parser.parseOptionalKeyword("packed").succeeded())
144+
packed = true;
145+
146+
if (parser.parseOptionalKeyword("padded").succeeded())
147+
padded = true;
148+
141149
// Parse record members or lack thereof.
142150
bool incomplete = true;
143151
llvm::SmallVector<mlir::Type> members;
@@ -159,8 +167,15 @@ Type RecordType::parse(mlir::AsmParser &parser) {
159167
mlir::Type type = {};
160168
if (name && incomplete) { // Identified & incomplete
161169
type = getChecked(eLoc, context, name, kind);
162-
} else if (!incomplete) { // complete
163-
parser.emitError(loc, "complete records are not yet supported");
170+
} else if (!name && !incomplete) { // Anonymous & complete
171+
type = getChecked(eLoc, context, membersRef, packed, padded, kind);
172+
} else if (!incomplete) { // Identified & complete
173+
type = getChecked(eLoc, context, membersRef, name, packed, padded, kind);
174+
// If the record has a self-reference, its type already exists in a
175+
// incomplete state. In this case, we must complete it.
176+
if (mlir::cast<RecordType>(type).isIncomplete())
177+
mlir::cast<RecordType>(type).complete(membersRef, packed, padded);
178+
assert(!cir::MissingFeatures::astRecordDeclAttr());
164179
} else { // anonymous & incomplete
165180
parser.emitError(loc, "anonymous records must be complete");
166181
return {};

clang/test/CIR/IR/struct.cir

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,74 @@
11
// RUN: cir-opt %s | FileCheck %s
22

3+
!u8i = !cir.int<u, 8>
4+
!u16i = !cir.int<u, 16>
5+
!s32i = !cir.int<s, 32>
6+
!u32i = !cir.int<u, 32>
7+
38
!rec_C = !cir.record<class "C" incomplete>
49
!rec_S = !cir.record<struct "S" incomplete>
510
!rec_U = !cir.record<union "U" incomplete>
611

7-
// CHECK: !rec_C = !cir.record<class "C" incomplete>
8-
// CHECK: !rec_S = !cir.record<struct "S" incomplete>
9-
// CHECK: !rec_U = !cir.record<union "U" incomplete>
12+
// CHECK-DAG: !rec_C = !cir.record<class "C" incomplete>
13+
// CHECK-DAG: !rec_S = !cir.record<struct "S" incomplete>
14+
// CHECK-DAG: !rec_U = !cir.record<union "U" incomplete>
15+
16+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 5>}>
17+
!rec_anon_struct1 = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
18+
!rec_S1 = !cir.record<struct "S1" {!s32i, !s32i}>
19+
!rec_Sc = !cir.record<struct "Sc" {!u8i, !u16i, !u32i}>
20+
21+
// CHECK-DAG: !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 5>}>
22+
// CHECK-DAG: !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
23+
// CHECK-DAG: !rec_S1 = !cir.record<struct "S1" {!s32i, !s32i}>
24+
// CHECK-DAG: !rec_Sc = !cir.record<struct "Sc" {!u8i, !u16i, !u32i}>
25+
26+
// Packed and padded structs
27+
!rec_P1 = !cir.record<struct "P1" packed {!s32i, !s32i}>
28+
!rec_P2 = !cir.record<struct "P2" padded {!u8i, !u16i, !u32i}>
29+
!rec_P3 = !cir.record<struct "P3" packed padded {!u8i, !u16i, !u32i}>
30+
31+
// CHECK-DAG: !rec_P1 = !cir.record<struct "P1" packed {!s32i, !s32i}>
32+
// CHECK-DAG: !rec_P2 = !cir.record<struct "P2" padded {!u8i, !u16i, !u32i}>
33+
// CHECK-DAG: !rec_P3 = !cir.record<struct "P3" packed padded {!u8i, !u16i, !u32i}>
1034

11-
module {
12-
cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
13-
cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
14-
cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
15-
}
1635

36+
// Complete a previously incomplete record
37+
!rec_A = !cir.record<class "A" incomplete>
38+
!rec_Ac = !cir.record<class "A" {!u8i, !s32i}>
39+
// CHECK-DAG: !rec_A = !cir.record<class "A" {!u8i, !s32i}>
40+
41+
// Test recursive struct parsing/printing.
42+
!rec_Node = !cir.record<struct "Node" {!cir.ptr<!cir.record<struct "Node">>}>
43+
// CHECK-DAG: !cir.record<struct "Node" {!cir.ptr<!cir.record<struct "Node">>}>
44+
45+
module {
46+
cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
47+
cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
48+
cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
1749
// CHECK: cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
1850
// CHECK: cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
1951
// CHECK: cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
52+
53+
// Dummy function to use types and force them to be printed.
54+
cir.func @useTypes(%arg0: !rec_Node,
55+
%arg1: !rec_anon_struct1,
56+
%arg2: !rec_anon_struct,
57+
%arg3: !rec_S1,
58+
%arg4: !rec_Ac,
59+
%arg5: !rec_P1,
60+
%arg6: !rec_P2,
61+
%arg7: !rec_P3) {
62+
cir.return
63+
}
64+
65+
cir.func @structs() {
66+
%0 = cir.alloca !cir.ptr<!cir.record<struct "Sc" {!u8i, !u16i, !u32i}>>, !cir.ptr<!cir.ptr<!cir.record<struct "Sc" {!u8i, !u16i, !u32i}>>>, ["sc", init]
67+
%1 = cir.alloca !cir.ptr<!cir.record<union "U" incomplete>>, !cir.ptr<!cir.ptr<!cir.record<union "U" incomplete>>>, ["u", init]
68+
cir.return
69+
}
70+
71+
// CHECK: cir.func @structs() {
72+
// CHECK: %0 = cir.alloca !cir.ptr<!rec_Sc>, !cir.ptr<!cir.ptr<!rec_Sc>>, ["sc", init]
73+
// CHECK: %1 = cir.alloca !cir.ptr<!rec_U>, !cir.ptr<!cir.ptr<!rec_U>>, ["u", init]
74+
}

0 commit comments

Comments
 (0)