[clang] [clang] Fix array filler lowering for _BitInt arrays (PR #189954)
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 1 06:05:36 PDT 2026
https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/189954
Sometimes we use array of bytes to represent `_BitInt` types in memory. When this is the case the lowered array filler expression reaches `ConstantEmitter::emitForMemory` already with memory type which will be array of i8 instead of a single iN, so `cast<llvm::ConstantInt>` was failing within `ConstantEmitter::emitForMemory`. This patch fixes the assertion failure by not attempting any type changes if the type is right already.
Fixes https://github.com/llvm/llvm-project/issues/189643
Assisted-by: claude in FileCheck CHECK lines fixing
>From 17f96eb874d732435a581d1098b9966646e8fa31 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Wed, 1 Apr 2026 05:53:46 -0700
Subject: [PATCH] [clang] Fix array filler lowering for _BitInt arrays
Sometimes we use array of bytes to represent `_BitInt` types in memory.
When this is the case the lowered array filler expression reaches
`ConstantEmitter::emitForMemory` already with memory type which will be array
of i8 instead of a single iN, so `cast<llvm::ConstantInt>` was failing.
This patch fixes the assertion failure by not attempting any type changes if
the type is right already.
Fixes https://github.com/llvm/llvm-project/issues/189643
Assisted-by: claude in FileCkeck CHECK likes fixing
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/CodeGen/CGExprConstant.cpp | 40 ++++++++++++++++------------
clang/test/CodeGenCXX/ext-int.cpp | 30 +++++++++++++++++++++
3 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cd7f280fbb6db..e1d12bae134e5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -384,6 +384,7 @@ Bug Fixes in This Version
- Correctly diagnosing and no longer crashing when ``export module foo``
(without a semicolon) are the final tokens in a module file. (#GH187771)
- Fixed a crash in duplicate attribute checking caused by comparing constant arguments with different integer signedness. (#GH188259)
+- Fixed a crash on _BitInt(N) arrays where 129 ≤ N ≤ 192 due to incorrect array filler lowering. (#GH189643)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index d69e825e0cbd7..8c6f40a170e6f 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2032,24 +2032,30 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
}
if (destType->isBitIntType()) {
- ConstantAggregateBuilder Builder(CGM);
- llvm::Type *LoadStoreTy = CGM.getTypes().convertTypeForLoadStore(destType);
- // ptrtoint/inttoptr should not involve _BitInt in constant expressions, so
- // casting to ConstantInt is safe here.
- auto *CI = cast<llvm::ConstantInt>(C);
- llvm::Constant *Res = llvm::ConstantFoldCastOperand(
- destType->isSignedIntegerOrEnumerationType() ? llvm::Instruction::SExt
- : llvm::Instruction::ZExt,
- CI, LoadStoreTy, CGM.getDataLayout());
- if (CGM.getTypes().typeRequiresSplitIntoByteArray(destType, C->getType())) {
- // Long _BitInt has array of bytes as in-memory type.
- // So, split constant into individual bytes.
- llvm::Type *DesiredTy = CGM.getTypes().ConvertTypeForMem(destType);
- llvm::APInt Value = cast<llvm::ConstantInt>(Res)->getValue();
- Builder.addBits(Value, /*OffsetInBits=*/0, /*AllowOverwrite=*/false);
- return Builder.build(DesiredTy, /*AllowOversized*/ false);
+ llvm::Type *MemTy = CGM.getTypes().ConvertTypeForMem(destType);
+ if (C->getType() != MemTy) {
+ ConstantAggregateBuilder Builder(CGM);
+ llvm::Type *LoadStoreTy =
+ CGM.getTypes().convertTypeForLoadStore(destType);
+ // ptrtoint/inttoptr should not involve _BitInt in constant expressions,
+ // so casting to ConstantInt is safe here.
+ auto *CI = cast<llvm::ConstantInt>(C);
+ llvm::Constant *Res = llvm::ConstantFoldCastOperand(
+ destType->isSignedIntegerOrEnumerationType()
+ ? llvm::Instruction::SExt
+ : llvm::Instruction::ZExt,
+ CI, LoadStoreTy, CGM.getDataLayout());
+ if (CGM.getTypes().typeRequiresSplitIntoByteArray(destType,
+ C->getType())) {
+ // Long _BitInt has array of bytes as in-memory type.
+ // So, split constant into individual bytes.
+ llvm::Type *DesiredTy = CGM.getTypes().ConvertTypeForMem(destType);
+ llvm::APInt Value = cast<llvm::ConstantInt>(Res)->getValue();
+ Builder.addBits(Value, /*OffsetInBits=*/0, /*AllowOverwrite=*/false);
+ return Builder.build(DesiredTy, /*AllowOversized*/ false);
+ }
+ return Res;
}
- return Res;
}
return C;
diff --git a/clang/test/CodeGenCXX/ext-int.cpp b/clang/test/CodeGenCXX/ext-int.cpp
index a75b3701e36ef..a45720c53e877 100644
--- a/clang/test/CodeGenCXX/ext-int.cpp
+++ b/clang/test/CodeGenCXX/ext-int.cpp
@@ -67,6 +67,18 @@ struct HasBitIntMiddle {
};
// CHECK: %struct.HasBitIntMiddle = type { i32, i64, i32 }
+// Check array filler lowering.
+namespace gh189643 {
+_BitInt(129) arr[2] = {};
+// LIN64: {{.*}}arr{{.*}} = {{.*}}global [2 x [24 x i8]] zeroinitializer
+// LIN32: {{.*}}arr{{.*}} = {{.*}}global [2 x [20 x i8]] zeroinitializer
+// WIN: {{.*}}arr{{.*}} = {{.*}}global [2 x [24 x i8]] zeroinitializer
+_BitInt(129) arr2[10] = {1};
+// LIN64: {{.*}}arr2{{.*}} = {{.*}}global <{ <{ i8, [23 x i8] }>, [9 x <{ i8, [23 x i8] }>] }> <{ <{ i8, [23 x i8] }> <{ i8 1, [23 x i8] zeroinitializer }>, [9 x <{ i8, [23 x i8] }>] zeroinitializer }>
+// LIN32: {{.*}}arr2{{.*}} = {{.*}}global <{ <{ i8, [19 x i8] }>, [9 x <{ i8, [19 x i8] }>] }> <{ <{ i8, [19 x i8] }> <{ i8 1, [19 x i8] zeroinitializer }>, [9 x <{ i8, [19 x i8] }>] zeroinitializer }>
+// WIN: {{.*}}arr2{{.*}} = {{.*}}global <{ <{ i8, [23 x i8] }>, [9 x <{ i8, [23 x i8] }>] }> <{ <{ i8, [23 x i8] }> <{ i8 1, [23 x i8] zeroinitializer }>, [9 x <{ i8, [23 x i8] }>] zeroinitializer }>
+}
+
// Force emitting of the above structs.
void StructEmit() {
BitFieldsByte A;
@@ -618,6 +630,24 @@ void TBAATest(_BitInt(sizeof(int) * 8) ExtInt,
Other = 5;
}
+namespace gh189643 {
+void test() {
+// LIN: define{{.*}} void @_ZN8gh1896434testEv()
+// WIN: define dso_local void @"?test at gh189643@@YAXXZ"()
+_BitInt(140) arr3[2] = {};
+// LIN64: %[[ARR3:.+]] = alloca [2 x [24 x i8]], align 16
+// LIN32: %[[ARR3:.+]] = alloca [2 x [20 x i8]], align 4
+// WIN: %[[ARR3:.+]] = alloca [2 x [24 x i8]],
+_BitInt(239) arr4[10] = {1};
+// CHECK: %[[ARR4:.+]] = alloca [10 x i256],
+// LIN64: call void @llvm.memset{{.+}}(ptr align 16 %[[ARR3]], i8 0, i64 48,
+// LIN32: call void @llvm.memset{{.+}}(ptr align 4 %[[ARR3]], i8 0, i32 40,
+// WIN: call void @llvm.memset{{.+}}(ptr {{.*}} %[[ARR3]], i8 0, {{.*}} 48,
+// CHECK: call void @llvm.memset{{.+}}(ptr {{.*}} %[[ARR4]], i8 0, {{.*}} 320,
+// CHECK: store i256 1, ptr {{.*}}
+}
+}
+
// NoNewStructPathTBAA-DAG: ![[CHAR_TBAA_ROOT:.+]] = !{!"omnipotent char", ![[TBAA_ROOT:.+]], i64 0}
// NoNewStructPathTBAA-DAG: ![[TBAA_ROOT]] = !{!"Simple C++ TBAA"}
// NoNewStructPathTBAA-DAG: ![[EXTINT_TBAA]] = !{![[EXTINT_TBAA_ROOT:.+]], ![[EXTINT_TBAA_ROOT]], i64 0}
More information about the cfe-commits
mailing list