https://github.com/john-brawn-arm created https://github.com/llvm/llvm-project/pull/94632
Currently we use DW_OP_plus_uconst to handle the bitfield offset and handle the bitfield size by choosing a type size that matches, but this doesn't work if either offset or size aren't byte-aligned. Extracting the bits using DW_OP_LLVM_extract_bits means we can handle any kind of offset or size. TODO: test signed type, nonzero StorageOffset, oversized bitfield >From 7b0ac402bcebd905fd669bb6de2e39209fadda09 Mon Sep 17 00:00:00 2001 From: John Brawn <john.br...@arm.com> Date: Wed, 29 May 2024 10:38:28 +0100 Subject: [PATCH 1/5] [DebugInfo] Add DW_OP_LLVM_extract_bits This operation extracts a number of bits at a given offset and sign or zero extends them, which is done by emitting it as a left shift followed by a right shift. This is being added for use in clang for C++ structured bindings of bitfields that have offset or size that aren't a byte multiple. A new operation is being added, instead of shifts being used directly, as it makes correctly handling it in optimisations (which will be done in a later patch) much easier. --- llvm/docs/LangRef.rst | 7 ++ llvm/include/llvm/BinaryFormat/Dwarf.h | 1 + llvm/lib/BinaryFormat/Dwarf.cpp | 3 + .../CodeGen/AsmPrinter/DwarfExpression.cpp | 32 ++++++ llvm/lib/IR/AsmWriter.cpp | 4 + llvm/lib/IR/DebugInfoMetadata.cpp | 3 + .../DebugInfo/X86/DW_OP_LLVM_extract_bits.ll | 99 +++++++++++++++++++ 7 files changed, 149 insertions(+) create mode 100644 llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index c58f7f7140e47..7b4e91d09f342 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -6312,6 +6312,13 @@ The current supported opcode vocabulary is limited: (``16`` and ``DW_ATE_signed`` here, respectively) to which the top of the expression stack is to be converted. Maps into a ``DW_OP_convert`` operation that references a base type constructed from the supplied values. +- ``DW_OP_LLVM_extract_bits, 16, 8, DW_ATE_signed`` specifies the offset, size, + and encoding (``16``, ``8``, and ``DW_ATE_signed`` here, respectively) of bits + that are to be extracted from the value at the top of the expression stack. + If the top of the expression stack is a memory location then these bits are + extracted from the value pointed to by that memory location. Maps into a + ``DW_OP_shl`` followed by ``DW_OP_shr`` or ``DW_OP_shra`` (depending on + encoding). - ``DW_OP_LLVM_tag_offset, tag_offset`` specifies that a memory tag should be optionally applied to the pointer. The memory tag is derived from the given tag offset in an implementation-defined manner. diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h index 74c4d6ff3a716..7ae265484be58 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.h +++ b/llvm/include/llvm/BinaryFormat/Dwarf.h @@ -144,6 +144,7 @@ enum LocationAtom { DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata. DW_OP_LLVM_arg = 0x1005, ///< Only used in LLVM metadata. + DW_OP_LLVM_extract_bits = 0x1006, ///< Only used in LLVM metadata. }; enum LlvmUserLocationAtom { diff --git a/llvm/lib/BinaryFormat/Dwarf.cpp b/llvm/lib/BinaryFormat/Dwarf.cpp index 7324266172684..d9668dffabec6 100644 --- a/llvm/lib/BinaryFormat/Dwarf.cpp +++ b/llvm/lib/BinaryFormat/Dwarf.cpp @@ -155,6 +155,8 @@ StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) { return "DW_OP_LLVM_implicit_pointer"; case DW_OP_LLVM_arg: return "DW_OP_LLVM_arg"; + case DW_OP_LLVM_extract_bits: + return "DW_OP_LLVM_extract_bits"; } } @@ -169,6 +171,7 @@ unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) { .Case("DW_OP_LLVM_entry_value", DW_OP_LLVM_entry_value) .Case("DW_OP_LLVM_implicit_pointer", DW_OP_LLVM_implicit_pointer) .Case("DW_OP_LLVM_arg", DW_OP_LLVM_arg) + .Case("DW_OP_LLVM_extract_bits", DW_OP_LLVM_extract_bits) .Default(0); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index a74d43897d45b..87beeb7d6bc9a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -18,6 +18,7 @@ #include "llvm/CodeGen/Register.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> @@ -546,6 +547,37 @@ bool DwarfExpression::addExpression( LocationKind = Unknown; return true; } + case dwarf::DW_OP_LLVM_extract_bits: { + unsigned SizeInBits = Op->getArg(1); + unsigned BitOffset = Op->getArg(0); + dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(2)); + + // If we have a memory location then dereference to get the value + if (isMemoryLocation()) + emitOp(dwarf::DW_OP_deref); + + // Extract the bits by a shift left (to shift out the bits after what we + // want to extract) followed by shift right (to shift the bits to position + // 0 and also sign/zero extend). These operations are done in the DWARF + // "generic type" whose size is the size of a pointer. + unsigned PtrSizeInBytes = CU.getAsmPrinter()->MAI->getCodePointerSize(); + unsigned LeftShift = PtrSizeInBytes * 8 - (SizeInBits + BitOffset); + unsigned RightShift = LeftShift + BitOffset; + if (LeftShift) { + emitOp(dwarf::DW_OP_constu); + emitUnsigned(LeftShift); + emitOp(dwarf::DW_OP_shl); + } + emitOp(dwarf::DW_OP_constu); + emitUnsigned(RightShift); + emitOp(Encoding == dwarf::DW_ATE_signed ? dwarf::DW_OP_shra + : dwarf::DW_OP_shr); + + // The value is now at the top of the stack, so set the location to + // implicit so that we get a stack_value at the end. + LocationKind = Implicit; + break; + } case dwarf::DW_OP_plus_uconst: assert(!isRegisterLocation()); emitOp(dwarf::DW_OP_plus_uconst); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 8b1a21f962b08..4f5935de42bb0 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2468,6 +2468,10 @@ static void writeDIExpression(raw_ostream &Out, const DIExpression *N, if (Op.getOp() == dwarf::DW_OP_LLVM_convert) { Out << FS << Op.getArg(0); Out << FS << dwarf::AttributeEncodingString(Op.getArg(1)); + } else if (Op.getOp() == dwarf::DW_OP_LLVM_extract_bits) { + Out << FS << Op.getArg(0); + Out << FS << Op.getArg(1); + Out << FS << dwarf::AttributeEncodingString(Op.getArg(2)); } else { for (unsigned A = 0, AE = Op.getNumArgs(); A != AE; ++A) Out << FS << Op.getArg(A); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 9bd1d7880c9f8..5e69192d5c52f 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1402,6 +1402,8 @@ unsigned DIExpression::ExprOperand::getSize() const { return 2; switch (Op) { + case dwarf::DW_OP_LLVM_extract_bits: + return 4; case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_fragment: case dwarf::DW_OP_bregx: @@ -1474,6 +1476,7 @@ bool DIExpression::isValid() const { case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_arg: case dwarf::DW_OP_LLVM_tag_offset: + case dwarf::DW_OP_LLVM_extract_bits: case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: diff --git a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll new file mode 100644 index 0000000000000..da0eec669b50c --- /dev/null +++ b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll @@ -0,0 +1,99 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu %s -o %t -filetype=obj +; RUN: llvm-dwarfdump --debug-info %t | FileCheck %s + +%struct.struct_t = type { i8 } + +@g = dso_local global %struct.struct_t zeroinitializer, align 1, !dbg !0 + +; CHECK-LABEL: DW_TAG_subprogram +; CHECK: DW_AT_name ("test1") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location (DW_OP_fbreg -1, DW_OP_deref, DW_OP_constu 0x3d, DW_OP_shl, DW_OP_constu 0x3d, DW_OP_shr, DW_OP_stack_value) +; CHECK: DW_AT_name ("x") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location (DW_OP_fbreg -1, DW_OP_deref, DW_OP_constu 0x39, DW_OP_shl, DW_OP_constu 0x3c, DW_OP_shra, DW_OP_stack_value) +; CHECK: DW_AT_name ("y") + +define i32 @test1() !dbg !13 { +entry: + %0 = alloca %struct.struct_t, align 1 + tail call void @llvm.dbg.declare(metadata ptr %0, metadata !17, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !18 + tail call void @llvm.dbg.declare(metadata ptr %0, metadata !19, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !21 + ret i32 0, !dbg !22 +} + +; CHECK-LABEL: DW_TAG_subprogram +; CHECK: DW_AT_name ("test2") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x3d, DW_OP_shl, DW_OP_constu 0x3d, DW_OP_shr, DW_OP_stack_value) +; CHECK: DW_AT_name ("x") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x39, DW_OP_shl, DW_OP_constu 0x3c, DW_OP_shra, DW_OP_stack_value) +; CHECK: DW_AT_name ("y") + +define i8 @test2() !dbg !23 { +entry: + %0 = load i8, ptr @g, align 1 + tail call void @llvm.dbg.value(metadata i8 %0, metadata !24, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !25 + tail call void @llvm.dbg.value(metadata i8 %0, metadata !26, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !27 + ret i8 %0, !dbg !28 +} + +; CHECK-LABEL: DW_TAG_subprogram +; CHECK: DW_AT_name ("test3") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0x3f, DW_OP_shr, DW_OP_stack_value) +; CHECK: DW_AT_name ("x") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0x3f, DW_OP_shra, DW_OP_stack_value) +; CHECK: DW_AT_name ("y") + +define i64 @test3(ptr %p) !dbg !29 { +entry: + %0 = load i64, ptr %p, align 8 + tail call void @llvm.dbg.value(metadata i64 %0, metadata !33, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_unsigned)), !dbg !30 + tail call void @llvm.dbg.value(metadata i64 %0, metadata !34, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_signed)), !dbg !31 + ret i64 %0, !dbg !32 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 6, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "DW_OP_bit_piece.cpp", directory: "./") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "struct_t", file: !3, line: 4, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS8struct_t") +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !6, file: !3, line: 2, baseType: !9, size: 3, flags: DIFlagBitField, extraData: i64 0) +!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !6, file: !3, line: 3, baseType: !9, size: 4, offset: 3, flags: DIFlagBitField, extraData: i64 0) +!11 = !{i32 7, !"Dwarf Version", i32 5} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = distinct !DISubprogram(name: "test1", linkageName: "test1", scope: !3, file: !3, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16) +!14 = !DISubroutineType(types: !15) +!15 = !{!9} +!16 = !{} +!17 = !DILocalVariable(name: "x", scope: !13, file: !3, line: 9, type: !9) +!18 = !DILocation(line: 9, column: 9, scope: !13) +!19 = !DILocalVariable(name: "y", scope: !13, file: !3, line: 9, type: !20) +!20 = !DIBasicType(name: "signed int", size: 32, encoding: DW_ATE_signed) +!21 = !DILocation(line: 9, column: 12, scope: !13) +!22 = !DILocation(line: 10, column: 3, scope: !13) +!23 = distinct !DISubprogram(name: "test2", linkageName: "test2", scope: !3, file: !3, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16) +!24 = !DILocalVariable(name: "x", scope: !23, file: !3, line: 9, type: !9) +!25 = !DILocation(line: 9, column: 9, scope: !23) +!26 = !DILocalVariable(name: "y", scope: !23, file: !3, line: 9, type: !20) +!27 = !DILocation(line: 9, column: 12, scope: !23) +!28 = !DILocation(line: 10, column: 3, scope: !23) +!29 = distinct !DISubprogram(name: "test3", linkageName: "test3", scope: !3, file: !3, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16) +!30 = !DILocation(line: 9, column: 9, scope: !29) +!31 = !DILocation(line: 9, column: 12, scope: !29) +!32 = !DILocation(line: 10, column: 3, scope: !29) +!33 = !DILocalVariable(name: "x", scope: !29, file: !3, line: 9, type: !9) +!34 = !DILocalVariable(name: "y", scope: !29, file: !3, line: 9, type: !20) >From 7dab730797a93d7534a607fc50e0947510a598da Mon Sep 17 00:00:00 2001 From: John Brawn <john.br...@arm.com> Date: Mon, 3 Jun 2024 16:12:19 +0100 Subject: [PATCH 2/5] Remove some unnecessary debug metadata in test --- .../DebugInfo/X86/DW_OP_LLVM_extract_bits.ll | 65 +++++++++---------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll index da0eec669b50c..eeaffb47817a7 100644 --- a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll +++ b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll @@ -17,9 +17,9 @@ define i32 @test1() !dbg !13 { entry: %0 = alloca %struct.struct_t, align 1 - tail call void @llvm.dbg.declare(metadata ptr %0, metadata !17, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !18 - tail call void @llvm.dbg.declare(metadata ptr %0, metadata !19, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !21 - ret i32 0, !dbg !22 + tail call void @llvm.dbg.declare(metadata ptr %0, metadata !16, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !17 + tail call void @llvm.dbg.declare(metadata ptr %0, metadata !18, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !17 + ret i32 0, !dbg !17 } ; CHECK-LABEL: DW_TAG_subprogram @@ -31,12 +31,12 @@ entry: ; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x39, DW_OP_shl, DW_OP_constu 0x3c, DW_OP_shra, DW_OP_stack_value) ; CHECK: DW_AT_name ("y") -define i8 @test2() !dbg !23 { +define i8 @test2() !dbg !20 { entry: %0 = load i8, ptr @g, align 1 - tail call void @llvm.dbg.value(metadata i8 %0, metadata !24, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !25 - tail call void @llvm.dbg.value(metadata i8 %0, metadata !26, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !27 - ret i8 %0, !dbg !28 + tail call void @llvm.dbg.value(metadata i8 %0, metadata !21, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !22 + tail call void @llvm.dbg.value(metadata i8 %0, metadata !23, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !22 + ret i8 %0, !dbg !22 } ; CHECK-LABEL: DW_TAG_subprogram @@ -48,12 +48,12 @@ entry: ; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0x3f, DW_OP_shra, DW_OP_stack_value) ; CHECK: DW_AT_name ("y") -define i64 @test3(ptr %p) !dbg !29 { +define i64 @test3(ptr %p) !dbg !24 { entry: %0 = load i64, ptr %p, align 8 - tail call void @llvm.dbg.value(metadata i64 %0, metadata !33, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_unsigned)), !dbg !30 - tail call void @llvm.dbg.value(metadata i64 %0, metadata !34, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_signed)), !dbg !31 - ret i64 %0, !dbg !32 + tail call void @llvm.dbg.value(metadata i64 %0, metadata !25, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_unsigned)), !dbg !26 + tail call void @llvm.dbg.value(metadata i64 %0, metadata !27, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_signed)), !dbg !26 + ret i64 %0, !dbg !26 } declare void @llvm.dbg.declare(metadata, metadata, metadata) @@ -63,37 +63,30 @@ declare void @llvm.dbg.value(metadata, metadata, metadata) !llvm.module.flags = !{!11, !12} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) -!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 6, type: !5, isLocal: false, isDefinition: true) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, type: !5, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) !3 = !DIFile(filename: "DW_OP_bit_piece.cpp", directory: "./") !4 = !{!0} -!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "struct_t", file: !3, line: 4, baseType: !6) -!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS8struct_t") +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "struct_t", file: !3, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS8struct_t") !7 = !{!8, !10} -!8 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !6, file: !3, line: 2, baseType: !9, size: 3, flags: DIFlagBitField, extraData: i64 0) +!8 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !6, file: !3, baseType: !9, size: 3, flags: DIFlagBitField, extraData: i64 0) !9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) -!10 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !6, file: !3, line: 3, baseType: !9, size: 4, offset: 3, flags: DIFlagBitField, extraData: i64 0) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !6, file: !3, baseType: !9, size: 4, offset: 3, flags: DIFlagBitField, extraData: i64 0) !11 = !{i32 7, !"Dwarf Version", i32 5} !12 = !{i32 2, !"Debug Info Version", i32 3} -!13 = distinct !DISubprogram(name: "test1", linkageName: "test1", scope: !3, file: !3, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16) +!13 = distinct !DISubprogram(name: "test1", linkageName: "test1", scope: !3, file: !3, type: !14, spFlags: DISPFlagDefinition, unit: !2) !14 = !DISubroutineType(types: !15) !15 = !{!9} -!16 = !{} -!17 = !DILocalVariable(name: "x", scope: !13, file: !3, line: 9, type: !9) -!18 = !DILocation(line: 9, column: 9, scope: !13) -!19 = !DILocalVariable(name: "y", scope: !13, file: !3, line: 9, type: !20) -!20 = !DIBasicType(name: "signed int", size: 32, encoding: DW_ATE_signed) -!21 = !DILocation(line: 9, column: 12, scope: !13) -!22 = !DILocation(line: 10, column: 3, scope: !13) -!23 = distinct !DISubprogram(name: "test2", linkageName: "test2", scope: !3, file: !3, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16) -!24 = !DILocalVariable(name: "x", scope: !23, file: !3, line: 9, type: !9) -!25 = !DILocation(line: 9, column: 9, scope: !23) -!26 = !DILocalVariable(name: "y", scope: !23, file: !3, line: 9, type: !20) -!27 = !DILocation(line: 9, column: 12, scope: !23) -!28 = !DILocation(line: 10, column: 3, scope: !23) -!29 = distinct !DISubprogram(name: "test3", linkageName: "test3", scope: !3, file: !3, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16) -!30 = !DILocation(line: 9, column: 9, scope: !29) -!31 = !DILocation(line: 9, column: 12, scope: !29) -!32 = !DILocation(line: 10, column: 3, scope: !29) -!33 = !DILocalVariable(name: "x", scope: !29, file: !3, line: 9, type: !9) -!34 = !DILocalVariable(name: "y", scope: !29, file: !3, line: 9, type: !20) +!16 = !DILocalVariable(name: "x", scope: !13, file: !3, type: !9) +!17 = !DILocation(line: 0, scope: !13) +!18 = !DILocalVariable(name: "y", scope: !13, file: !3, type: !19) +!19 = !DIBasicType(name: "signed int", size: 32, encoding: DW_ATE_signed) +!20 = distinct !DISubprogram(name: "test2", linkageName: "test2", scope: !3, file: !3, type: !14, spFlags: DISPFlagDefinition, unit: !2) +!21 = !DILocalVariable(name: "x", scope: !20, file: !3, type: !9) +!22 = !DILocation(line: 0, scope: !20) +!23 = !DILocalVariable(name: "y", scope: !20, file: !3, type: !19) +!24 = distinct !DISubprogram(name: "test3", linkageName: "test3", scope: !3, file: !3, type: !14, spFlags: DISPFlagDefinition, unit: !2) +!25 = !DILocalVariable(name: "x", scope: !24, file: !3, type: !9) +!26 = !DILocation(line: 0, scope: !24) +!27 = !DILocalVariable(name: "y", scope: !24, file: !3, type: !19) >From 083dc52f7fff76e095f2242a63356599872c3fff Mon Sep 17 00:00:00 2001 From: John Brawn <john.br...@arm.com> Date: Thu, 6 Jun 2024 14:20:01 +0100 Subject: [PATCH 3/5] Put sign information in the opcode instead of as an operand. --- llvm/docs/LangRef.rst | 16 +++++++++------- llvm/include/llvm/BinaryFormat/Dwarf.h | 15 ++++++++------- llvm/lib/BinaryFormat/Dwarf.cpp | 9 ++++++--- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp | 8 ++++---- llvm/lib/IR/AsmWriter.cpp | 4 ---- llvm/lib/IR/DebugInfoMetadata.cpp | 7 ++++--- .../DebugInfo/X86/DW_OP_LLVM_extract_bits.ll | 12 ++++++------ 7 files changed, 37 insertions(+), 34 deletions(-) diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 7b4e91d09f342..d1edbb48b654c 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -6312,13 +6312,15 @@ The current supported opcode vocabulary is limited: (``16`` and ``DW_ATE_signed`` here, respectively) to which the top of the expression stack is to be converted. Maps into a ``DW_OP_convert`` operation that references a base type constructed from the supplied values. -- ``DW_OP_LLVM_extract_bits, 16, 8, DW_ATE_signed`` specifies the offset, size, - and encoding (``16``, ``8``, and ``DW_ATE_signed`` here, respectively) of bits - that are to be extracted from the value at the top of the expression stack. - If the top of the expression stack is a memory location then these bits are - extracted from the value pointed to by that memory location. Maps into a - ``DW_OP_shl`` followed by ``DW_OP_shr`` or ``DW_OP_shra`` (depending on - encoding). +- ``DW_OP_LLVM_extract_bits_sext, 16, 8,`` specifies the offset and size + (``16`` and ``8`` here, respectively) of bits that are to be extracted and + sign-extended from the value at the top of the expression stack. If the top of + the expression stack is a memory location then these bits are extracted from + the value pointed to by that memory location. Maps into a ``DW_OP_shl`` + followed by ``DW_OP_shra``. +- ``DW_OP_LLVM_extract_bits_zext`` behaves similarly to + ``DW_OP_LLVM_extract_bits_sext``, but zero-extends instead of sign-extending. + Maps into a ``DW_OP_shl`` followed by ``DW_OP_shr``. - ``DW_OP_LLVM_tag_offset, tag_offset`` specifies that a memory tag should be optionally applied to the pointer. The memory tag is derived from the given tag offset in an implementation-defined manner. diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h index 7ae265484be58..607f3eb9d4c22 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.h +++ b/llvm/include/llvm/BinaryFormat/Dwarf.h @@ -138,13 +138,14 @@ enum LocationAtom { #include "llvm/BinaryFormat/Dwarf.def" DW_OP_lo_user = 0xe0, DW_OP_hi_user = 0xff, - DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. - DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata. - DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. - DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. - DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata. - DW_OP_LLVM_arg = 0x1005, ///< Only used in LLVM metadata. - DW_OP_LLVM_extract_bits = 0x1006, ///< Only used in LLVM metadata. + DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. + DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata. + DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. + DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. + DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata. + DW_OP_LLVM_arg = 0x1005, ///< Only used in LLVM metadata. + DW_OP_LLVM_extract_bits_sext = 0x1006, ///< Only used in LLVM metadata. + DW_OP_LLVM_extract_bits_zext = 0x1007, ///< Only used in LLVM metadata. }; enum LlvmUserLocationAtom { diff --git a/llvm/lib/BinaryFormat/Dwarf.cpp b/llvm/lib/BinaryFormat/Dwarf.cpp index d9668dffabec6..0bf4f201dbe10 100644 --- a/llvm/lib/BinaryFormat/Dwarf.cpp +++ b/llvm/lib/BinaryFormat/Dwarf.cpp @@ -155,8 +155,10 @@ StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) { return "DW_OP_LLVM_implicit_pointer"; case DW_OP_LLVM_arg: return "DW_OP_LLVM_arg"; - case DW_OP_LLVM_extract_bits: - return "DW_OP_LLVM_extract_bits"; + case DW_OP_LLVM_extract_bits_sext: + return "DW_OP_LLVM_extract_bits_sext"; + case DW_OP_LLVM_extract_bits_zext: + return "DW_OP_LLVM_extract_bits_zext"; } } @@ -171,7 +173,8 @@ unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) { .Case("DW_OP_LLVM_entry_value", DW_OP_LLVM_entry_value) .Case("DW_OP_LLVM_implicit_pointer", DW_OP_LLVM_implicit_pointer) .Case("DW_OP_LLVM_arg", DW_OP_LLVM_arg) - .Case("DW_OP_LLVM_extract_bits", DW_OP_LLVM_extract_bits) + .Case("DW_OP_LLVM_extract_bits_sext", DW_OP_LLVM_extract_bits_sext) + .Case("DW_OP_LLVM_extract_bits_zext", DW_OP_LLVM_extract_bits_zext) .Default(0); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 87beeb7d6bc9a..cc96d3c481f70 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -547,10 +547,10 @@ bool DwarfExpression::addExpression( LocationKind = Unknown; return true; } - case dwarf::DW_OP_LLVM_extract_bits: { + case dwarf::DW_OP_LLVM_extract_bits_sext: + case dwarf::DW_OP_LLVM_extract_bits_zext: { unsigned SizeInBits = Op->getArg(1); unsigned BitOffset = Op->getArg(0); - dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(2)); // If we have a memory location then dereference to get the value if (isMemoryLocation()) @@ -570,8 +570,8 @@ bool DwarfExpression::addExpression( } emitOp(dwarf::DW_OP_constu); emitUnsigned(RightShift); - emitOp(Encoding == dwarf::DW_ATE_signed ? dwarf::DW_OP_shra - : dwarf::DW_OP_shr); + emitOp(OpNum == dwarf::DW_OP_LLVM_extract_bits_sext ? dwarf::DW_OP_shra + : dwarf::DW_OP_shr); // The value is now at the top of the stack, so set the location to // implicit so that we get a stack_value at the end. diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 4f5935de42bb0..8b1a21f962b08 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2468,10 +2468,6 @@ static void writeDIExpression(raw_ostream &Out, const DIExpression *N, if (Op.getOp() == dwarf::DW_OP_LLVM_convert) { Out << FS << Op.getArg(0); Out << FS << dwarf::AttributeEncodingString(Op.getArg(1)); - } else if (Op.getOp() == dwarf::DW_OP_LLVM_extract_bits) { - Out << FS << Op.getArg(0); - Out << FS << Op.getArg(1); - Out << FS << dwarf::AttributeEncodingString(Op.getArg(2)); } else { for (unsigned A = 0, AE = Op.getNumArgs(); A != AE; ++A) Out << FS << Op.getArg(A); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 5e69192d5c52f..2b45932093f0f 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1402,10 +1402,10 @@ unsigned DIExpression::ExprOperand::getSize() const { return 2; switch (Op) { - case dwarf::DW_OP_LLVM_extract_bits: - return 4; case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_fragment: + case dwarf::DW_OP_LLVM_extract_bits_sext: + case dwarf::DW_OP_LLVM_extract_bits_zext: case dwarf::DW_OP_bregx: return 3; case dwarf::DW_OP_constu: @@ -1476,7 +1476,8 @@ bool DIExpression::isValid() const { case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_arg: case dwarf::DW_OP_LLVM_tag_offset: - case dwarf::DW_OP_LLVM_extract_bits: + case dwarf::DW_OP_LLVM_extract_bits_sext: + case dwarf::DW_OP_LLVM_extract_bits_zext: case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: diff --git a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll index eeaffb47817a7..6fbf788e4cf94 100644 --- a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll +++ b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll @@ -17,8 +17,8 @@ define i32 @test1() !dbg !13 { entry: %0 = alloca %struct.struct_t, align 1 - tail call void @llvm.dbg.declare(metadata ptr %0, metadata !16, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !17 - tail call void @llvm.dbg.declare(metadata ptr %0, metadata !18, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !17 + tail call void @llvm.dbg.declare(metadata ptr %0, metadata !16, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 3)), !dbg !17 + tail call void @llvm.dbg.declare(metadata ptr %0, metadata !18, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 3, 4)), !dbg !17 ret i32 0, !dbg !17 } @@ -34,8 +34,8 @@ entry: define i8 @test2() !dbg !20 { entry: %0 = load i8, ptr @g, align 1 - tail call void @llvm.dbg.value(metadata i8 %0, metadata !21, metadata !DIExpression(DW_OP_LLVM_extract_bits, 0, 3, DW_ATE_unsigned)), !dbg !22 - tail call void @llvm.dbg.value(metadata i8 %0, metadata !23, metadata !DIExpression(DW_OP_LLVM_extract_bits, 3, 4, DW_ATE_signed)), !dbg !22 + tail call void @llvm.dbg.value(metadata i8 %0, metadata !21, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 3)), !dbg !22 + tail call void @llvm.dbg.value(metadata i8 %0, metadata !23, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 3, 4)), !dbg !22 ret i8 %0, !dbg !22 } @@ -51,8 +51,8 @@ entry: define i64 @test3(ptr %p) !dbg !24 { entry: %0 = load i64, ptr %p, align 8 - tail call void @llvm.dbg.value(metadata i64 %0, metadata !25, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_unsigned)), !dbg !26 - tail call void @llvm.dbg.value(metadata i64 %0, metadata !27, metadata !DIExpression(DW_OP_LLVM_extract_bits, 63, 1, DW_ATE_signed)), !dbg !26 + tail call void @llvm.dbg.value(metadata i64 %0, metadata !25, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 63, 1)), !dbg !26 + tail call void @llvm.dbg.value(metadata i64 %0, metadata !27, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 63, 1)), !dbg !26 ret i64 %0, !dbg !26 } >From 342011f96768a0827198482a6884325534acd5ae Mon Sep 17 00:00:00 2001 From: John Brawn <john.br...@arm.com> Date: Thu, 6 Jun 2024 16:39:16 +0100 Subject: [PATCH 4/5] Use regex in tests --- llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll index 6fbf788e4cf94..18fdfa579b9f1 100644 --- a/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll +++ b/llvm/test/DebugInfo/X86/DW_OP_LLVM_extract_bits.ll @@ -25,10 +25,10 @@ entry: ; CHECK-LABEL: DW_TAG_subprogram ; CHECK: DW_AT_name ("test2") ; CHECK: DW_TAG_variable -; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x3d, DW_OP_shl, DW_OP_constu 0x3d, DW_OP_shr, DW_OP_stack_value) +; CHECK: DW_AT_location (DW_OP_breg0 {{R[^+]+}}+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x3d, DW_OP_shl, DW_OP_constu 0x3d, DW_OP_shr, DW_OP_stack_value) ; CHECK: DW_AT_name ("x") ; CHECK: DW_TAG_variable -; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x39, DW_OP_shl, DW_OP_constu 0x3c, DW_OP_shra, DW_OP_stack_value) +; CHECK: DW_AT_location (DW_OP_breg0 {{R[^+]+}}+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_constu 0x39, DW_OP_shl, DW_OP_constu 0x3c, DW_OP_shra, DW_OP_stack_value) ; CHECK: DW_AT_name ("y") define i8 @test2() !dbg !20 { @@ -42,10 +42,10 @@ entry: ; CHECK-LABEL: DW_TAG_subprogram ; CHECK: DW_AT_name ("test3") ; CHECK: DW_TAG_variable -; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0x3f, DW_OP_shr, DW_OP_stack_value) +; CHECK: DW_AT_location (DW_OP_breg0 {{R[^+]+}}+0, DW_OP_constu 0x3f, DW_OP_shr, DW_OP_stack_value) ; CHECK: DW_AT_name ("x") ; CHECK: DW_TAG_variable -; CHECK: DW_AT_location (DW_OP_breg0 RAX+0, DW_OP_constu 0x3f, DW_OP_shra, DW_OP_stack_value) +; CHECK: DW_AT_location (DW_OP_breg0 {{R[^+]+}}+0, DW_OP_constu 0x3f, DW_OP_shra, DW_OP_stack_value) ; CHECK: DW_AT_name ("y") define i64 @test3(ptr %p) !dbg !24 { >From f7d42cbeb8ae185c7bc5f33fafbdae64738493bd Mon Sep 17 00:00:00 2001 From: John Brawn <john.br...@arm.com> Date: Thu, 14 Mar 2024 16:17:03 +0000 Subject: [PATCH 5/5] [DebugInfo] Change handling of structured bindings of bitfields Currently we use DW_OP_plus_uconst to handle the bitfield offset and handle the bitfield size by choosing a type size that matches, but this doesn't work if either offset or size aren't byte-aligned. Extracting the bits using DW_OP_LLVM_extract_bits means we can handle any kind of offset or size. TODO: test signed type, nonzero StorageOffset, oversized bitfield --- clang/lib/CodeGen/CGDebugInfo.cpp | 60 +++------ clang/lib/CodeGen/CGDebugInfo.h | 3 - ...debug-info-structured-binding-bitfield.cpp | 118 +++++++++--------- 3 files changed, 73 insertions(+), 108 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 1713f7065e7a2..d8cdf0c295183 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4865,40 +4865,6 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, return D; } -llvm::DIType *CGDebugInfo::CreateBindingDeclType(const BindingDecl *BD) { - llvm::DIFile *Unit = getOrCreateFile(BD->getLocation()); - - // If the declaration is bound to a bitfield struct field, its type may have a - // size that is different from its deduced declaration type's. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(BD->getBinding())) { - if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { - if (FD->isBitField()) { - ASTContext &Context = CGM.getContext(); - const CGRecordLayout &RL = - CGM.getTypes().getCGRecordLayout(FD->getParent()); - const CGBitFieldInfo &Info = RL.getBitFieldInfo(FD); - - // Find an integer type with the same bitwidth as the bitfield size. If - // no suitable type is present in the target, give up on producing debug - // information as it would be wrong. It is certainly possible to produce - // correct debug info, but the logic isn't currently implemented. - uint64_t BitfieldSizeInBits = Info.Size; - QualType IntTy = - Context.getIntTypeForBitwidth(BitfieldSizeInBits, Info.IsSigned); - if (IntTy.isNull()) - return nullptr; - Qualifiers Quals = BD->getType().getQualifiers(); - QualType FinalTy = Context.getQualifiedType(IntTy, Quals); - llvm::DIType *Ty = getOrCreateType(FinalTy, Unit); - assert(Ty); - return Ty; - } - } - } - - return getOrCreateType(BD->getType(), Unit); -} - llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD, llvm::Value *Storage, std::optional<unsigned> ArgNo, @@ -4913,7 +4879,8 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD, if (isa<DeclRefExpr>(BD->getBinding())) return nullptr; - llvm::DIType *Ty = CreateBindingDeclType(BD); + llvm::DIFile *Unit = getOrCreateFile(BD->getLocation()); + llvm::DIType *Ty = getOrCreateType(BD->getType(), Unit); // If there is no debug info for this type then do not emit debug info // for this variable. @@ -4939,7 +4906,6 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD, unsigned Column = getColumnNumber(BD->getLocation()); StringRef Name = BD->getName(); auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back()); - llvm::DIFile *Unit = getOrCreateFile(BD->getLocation()); // Create the descriptor for the variable. llvm::DILocalVariable *D = DBuilder.createAutoVariable( Scope, Name, Unit, Line, Ty, CGM.getLangOpts().Optimize, @@ -4953,13 +4919,21 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD, const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(parent); const uint64_t fieldOffset = layout.getFieldOffset(fieldIndex); - - if (fieldOffset != 0) { - // Currently if the field offset is not a multiple of byte, the produced - // location would not be accurate. Therefore give up. - if (fieldOffset % CGM.getContext().getCharWidth() != 0) - return nullptr; - + if (FD->isBitField()) { + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(FD->getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(FD); + if (!Info.StorageOffset.isZero()) { + Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); + Expr.push_back(Info.StorageOffset.getQuantity()); + } + Expr.push_back(Info.IsSigned ? llvm::dwarf::DW_OP_LLVM_extract_bits_sext + : llvm::dwarf::DW_OP_LLVM_extract_bits_zext); + Expr.push_back(Info.Offset); + Expr.push_back(Info.Size); + } else if (fieldOffset != 0) { + assert(fieldOffset % CGM.getContext().getCharWidth() == 0 && + "Unexpected non-bitfield with non-byte-aligned offset"); Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); Expr.push_back( CGM.getContext().toCharUnitsFromBits(fieldOffset).getQuantity()); diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index d6db4d711366a..f358e1ff79f13 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -337,9 +337,6 @@ class CGDebugInfo { llvm::DIScope *RecordTy, const RecordDecl *RD); - /// Create type for binding declarations. - llvm::DIType *CreateBindingDeclType(const BindingDecl *BD); - /// Create an anonnymous zero-size separator for bit-field-decl if needed on /// the target. llvm::DIDerivedType *createBitFieldSeparatorIfNeeded( diff --git a/clang/test/CodeGenCXX/debug-info-structured-binding-bitfield.cpp b/clang/test/CodeGenCXX/debug-info-structured-binding-bitfield.cpp index d9f5e3eacac37..dfdec9f08b8ff 100644 --- a/clang/test/CodeGenCXX/debug-info-structured-binding-bitfield.cpp +++ b/clang/test/CodeGenCXX/debug-info-structured-binding-bitfield.cpp @@ -8,8 +8,8 @@ struct S0 { // CHECK-LABEL: define dso_local void @_Z3fS0v // CHECK: alloca %struct.S0, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S0, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S0_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S0_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 2)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S0_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S0_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 16)) // void fS0() { S0 s0; @@ -24,8 +24,8 @@ struct S1 { // CHECK-LABEL: define dso_local void @_Z3fS1v // CHECK: alloca %struct.S1, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S1, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S1_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S1_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 2)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S1_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S1_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 16)) // void fS1() { S1 s1; @@ -40,8 +40,8 @@ struct S2 { // CHECK-LABEL: define dso_local void @_Z3fS2v // CHECK: alloca %struct.S2, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S2, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S2_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S2_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 1)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S2_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S2_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 8)) // void fS2() { S2 s2; @@ -56,8 +56,8 @@ struct S3 { // CHECK-LABEL: define dso_local void @_Z3fS3v // CHECK: alloca %struct.S3, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S3, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S3_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S3_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 1)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S3_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S3_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 8)) // void fS3() { S3 s3; @@ -72,8 +72,8 @@ struct S4 { // CHECK-LABEL: define dso_local void @_Z3fS4v // CHECK: alloca %struct.S4, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S4, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S4_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S4_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 1)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S4_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S4_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 16)) // void fS4() { S4 s4; @@ -88,8 +88,8 @@ struct S5 { // CHECK-LABEL: define dso_local void @_Z3fS5v // CHECK: alloca %struct.S5, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S5, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S5_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S5_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 1)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S5_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S5_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 16)) // void fS5() { S5 s5; @@ -104,8 +104,8 @@ struct S6 { // CHECK-LABEL: define dso_local void @_Z3fS6v // CHECK: alloca %struct.S6, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S6, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S6_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S6_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 2)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S6_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S6_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 8)) // void fS6() { S6 s6; @@ -120,8 +120,8 @@ struct S7 { // CHECK-LABEL: define dso_local void @_Z3fS7v // CHECK: alloca %struct.S7, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S7, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S7_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S7_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 2)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S7_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S7_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 8)) // void fS7() { S7 s7; @@ -136,8 +136,8 @@ struct S8 { // CHECK-LABEL: define dso_local void @_Z3fS8v // CHECK: alloca %struct.S8, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S8, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S8_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S8_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 2)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S8_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S8_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 16)) // void fS8() { S8 s8; @@ -152,8 +152,8 @@ struct S9 { // CHECK-LABEL: define dso_local void @_Z3fS9v // CHECK: alloca %struct.S9, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S9, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S9_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S9_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 4)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S9_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S9_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 32, 32)) // void fS9() { S9 s9; @@ -167,8 +167,8 @@ struct S10 { // CHECK-LABEL: define dso_local void @_Z4fS10v // CHECK: alloca %struct.S10, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S10, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S10_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S10_B:![0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 1)) +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S10_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S10_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 8)) // S10() : x(0), y(0) {} }; @@ -178,9 +178,6 @@ void fS10() { auto [a, b] = s10; } -// It's currently not possible to produce complete debug information for the following cases. -// Confirm that no wrong debug info is output. -// Once this is implemented, these tests should be amended. struct S11 { unsigned int x : 15; unsigned int y : 16; @@ -189,7 +186,8 @@ struct S11 { // CHECK-LABEL: define dso_local void @_Z4fS11v // CHECK: alloca %struct.S11, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S11, align 4 -// CHECK-NOT: call void @llvm.dbg.declare(metadata ptr [[TMP0]] +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S11_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 15)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S11_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 15, 16)) // void fS11() { S11 s11; @@ -204,8 +202,8 @@ struct S12 { // CHECK-LABEL: define dso_local void @_Z4fS12v // CHECK: alloca %struct.S12, align 4 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S12, align 4 -// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S12_A:![0-9]+]], metadata !DIExpression()) -// CHECK-NOT: call void @llvm.dbg.declare(metadata ptr [[TMP0]] +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S12_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S12_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 32, 17)) // void fS12() { S12 s12; @@ -220,7 +218,8 @@ struct __attribute__((packed)) S13 { // CHECK-LABEL: define dso_local void @_Z4fS13v // CHECK: alloca %struct.S13, align 1 // CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S13, align 1 -// CHECK-NOT: call void @llvm.dbg.declare(metadata ptr [[TMP0]] +// CHECK: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S13_A:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 15)) +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[TMP0]], metadata [[S13_B:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 15, 16)) // void fS13() { S13 s13; @@ -228,55 +227,50 @@ void fS13() { } // CHECK: [[UINT_TY:![0-9]+]] = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) -// CHECK: [[S0_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY:![0-9]+]]) -// CHECK: [[USHORT_TY]] = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) -// CHECK: [[S0_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY]]) +// CHECK: [[S0_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S0_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) // CHECK: [[VOLATILE_UINT_TY:![0-9]+]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: [[UINT_TY]]) -// CHECK: [[S1_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_USHORT_TY:![0-9]+]]) -// CHECK: [[VOLATILE_USHORT_TY]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: [[USHORT_TY]]) -// CHECK: [[S1_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_USHORT_TY]]) +// CHECK: [[S1_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY:![0-9]+]]) +// CHECK: [[S1_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) -// CHECK: [[S2_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UCHAR_TY:![0-9]+]]) -// CHECK: [[UCHAR_TY]] = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) -// CHECK: [[S2_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UCHAR_TY]]) +// CHECK: [[S2_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S2_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) -// CHECK: [[S3_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UCHAR_TY:![0-9]+]]) -// CHECK: [[VOLATILE_UCHAR_TY]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: [[UCHAR_TY]]) -// CHECK: [[S3_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UCHAR_TY]]) +// CHECK: [[S3_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) +// CHECK: [[S3_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) -// CHECK: [[S4_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UCHAR_TY]]) -// CHECK: [[S4_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY]]) +// CHECK: [[S4_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S4_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) -// CHECK: [[S5_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UCHAR_TY]]) -// CHECK: [[S5_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_USHORT_TY]]) +// CHECK: [[S5_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) +// CHECK: [[S5_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) -// CHECK: [[S6_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY]]) -// CHECK: [[S6_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UCHAR_TY]]) +// CHECK: [[S6_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S6_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) -// CHECK: [[S7_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_USHORT_TY]]) -// CHECK: [[S7_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UCHAR_TY]]) +// CHECK: [[S7_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) +// CHECK: [[S7_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) -// CHECK: [[S8_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY]]) -// CHECK: [[S8_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_USHORT_TY]]) +// CHECK: [[S8_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S8_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[VOLATILE_UINT_TY]]) -// CHECK: [[S9_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY]]) +// CHECK: [[S9_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) // CHECK: [[S9_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) // CHECK: [[CONST_UINT_TY:![0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[UINT_TY]]) -// CHECK: [[S10_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[CONST_UCHAR_TY:![0-9]+]]) -// CHECK: [[CONST_UCHAR_TY]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[UCHAR_TY]]) -// CHECK: [[S10_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[CONST_VOLATILE_UCHAR_TY:![0-9]+]]) -// CHECK: [[CONST_VOLATILE_UCHAR_TY]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[VOLATILE_UCHAR_TY]]) +// CHECK: [[CONST_VOLATILE_UINT_TY:![0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[VOLATILE_UINT_TY]]) +// CHECK: [[S10_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[CONST_UINT_TY]]) +// CHECK: [[S10_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[CONST_VOLATILE_UINT_TY]]) // S11 -// CHECK-NOT: !DILocalVariable(name: "a" -// CHECK-NOT: !DILocalVariable(name: "b" +// CHECK: [[S11_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S11_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) // S12 -// CHECK: [[S12_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[USHORT_TY]]) -// CHECK-NOT: !DILocalVariable(name: "b" +// CHECK: [[S12_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S12_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) // S13 -// CHECK-NOT: !DILocalVariable(name: "a" -// CHECK-NOT: !DILocalVariable(name: "b" \ No newline at end of file +// CHECK: [[S13_A]] = !DILocalVariable(name: "a", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) +// CHECK: [[S13_B]] = !DILocalVariable(name: "b", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: [[UINT_TY]]) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits