-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[CIR] Add support for parsing complete records #147403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
When complete record support was initially added, the parsing support was left incomplete. This change adds the necessary parsing.
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesWhen complete record support was initially added, the parsing support was left incomplete. This change adds the necessary parsing. Full diff: https://github.com/llvm/llvm-project/pull/147403.diff 3 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 898c26d22f6d1..2e21ce1f44d11 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -552,7 +552,7 @@ def CIR_RecordType : CIR_Type<"Record", "record", [
"bool":$padded,
"RecordKind":$kind
), [{
- return $_get($_ctxt, members, name, /*complete=*/true, packed, padded,
+ return $_get($_ctxt, members, name, /*incomplete=*/false, packed, padded,
kind);
}]>,
@@ -564,6 +564,17 @@ def CIR_RecordType : CIR_Type<"Record", "record", [
return $_get($_ctxt, /*members=*/llvm::ArrayRef<Type>{}, name,
/*incomplete=*/true, /*packed=*/false,
/*padded=*/false, kind);
+ }]>,
+
+ // Create an anonymous record type (always complete).
+ TypeBuilder<(ins
+ "llvm::ArrayRef<mlir::Type>":$members,
+ "bool":$packed,
+ "bool":$padded,
+ "RecordKind":$kind
+ ), [{
+ return $_get($_ctxt, members, mlir::StringAttr{}, /*incomplete=*/false,
+ packed, padded, kind);
}]>];
let extraClassDeclaration = [{
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index c6760cf1618cb..40da5e60a93f9 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -96,6 +96,8 @@ Type RecordType::parse(mlir::AsmParser &parser) {
FailureOr<AsmParser::CyclicParseReset> cyclicParseGuard;
const llvm::SMLoc loc = parser.getCurrentLocation();
const mlir::Location eLoc = parser.getEncodedSourceLoc(loc);
+ bool packed = false;
+ bool padded = false;
RecordKind kind;
mlir::MLIRContext *context = parser.getContext();
@@ -138,6 +140,12 @@ Type RecordType::parse(mlir::AsmParser &parser) {
}
}
+ if (parser.parseOptionalKeyword("packed").succeeded())
+ packed = true;
+
+ if (parser.parseOptionalKeyword("padded").succeeded())
+ padded = true;
+
// Parse record members or lack thereof.
bool incomplete = true;
llvm::SmallVector<mlir::Type> members;
@@ -159,8 +167,15 @@ Type RecordType::parse(mlir::AsmParser &parser) {
mlir::Type type = {};
if (name && incomplete) { // Identified & incomplete
type = getChecked(eLoc, context, name, kind);
- } else if (!incomplete) { // complete
- parser.emitError(loc, "complete records are not yet supported");
+ } else if (!name && !incomplete) { // Anonymous & complete
+ type = getChecked(eLoc, context, membersRef, packed, padded, kind);
+ } else if (!incomplete) { // Identified & complete
+ type = getChecked(eLoc, context, membersRef, name, packed, padded, kind);
+ // If the record has a self-reference, its type already exists in a
+ // incomplete state. In this case, we must complete it.
+ if (mlir::cast<RecordType>(type).isIncomplete())
+ mlir::cast<RecordType>(type).complete(membersRef, packed, padded);
+ assert(!cir::MissingFeatures::astRecordDeclAttr());
} else { // anonymous & incomplete
parser.emitError(loc, "anonymous records must be complete");
return {};
diff --git a/clang/test/CIR/IR/struct.cir b/clang/test/CIR/IR/struct.cir
index 5ff5ff7cd1f69..85f475f643ee5 100644
--- a/clang/test/CIR/IR/struct.cir
+++ b/clang/test/CIR/IR/struct.cir
@@ -1,19 +1,74 @@
// RUN: cir-opt %s | FileCheck %s
+!u8i = !cir.int<u, 8>
+!u16i = !cir.int<u, 16>
+!s32i = !cir.int<s, 32>
+!u32i = !cir.int<u, 32>
+
!rec_C = !cir.record<class "C" incomplete>
!rec_S = !cir.record<struct "S" incomplete>
!rec_U = !cir.record<union "U" incomplete>
-// CHECK: !rec_C = !cir.record<class "C" incomplete>
-// CHECK: !rec_S = !cir.record<struct "S" incomplete>
-// CHECK: !rec_U = !cir.record<union "U" incomplete>
+// CHECK-DAG: !rec_C = !cir.record<class "C" incomplete>
+// CHECK-DAG: !rec_S = !cir.record<struct "S" incomplete>
+// CHECK-DAG: !rec_U = !cir.record<union "U" incomplete>
+
+!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 5>}>
+!rec_anon_struct1 = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
+!rec_S1 = !cir.record<struct "S1" {!s32i, !s32i}>
+!rec_Sc = !cir.record<struct "Sc" {!u8i, !u16i, !u32i}>
+
+// CHECK-DAG: !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 5>}>
+// CHECK-DAG: !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
+// CHECK-DAG: !rec_S1 = !cir.record<struct "S1" {!s32i, !s32i}>
+// CHECK-DAG: !rec_Sc = !cir.record<struct "Sc" {!u8i, !u16i, !u32i}>
+
+// Packed and padded structs
+!rec_P1 = !cir.record<struct "P1" packed {!s32i, !s32i}>
+!rec_P2 = !cir.record<struct "P2" padded {!u8i, !u16i, !u32i}>
+!rec_P3 = !cir.record<struct "P3" packed padded {!u8i, !u16i, !u32i}>
+
+// CHECK-DAG: !rec_P1 = !cir.record<struct "P1" packed {!s32i, !s32i}>
+// CHECK-DAG: !rec_P2 = !cir.record<struct "P2" padded {!u8i, !u16i, !u32i}>
+// CHECK-DAG: !rec_P3 = !cir.record<struct "P3" packed padded {!u8i, !u16i, !u32i}>
-module {
- cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
- cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
- cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
-}
+// Complete a previously incomplete record
+!rec_A = !cir.record<class "A" incomplete>
+!rec_Ac = !cir.record<class "A" {!u8i, !s32i}>
+// CHECK-DAG: !rec_A = !cir.record<class "A" {!u8i, !s32i}>
+
+// Test recursive struct parsing/printing.
+!rec_Node = !cir.record<struct "Node" {!cir.ptr<!cir.record<struct "Node">>}>
+// CHECK-DAG: !cir.record<struct "Node" {!cir.ptr<!cir.record<struct "Node">>}>
+
+module {
+ cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
+ cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
+ cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
// CHECK: cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
// CHECK: cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
// CHECK: cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
+
+ // Dummy function to use types and force them to be printed.
+ cir.func @useTypes(%arg0: !rec_Node,
+ %arg1: !rec_anon_struct1,
+ %arg2: !rec_anon_struct,
+ %arg3: !rec_S1,
+ %arg4: !rec_Ac,
+ %arg5: !rec_P1,
+ %arg6: !rec_P2,
+ %arg7: !rec_P3) {
+ cir.return
+ }
+
+ cir.func @structs() {
+ %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]
+ %1 = cir.alloca !cir.ptr<!cir.record<union "U" incomplete>>, !cir.ptr<!cir.ptr<!cir.record<union "U" incomplete>>>, ["u", init]
+ cir.return
+ }
+
+// CHECK: cir.func @structs() {
+// CHECK: %0 = cir.alloca !cir.ptr<!rec_Sc>, !cir.ptr<!cir.ptr<!rec_Sc>>, ["sc", init]
+// CHECK: %1 = cir.alloca !cir.ptr<!rec_U>, !cir.ptr<!cir.ptr<!rec_U>>, ["u", init]
+}
|
Can you add to CIR_RecordType description an example with packed/padded flag? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
When complete record support was initially added, the parsing support was left incomplete. This change adds the necessary parsing.