From 782f5aa19a2d3edbbb2fe894a7ac324d4c39e658 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Mon, 16 Dec 2024 15:27:48 +0800 Subject: [PATCH] [CIR] [CIRGen] Handle CIR Gen for array of unions Close https://github.com/llvm/clangir/issues/1185 The patch itself seems slightly ad-hoc. As the issue tracked by https://github.com/llvm/clangir/issues/1178, the fundamental solution may be to introduce two type systems to solve the inconsistent semantics for Union between LLVM IR and CIR. This will be great to handle other inconsistent semantics between LLVM IR and CIR if any. Back to the patch itself, although the code looks not good initially to me too. But I feel it may be a good workaround since clang/test/CIR/Lowering/union-array.c is an example for array of unions directly and clang/test/CIR/Lowering/nested-union-array.c gives an example for array of unions indirectly (array of structs which contain unions). So I feel we've already covered all the cases. And generally it should be good to use some simple and solid workaround before we introduce the formal full solution. --- clang/lib/CIR/CodeGen/CIRGenExprConst.cpp | 18 +++++++++++++++++- clang/test/CIR/Lowering/union-array.c | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/Lowering/union-array.c diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp index dbd78284349d..776d99ca75c3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp @@ -1015,6 +1015,20 @@ class ConstExprEmitter return {}; } + auto desiredType = CGM.getTypes().ConvertType(T); + bool isDesiredArrayOfUnionDirectly = [&]() { + auto desiredArrayType = dyn_cast(desiredType); + if (!desiredArrayType) + return false; + + auto elementStructType = + dyn_cast(desiredArrayType.getEltType()); + if (!elementStructType) + return false; + + return elementStructType.isUnion(); + }(); + // Emit initializer elements as MLIR attributes and check for common type. mlir::Type CommonElementType; for (unsigned i = 0; i != NumInitableElts; ++i) { @@ -1024,10 +1038,12 @@ class ConstExprEmitter return {}; if (i == 0) CommonElementType = C.getType(); + else if (isDesiredArrayOfUnionDirectly && + C.getType() != CommonElementType) + CommonElementType = nullptr; Elts.push_back(std::move(C)); } - auto desiredType = CGM.getTypes().ConvertType(T); auto typedFiller = llvm::dyn_cast_or_null(Filler); if (Filler && !typedFiller) llvm_unreachable("We shouldn't be receiving untyped attrs here"); diff --git a/clang/test/CIR/Lowering/union-array.c b/clang/test/CIR/Lowering/union-array.c new file mode 100644 index 000000000000..76ac21dda6c2 --- /dev/null +++ b/clang/test/CIR/Lowering/union-array.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -fno-clangir-call-conv-lowering %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM + +typedef struct { + char a; +} S_1; + +typedef struct { + long a, b; +} S_2; + +typedef union { + S_1 a; + S_2 b; +} U; + +void foo() { U arr[2] = {{.b = {1, 2}}, {.a = {1}}}; } + +// LLVM: store { { %struct.S_2 }, { %struct.S_1, [15 x i8] } } { { %struct.S_2 } { %struct.S_2 { i64 1, i64 2 } }, { %struct.S_1, [15 x i8] } { %struct.S_1 { i8 1 }, [15 x i8] zeroinitializer } }