[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-06 Thread Akimasa Watanuki via cfe-commits

https://github.com/Men-cotton edited 
https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-06 Thread Akimasa Watanuki via cfe-commits

https://github.com/Men-cotton updated 
https://github.com/llvm/llvm-project/pull/172666

>From b19f14a588d3e5e7b47713c9081bd1b6ee2c9ba1 Mon Sep 17 00:00:00 2001
From: mencotton 
Date: Wed, 17 Dec 2025 23:03:09 +0900
Subject: [PATCH 1/6] [CIR] Handle empty unions in record lowering

---
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  2 ++
 clang/test/CIR/Lowering/union.cir   | 10 ++
 2 files changed, 12 insertions(+)
 create mode 100644 clang/test/CIR/Lowering/union.cir

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7d854997848aa..06cce00a9aca4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,6 +2969,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
   break;
 // Unions are lowered as only the largest member.
 case cir::RecordType::Union:
+  if (type.getMembers().empty())
+break;
   if (auto largestMember = type.getLargestMember(dataLayout))
 llvmMembers.push_back(
 convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/union.cir
new file mode 100644
index 0..c7bb8efccadcd
--- /dev/null
+++ b/clang/test/CIR/Lowering/union.cir
@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record
+
+module {
+  cir.func @empty_union(%u: !u_empty) {
+// CHECK-LABEL:   llvm.func @empty_union
+cir.return
+  }
+}

>From f92afec2d910b9bcd2cb5fcec2c74ac307934efa Mon Sep 17 00:00:00 2001
From: mencotton 
Date: Fri, 19 Dec 2025 23:56:32 +0900
Subject: [PATCH 2/6] fix: correct getLargestMember crash and lower padded
 empty unions

---
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp |  9 +++--
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp   |  6 +-
 clang/test/CIR/Lowering/empty-union-padded.cir| 11 +++
 .../test/CIR/Lowering/{union.cir => empty-union.cir}  |  0
 4 files changed, 23 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/Lowering/empty-union-padded.cir
 rename clang/test/CIR/Lowering/{union.cir => empty-union.cir} (100%)

diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9a37a4f4e3996..becb5696ec196 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -297,11 +297,16 @@ void RecordType::complete(ArrayRef members, bool 
packed, bool padded) {
 Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
   assert(isUnion() && "Only call getLargestMember on unions");
   llvm::ArrayRef members = getMembers();
+  if (members.empty())
+return {};
+
   // If the union is padded, we need to ignore the last member,
   // which is the padding.
+  auto endIt = getPadded() ? std::prev(members.end()) : members.end();
+  if (endIt == members.begin())
+return {};
   return *std::max_element(
-  members.begin(), getPadded() ? members.end() - 1 : members.end(),
-  [&](Type lhs, Type rhs) {
+  members.begin(), endIt, [&](Type lhs, Type rhs) {
 return dataLayout.getTypeABIAlignment(lhs) <
dataLayout.getTypeABIAlignment(rhs) ||
(dataLayout.getTypeABIAlignment(lhs) ==
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 06cce00a9aca4..ede1c656c66d9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,8 +2969,12 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
   break;
 // Unions are lowered as only the largest member.
 case cir::RecordType::Union:
-  if (type.getMembers().empty())
+  if (type.getMembers().empty()) {
+if (type.getPadded())
+  llvmMembers.push_back(
+  mlir::IntegerType::get(&converter.getContext(), 8));
 break;
+  }
   if (auto largestMember = type.getLargestMember(dataLayout))
 llvmMembers.push_back(
 convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/empty-union-padded.cir 
b/clang/test/CIR/Lowering/empty-union-padded.cir
new file mode 100644
index 0..266368a11ed36
--- /dev/null
+++ b/clang/test/CIR/Lowering/empty-union-padded.cir
@@ -0,0 +1,11 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_padded = !cir.record
+
+module {
+  cir.func @test_empty_padded_union(%arg0: !u_padded) {
+// CHECK-LABEL: llvm.func @test_empty_padded_union
+// CHECK-SAME: ({{.*}}: !llvm.struct<(i8)>)
+cir.return
+  }
+}
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/empty-union.cir
similarity index 100%
rename from clang/test/CIR/Lowering/union.cir
rename to clang/t

[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-05 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor edited 
https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-05 Thread Andy Kaylor via cfe-commits


@@ -0,0 +1,11 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s

andykaylor wrote:

I don't think the lowering tests are needed. They are sufficiently covered by 
the CodeGen tests.

https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-05 Thread Andy Kaylor via cfe-commits


@@ -811,9 +811,15 @@ void CIRRecordLowering::lowerUnion() {
 fieldTypes.push_back(fieldType);
   }
 
-  if (!storageType)
-cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
-   "No-storage Union NYI");
+  if (!storageType) {
+if (layoutSize.isZero())

andykaylor wrote:

Both classic codegen and the incubator just call 
`appendPaddingBytes(LayoutSize);` here. Why not do that? I believe the AST will 
have set the size appropriately to handle the alignment.

https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-05 Thread Andy Kaylor via cfe-commits


@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM

andykaylor wrote:

Pleaser add OGCG checks here also.

https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2026-01-05 Thread Andy Kaylor via cfe-commits


@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM

andykaylor wrote:

```suggestion
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
- | FileCheck %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | 
FileCheck %s --check-prefix=OGCG
```
Please add OGCG checks.

https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2025-12-20 Thread Akimasa Watanuki via cfe-commits

https://github.com/Men-cotton updated 
https://github.com/llvm/llvm-project/pull/172666

>From b19f14a588d3e5e7b47713c9081bd1b6ee2c9ba1 Mon Sep 17 00:00:00 2001
From: mencotton 
Date: Wed, 17 Dec 2025 23:03:09 +0900
Subject: [PATCH 1/3] [CIR] Handle empty unions in record lowering

---
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  2 ++
 clang/test/CIR/Lowering/union.cir   | 10 ++
 2 files changed, 12 insertions(+)
 create mode 100644 clang/test/CIR/Lowering/union.cir

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7d854997848aa..06cce00a9aca4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,6 +2969,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
   break;
 // Unions are lowered as only the largest member.
 case cir::RecordType::Union:
+  if (type.getMembers().empty())
+break;
   if (auto largestMember = type.getLargestMember(dataLayout))
 llvmMembers.push_back(
 convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/union.cir
new file mode 100644
index 0..c7bb8efccadcd
--- /dev/null
+++ b/clang/test/CIR/Lowering/union.cir
@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record
+
+module {
+  cir.func @empty_union(%u: !u_empty) {
+// CHECK-LABEL:   llvm.func @empty_union
+cir.return
+  }
+}

>From f92afec2d910b9bcd2cb5fcec2c74ac307934efa Mon Sep 17 00:00:00 2001
From: mencotton 
Date: Fri, 19 Dec 2025 23:56:32 +0900
Subject: [PATCH 2/3] fix: correct getLargestMember crash and lower padded
 empty unions

---
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp |  9 +++--
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp   |  6 +-
 clang/test/CIR/Lowering/empty-union-padded.cir| 11 +++
 .../test/CIR/Lowering/{union.cir => empty-union.cir}  |  0
 4 files changed, 23 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/Lowering/empty-union-padded.cir
 rename clang/test/CIR/Lowering/{union.cir => empty-union.cir} (100%)

diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9a37a4f4e3996..becb5696ec196 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -297,11 +297,16 @@ void RecordType::complete(ArrayRef members, bool 
packed, bool padded) {
 Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
   assert(isUnion() && "Only call getLargestMember on unions");
   llvm::ArrayRef members = getMembers();
+  if (members.empty())
+return {};
+
   // If the union is padded, we need to ignore the last member,
   // which is the padding.
+  auto endIt = getPadded() ? std::prev(members.end()) : members.end();
+  if (endIt == members.begin())
+return {};
   return *std::max_element(
-  members.begin(), getPadded() ? members.end() - 1 : members.end(),
-  [&](Type lhs, Type rhs) {
+  members.begin(), endIt, [&](Type lhs, Type rhs) {
 return dataLayout.getTypeABIAlignment(lhs) <
dataLayout.getTypeABIAlignment(rhs) ||
(dataLayout.getTypeABIAlignment(lhs) ==
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 06cce00a9aca4..ede1c656c66d9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,8 +2969,12 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
   break;
 // Unions are lowered as only the largest member.
 case cir::RecordType::Union:
-  if (type.getMembers().empty())
+  if (type.getMembers().empty()) {
+if (type.getPadded())
+  llvmMembers.push_back(
+  mlir::IntegerType::get(&converter.getContext(), 8));
 break;
+  }
   if (auto largestMember = type.getLargestMember(dataLayout))
 llvmMembers.push_back(
 convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/empty-union-padded.cir 
b/clang/test/CIR/Lowering/empty-union-padded.cir
new file mode 100644
index 0..266368a11ed36
--- /dev/null
+++ b/clang/test/CIR/Lowering/empty-union-padded.cir
@@ -0,0 +1,11 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_padded = !cir.record
+
+module {
+  cir.func @test_empty_padded_union(%arg0: !u_padded) {
+// CHECK-LABEL: llvm.func @test_empty_padded_union
+// CHECK-SAME: ({{.*}}: !llvm.struct<(i8)>)
+cir.return
+  }
+}
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/empty-union.cir
similarity index 100%
rename from clang/test/CIR/Lowering/union.cir
rename to clang/t

[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2025-12-17 Thread Andy Kaylor via cfe-commits


@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record

andykaylor wrote:

Let me amend what I said above. I didn't realize the classic codegen I was 
referring to was using the Windows C ABI. Classic codegen does generate 
`%union.U = type {}` for C and `%union.U = type { i8 }` for C++ (which the 
incubator also does).

So, I guess my question is whether we identify these padded forms as "empty".

https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2025-12-17 Thread Andy Kaylor via cfe-commits


@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record

andykaylor wrote:

Can you add a check for the LLVM IR type here? I think we're probably 
generating the wrong thing. In the incubator, we generate this:

`%union.U = type {}`

Whereas classic codegen generates this:

`%union.U = type { [4 x i8] }`


https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2025-12-17 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Akimasa Watanuki (Men-cotton)


Changes

Handles empty unions (`cir.record`) by generating empty LLVM 
structs. This ensures successful lowering without triggering crashes in 
`getLargestMember` due to missing members.

Added regression test in `clang/test/CIR/Lowering/union.cir`.

---
Full diff: https://github.com/llvm/llvm-project/pull/172666.diff


2 Files Affected:

- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+2) 
- (added) clang/test/CIR/Lowering/union.cir (+10) 


``diff
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7d854997848aa..06cce00a9aca4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,6 +2969,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
   break;
 // Unions are lowered as only the largest member.
 case cir::RecordType::Union:
+  if (type.getMembers().empty())
+break;
   if (auto largestMember = type.getLargestMember(dataLayout))
 llvmMembers.push_back(
 convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/union.cir
new file mode 100644
index 0..c7bb8efccadcd
--- /dev/null
+++ b/clang/test/CIR/Lowering/union.cir
@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record
+
+module {
+  cir.func @empty_union(%u: !u_empty) {
+// CHECK-LABEL:   llvm.func @empty_union
+cir.return
+  }
+}

``




https://github.com/llvm/llvm-project/pull/172666
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Handle empty unions in record lowering (PR #172666)

2025-12-17 Thread Akimasa Watanuki via cfe-commits

https://github.com/Men-cotton created 
https://github.com/llvm/llvm-project/pull/172666

Handles empty unions (`cir.record`) by generating empty LLVM structs. 
This ensures successful lowering without triggering crashes in 
`getLargestMember` due to missing members.

Added regression test in `clang/test/CIR/Lowering/union.cir`.

>From b19f14a588d3e5e7b47713c9081bd1b6ee2c9ba1 Mon Sep 17 00:00:00 2001
From: mencotton 
Date: Wed, 17 Dec 2025 23:03:09 +0900
Subject: [PATCH] [CIR] Handle empty unions in record lowering

---
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  2 ++
 clang/test/CIR/Lowering/union.cir   | 10 ++
 2 files changed, 12 insertions(+)
 create mode 100644 clang/test/CIR/Lowering/union.cir

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7d854997848aa..06cce00a9aca4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2969,6 +2969,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
   break;
 // Unions are lowered as only the largest member.
 case cir::RecordType::Union:
+  if (type.getMembers().empty())
+break;
   if (auto largestMember = type.getLargestMember(dataLayout))
 llvmMembers.push_back(
 convertTypeForMemory(converter, dataLayout, largestMember));
diff --git a/clang/test/CIR/Lowering/union.cir 
b/clang/test/CIR/Lowering/union.cir
new file mode 100644
index 0..c7bb8efccadcd
--- /dev/null
+++ b/clang/test/CIR/Lowering/union.cir
@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --cir-to-llvm | FileCheck %s
+
+!u_empty = !cir.record
+
+module {
+  cir.func @empty_union(%u: !u_empty) {
+// CHECK-LABEL:   llvm.func @empty_union
+cir.return
+  }
+}

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits