[clang] [CIR] Add support for recursive record layouts (PR #140811)

2025-05-21 Thread Andy Kaylor via cfe-commits

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)

2025-05-21 Thread Henrich Lauko via cfe-commits

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)

2025-05-21 Thread Henrich Lauko via cfe-commits

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)

2025-05-20 Thread Erich Keane via cfe-commits

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)

2025-05-20 Thread via cfe-commits

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)

2025-05-20 Thread Andy Kaylor via cfe-commits

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 {