From 4e40ed63cd3d47ca3c113d88cd10f776bf71f659 Mon Sep 17 00:00:00 2001 From: Tommy McMichen Date: Wed, 6 Aug 2025 13:47:25 -0700 Subject: [PATCH 1/4] [CIR][CodeGen] Removed special handling for array of union Special handling for array of union was forcing all non-union C arrays to be emitted as CIR arrays, which differs from OG CodeGen, where some arrays are emitted as structs. --- clang/lib/CIR/CodeGen/CIRGenExprConst.cpp | 45 +------------------- clang/test/CIR/CodeGen/array-init.c | 16 +++++++ clang/test/CIR/Lowering/nested-union-array.c | 28 ------------ 3 files changed, 17 insertions(+), 72 deletions(-) delete mode 100644 clang/test/CIR/Lowering/nested-union-array.c diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp index 61a3d66fea08..168b1c61792a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp @@ -1106,48 +1106,6 @@ class ConstExprEmitter } auto desiredType = CGM.convertType(T); - // FIXME(cir): A hack to handle the emission of arrays of unions directly. - // See clang/test/CIR/CodeGen/union-array.c and - // clang/test/CIR/Lowering/nested-union-array.c for example. The root - // cause of these problems is CIR handles union differently than LLVM IR. - // So we can't fix the problem fundamentally by mocking LLVM's handling for - // unions. In LLVM, the union is basically a struct with the largest member - // of the union and consumers cast the union arbitrarily according to their - // needs. But in CIR, we tried to express union semantics properly. This is - // a fundamental difference. - // - // Concretely, for the problem here, if we're constructing the initializer - // for the array of unions, we can't even assume the type of the elements in - // the initializer are the same! It is odd that we can have an array with - // different element types. Here we just pretend it is fine by checking if - // we're constructing an array for an array of unions. If we didn't do so, - // we may meet problems during lowering to LLVM. To solve the problem, we - // may need to introduce 2 type systems for CIR: one for the CIR itself and - // one for lowering. e.g., we can compare the type of CIR during CIRGen, - // analysis and transformations without worrying the concerns here. And - // lower to LLVM IR (or anyother dialects) with the proper type. - // - // (Although the idea to make CIR's type system self contained and generate - // LLVM's - // types in later passes look fine, it has engineering level concern that - // it will make the skeleton of CIRGen to be diverged from the traditional - // CodeGen.) - // - // Besides union, there are other differences between CIR and LLVM's type - // system. e.g., LLVM's pointer types are opaque while CIR has concrete - // pointer types. - bool isDesiredArrayOfUnionDirectly = [&]() { - auto desiredArrayType = dyn_cast(desiredType); - if (!desiredArrayType) - return false; - - auto elementRecordType = - dyn_cast(desiredArrayType.getElementType()); - if (!elementRecordType) - return false; - - return elementRecordType.isUnion(); - }(); // Emit initializer elements as MLIR attributes and check for common type. mlir::Type CommonElementType; @@ -1159,8 +1117,7 @@ class ConstExprEmitter if (i == 0) CommonElementType = C.getType(); - else if (isDesiredArrayOfUnionDirectly && - C.getType() != CommonElementType) + else if (C.getType() != CommonElementType) CommonElementType = nullptr; Elts.push_back(std::move(C)); } diff --git a/clang/test/CIR/CodeGen/array-init.c b/clang/test/CIR/CodeGen/array-init.c index 12f07219999b..2ca5211dd9df 100644 --- a/clang/test/CIR/CodeGen/array-init.c +++ b/clang/test/CIR/CodeGen/array-init.c @@ -9,6 +9,22 @@ typedef struct { long b; } T; +// Test array initialization with different elements. +typedef struct { + long a0; + int a1; +} Inner; +typedef struct { + int b0; + Inner b1[1]; +} Outer; +Outer outers[2] = { + {1, {0, 1} }, + {1, {0, 0} } +}; +// CIR: cir.global{{.*}} @outers = #cir.const_record<{#cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, #cir.const_array<[#cir.const_record<{#cir.int<0> : !s64i, #cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array}> : !rec_anon_struct]> : !cir.array}> : !rec_anon_struct2, #cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, #cir.zero : !cir.array}> : !rec_anon_struct1}> : !rec_anon_struct3 {alignment = 16 : i64} +// LLVM: @outers = {{.*}}global { { i32, [4 x i8], [1 x { i64, i32, [4 x i8] }] }, { i32, [4 x i8], [1 x %struct.Inner] } } { { i32, [4 x i8], [1 x { i64, i32, [4 x i8] }] } { i32 1, [4 x i8] zeroinitializer, [1 x { i64, i32, [4 x i8] }] [{ i64, i32, [4 x i8] } { i64 0, i32 1, [4 x i8] zeroinitializer }] }, { i32, [4 x i8], [1 x %struct.Inner] } { i32 1, [4 x i8] zeroinitializer, [1 x %struct.Inner] zeroinitializer } }, align 16 + void buz(int x) { T arr[] = { {x, x}, {0, 0} }; } diff --git a/clang/test/CIR/Lowering/nested-union-array.c b/clang/test/CIR/Lowering/nested-union-array.c deleted file mode 100644 index f48f687dc2ab..000000000000 --- a/clang/test/CIR/Lowering/nested-union-array.c +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM - -struct nested -{ - union { - const char *single; - const char *const *multi; - } output; -}; -static const char * const test[] = { - "test", -}; -const struct nested data[] = -{ - { - { - .multi = test, - }, - }, - { - { - .single = "hello", - }, - }, -}; - -// LLVM: @data = constant [2 x {{.*}}] From 495d905c28a3c292e91b2e2229d912cadc630f27 Mon Sep 17 00:00:00 2001 From: Tommy McMichen Date: Thu, 7 Aug 2025 09:40:38 -0700 Subject: [PATCH 2/4] [CIR][CodeGen] Formatted checks in array-init test --- clang/test/CIR/CodeGen/array-init.c | 30 +++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/clang/test/CIR/CodeGen/array-init.c b/clang/test/CIR/CodeGen/array-init.c index 2ca5211dd9df..50444f2f39b2 100644 --- a/clang/test/CIR/CodeGen/array-init.c +++ b/clang/test/CIR/CodeGen/array-init.c @@ -22,8 +22,34 @@ Outer outers[2] = { {1, {0, 1} }, {1, {0, 0} } }; -// CIR: cir.global{{.*}} @outers = #cir.const_record<{#cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, #cir.const_array<[#cir.const_record<{#cir.int<0> : !s64i, #cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array}> : !rec_anon_struct]> : !cir.array}> : !rec_anon_struct2, #cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, #cir.zero : !cir.array}> : !rec_anon_struct1}> : !rec_anon_struct3 {alignment = 16 : i64} -// LLVM: @outers = {{.*}}global { { i32, [4 x i8], [1 x { i64, i32, [4 x i8] }] }, { i32, [4 x i8], [1 x %struct.Inner] } } { { i32, [4 x i8], [1 x { i64, i32, [4 x i8] }] } { i32 1, [4 x i8] zeroinitializer, [1 x { i64, i32, [4 x i8] }] [{ i64, i32, [4 x i8] } { i64 0, i32 1, [4 x i8] zeroinitializer }] }, { i32, [4 x i8], [1 x %struct.Inner] } { i32 1, [4 x i8] zeroinitializer, [1 x %struct.Inner] zeroinitializer } }, align 16 +// CIR: cir.global{{.*}} @outers = +// CIR-SAME: #cir.const_record<{ +// CIR-SAME: #cir.const_record<{ +// CIR-SAME: #cir.int<1> : !s32i, +// CIR-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, +// CIR-SAME: #cir.const_array<[ +// CIR-SAME: #cir.const_record<{#cir.int<0> : !s64i, +// CIR-SAME: #cir.int<1> : !s32i, +// CIR-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array +// CIR-SAME: }> : !rec_anon_struct +// CIR-SAME: ]> : !cir.array +// CIR-SAME: }> : !rec_anon_struct2, +// CIR-SAME: #cir.const_record<{#cir.int<1> : !s32i, +// CIR-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, +// CIR-SAME: #cir.zero : !cir.array +// CIR-SAME: }> : !rec_anon_struct1 +// CIR-SAME: }> : !rec_anon_struct3 +// LLVM: @outers = {{.*}}global +// LLVM-SAME: { +// LLVM-SAME: { i32, [4 x i8], [1 x { i64, i32, [4 x i8] }] }, +// LLVM-SAME: { i32, [4 x i8], [1 x %struct.Inner] } +// LLVM-SAME: } +// LLVM-SAME: { +// LLVM-SAME: { i32, [4 x i8], [1 x { i64, i32, [4 x i8] }] } +// LLVM-SAME: { i32 1, [4 x i8] zeroinitializer, [1 x { i64, i32, [4 x i8] }] [{ i64, i32, [4 x i8] } { i64 0, i32 1, [4 x i8] zeroinitializer }] }, +// LLVM-SAME: { i32, [4 x i8], [1 x %struct.Inner] } +// LLVM-SAME: { i32 1, [4 x i8] zeroinitializer, [1 x %struct.Inner] zeroinitializer } +// LLVM-SAME: } void buz(int x) { T arr[] = { {x, x}, {0, 0} }; From b8e75e8aa1d4d062c6461b7a060b977183999f77 Mon Sep 17 00:00:00 2001 From: Tommy McMichen Date: Thu, 7 Aug 2025 09:46:16 -0700 Subject: [PATCH 3/4] [CIR][Lowering] Updated nested-union-array test to remove special case handling result --- clang/test/CIR/Lowering/nested-union-array.c | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 clang/test/CIR/Lowering/nested-union-array.c diff --git a/clang/test/CIR/Lowering/nested-union-array.c b/clang/test/CIR/Lowering/nested-union-array.c new file mode 100644 index 000000000000..f48f687dc2ab --- /dev/null +++ b/clang/test/CIR/Lowering/nested-union-array.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM + +struct nested +{ + union { + const char *single; + const char *const *multi; + } output; +}; +static const char * const test[] = { + "test", +}; +const struct nested data[] = +{ + { + { + .multi = test, + }, + }, + { + { + .single = "hello", + }, + }, +}; + +// LLVM: @data = constant [2 x {{.*}}] From c060df42334fa10207b0133d971292fef3ca5fe0 Mon Sep 17 00:00:00 2001 From: Tommy McMichen Date: Thu, 7 Aug 2025 14:42:00 -0700 Subject: [PATCH 4/4] [CIR][Lowering] Fixed type in check from array to struct --- clang/test/CIR/Lowering/nested-union-array.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CIR/Lowering/nested-union-array.c b/clang/test/CIR/Lowering/nested-union-array.c index f48f687dc2ab..1cf04242d398 100644 --- a/clang/test/CIR/Lowering/nested-union-array.c +++ b/clang/test/CIR/Lowering/nested-union-array.c @@ -11,7 +11,7 @@ struct nested static const char * const test[] = { "test", }; -const struct nested data[] = +const struct nested data[] = { { { @@ -25,4 +25,4 @@ const struct nested data[] = }, }; -// LLVM: @data = constant [2 x {{.*}}] +// LLVM: @data = constant { { { ptr } }, { { ptr } } }