[clang] [CIR] Handle empty unions in record lowering (PR #172666)
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)
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)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
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)
@@ -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)
@@ -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)
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)
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
