https://github.com/phyBrackets updated https://github.com/llvm/llvm-project/pull/182442
>From 94218e0815c4552e3ff9949e752f18aeb16bdd08 Mon Sep 17 00:00:00 2001 From: Shivam Kunwar <[email protected]> Date: Fri, 20 Feb 2026 11:51:31 +0530 Subject: [PATCH 1/2] [DebugInfo] Emit DW_AT_const_value for constexpr array static members --- clang/lib/CodeGen/CGDebugInfo.cpp | 47 ++++++++++++ .../CodeGenCXX/debug-info-constexpr-array.cpp | 23 ++++++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 11 ++- .../X86/debug-info-constexpr-array.ll | 73 +++++++++++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/debug-info-constexpr-array.cpp create mode 100644 llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 5e452245ee627..951cb3d6b5b7e 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2092,6 +2092,53 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); if (Value->isFloat()) C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat()); + if (Value->isArray()) { + // Handle constexpr array constants for debug info + // We handle arrays of integer types (char, short, int, long), + // which covers the most common and useful cases. + if (const auto *ArrayTy = + CGM.getContext().getAsArrayType(Var->getType())) { + QualType ElemQTy = ArrayTy->getElementType(); + if (ElemQTy->isIntegerType()) { + unsigned ElemBitWidth = CGM.getContext().getTypeSize(ElemQTy); + unsigned NumElts = Value->getArraySize(); + unsigned NumInits = Value->getArrayInitializedElts(); + SmallVector<uint64_t, 64> Vals; + Vals.reserve(NumElts); + bool Success = true; + for (unsigned I = 0; I < NumInits && Success; ++I) { + const APValue &Elt = Value->getArrayInitializedElt(I); + if (Elt.isInt()) + Vals.push_back(Elt.getInt().getZExtValue()); + else + Success = false; + } + // Fill remaining elements with the filler value (e.g., the + // null terminator region for strings). + if (Success && NumInits < NumElts) { + const APValue &Filler = Value->getArrayFiller(); + if (Filler.isInt()) + Vals.resize(NumElts, Filler.getInt().getZExtValue()); + else + Success = false; + } + if (Success && Vals.size() == NumElts) { + if (ElemBitWidth == 8) { + SmallVector<uint8_t, 64> Bytes(Vals.begin(), Vals.end()); + C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Bytes); + } else if (ElemBitWidth == 16) { + SmallVector<uint16_t, 64> Elts(Vals.begin(), Vals.end()); + C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts); + } else if (ElemBitWidth == 32) { + SmallVector<uint32_t, 32> Elts(Vals.begin(), Vals.end()); + C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts); + } else if (ElemBitWidth == 64) { + C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Vals); + } + } + } + } + } } } diff --git a/clang/test/CodeGenCXX/debug-info-constexpr-array.cpp b/clang/test/CodeGenCXX/debug-info-constexpr-array.cpp new file mode 100644 index 0000000000000..289eb9f7e7a9c --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-constexpr-array.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm \ +// RUN: -debug-info-kind=standalone -o - %s | FileCheck %s + +struct Test { + static inline constexpr char STR[] = "Hello"; + static inline constexpr int NUMS[] = {1, 2, 3}; + static inline constexpr unsigned char BYTES[] = {0xDE, 0xAD}; +}; + +void use() { + (void)Test::STR; + (void)Test::NUMS; + (void)Test::BYTES; +} + +// "Hello\0" as [6 x i8] +// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "STR"{{.*}}extraData: [6 x i8] c"Hello\00" + +// {1, 2, 3} as [3 x i32] +// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "NUMS"{{.*}}extraData: [3 x i32] [i32 1, i32 2, i32 3] + +// {0xDE, 0xAD} as [2 x i8] +// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "BYTES"{{.*}}extraData: [2 x i8] c"\DE\AD" \ No newline at end of file diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index baffd81b4f336..d3a03429f82f4 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -2036,8 +2036,17 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { if (const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(DT->getConstant())) addConstantValue(StaticMemberDIE, CI, Ty); - if (const ConstantFP *CFP = dyn_cast_or_null<ConstantFP>(DT->getConstant())) + else if (const ConstantFP *CFP = + dyn_cast_or_null<ConstantFP>(DT->getConstant())) addConstantFPValue(StaticMemberDIE, CFP); + else if (auto *CDS = + dyn_cast_or_null<ConstantDataSequential>(DT->getConstant())) { + StringRef RawData = CDS->getRawDataValues(); + auto *Block = new (DIEValueAllocator) DIEBlock; + for (unsigned char Byte : RawData) + addUInt(*Block, dwarf::DW_FORM_data1, Byte); + addBlock(StaticMemberDIE, dwarf::DW_AT_const_value, Block); + } if (uint32_t AlignInBytes = DT->getAlignInBytes()) addUInt(StaticMemberDIE, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata, diff --git a/llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll b/llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll new file mode 100644 index 0000000000000..ef699f7e8a6c1 --- /dev/null +++ b/llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll @@ -0,0 +1,73 @@ +; RUN: llc -mtriple=x86_64-linux-gnu -filetype=obj %s -o %t.o +; RUN: llvm-dwarfdump --debug-info %t.o | FileCheck %s +; +; Reduced from clang output for: +; struct Test { +; static inline constexpr char STR[] = "Hello"; +; static inline constexpr int NUMS[] = {1, 2, 3}; +; static inline constexpr unsigned char BYTES[] = {0xDE, 0xAD}; +; }; +; void use() { (void)Test::STR; (void)Test::NUMS; (void)Test::BYTES; } + +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("Test") +; +; CHECK: DW_TAG_member +; CHECK: DW_AT_name ("STR") +; CHECK: DW_AT_const_value (<0x06> 48 65 6c 6c 6f 00 ) +; +; CHECK: DW_TAG_member +; CHECK: DW_AT_name ("NUMS") +; CHECK: DW_AT_const_value (<0x0c> 01 00 00 00 02 00 00 00 03 00 00 00 ) +; +; CHECK: DW_TAG_member +; CHECK: DW_AT_name ("BYTES") +; CHECK: DW_AT_const_value (<0x02> de ad ) + +@_ZN4Test3STRE = linkonce_odr constant [6 x i8] c"Hello\00", align 1, !dbg !0 +@_ZN4Test4NUMSE = linkonce_odr constant [3 x i32] [i32 1, i32 2, i32 3], align 4, !dbg !5 +@_ZN4Test5BYTESE = linkonce_odr constant [2 x i8] c"\DE\AD", align 1, !dbg !28 + +define dso_local void @_Z3usev() !dbg !33 { + ret void, !dbg !36 +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!30, !31} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "STR", linkageName: "_ZN4Test3STRE", scope: !2, file: !7, line: 5, type: !17, isLocal: false, isDefinition: true, declaration: !16) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.cpp", directory: "") +!4 = !{!0, !5, !28} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +!6 = distinct !DIGlobalVariable(name: "NUMS", linkageName: "_ZN4Test4NUMSE", scope: !2, file: !7, line: 6, type: !8, isLocal: false, isDefinition: true, declaration: !13) +!7 = !DIFile(filename: "test.cpp", directory: "") +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 96, elements: !11) +!9 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !10) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DISubrange(count: 3) +!13 = !DIDerivedType(tag: DW_TAG_member, name: "NUMS", scope: !14, file: !7, line: 6, baseType: !8, flags: DIFlagStaticMember, extraData: [3 x i32] [i32 1, i32 2, i32 3]) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Test", file: !7, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !15, identifier: "_ZTS4Test") +!15 = !{!16, !13, !22} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "STR", scope: !14, file: !7, line: 5, baseType: !17, flags: DIFlagStaticMember, extraData: [6 x i8] c"Hello\00") +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 48, elements: !20) +!18 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !19) +!19 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!20 = !{!21} +!21 = !DISubrange(count: 6) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "BYTES", scope: !14, file: !7, line: 7, baseType: !23, flags: DIFlagStaticMember, extraData: [2 x i8] c"\DE\AD") +!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 16, elements: !26) +!24 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !25) +!25 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!26 = !{!27} +!27 = !DISubrange(count: 2) +!28 = !DIGlobalVariableExpression(var: !29, expr: !DIExpression()) +!29 = distinct !DIGlobalVariable(name: "BYTES", linkageName: "_ZN4Test5BYTESE", scope: !2, file: !7, line: 7, type: !23, isLocal: false, isDefinition: true, declaration: !22) +!30 = !{i32 2, !"Debug Info Version", i32 3} +!31 = !{i32 1, !"wchar_size", i32 4} +!33 = distinct !DISubprogram(name: "use", linkageName: "_Z3usev", scope: !7, file: !7, line: 10, type: !34, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2) +!34 = !DISubroutineType(types: !35) +!35 = !{null} +!36 = !DILocation(line: 14, column: 1, scope: !33) \ No newline at end of file >From 5779b6ec25dade8fd548b148034c21052c12f557 Mon Sep 17 00:00:00 2001 From: Shivam Kunwar <[email protected]> Date: Mon, 23 Feb 2026 12:12:16 +0530 Subject: [PATCH 2/2] refactored based on the review comments --- clang/lib/CodeGen/CGDebugInfo.cpp | 94 +++++++++++++++++-------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 951cb3d6b5b7e..ff64117b5e727 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2094,50 +2094,58 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat()); if (Value->isArray()) { // Handle constexpr array constants for debug info - // We handle arrays of integer types (char, short, int, long), - // which covers the most common and useful cases. - if (const auto *ArrayTy = - CGM.getContext().getAsArrayType(Var->getType())) { - QualType ElemQTy = ArrayTy->getElementType(); - if (ElemQTy->isIntegerType()) { - unsigned ElemBitWidth = CGM.getContext().getTypeSize(ElemQTy); - unsigned NumElts = Value->getArraySize(); - unsigned NumInits = Value->getArrayInitializedElts(); - SmallVector<uint64_t, 64> Vals; - Vals.reserve(NumElts); - bool Success = true; - for (unsigned I = 0; I < NumInits && Success; ++I) { - const APValue &Elt = Value->getArrayInitializedElt(I); - if (Elt.isInt()) - Vals.push_back(Elt.getInt().getZExtValue()); - else - Success = false; - } - // Fill remaining elements with the filler value (e.g., the - // null terminator region for strings). - if (Success && NumInits < NumElts) { - const APValue &Filler = Value->getArrayFiller(); - if (Filler.isInt()) - Vals.resize(NumElts, Filler.getInt().getZExtValue()); - else - Success = false; - } - if (Success && Vals.size() == NumElts) { - if (ElemBitWidth == 8) { - SmallVector<uint8_t, 64> Bytes(Vals.begin(), Vals.end()); - C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Bytes); - } else if (ElemBitWidth == 16) { - SmallVector<uint16_t, 64> Elts(Vals.begin(), Vals.end()); - C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts); - } else if (ElemBitWidth == 32) { - SmallVector<uint32_t, 32> Elts(Vals.begin(), Vals.end()); - C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts); - } else if (ElemBitWidth == 64) { - C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Vals); - } - } + // We handle arrays of integer types (char, short, int, long) + // with element width up to 64 bits. + auto TryEmitArrayConstant = [&]() -> llvm::Constant * { + const auto *ArrayTy = CGM.getContext().getAsArrayType(Var->getType()); + if (!ArrayTy) + return nullptr; + + const QualType ElemQTy = ArrayTy->getElementType(); + if (!ElemQTy->isIntegerType()) + return nullptr; + + const unsigned ElemBitWidth = CGM.getContext().getTypeSize(ElemQTy); + // ConstantDataArray only supports 8/16/32/64-bit elements, and + // getZExtValue() asserts on wider types (e.g. __int128). + if (ElemBitWidth > 64) + return nullptr; + + const unsigned NumElts = Value->getArraySize(); + const unsigned NumInits = Value->getArrayInitializedElts(); + + // Preallocate with filler value, then overwrite initialized elements. + uint64_t FillVal = 0; + if (NumInits < NumElts) { + const APValue &Filler = Value->getArrayFiller(); + if (!Filler.isInt()) + return nullptr; + FillVal = Filler.getInt().getZExtValue(); } - } + + SmallVector<uint64_t, 64> Vals(NumElts, FillVal); + for (unsigned I = 0; I < NumInits; ++I) { + const APValue &Elt = Value->getArrayInitializedElt(I); + if (!Elt.isInt()) + return nullptr; + Vals[I] = Elt.getInt().getZExtValue(); + } + + if (ElemBitWidth == 8) { + SmallVector<uint8_t, 64> Bytes(Vals.begin(), Vals.end()); + return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Bytes); + } else if (ElemBitWidth == 16) { + SmallVector<uint16_t, 64> Elts(Vals.begin(), Vals.end()); + return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts); + } else if (ElemBitWidth == 32) { + SmallVector<uint32_t, 32> Elts(Vals.begin(), Vals.end()); + return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts); + } else if (ElemBitWidth == 64) { + return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Vals); + } + return nullptr; + }; + C = TryEmitArrayConstant(); } } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
