Initially added in #187709. It was reverted in #188833, because [llvm-clang-x86_64-sie-win](https://lab.llvm.org/buildbot/#/builders/46/builds/32873) was failing in `cross-project-tests/debuginfo-tests/dexter-tests/nrvo.cpp`. The test passed for me locally. After checking on another machine, I found that `S_DEFRANGE_REGISTER_REL_INDIR` is only supported by dbgeng/WinDbg from Windows 10.0 Build 19041 (released 2020) onwards. SDKs before this will fail to read the value. That buildbot is on Windows 10.0 Build 17763. I'm not sure if we should make the generation of that record conditional. Debuggers that can't read the record will skip it. They'll still see that there's some local variable, but won't be able to display the value. As far as I know, users of older Windows 10 builds should be able to install a newer Windows SDK and use the WinDbg from that version. But I haven't tested that.
213 lines
8.7 KiB
LLVM
213 lines
8.7 KiB
LLVM
; RUN: llc < %s | FileCheck %s --check-prefix=ASM
|
|
; RUN: llc < %s -filetype=obj | llvm-readobj - --codeview | FileCheck %s --check-prefix=OBJ
|
|
|
|
|
|
; C++ source to regenerate:
|
|
; struct Foo {
|
|
; int a;
|
|
; int b;
|
|
; int c;
|
|
; int d;
|
|
; };
|
|
;
|
|
; int main() {
|
|
; Foo f{1, 2, 3, 4};
|
|
; auto &[a, b, c, d] = f;
|
|
; return a;
|
|
; }
|
|
; $ clang t.cpp -S -emit-llvm -g -o t.ll -std=c++17
|
|
|
|
; ASM-LABEL: .long 241 # Symbol subsection for main
|
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
|
; ASM-NEXT: .long 4101 # TypeIndex
|
|
; ASM-NEXT: .short 0 # Flags
|
|
; ASM-NEXT: .asciz "f"
|
|
; ASM-NEXT: .p2align 2, 0x0
|
|
; ASM-NEXT: .Ltmp{{.*}}:
|
|
; ASM-NEXT: .cv_def_range .Ltmp0 .Ltmp1, frame_ptr_rel, 16
|
|
|
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
|
; ASM-NEXT: .long 116 # TypeIndex
|
|
; ASM-NEXT: .short 0 # Flags
|
|
; ASM-NEXT: .asciz "a"
|
|
; ASM-NEXT: .p2align 2, 0x0
|
|
; ASM-NEXT: .Ltmp{{.*}}:
|
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 0
|
|
|
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
|
; ASM-NEXT: .long 116 # TypeIndex
|
|
; ASM-NEXT: .short 0 # Flags
|
|
; ASM-NEXT: .asciz "b"
|
|
; ASM-NEXT: .p2align 2, 0x0
|
|
; ASM-NEXT: .Ltmp{{.*}}:
|
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 4
|
|
|
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
|
; ASM-NEXT: .long 116 # TypeIndex
|
|
; ASM-NEXT: .short 0 # Flags
|
|
; ASM-NEXT: .asciz "c"
|
|
; ASM-NEXT: .p2align 2, 0x0
|
|
; ASM-NEXT: .Ltmp{{.*}}:
|
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 8
|
|
|
|
; ASM: .short 4414 # Record kind: S_LOCAL
|
|
; ASM-NEXT: .long 116 # TypeIndex
|
|
; ASM-NEXT: .short 0 # Flags
|
|
; ASM-NEXT: .asciz "d"
|
|
; ASM-NEXT: .p2align 2, 0x0
|
|
; ASM-NEXT: .Ltmp{{.*}}:
|
|
; ASM-NEXT: .cv_def_range .Ltmp{{.*}} .Ltmp{{.*}}, reg_rel_indir, 335, 0, 0, 12
|
|
|
|
; OBJ: Subsection [
|
|
; OBJ: SubSectionType: Symbols (0xF1)
|
|
; OBJ: GlobalProcIdSym {
|
|
; OBJ: FunctionType: main (0x1002)
|
|
; OBJ: }
|
|
; OBJ: LocalSym {
|
|
; OBJ: Kind: S_LOCAL (0x113E)
|
|
; OBJ: Type: Foo (0x1005)
|
|
; OBJ: VarName: f
|
|
; OBJ: }
|
|
; OBJ: DefRangeFramePointerRelSym {
|
|
; OBJ: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
|
|
; OBJ: Offset: 16
|
|
; OBJ: LocalVariableAddrRange {
|
|
; OBJ: }
|
|
; OBJ: }
|
|
; OBJ: LocalSym {
|
|
; OBJ: Kind: S_LOCAL (0x113E)
|
|
; OBJ: Type: int (0x74)
|
|
; OBJ: Flags [ (0x0)
|
|
; OBJ: ]
|
|
; OBJ: VarName: a
|
|
; OBJ: }
|
|
; OBJ: DefRangeRegisterRelIndirSym {
|
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
|
; OBJ: BaseRegister: RSP (0x14F)
|
|
; OBJ: HasSpilledUDTMember: No
|
|
; OBJ: OffsetInParent: 0
|
|
; OBJ: BasePointerOffset: 0
|
|
; OBJ: OffsetInUDT: 0
|
|
; OBJ: LocalVariableAddrRange {
|
|
; OBJ: }
|
|
; OBJ: }
|
|
; OBJ: LocalSym {
|
|
; OBJ: Kind: S_LOCAL (0x113E)
|
|
; OBJ: Type: int (0x74)
|
|
; OBJ: Flags [ (0x0)
|
|
; OBJ: ]
|
|
; OBJ: VarName: b
|
|
; OBJ: }
|
|
; OBJ: DefRangeRegisterRelIndirSym {
|
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
|
; OBJ: BaseRegister: RSP (0x14F)
|
|
; OBJ: HasSpilledUDTMember: No
|
|
; OBJ: OffsetInParent: 0
|
|
; OBJ: BasePointerOffset: 0
|
|
; OBJ: OffsetInUDT: 4
|
|
; OBJ: LocalVariableAddrRange {
|
|
; OBJ: }
|
|
; OBJ: }
|
|
; OBJ: LocalSym {
|
|
; OBJ: Kind: S_LOCAL (0x113E)
|
|
; OBJ: Type: int (0x74)
|
|
; OBJ: Flags [ (0x0)
|
|
; OBJ: ]
|
|
; OBJ: VarName: c
|
|
; OBJ: }
|
|
; OBJ: DefRangeRegisterRelIndirSym {
|
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
|
; OBJ: BaseRegister: RSP (0x14F)
|
|
; OBJ: HasSpilledUDTMember: No
|
|
; OBJ: OffsetInParent: 0
|
|
; OBJ: BasePointerOffset: 0
|
|
; OBJ: OffsetInUDT: 8
|
|
; OBJ: LocalVariableAddrRange {
|
|
; OBJ: }
|
|
; OBJ: }
|
|
; OBJ: LocalSym {
|
|
; OBJ: Kind: S_LOCAL (0x113E)
|
|
; OBJ: Type: int (0x74)
|
|
; OBJ: Flags [ (0x0)
|
|
; OBJ: ]
|
|
; OBJ: VarName: d
|
|
; OBJ: }
|
|
; OBJ: DefRangeRegisterRelIndirSym {
|
|
; OBJ: Kind: S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
|
|
; OBJ: BaseRegister: RSP (0x14F)
|
|
; OBJ: HasSpilledUDTMember: No
|
|
; OBJ: OffsetInParent: 0
|
|
; OBJ: BasePointerOffset: 0
|
|
; OBJ: OffsetInUDT: 12
|
|
; OBJ: LocalVariableAddrRange {
|
|
; OBJ: }
|
|
; OBJ: }
|
|
|
|
; ModuleID = 't.cpp'
|
|
source_filename = "t.cpp"
|
|
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-pc-windows-msvc19.50.35725"
|
|
|
|
%struct.Foo = type { i32, i32, i32, i32 }
|
|
|
|
@__const.main.f = private unnamed_addr constant %struct.Foo { i32 1, i32 2, i32 3, i32 4 }, align 4
|
|
|
|
; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable
|
|
define dso_local noundef i32 @main() #0 !dbg !9 {
|
|
%1 = alloca i32, align 4
|
|
%2 = alloca %struct.Foo, align 4
|
|
%3 = alloca ptr, align 8
|
|
store i32 0, ptr %1, align 4
|
|
#dbg_declare(ptr %2, !14, !DIExpression(), !21)
|
|
call void @llvm.memcpy.p0.p0.i64(ptr align 4 %2, ptr align 4 @__const.main.f, i64 16, i1 false), !dbg !21
|
|
#dbg_declare(ptr %3, !22, !DIExpression(DW_OP_deref), !23)
|
|
#dbg_declare(ptr %3, !24, !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 4), !23)
|
|
#dbg_declare(ptr %3, !25, !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 8), !23)
|
|
#dbg_declare(ptr %3, !26, !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 12), !23)
|
|
store ptr %2, ptr %3, align 8, !dbg !23
|
|
%4 = load ptr, ptr %3, align 8, !dbg !27, !nonnull !13, !align !28
|
|
%5 = getelementptr inbounds nuw %struct.Foo, ptr %4, i32 0, i32 0, !dbg !27
|
|
%6 = load i32, ptr %5, align 4, !dbg !27
|
|
ret i32 %6, !dbg !27
|
|
}
|
|
|
|
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
|
declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
|
|
|
|
attributes #0 = { mustprogress noinline norecurse nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
|
attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
|
|
!llvm.ident = !{!8}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 21.1.8", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
|
|
!1 = !DIFile(filename: "t.cpp", directory: "F:\\Dev\\dummy", checksumkind: CSK_MD5, checksum: "e257352cbba404e4548bc4500877ceb0")
|
|
!2 = !{i32 2, !"CodeView", i32 1}
|
|
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!4 = !{i32 1, !"wchar_size", i32 2}
|
|
!5 = !{i32 8, !"PIC Level", i32 2}
|
|
!6 = !{i32 7, !"uwtable", i32 2}
|
|
!7 = !{i32 1, !"MaxTLSAlign", i32 65536}
|
|
!8 = !{!"clang version 21.1.8"}
|
|
!9 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !10, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13)
|
|
!10 = !DISubroutineType(types: !11)
|
|
!11 = !{!12}
|
|
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
|
!13 = !{}
|
|
!14 = !DILocalVariable(name: "f", scope: !9, file: !1, line: 9, type: !15)
|
|
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 128, flags: DIFlagTypePassByValue, elements: !16, identifier: ".?AUFoo@@")
|
|
!16 = !{!17, !18, !19, !20}
|
|
!17 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !15, file: !1, line: 2, baseType: !12, size: 32)
|
|
!18 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !15, file: !1, line: 3, baseType: !12, size: 32, offset: 32)
|
|
!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !15, file: !1, line: 4, baseType: !12, size: 32, offset: 64)
|
|
!20 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !15, file: !1, line: 5, baseType: !12, size: 32, offset: 96)
|
|
!21 = !DILocation(line: 9, scope: !9)
|
|
!22 = !DILocalVariable(name: "a", scope: !9, file: !1, line: 10, type: !12)
|
|
!23 = !DILocation(line: 10, scope: !9)
|
|
!24 = !DILocalVariable(name: "b", scope: !9, file: !1, line: 10, type: !12)
|
|
!25 = !DILocalVariable(name: "c", scope: !9, file: !1, line: 10, type: !12)
|
|
!26 = !DILocalVariable(name: "d", scope: !9, file: !1, line: 10, type: !12)
|
|
!27 = !DILocation(line: 11, scope: !9)
|
|
!28 = !{i64 4}
|