[clang] [CIR] Handle overlapping values in constant init expressions (PR #164508)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 22 15:48:33 PDT 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/164508
>From 08353a39097576500fa3516b121c87e7711d30b7 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Tue, 21 Oct 2025 15:17:45 -0700
Subject: [PATCH 1/2] [CIR] Handle overlapping values in constant init
expressions
This adds handling for generating constant initializers in the case
where a value we are emitting overlaps with a previous constant,
such as can happen when initializing a structure with bitfields.
---
clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 19 +++++++++++++++++--
clang/test/CIR/CodeGen/struct-init.cpp | 15 +++++++++++++++
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 800262aac8fa4..8f05014811a1f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -179,8 +179,23 @@ bool ConstantAggregateBuilder::add(mlir::TypedAttr typedAttr, CharUnits offset,
}
// Uncommon case: constant overlaps what we've already created.
- cgm.errorNYI("overlapping constants");
- return false;
+ std::optional<size_t> firstElemToReplace = splitAt(offset);
+ if (!firstElemToReplace)
+ return false;
+
+ CharUnits cSize = getSize(typedAttr);
+ std::optional<size_t> lastElemToReplace = splitAt(offset + cSize);
+ if (!lastElemToReplace)
+ return false;
+
+ assert((firstElemToReplace == lastElemToReplace || allowOverwrite) &&
+ "unexpectedly overwriting field");
+
+ Element newElt(typedAttr, offset);
+ replace(elements, *firstElemToReplace, *lastElemToReplace, {newElt});
+ size = std::max(size, offset + cSize);
+ naturalLayout = false;
+ return true;
}
bool ConstantAggregateBuilder::addBits(llvm::APInt bits, uint64_t offsetInBits,
diff --git a/clang/test/CIR/CodeGen/struct-init.cpp b/clang/test/CIR/CodeGen/struct-init.cpp
index cb509994d1cbf..9d6389f5ad977 100644
--- a/clang/test/CIR/CodeGen/struct-init.cpp
+++ b/clang/test/CIR/CodeGen/struct-init.cpp
@@ -5,6 +5,21 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+struct O {
+ unsigned int a:4;
+ unsigned int b:14;
+ unsigned int c:14;
+};
+
+O overlapping_init = { 3, 2, 1 };
+
+// This is unintuitive. The bitfields are initialized using a struct of constants
+// that maps to the bitfields but splits the value into bytes.
+
+// CIR: cir.global external @overlapping_init = #cir.const_record<{#cir.int<35> : !u8i, #cir.int<0> : !u8i, #cir.int<4> : !u8i, #cir.int<0> : !u8i}> : !rec_anon_struct
+// LLVM: @overlapping_init = global { i8, i8, i8, i8 } { i8 35, i8 0, i8 4, i8 0 }
+// OGCG: @overlapping_init = global { i8, i8, i8, i8 } { i8 35, i8 0, i8 4, i8 0 }
+
struct S {
int a, b, c;
};
>From f4a6bb74a767df0dd51177d75d214d8b7e0fdf28 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 22 Oct 2025 14:02:25 -0700
Subject: [PATCH 2/2] Rename test struct
---
clang/test/CIR/CodeGen/struct-init.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CIR/CodeGen/struct-init.cpp b/clang/test/CIR/CodeGen/struct-init.cpp
index 9d6389f5ad977..63e13dd708392 100644
--- a/clang/test/CIR/CodeGen/struct-init.cpp
+++ b/clang/test/CIR/CodeGen/struct-init.cpp
@@ -5,13 +5,13 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
-struct O {
+struct BitfieldStruct {
unsigned int a:4;
unsigned int b:14;
unsigned int c:14;
};
-O overlapping_init = { 3, 2, 1 };
+BitfieldStruct overlapping_init = { 3, 2, 1 };
// This is unintuitive. The bitfields are initialized using a struct of constants
// that maps to the bitfields but splits the value into bytes.
More information about the cfe-commits
mailing list