Index: lib/CodeGen/LiveDebugVariables.cpp =================================================================== --- lib/CodeGen/LiveDebugVariables.cpp +++ lib/CodeGen/LiveDebugVariables.cpp @@ -22,12 +22,14 @@ #include "LiveDebugVariables.h" #include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/VirtRegMap.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" @@ -102,6 +104,10 @@ /// Map of slot indices where this value is live. LocMap locInts; + // Set of interval start indexes that have been trimmed to the + // lexical scope. + SmallSet trimmedDefs; + /// coalesceLocation - After LocNo was changed, check if it has become /// identical to another location, and coalesce them. This may cause LocNo or /// a later location to be erased, but no earlier location will be erased. @@ -230,7 +236,7 @@ /// computeIntervals - Compute the live intervals of all locations after /// collecting all their def points. void computeIntervals(MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, - LiveIntervals &LIS); + LiveIntervals &LIS, LexicalScopes &LS); /// splitRegister - Replace OldReg ranges with NewRegs ranges where NewRegs is /// live. Returns true if any changes were made. @@ -259,6 +265,7 @@ MachineFunction *MF; LiveIntervals *LIS; const TargetRegisterInfo *TRI; + LexicalScopes LS; /// Whether emitDebugValues is called. bool EmitDone; @@ -631,7 +638,8 @@ void UserValue::computeIntervals(MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, - LiveIntervals &LIS) { + LiveIntervals &LIS, + LexicalScopes &LS) { SmallVector, 16> Defs; // Collect all defs to be extended (Skipping undefs). @@ -673,17 +681,65 @@ extendDef(Idx, LocNo, LR, VNI, nullptr, LIS); } - // Finally, erase all the undefs. + // Erase all the undefs. for (LocMap::iterator I = locInts.begin(); I.valid();) if (I.value() == ~0u) I.erase(); else ++I; + + // If the user value has been inlined trim the computed intervals + // to the inlined lexical scope (see PR33730). + + if (!dl->getInlinedAt()) + return; + + LexicalScope *Scope = LS.findLexicalScope(dl); + if (!Scope) + return; + + SlotIndex PrevEnd; + LocMap::iterator I = locInts.begin(); + + for(const InsnRange &R : Scope->getRanges()) { + SlotIndex RStart = LIS.getInstructionIndex(*R.first); + + if(PrevEnd && I.start() < PrevEnd) { + SlotIndex IStop = I.stop(); + unsigned LocNo = I.value(); + + I.setStopUnchecked(PrevEnd); + ++I; + + if(RStart < IStop) + I.insert(RStart, IStop, LocNo); + } + + I.advanceTo(RStart); + if(!I.valid()) + return; + + if (I.start() < RStart) { + I.setStartUnchecked(RStart); + // Remember that this interval was trimmed. + trimmedDefs.insert(RStart); + } + + PrevEnd = LIS.getInstructionIndex(*R.second); + PrevEnd = PrevEnd.getNextIndex(); + + I.advanceTo(PrevEnd); + if(!I.valid()) + return; + } + + if(PrevEnd && I.start() < PrevEnd) + I.setStopUnchecked(PrevEnd); } void LDVImpl::computeIntervals() { for (unsigned i = 0, e = userValues.size(); i != e; ++i) { - userValues[i]->computeIntervals(MF->getRegInfo(), *TRI, *LIS); + userValues[i]->computeIntervals(MF->getRegInfo(), *TRI, *LIS, LS); userValues[i]->mapVirtRegs(this); } } @@ -691,6 +747,7 @@ bool LDVImpl::runOnMachineFunction(MachineFunction &mf) { clear(); MF = &mf; + LS.initialize(mf); LIS = &pass.getAnalysis(); TRI = mf.getSubtarget().getRegisterInfo(); DEBUG(dbgs() << "********** COMPUTING LIVE DEBUG VARIABLES: " @@ -958,6 +1015,13 @@ SlotIndex Start = I.start(); SlotIndex Stop = I.stop(); unsigned LocNo = I.value(); + + // If the interval start was trimmed to the lexical scope insert the + // DBG_VALUE at the previous index (otherwise it appears after the + // first instruction in the range). + if (trimmedDefs.count(Start)) + Start = Start.getPrevIndex(); + DEBUG(dbgs() << "\t[" << Start << ';' << Stop << "):" << LocNo); MachineFunction::iterator MBB = LIS.getMBBFromIndex(Start)->getIterator(); SlotIndex MBBEnd = LIS.getMBBEndIdx(&*MBB); Index: test/DebugInfo/X86/live-debug-variables.ll =================================================================== --- test/DebugInfo/X86/live-debug-variables.ll +++ test/DebugInfo/X86/live-debug-variables.ll @@ -0,0 +1,153 @@ +; RUN: llc -mtriple=x86_64-linux-gnu -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s + +; The test inlines the function F four times, generating four inlined debug +; values for "i4" all of which refer to the same virtual register. This +; virtual register is then split by the register allocator. Check that this +; does not generate multiple entries within the debug location (see PR33730). +; +; Generated from: +; +; extern int foobar(int, int, int, int, int); +; +; int F(int i1, int i2, int i3, int i4, int i5) { +; return foobar(i1, i2, i3, i4, i5); +; } +; +; int foo(int a, int b, int c, int d, int e) { +; return F(a,b,c,d,e) + +; F(a,b,c,d,e) + +; F(a,b,c,d,e) + +; F(a,b,c,d,e); +; } + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[LOC:0x[0-9a-f]+]]){{[[:space:]].*}} "i4" +; CHECK: [[LOC]]: Beginning address offset +; CHECK-NOT: Beginning address offset +; CHECK: 0x{{[0-9a-f]+}}: Beginning address offset + +define i32 @F(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5) !dbg !7 { +entry: + tail call void @llvm.dbg.value(metadata i32 %i1, i64 0, metadata !12, metadata !17), !dbg !18 + tail call void @llvm.dbg.value(metadata i32 %i2, i64 0, metadata !13, metadata !17), !dbg !19 + tail call void @llvm.dbg.value(metadata i32 %i3, i64 0, metadata !14, metadata !17), !dbg !20 + tail call void @llvm.dbg.value(metadata i32 %i4, i64 0, metadata !15, metadata !17), !dbg !21 + tail call void @llvm.dbg.value(metadata i32 %i5, i64 0, metadata !16, metadata !17), !dbg !22 + %call = tail call i32 @foobar(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5) #3, !dbg !23 + ret i32 %call, !dbg !24 +} + +declare i32 @foobar(i32, i32, i32, i32, i32) + +define i32 @foo(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) !dbg !25 { +entry: + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !27, metadata !17), !dbg !32 + tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !28, metadata !17), !dbg !33 + tail call void @llvm.dbg.value(metadata i32 %c, i64 0, metadata !29, metadata !17), !dbg !34 + tail call void @llvm.dbg.value(metadata i32 %d, i64 0, metadata !30, metadata !17), !dbg !35 + tail call void @llvm.dbg.value(metadata i32 %e, i64 0, metadata !31, metadata !17), !dbg !36 + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !12, metadata !17) #3, !dbg !37 + tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !13, metadata !17) #3, !dbg !39 + tail call void @llvm.dbg.value(metadata i32 %c, i64 0, metadata !14, metadata !17) #3, !dbg !40 + tail call void @llvm.dbg.value(metadata i32 %d, i64 0, metadata !15, metadata !17) #3, !dbg !41 + tail call void @llvm.dbg.value(metadata i32 %e, i64 0, metadata !16, metadata !17) #3, !dbg !42 + %call.i = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !43 + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !12, metadata !17) #3, !dbg !44 + tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !13, metadata !17) #3, !dbg !46 + tail call void @llvm.dbg.value(metadata i32 %c, i64 0, metadata !14, metadata !17) #3, !dbg !47 + tail call void @llvm.dbg.value(metadata i32 %d, i64 0, metadata !15, metadata !17) #3, !dbg !48 + tail call void @llvm.dbg.value(metadata i32 %e, i64 0, metadata !16, metadata !17) #3, !dbg !49 + %call.i21 = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !50 + %add = add nsw i32 %call.i21, %call.i, !dbg !51 + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !12, metadata !17) #3, !dbg !52 + tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !13, metadata !17) #3, !dbg !54 + tail call void @llvm.dbg.value(metadata i32 %c, i64 0, metadata !14, metadata !17) #3, !dbg !55 + tail call void @llvm.dbg.value(metadata i32 %d, i64 0, metadata !15, metadata !17) #3, !dbg !56 + tail call void @llvm.dbg.value(metadata i32 %e, i64 0, metadata !16, metadata !17) #3, !dbg !57 + %call.i22 = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !58 + %add3 = add nsw i32 %add, %call.i22, !dbg !59 + tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !12, metadata !17) #3, !dbg !60 + tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !13, metadata !17) #3, !dbg !62 + tail call void @llvm.dbg.value(metadata i32 %c, i64 0, metadata !14, metadata !17) #3, !dbg !63 + tail call void @llvm.dbg.value(metadata i32 %d, i64 0, metadata !15, metadata !17) #3, !dbg !64 + tail call void @llvm.dbg.value(metadata i32 %e, i64 0, metadata !16, metadata !17) #3, !dbg !65 + %call.i23 = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !66 + %add5 = add nsw i32 %add3, %call.i23, !dbg !67 + ret i32 %add5, !dbg !68 +} + +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!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 6.0.0 (trunk 308976)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!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 6.0.0 (trunk 308976)"} +!7 = distinct !DISubprogram(name: "F", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10, !10, !10, !10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12, !13, !14, !15, !16} +!12 = !DILocalVariable(name: "i1", arg: 1, scope: !7, file: !1, line: 3, type: !10) +!13 = !DILocalVariable(name: "i2", arg: 2, scope: !7, file: !1, line: 3, type: !10) +!14 = !DILocalVariable(name: "i3", arg: 3, scope: !7, file: !1, line: 3, type: !10) +!15 = !DILocalVariable(name: "i4", arg: 4, scope: !7, file: !1, line: 3, type: !10) +!16 = !DILocalVariable(name: "i5", arg: 5, scope: !7, file: !1, line: 3, type: !10) +!17 = !DIExpression() +!18 = !DILocation(line: 3, column: 11, scope: !7) +!19 = !DILocation(line: 3, column: 19, scope: !7) +!20 = !DILocation(line: 3, column: 27, scope: !7) +!21 = !DILocation(line: 3, column: 35, scope: !7) +!22 = !DILocation(line: 3, column: 43, scope: !7) +!23 = !DILocation(line: 4, column: 10, scope: !7) +!24 = !DILocation(line: 4, column: 3, scope: !7) +!25 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 7, type: !8, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !26) +!26 = !{!27, !28, !29, !30, !31} +!27 = !DILocalVariable(name: "a", arg: 1, scope: !25, file: !1, line: 7, type: !10) +!28 = !DILocalVariable(name: "b", arg: 2, scope: !25, file: !1, line: 7, type: !10) +!29 = !DILocalVariable(name: "c", arg: 3, scope: !25, file: !1, line: 7, type: !10) +!30 = !DILocalVariable(name: "d", arg: 4, scope: !25, file: !1, line: 7, type: !10) +!31 = !DILocalVariable(name: "e", arg: 5, scope: !25, file: !1, line: 7, type: !10) +!32 = !DILocation(line: 7, column: 13, scope: !25) +!33 = !DILocation(line: 7, column: 20, scope: !25) +!34 = !DILocation(line: 7, column: 27, scope: !25) +!35 = !DILocation(line: 7, column: 34, scope: !25) +!36 = !DILocation(line: 7, column: 41, scope: !25) +!37 = !DILocation(line: 3, column: 11, scope: !7, inlinedAt: !38) +!38 = distinct !DILocation(line: 8, column: 10, scope: !25) +!39 = !DILocation(line: 3, column: 19, scope: !7, inlinedAt: !38) +!40 = !DILocation(line: 3, column: 27, scope: !7, inlinedAt: !38) +!41 = !DILocation(line: 3, column: 35, scope: !7, inlinedAt: !38) +!42 = !DILocation(line: 3, column: 43, scope: !7, inlinedAt: !38) +!43 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !38) +!44 = !DILocation(line: 3, column: 11, scope: !7, inlinedAt: !45) +!45 = distinct !DILocation(line: 9, column: 10, scope: !25) +!46 = !DILocation(line: 3, column: 19, scope: !7, inlinedAt: !45) +!47 = !DILocation(line: 3, column: 27, scope: !7, inlinedAt: !45) +!48 = !DILocation(line: 3, column: 35, scope: !7, inlinedAt: !45) +!49 = !DILocation(line: 3, column: 43, scope: !7, inlinedAt: !45) +!50 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !45) +!51 = !DILocation(line: 8, column: 23, scope: !25) +!52 = !DILocation(line: 3, column: 11, scope: !7, inlinedAt: !53) +!53 = distinct !DILocation(line: 10, column: 10, scope: !25) +!54 = !DILocation(line: 3, column: 19, scope: !7, inlinedAt: !53) +!55 = !DILocation(line: 3, column: 27, scope: !7, inlinedAt: !53) +!56 = !DILocation(line: 3, column: 35, scope: !7, inlinedAt: !53) +!57 = !DILocation(line: 3, column: 43, scope: !7, inlinedAt: !53) +!58 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !53) +!59 = !DILocation(line: 9, column: 23, scope: !25) +!60 = !DILocation(line: 3, column: 11, scope: !7, inlinedAt: !61) +!61 = distinct !DILocation(line: 11, column: 10, scope: !25) +!62 = !DILocation(line: 3, column: 19, scope: !7, inlinedAt: !61) +!63 = !DILocation(line: 3, column: 27, scope: !7, inlinedAt: !61) +!64 = !DILocation(line: 3, column: 35, scope: !7, inlinedAt: !61) +!65 = !DILocation(line: 3, column: 43, scope: !7, inlinedAt: !61) +!66 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !61) +!67 = !DILocation(line: 10, column: 23, scope: !25) +!68 = !DILocation(line: 8, column: 3, scope: !25)