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 <[email protected]> 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 0000000000000..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<union {}> + +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 <[email protected]> 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<Type> members, bool packed, bool padded) { Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const { assert(isUnion() && "Only call getLargestMember on unions"); llvm::ArrayRef<Type> 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 0000000000000..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<union padded {}> + +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/test/CIR/Lowering/empty-union.cir >From 8311330336a8dc64448db221f762e8a45f046268 Mon Sep 17 00:00:00 2001 From: mencotton <[email protected]> Date: Sat, 20 Dec 2025 01:34:38 +0900 Subject: [PATCH 3/3] fix: implement empty union support in CIRGen --- .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 12 ++++++-- clang/test/CIR/CodeGen/empty-union.c | 28 ++++++++++++++++++ clang/test/CIR/CodeGen/empty-union.cpp | 29 +++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 clang/test/CIR/CodeGen/empty-union.c create mode 100644 clang/test/CIR/CodeGen/empty-union.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index 87f23409e8e4b..a23a625eea911 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -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()) + return; + // C++ empty unions can have non-zero size/alignment, so use an integer type + // sized to the required alignment. + CharUnits requiredAlign = astRecordLayout.getAlignment(); + storageType = getUIntNType(astContext.toBits(requiredAlign)); + fieldTypes.push_back(storageType); + } if (layoutSize < getSize(storageType)) storageType = getByteArrayType(layoutSize); diff --git a/clang/test/CIR/CodeGen/empty-union.c b/clang/test/CIR/CodeGen/empty-union.c new file mode 100644 index 0000000000000..79fa029748b81 --- /dev/null +++ b/clang/test/CIR/CodeGen/empty-union.c @@ -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 + +// Empty union (no padding, size 0 in CIR) +union Empty {}; +// CIR: !rec_Empty = !cir.record<union "Empty" {}> +// LLVM: %union.Empty = type {} + +// Aligned empty union (size 0, alignment 16) +union EmptyAligned {} __attribute__((aligned(16))); +// CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" {}> +// LLVM: %union.EmptyAligned = type {} + +void useEmpty() { + union Empty e; +} +// CIR: cir.func {{.*}}@useEmpty() +// CIR: cir.alloca !rec_Empty, !cir.ptr<!rec_Empty>, ["e"] {alignment = 1 : i64} +// LLVM: define {{.*}} void @useEmpty() +// LLVM: alloca %union.Empty, i64 1, align 1 + +void useEmptyAligned() { + union EmptyAligned e; +} +// CIR: cir.func {{.*}}@useEmptyAligned() +// CIR: cir.alloca !rec_EmptyAligned, !cir.ptr<!rec_EmptyAligned>, ["e"] {alignment = 16 : i64} +// LLVM: define {{.*}} void @useEmptyAligned() +// LLVM: alloca %union.EmptyAligned, i64 1, align 16 diff --git a/clang/test/CIR/CodeGen/empty-union.cpp b/clang/test/CIR/CodeGen/empty-union.cpp new file mode 100644 index 0000000000000..030287c9782e8 --- /dev/null +++ b/clang/test/CIR/CodeGen/empty-union.cpp @@ -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 + +// Empty union (should be padded to size 1) +union Empty {}; +// CIR: ![[INT128:.*]] = !cir.int<u, 128> +// CIR: !rec_Empty = !cir.record<union "Empty" {!u8i}> +// LLVM: %union.Empty = type { i8 } + +// Aligned empty union (should have aligned integer member in CIR) +union alignas(16) EmptyAligned {}; +// CIR: !rec_EmptyAligned = !cir.record<union "EmptyAligned" {![[INT128]]}> +// LLVM: %union.EmptyAligned = type { i128 } + +void useEmpty() { + Empty e; +} +// CIR: cir.func {{.*}}@_Z8useEmptyv() +// CIR: cir.alloca !rec_Empty, !cir.ptr<!rec_Empty>, ["e"] {alignment = 1 : i64} +// LLVM: define {{.*}} void @_Z8useEmptyv() +// LLVM: alloca %union.Empty, i64 1, align 1 + +void useEmptyAligned() { + EmptyAligned e; +} +// CIR: cir.func {{.*}}@_Z15useEmptyAlignedv() +// CIR: cir.alloca !rec_EmptyAligned, !cir.ptr<!rec_EmptyAligned>, ["e"] {alignment = 16 : i64} +// LLVM: define {{.*}} void @_Z15useEmptyAlignedv() +// LLVM: alloca %union.EmptyAligned, i64 1, align 16 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
