[clang] [CIR] Add support for recursive record layouts (PR #140811)
https://github.com/andykaylor closed https://github.com/llvm/llvm-project/pull/140811 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for recursive record layouts (PR #140811)
https://github.com/xlauko edited https://github.com/llvm/llvm-project/pull/140811 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for recursive record layouts (PR #140811)
https://github.com/xlauko approved this pull request. lgtm https://github.com/llvm/llvm-project/pull/140811 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for recursive record layouts (PR #140811)
https://github.com/erichkeane approved this pull request. Want someone else to poke at it, but nothing from my end. https://github.com/llvm/llvm-project/pull/140811 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for recursive record layouts (PR #140811)
llvmbot wrote:
@llvm/pr-subscribers-clang
Author: Andy Kaylor (andykaylor)
Changes
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/140811.diff
4 Files Affected:
- (modified) clang/include/clang/CIR/MissingFeatures.h (-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+4-2)
- (modified) clang/lib/CIR/CodeGen/CIRGenTypes.h (+2)
- (modified) clang/test/CIR/CodeGen/struct.c (+108)
``diff
diff --git a/clang/include/clang/CIR/MissingFeatures.h
b/clang/include/clang/CIR/MissingFeatures.h
index 7b33d94483d5f..3c21b8c629422 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -127,7 +127,6 @@ struct MissingFeatures {
static bool shouldReverseUnaryCondOnBoolExpr() { return false; }
// RecordType
- static bool recursiveRecordLayout() { return false; }
static bool skippedLayout() { return false; }
static bool astRecordDeclAttr() { return false; }
static bool cxxSupport() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index d4e0bdb52..17ed4a6bc7037 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -226,7 +226,7 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const
clang::RecordDecl *rd) {
// If converting this type would cause us to infinitely loop, don't do it!
if (!isSafeToConvert(rd, *this)) {
-cgm.errorNYI(rd->getSourceRange(), "recursive record layout");
+deferredRecords.push_back(rd);
return entry;
}
@@ -259,7 +259,9 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const
clang::RecordDecl *rd) {
// If we're done converting the outer-most record, then convert any deferred
// records as well.
- assert(!cir::MissingFeatures::recursiveRecordLayout());
+ if (recordsBeingLaidOut.empty())
+while (!deferredRecords.empty())
+ convertRecordDeclType(deferredRecords.pop_back_val());
return entry;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index a0f546d0a7cd6..7a4301ed38d04 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -68,6 +68,8 @@ class CIRGenTypes {
/// types will be in this set.
llvm::SmallPtrSet recordsBeingLaidOut;
+ llvm::SmallVector deferredRecords;
+
/// Heper for convertType.
mlir::Type convertFunctionTypeInternal(clang::QualType ft);
diff --git a/clang/test/CIR/CodeGen/struct.c b/clang/test/CIR/CodeGen/struct.c
index c91a14e0637c1..725b56a068488 100644
--- a/clang/test/CIR/CodeGen/struct.c
+++ b/clang/test/CIR/CodeGen/struct.c
@@ -13,16 +13,34 @@
// CIR-DAG: !rec_InnerS = !cir.record
// CIR-DAG: !rec_PackedS = !cir.record
// CIR-DAG: !rec_PackedAndPaddedS = !cir.record
+// CIR-DAG: !rec_NodeS = !cir.record>}>
+// CIR-DAG: !rec_RightS = !cir.record>}>>}>
+// CIR-DAG: !rec_LeftS = !cir.record}>
+// CIR-DAG: !rec_CycleEnd = !cir.record>}>>}>>}>
+// CIR-DAG: !rec_CycleMiddle = !cir.record}>
+// CIR-DAG: !rec_CycleStart = !cir.record}>
// LLVM-DAG: %struct.CompleteS = type { i32, i8 }
// LLVM-DAG: %struct.OuterS = type { %struct.InnerS, i32 }
// LLVM-DAG: %struct.InnerS = type { i32, i8 }
// LLVM-DAG: %struct.PackedS = type <{ i32, i8 }>
// LLVM-DAG: %struct.PackedAndPaddedS = type <{ i32, i8, i8 }>
+// LLVM-DAG: %struct.NodeS = type { ptr }
+// LLVM-DAG: %struct.LeftS = type { ptr }
+// LLVM-DAG: %struct.RightS = type { ptr }
+// LLVM-DAG: %struct.CycleStart = type { ptr }
+// LLVM-DAG: %struct.CycleMiddle = type { ptr }
+// LLVM-DAG: %struct.CycleEnd = type { ptr }
// OGCG-DAG: %struct.CompleteS = type { i32, i8 }
// OGCG-DAG: %struct.OuterS = type { %struct.InnerS, i32 }
// OGCG-DAG: %struct.InnerS = type { i32, i8 }
// OGCG-DAG: %struct.PackedS = type <{ i32, i8 }>
// OGCG-DAG: %struct.PackedAndPaddedS = type <{ i32, i8, i8 }>
+// OGCG-DAG: %struct.NodeS = type { ptr }
+// OGCG-DAG: %struct.LeftS = type { ptr }
+// OGCG-DAG: %struct.RightS = type { ptr }
+// OGCG-DAG: %struct.CycleStart = type { ptr }
+// OGCG-DAG: %struct.CycleMiddle = type { ptr }
+// OGCG-DAG: %struct.CycleEnd = type { ptr }
struct IncompleteS *p;
@@ -78,6 +96,59 @@ struct PackedAndPaddedS {
#pragma pack(pop)
+// Recursive type
+struct NodeS {
+ struct NodeS* next;
+} node;
+
+// CIR: cir.global{{.*}} @node = #cir.zero : !rec_NodeS
+// LLVM-DAG: @node = dso_local global %struct.NodeS zeroinitializer
+// OGCG-DAG: @node = global %struct.NodeS zeroinitializer
+
+// Mutually dependent types
+struct RightS;
+struct LeftS {
+ struct Right
[clang] [CIR] Add support for recursive record layouts (PR #140811)
https://github.com/andykaylor created
https://github.com/llvm/llvm-project/pull/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.
>From 3bd1bb6a71b32015d9461122cf1a8537dd6f819a Mon Sep 17 00:00:00 2001
From: Andy Kaylor
Date: Tue, 20 May 2025 14:35:01 -0700
Subject: [PATCH] [CIR] Add support for recursive record layouts
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.
---
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 6 +-
clang/lib/CIR/CodeGen/CIRGenTypes.h | 2 +
clang/test/CIR/CodeGen/struct.c | 108 ++
4 files changed, 114 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h
b/clang/include/clang/CIR/MissingFeatures.h
index 7b33d94483d5f..3c21b8c629422 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -127,7 +127,6 @@ struct MissingFeatures {
static bool shouldReverseUnaryCondOnBoolExpr() { return false; }
// RecordType
- static bool recursiveRecordLayout() { return false; }
static bool skippedLayout() { return false; }
static bool astRecordDeclAttr() { return false; }
static bool cxxSupport() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index d4e0bdb52..17ed4a6bc7037 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -226,7 +226,7 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const
clang::RecordDecl *rd) {
// If converting this type would cause us to infinitely loop, don't do it!
if (!isSafeToConvert(rd, *this)) {
-cgm.errorNYI(rd->getSourceRange(), "recursive record layout");
+deferredRecords.push_back(rd);
return entry;
}
@@ -259,7 +259,9 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const
clang::RecordDecl *rd) {
// If we're done converting the outer-most record, then convert any deferred
// records as well.
- assert(!cir::MissingFeatures::recursiveRecordLayout());
+ if (recordsBeingLaidOut.empty())
+while (!deferredRecords.empty())
+ convertRecordDeclType(deferredRecords.pop_back_val());
return entry;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index a0f546d0a7cd6..7a4301ed38d04 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -68,6 +68,8 @@ class CIRGenTypes {
/// types will be in this set.
llvm::SmallPtrSet recordsBeingLaidOut;
+ llvm::SmallVector deferredRecords;
+
/// Heper for convertType.
mlir::Type convertFunctionTypeInternal(clang::QualType ft);
diff --git a/clang/test/CIR/CodeGen/struct.c b/clang/test/CIR/CodeGen/struct.c
index c91a14e0637c1..725b56a068488 100644
--- a/clang/test/CIR/CodeGen/struct.c
+++ b/clang/test/CIR/CodeGen/struct.c
@@ -13,16 +13,34 @@
// CIR-DAG: !rec_InnerS = !cir.record
// CIR-DAG: !rec_PackedS = !cir.record
// CIR-DAG: !rec_PackedAndPaddedS = !cir.record
+// CIR-DAG: !rec_NodeS = !cir.record>}>
+// CIR-DAG: !rec_RightS = !cir.record>}>>}>
+// CIR-DAG: !rec_LeftS = !cir.record}>
+// CIR-DAG: !rec_CycleEnd = !cir.record>}>>}>>}>
+// CIR-DAG: !rec_CycleMiddle = !cir.record}>
+// CIR-DAG: !rec_CycleStart = !cir.record}>
// LLVM-DAG: %struct.CompleteS = type { i32, i8 }
// LLVM-DAG: %struct.OuterS = type { %struct.InnerS, i32 }
// LLVM-DAG: %struct.InnerS = type { i32, i8 }
// LLVM-DAG: %struct.PackedS = type <{ i32, i8 }>
// LLVM-DAG: %struct.PackedAndPaddedS = type <{ i32, i8, i8 }>
+// LLVM-DAG: %struct.NodeS = type { ptr }
+// LLVM-DAG: %struct.LeftS = type { ptr }
+// LLVM-DAG: %struct.RightS = type { ptr }
+// LLVM-DAG: %struct.CycleStart = type { ptr }
+// LLVM-DAG: %struct.CycleMiddle = type { ptr }
+// LLVM-DAG: %struct.CycleEnd = type { ptr }
// OGCG-DAG: %struct.CompleteS = type { i32, i8 }
// OGCG-DAG: %struct.OuterS = type { %struct.InnerS, i32 }
// OGCG-DAG: %struct.InnerS = type { i32, i8 }
// OGCG-DAG: %struct.PackedS = type <{ i32, i8 }>
// OGCG-DAG: %struct.PackedAndPaddedS = type <{ i32, i8, i8 }>
+// OGCG-DAG: %struct.NodeS = type { ptr }
+// OGCG-DAG: %struct.LeftS = type { ptr }
+// OGCG-DAG: %struct.RightS = type { ptr }
+// OGCG-DAG: %struct.CycleStart = type {
