Skip to content

Conversation

@andykaylor
Copy link
Contributor

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.

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Oct 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Andy Kaylor (andykaylor)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/164508.diff

2 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp (+17-2)
  • (modified) clang/test/CIR/CodeGen/struct-init.cpp (+15)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 65e6a3915f241..13bcd54ece291 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 2887e6f404ffc..ff1b06308e74e 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;
 };

Copy link
Member

@AmrDeveloper AmrDeveloper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

// 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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would love for this to have a better name :) Just a few characters even. Otherwise O overlapping_init looks a LOT like 1 word/was jarring.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn't like that either and I'm the one who wrote it! I'm not sure why I left it that way.

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.
@andykaylor andykaylor force-pushed the cir-overlapping-const branch from 6dff586 to f4a6bb7 Compare October 22, 2025 22:48
@andykaylor andykaylor merged commit e2b873a into llvm:main Oct 22, 2025
10 checks passed
@andykaylor andykaylor deleted the cir-overlapping-const branch October 22, 2025 23:32
mikolaj-pirog pushed a commit to mikolaj-pirog/llvm-project that referenced this pull request Oct 23, 2025
…4508)

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.
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
…4508)

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.
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
…4508)

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.
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
…4508)

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants