https://github.com/adams381 updated https://github.com/llvm/llvm-project/pull/205605
>From f3c0ecd1d616c006e081bc74a057c594c5e681d4 Mon Sep 17 00:00:00 2001 From: Adam Smith <[email protected]> Date: Wed, 24 Jun 2026 10:34:38 -0700 Subject: [PATCH 1/2] [CIR] Emit _BitInt constants in memory form ConstantEmitter::emitForMemory hit errorNYI for any _BitInt constant headed to memory, so a global or constexpr initialized with a _BitInt value (e.g. `_BitInt(128) g = 1234;`) failed to compile under -fclangir even though zero-initialized _BitInt globals already worked. Unlike classic CodeGen, CIR represents a _BitInt(N) value in memory at its exact width (!cir.int<N, bitint>): there is no separate load/store type to widen to (i8 for _BitInt(7)) and no byte-array split for long _BitInt, so the value constant is already in its in-memory form and is returned unchanged. This is independent of the ConstantAggregateBuilder machinery classic uses for the byte-split case. Extends bitint.c with explicitly-initialized globals across signed and unsigned, standard and non-standard widths (including _BitInt(1) and the wide 254/257 cases), and adds bitint-init.cpp covering a namespace-scope constexpr and a function-local static constexpr. The exact-width CIR representation diverging from OGCG's widened/byte-array storage is pre-existing and already pinned by the split LLVM/OGCG check prefixes. --- clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 9 ++++--- clang/test/CIR/CodeGen/bitint-init.cpp | 25 +++++++++++++++++++ clang/test/CIR/CodeGen/bitint.c | 26 ++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 clang/test/CIR/CodeGen/bitint-init.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index 8ee29484ce64b..701a9ec22d537 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -1819,10 +1819,11 @@ mlir::Attribute ConstantEmitter::emitForMemory(CIRGenModule &cgm, cgm.errorNYI("emitForMemory: zero-extend HLSL bool vectors"); } - if (destType->isBitIntType()) { - cgm.errorNYI("emitForMemory: _BitInt type"); - } - + // CIR represents a _BitInt(N) value in memory at its exact width + // (!cir.int<N, bitint>), unlike classic CodeGen which widens to a separate + // load/store type (e.g. i8 for _BitInt(7)) or a byte array for long + // _BitInt. The value constant is therefore already in its in-memory + // representation and needs no adjustment here. return c; } diff --git a/clang/test/CIR/CodeGen/bitint-init.cpp b/clang/test/CIR/CodeGen/bitint-init.cpp new file mode 100644 index 0000000000000..2da11f4361e65 --- /dev/null +++ b/clang/test/CIR/CodeGen/bitint-init.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefixes=LLVM,LLVMCIR --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefixes=LLVM,OGCG --input-file=%t.ll %s + +constexpr signed _BitInt(128) ci128 = 1234; +const signed _BitInt(128) *pci = &ci128; + +unsigned _BitInt(17) f() { + static constexpr unsigned _BitInt(17) sl = 100; + return sl; +} + +// CIR-DAG: cir.global "private" constant internal dso_local @_ZL5ci128 = #cir.int<1234> : !s128i_bitint +// CIR-DAG: cir.global external @pci = #cir.global_view<@_ZL5ci128> : !cir.ptr<!s128i_bitint> +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ1fvE2sl = #cir.int<100> : !cir.int<u, 17, bitint> + +// LLVM-DAG: @_ZL5ci128 = internal constant i128 1234, align 8 +// LLVM-DAG: @pci = global ptr @_ZL5ci128, align 8 + +// CIR keeps the exact width; OGCG widens i17 -> i32. +// LLVMCIR-DAG: @_ZZ1fvE2sl = internal constant i17 100, align 4 +// OGCG-DAG: @_ZZ1fvE2sl = internal constant i32 100, align 4 diff --git a/clang/test/CIR/CodeGen/bitint.c b/clang/test/CIR/CodeGen/bitint.c index e84b610c171b6..094478b83271b 100644 --- a/clang/test/CIR/CodeGen/bitint.c +++ b/clang/test/CIR/CodeGen/bitint.c @@ -15,6 +15,32 @@ // CIR-DAG: !s128i = !cir.int<s, 128> // CIR-DAG: !s256i_bitint = !cir.int<s, 256, bitint> +// Explicitly-initialized _BitInt globals (emitted before the tentative +// definitions below) exercise the constant emitter's in-memory path. +signed _BitInt(128) bitint128_init = 1234; +unsigned _BitInt(17) bitint17_init = 100; +signed _BitInt(254) bitint254_init = 5; +signed _BitInt(257) bitint257_init = 7; +unsigned _BitInt(1) bitint1_init = 1; + +// CIR: cir.global external @bitint128_init = #cir.int<1234> : !s128i_bitint {alignment = 8 : i64} +// CIR: cir.global external @bitint17_init = #cir.int<100> : !cir.int<u, 17, bitint> {alignment = 4 : i64} +// CIR: cir.global external @bitint254_init = #cir.int<5> : !cir.int<s, 254, bitint> {alignment = 8 : i64} +// CIR: cir.global external @bitint257_init = #cir.int<7> : !cir.int<s, 257, bitint> {alignment = 8 : i64} +// CIR: cir.global external @bitint1_init = #cir.int<1> : !cir.int<u, 1, bitint> {alignment = 1 : i64} + +// LLVM: @bitint128_init = global i128 1234, align 8 +// LLVM: @bitint17_init = global i17 100, align 4 +// LLVM: @bitint254_init = global i254 5, align 8 +// LLVM: @bitint257_init = global i257 7, align 8 +// LLVM: @bitint1_init = global i1 true, align 1 + +// OGCG: @bitint128_init = global i128 1234, align 8 +// OGCG: @bitint17_init = global i32 100, align 4 +// OGCG: @bitint254_init = global i256 5, align 8 +// OGCG: @bitint257_init = global <{ i8, [39 x i8] }> <{ i8 7, [39 x i8] zeroinitializer }>, align 8 +// OGCG: @bitint1_init = global i8 1, align 1 + // _BitInt(128) has alignment 8 while __int128 has alignment 16. signed _BitInt(128) bitint128_var; __int128 int128_var; >From dd531523275a74ed5e92825e3c64f8778d455251 Mon Sep 17 00:00:00 2001 From: Adam Smith <[email protected]> Date: Wed, 24 Jun 2026 11:47:05 -0700 Subject: [PATCH 2/2] [CIR] Test _BitInt constant as a struct member Add a single-member struct case (`struct BI { _BitInt(128) m; }`) to bitint-init.cpp. This exercises the memory-form constant path for a _BitInt that is a record field rather than a top-level global, and pins that CIR lays it out the same as classic CodeGen (`%struct.BI { i128 5678 }`, align 8) -- so the combined LLVM prefix covers both emitters. --- clang/test/CIR/CodeGen/bitint-init.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clang/test/CIR/CodeGen/bitint-init.cpp b/clang/test/CIR/CodeGen/bitint-init.cpp index 2da11f4361e65..e8fdd89b24de9 100644 --- a/clang/test/CIR/CodeGen/bitint-init.cpp +++ b/clang/test/CIR/CodeGen/bitint-init.cpp @@ -8,6 +8,10 @@ constexpr signed _BitInt(128) ci128 = 1234; const signed _BitInt(128) *pci = &ci128; +struct BI { _BitInt(128) m; }; +constexpr BI bi = {5678}; +const BI *pbi = &bi; + unsigned _BitInt(17) f() { static constexpr unsigned _BitInt(17) sl = 100; return sl; @@ -15,10 +19,14 @@ unsigned _BitInt(17) f() { // CIR-DAG: cir.global "private" constant internal dso_local @_ZL5ci128 = #cir.int<1234> : !s128i_bitint // CIR-DAG: cir.global external @pci = #cir.global_view<@_ZL5ci128> : !cir.ptr<!s128i_bitint> +// CIR-DAG: cir.global "private" constant internal dso_local @_ZL2bi = #cir.const_record<{#cir.int<5678> : !s128i_bitint}> : !rec_BI +// CIR-DAG: cir.global external @pbi = #cir.global_view<@_ZL2bi> : !cir.ptr<!rec_BI> // CIR-DAG: cir.global "private" constant internal dso_local @_ZZ1fvE2sl = #cir.int<100> : !cir.int<u, 17, bitint> // LLVM-DAG: @_ZL5ci128 = internal constant i128 1234, align 8 // LLVM-DAG: @pci = global ptr @_ZL5ci128, align 8 +// LLVM-DAG: @_ZL2bi = internal constant %struct.BI { i128 5678 }, align 8 +// LLVM-DAG: @pbi = global ptr @_ZL2bi, align 8 // CIR keeps the exact width; OGCG widens i17 -> i32. // LLVMCIR-DAG: @_ZZ1fvE2sl = internal constant i17 100, align 4 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
