#define LLVM_CODEGEN_FUNCTIONLOWERINGINFO_H
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/Optional.h"
/// function arguments that are inserted after scheduling is completed.
SmallVector<MachineInstr*, 8> ArgDbgValues;
+ /// Bitvector with a bit set if corresponding argument is described in
+ /// ArgDbgValues. Using arg numbers according to Argument numbering.
+ BitVector DescribedArgs;
+
/// RegFixups - Registers which need to be replaced after isel is done.
DenseMap<unsigned, unsigned> RegFixups;
LiveOutRegInfo.clear();
VisitedBBs.clear();
ArgDbgValues.clear();
+ DescribedArgs.clear();
ByValArgFrameIndexMap.clear();
RegFixups.clear();
RegsWithFixups.clear();
"Expected inlined-at fields to agree");
SDDbgValue *SDV;
if (Val.getNode()) {
+ // FIXME: I doubt that it is correct to resolve a dangling DbgValue as a
+ // FuncArgumentDbgValue (it would be hoisted to the function entry, and if
+ // we couldn't resolve it directly when examining the DbgValue intrinsic
+ // in the first place we should not be more successful here). Unless we
+ // have some test case that prove this to be correct we should avoid
+ // calling EmitFuncArgumentDbgValue here.
if (!EmitFuncArgumentDbgValue(V, Variable, Expr, dl, false, Val)) {
LLVM_DEBUG(dbgs() << "Resolve dangling debug info [order="
<< DbgSDNodeOrder << "] for:\n " << *DI << "\n");
if (!Arg)
return false;
+ if (!IsDbgDeclare) {
+ // ArgDbgValues are hoisted to the beginning of the entry block. So we
+ // should only emit as ArgDbgValue if the dbg.value intrinsic is found in
+ // the entry block.
+ bool IsInEntryBlock = FuncInfo.MBB == &FuncInfo.MF->front();
+ if (!IsInEntryBlock)
+ return false;
+
+ // ArgDbgValues are hoisted to the beginning of the entry block. So we
+ // should only emit as ArgDbgValue if the dbg.value intrinsic describes a
+ // variable that also is a param.
+ //
+ // Although, if we are at the top of the entry block already, we can still
+ // emit using ArgDbgValue. This might catch some situations when the
+ // dbg.value refers to an argument that isn't used in the entry block, so
+ // any CopyToReg node would be optimized out and the only way to express
+ // this DBG_VALUE is by using the physical reg (or FI) as done in this
+ // method. ArgDbgValues are hoisted to the beginning of the entry block. So
+ // we should only emit as ArgDbgValue if the Variable is an argument to the
+ // current function, and the dbg.value intrinsic is found in the entry
+ // block.
+ bool VariableIsFunctionInputArg = Variable->isParameter() &&
+ !DL->getInlinedAt();
+ bool IsInPrologue = SDNodeOrder == LowestSDNodeOrder;
+ if (!IsInPrologue && !VariableIsFunctionInputArg)
+ return false;
+
+ // Here we assume that a function argument on IR level only can be used to
+ // describe one input parameter on source level. If we for example have
+ // source code like this
+ //
+ // struct A { long x, y; };
+ // void foo(struct A a, long b) {
+ // ...
+ // b = a.x;
+ // ...
+ // }
+ //
+ // and IR like this
+ //
+ // define void @foo(i32 %a1, i32 %a2, i32 %b) {
+ // entry:
+ // call void @llvm.dbg.value(metadata i32 %a1, "a", DW_OP_LLVM_fragment
+ // call void @llvm.dbg.value(metadata i32 %a2, "a", DW_OP_LLVM_fragment
+ // call void @llvm.dbg.value(metadata i32 %b, "b",
+ // ...
+ // call void @llvm.dbg.value(metadata i32 %a1, "b"
+ // ...
+ //
+ // then the last dbg.value is describing a parameter "b" using a value that
+ // is an argument. But since we already has used %a1 to describe a parameter
+ // we should not handle that last dbg.value here (that would result in an
+ // incorrect hoisting of the DBG_VALUE to the function entry).
+ // Notice that we allow one dbg.value per IR level argument, to accomodate
+ // for the situation with fragments above.
+ if (VariableIsFunctionInputArg) {
+ unsigned ArgNo = Arg->getArgNo();
+ if (ArgNo >= FuncInfo.DescribedArgs.size())
+ FuncInfo.DescribedArgs.resize(ArgNo + 1, false);
+ else if (!IsInPrologue && FuncInfo.DescribedArgs.test(ArgNo))
+ return false;
+ FuncInfo.DescribedArgs.set(ArgNo);
+ }
+ }
+
MachineFunction &MF = DAG.getMachineFunction();
const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();
--- /dev/null
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -start-after=codegenprepare -stop-before=expand-isel-pseudos -o - %s | FileCheck %s
+
+; Input to this test looked like this and was compiled using: clang -g -O1 -mllvm -stop-after=codegenprepare -S
+;
+; extern void bar(int);
+;
+; void foo_local(int t1a) {
+; int local = 123;
+; bar(local);
+; local = t1a;
+; bar(local);
+; }
+;
+; void foo_other_param(int t2a, int t2b) {
+; bar(t2b);
+; t2b = 123;
+; bar(t2b);
+; t2b = t2a;
+; bar(t2b);
+; }
+;
+; void foo_same_param(int t3a) {
+; bar(t3a);
+; int tmp = t3a;
+; t3a = 123;
+; bar(t3a);
+; t3a = tmp;
+; bar(t3a);
+; }
+;
+
+; Catch metadata references for involved variables.
+;
+; CHECK-DAG: ![[T1A:.*]] = !DILocalVariable(name: "t1a"
+; CHECK-DAG: ![[LOCAL:.*]] = !DILocalVariable(name: "local"
+; CHECK-DAG: ![[T2A:.*]] = !DILocalVariable(name: "t2a"
+; CHECK-DAG: ![[T2B:.*]] = !DILocalVariable(name: "t2b"
+; CHECK-DAG: ![[T3A:.*]] = !DILocalVariable(name: "t3a"
+; CHECK-DAG: ![[TMP:.*]] = !DILocalVariable(name: "tmp"
+
+
+define dso_local void @foo_local(i32 %t1a) local_unnamed_addr #0 !dbg !7 {
+; CHECK-LABEL: name: foo_local
+; CHECK-NOT: DBG_VALUE
+; CHECK: DBG_VALUE $edi, $noreg, ![[T1A]], !DIExpression(),
+; CHECK-NEXT: %0:gr32 = COPY $edi
+; CHECK-NEXT: DBG_VALUE %0, $noreg, ![[T1A]], !DIExpression(),
+; CHECK-NEXT: DBG_VALUE 123, $noreg, ![[LOCAL]], !DIExpression(),
+; CHECK-NOT: DBG_VALUE
+; CHECK: CALL64pcrel32 @bar,
+; CHECK: DBG_VALUE %0, $noreg, ![[LOCAL]], !DIExpression(),
+; CHECK: DBG_VALUE $edi, $noreg, ![[T1A]], !DIExpression(),
+; CHECK-NOT: DBG_VALUE
+; CHECK: TCRETURNdi64 @bar,
+entry:
+ call void @llvm.dbg.value(metadata i32 %t1a, metadata !12, metadata !DIExpression()), !dbg !14
+ call void @llvm.dbg.value(metadata i32 123, metadata !13, metadata !DIExpression()), !dbg !15
+ tail call void @bar(i32 123) #3, !dbg !16
+ call void @llvm.dbg.value(metadata i32 %t1a, metadata !13, metadata !DIExpression()), !dbg !15
+ tail call void @bar(i32 %t1a) #3, !dbg !17
+ ret void, !dbg !18
+}
+
+define dso_local void @foo_other_param(i32 %t2a, i32 %t2b) local_unnamed_addr #0 !dbg !19 {
+; CHECK-LABEL: name: foo_other_param
+; CHECK: DBG_VALUE $edi, $noreg, ![[T2A]], !DIExpression(),
+; CHECK: DBG_VALUE $esi, $noreg, ![[T2B]], !DIExpression(),
+; CHECK: %1:gr32 = COPY $esi
+; CHECK: DBG_VALUE %1, $noreg, ![[T2B]], !DIExpression(),
+; CHECK: %0:gr32 = COPY $edi
+; CHECK: DBG_VALUE %0, $noreg, ![[T2A]], !DIExpression(),
+; CHECK: DBG_VALUE $edi, $noreg, ![[T2B]], !DIExpression(),
+; CHECK: CALL64pcrel32 @bar,
+; CHECK: DBG_VALUE 123, $noreg, ![[T2B]], !DIExpression(),
+; CHECK: CALL64pcrel32 @bar,
+; CHECK: DBG_VALUE %0, $noreg, ![[T2B]], !DIExpression(),
+; CHECK: DBG_VALUE $edi, $noreg, ![[T2A]], !DIExpression(),
+; CHECK: TCRETURNdi64 @bar,
+
+entry:
+ call void @llvm.dbg.value(metadata i32 %t2a, metadata !23, metadata !DIExpression()), !dbg !25
+ call void @llvm.dbg.value(metadata i32 %t2b, metadata !24, metadata !DIExpression()), !dbg !26
+ tail call void @bar(i32 %t2b) #3, !dbg !27
+ call void @llvm.dbg.value(metadata i32 123, metadata !24, metadata !DIExpression()), !dbg !26
+ tail call void @bar(i32 123) #3, !dbg !28
+ call void @llvm.dbg.value(metadata i32 %t2a, metadata !24, metadata !DIExpression()), !dbg !26
+ tail call void @bar(i32 %t2a) #3, !dbg !29
+ ret void, !dbg !30
+}
+
+define dso_local void @foo_same_param(i32 %t3a) local_unnamed_addr #0 !dbg !31 {
+; CHECK-LABEL: name: foo_same_param
+; CHECK: DBG_VALUE $edi, $noreg, ![[T3A]], !DIExpression(),
+; CHECK: %0:gr32 = COPY $edi
+; CHECK: DBG_VALUE %0, $noreg, ![[T3A]], !DIExpression(),
+; CHECK: CALL64pcrel32 @bar,
+; CHECK: DBG_VALUE %0, $noreg, ![[TMP]], !DIExpression(),
+; CHECK: DBG_VALUE 123, $noreg, ![[T3A]], !DIExpression(),
+; CHECK: CALL64pcrel32 @bar,
+; CHECK: DBG_VALUE %0, $noreg, ![[T3A]], !DIExpression(),
+; CHECK: TCRETURNdi64 @bar,
+entry:
+ call void @llvm.dbg.value(metadata i32 %t3a, metadata !33, metadata !DIExpression()), !dbg !35
+ tail call void @bar(i32 %t3a) #3, !dbg !36
+ call void @llvm.dbg.value(metadata i32 %t3a, metadata !34, metadata !DIExpression()), !dbg !37
+ call void @llvm.dbg.value(metadata i32 123, metadata !33, metadata !DIExpression()), !dbg !35
+ tail call void @bar(i32 123) #3, !dbg !38
+ call void @llvm.dbg.value(metadata i32 %t3a, metadata !33, metadata !DIExpression()), !dbg !35
+ tail call void @bar(i32 %t3a) #3, !dbg !39
+ ret void, !dbg !40
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+declare dso_local void @bar(i32) local_unnamed_addr
+
+attributes #0 = { nounwind uwtable }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "foo.c", directory: "")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 9.0.0"}
+!7 = distinct !DISubprogram(name: "foo_local", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "t1a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 4, type: !10)
+!14 = !DILocation(line: 3, column: 20, scope: !7)
+!15 = !DILocation(line: 4, column: 7, scope: !7)
+!16 = !DILocation(line: 5, column: 3, scope: !7)
+!17 = !DILocation(line: 7, column: 3, scope: !7)
+!18 = !DILocation(line: 8, column: 1, scope: !7)
+!19 = distinct !DISubprogram(name: "foo_other_param", scope: !1, file: !1, line: 10, type: !20, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22)
+!20 = !DISubroutineType(types: !21)
+!21 = !{null, !10, !10}
+!22 = !{!23, !24}
+!23 = !DILocalVariable(name: "t2a", arg: 1, scope: !19, file: !1, line: 10, type: !10)
+!24 = !DILocalVariable(name: "t2b", arg: 2, scope: !19, file: !1, line: 10, type: !10)
+!25 = !DILocation(line: 10, column: 26, scope: !19)
+!26 = !DILocation(line: 10, column: 35, scope: !19)
+!27 = !DILocation(line: 11, column: 3, scope: !19)
+!28 = !DILocation(line: 13, column: 3, scope: !19)
+!29 = !DILocation(line: 15, column: 3, scope: !19)
+!30 = !DILocation(line: 16, column: 1, scope: !19)
+!31 = distinct !DISubprogram(name: "foo_same_param", scope: !1, file: !1, line: 18, type: !8, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !32)
+!32 = !{!33, !34}
+!33 = !DILocalVariable(name: "t3a", arg: 1, scope: !31, file: !1, line: 18, type: !10)
+!34 = !DILocalVariable(name: "tmp", scope: !31, file: !1, line: 20, type: !10)
+!35 = !DILocation(line: 18, column: 25, scope: !31)
+!36 = !DILocation(line: 19, column: 3, scope: !31)
+!37 = !DILocation(line: 20, column: 7, scope: !31)
+!38 = !DILocation(line: 22, column: 3, scope: !31)
+!39 = !DILocation(line: 24, column: 3, scope: !31)
+!40 = !DILocation(line: 25, column: 1, scope: !31)
--- /dev/null
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -start-after=codegenprepare -stop-before=expand-isel-pseudos -o - %s | FileCheck %s
+
+; Test case was generated from the following C code,
+; using: clang -g -O1 -S -emit-llvm s.c -o s.ll
+;
+; struct s { long long int i, j; };
+;
+; extern void bar(struct s, struct s, struct s);
+;
+; int f(struct s s1, struct s s2) {
+; volatile struct s tmp = {0};
+; bar(s1, s2, tmp);
+; s1.i = s2.i;
+; s1.j = s2.j;
+; return s1.j + s1.j;
+; }
+
+; Catch metadata references for involved variables.
+;
+; CHECK-DAG: ![[S1:.*]] = !DILocalVariable(name: "s1"
+; CHECK-DAG: ![[S2:.*]] = !DILocalVariable(name: "s2"
+
+define dso_local i32 @f(i64 %s1.coerce0, i64 %s1.coerce1, i64 %s2.coerce0, i64 %s2.coerce1) local_unnamed_addr #0 !dbg !7 {
+; We expect DBG_VALUE instructions for the arguments at the entry.
+; CHECK-LABEL: name: f
+; CHECK-NOT: DBG_VALUE
+; CHECK-DAG: DBG_VALUE $rdi, $noreg, ![[S1]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
+; CHECK-DAG: DBG_VALUE $rsi, $noreg, ![[S1]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
+; CHECK-DAG: DBG_VALUE $rdx, $noreg, ![[S2]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
+; CHECK-DAG: DBG_VALUE $rcx, $noreg, ![[S2]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
+; CHECK-NOT: DBG_VALUE
+
+; Then arguments are copied to virtual registers.
+; CHECK-NOT: DBG_VALUE
+; CHECK-DAG: %[[R1:.*]]:gr64 = COPY $rcx
+; CHECK-DAG: DBG_VALUE %[[R1]], $noreg, ![[S2]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
+; CHECK-DAG: %[[R2:.*]]:gr64 = COPY $rdx
+; CHECK-DAG: DBG_VALUE %[[R2]], $noreg, ![[S2]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
+; CHECK-DAG: %[[R3:.*]]:gr64 = COPY $rsi
+; CHECK-DAG: DBG_VALUE %[[R3]], $noreg, ![[S1]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
+; CHECK-DAG: %[[R4:.*]]:gr64 = COPY $rdi
+; CHECK-DAG: DBG_VALUE %[[R4]], $noreg, ![[S1]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
+; CHECK-NOT: DBG_VALUE
+
+; We have the call to bar.
+; CHECK: ADJCALLSTACKDOWN
+; CHECK: CALL64pcrel32 @bar
+
+; After the call we expect to find new DBG_VALUE instructions for "s1".
+; CHECK: ADJCALLSTACKUP
+; CHECK-NOT: DBG_VALUE
+; CHECK-DAG: DBG_VALUE %[[R2]], $noreg, ![[S1]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
+; CHECK-DAG: DBG_VALUE %[[R1]], $noreg, ![[S1]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
+
+; And then no more DBG_VALUE instructions before the add.
+; CHECK-NOT: DBG_VALUE
+; CHECK: ADD32rr
+
+entry:
+ %tmp.sroa.0 = alloca i64, align 8
+ %tmp.sroa.4 = alloca i64, align 8
+ call void @llvm.dbg.declare(metadata i64* %tmp.sroa.0, metadata !19, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !21
+ call void @llvm.dbg.declare(metadata i64* %tmp.sroa.4, metadata !19, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)), !dbg !21
+ call void @llvm.dbg.value(metadata i64 %s1.coerce0, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !22
+ call void @llvm.dbg.value(metadata i64 %s1.coerce1, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)), !dbg !22
+ call void @llvm.dbg.value(metadata i64 %s2.coerce0, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !23
+ call void @llvm.dbg.value(metadata i64 %s2.coerce1, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)), !dbg !23
+ %tmp.sroa.0.0..sroa_cast = bitcast i64* %tmp.sroa.0 to i8*, !dbg !24
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %tmp.sroa.0.0..sroa_cast), !dbg !24
+ %tmp.sroa.4.0..sroa_cast = bitcast i64* %tmp.sroa.4 to i8*, !dbg !24
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %tmp.sroa.4.0..sroa_cast), !dbg !24
+ store volatile i64 0, i64* %tmp.sroa.0, align 8, !dbg !21
+ store volatile i64 0, i64* %tmp.sroa.4, align 8, !dbg !21
+ tail call void @bar(i64 %s1.coerce0, i64 %s1.coerce1, i64 %s2.coerce0, i64 %s2.coerce1, i64 0, i64 0) #4, !dbg !25
+ call void @llvm.dbg.value(metadata i64 %s2.coerce0, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !22
+ call void @llvm.dbg.value(metadata i64 %s2.coerce1, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)), !dbg !22
+ %s2.coerce1.tr = trunc i64 %s2.coerce1 to i32, !dbg !26
+ %conv = shl i32 %s2.coerce1.tr, 1, !dbg !26
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %tmp.sroa.0.0..sroa_cast), !dbg !27
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %tmp.sroa.4.0..sroa_cast), !dbg !27
+ ret i32 %conv, !dbg !28
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2
+
+declare dso_local void @bar(i64, i64, i64, i64, i64, i64) local_unnamed_addr
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind readnone speculatable }
+attributes #2 = { argmemonly nounwind }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "llvm-svn @ 353529", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "s.c", directory: "")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"llvm-svn @ 353529"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !11, !11}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 128, elements: !12)
+!12 = !{!13, !15}
+!13 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !11, file: !1, line: 1, baseType: !14, size: 64)
+!14 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !11, file: !1, line: 1, baseType: !14, size: 64, offset: 64)
+!16 = !{!17, !18, !19}
+!17 = !DILocalVariable(name: "s1", arg: 1, scope: !7, file: !1, line: 5, type: !11)
+!18 = !DILocalVariable(name: "s2", arg: 2, scope: !7, file: !1, line: 5, type: !11)
+!19 = !DILocalVariable(name: "tmp", scope: !7, file: !1, line: 6, type: !20)
+!20 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !11)
+!21 = !DILocation(line: 6, column: 21, scope: !7)
+!22 = !DILocation(line: 5, column: 16, scope: !7)
+!23 = !DILocation(line: 5, column: 29, scope: !7)
+!24 = !DILocation(line: 6, column: 3, scope: !7)
+!25 = !DILocation(line: 7, column: 3, scope: !7)
+!26 = !DILocation(line: 10, column: 10, scope: !7)
+!27 = !DILocation(line: 11, column: 1, scope: !7)
+!28 = !DILocation(line: 10, column: 3, scope: !7)