Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -683,11 +683,19 @@ // generate the debug data structures now that we've seen its definition. void resolveDanglingDebugInfo(const Value *V, SDValue Val); + // For the given dangling debuginfo record, perform last-ditch efforts to + // resolve the debuginfo to something that is represented in this DAG. If + // this cannot be done, produce an Undef debug value record. + void finalDebugFixup(DanglingDebugInfo &DDI); + // handleDebugValue: For a given Value, attempt to create and record a // SDDbgValue in the SelectionDAG. bool handleDebugValue(const Value *V, DILocalVariable *Var, DIExpression *Expr, DebugLoc dl, unsigned Order); + // Evict any dangling debug information, attempting to salvage it first. + void resolveOrClearDbgInfo(); + SDValue getValue(const Value *V); bool findValue(const Value *V) const; Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -108,6 +108,7 @@ #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/Utils/Local.h" #include #include #include @@ -1131,6 +1132,13 @@ for (auto &DDIMI : DanglingDebugInfoMap) { DanglingDebugInfoVector &DDIV = DDIMI.second; + + // If debug info is to be dropped, run it through final checks to see + // whether it can be salvaged. + for (auto &DDI : DDIV) + if (isMatchingDbgValue(DDI)) + finalDebugFixup(DDI); + DDIV.erase(remove_if(DDIV, isMatchingDbgValue), DDIV.end()); } } @@ -1173,12 +1181,72 @@ } else LLVM_DEBUG(dbgs() << "Resolved dangling debug info for " << *DI << "in EmitFuncArgumentDbgValue\n"); - } else + } else { LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n"); + auto Undef = UndefValue::get(Type::getInt32Ty(DDI.getDI()->getContext())); + auto SDV = + DAG.getConstantDbgValue(Variable, Expr, Undef, dl, DbgSDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); + } } DDIV.clear(); } +// Make some final attempts to salvage debugging information +void SelectionDAGBuilder::finalDebugFixup(DanglingDebugInfo &DDI) { + Value *V = DDI.getDI()->getValue(); + DILocalVariable *Var = DDI.getDI()->getVariable(); + DIExpression *Expr = DDI.getDI()->getExpression(); + auto dl = DDI.getdl(); + unsigned SDOrder = DDI.getSDNodeOrder(); + + // Currently we consider only dbg.value intrinsics -- we tell the salvager + // that DW_OP_stack_value is desired. + assert(isa(DDI.getDI())); + bool StackValue = true; + + // Can this Value can be encoded without any further work? + if (handleDebugValue(V, Var, Expr, dl, SDOrder)) + return; + + // Attempt to salvage back through as many instructions as possible. Bail if + // a non-instruction is seen, such as a constant expression or global + // variable. FIXME: Further work could recover those too. + while (isa(V)) { + Instruction &VAsInst = *cast(V); + DIExpression *NewExpr = salvageDebugInfoImpl(VAsInst, Expr, StackValue); + + // If we cannot salvage any further, and haven't yet found a suitable debug + // expression, bail out. + if (NewExpr == nullptr) + break; + + // New value and expr now represent this debuginfo. + V = VAsInst.getOperand(0); + Expr = NewExpr; + + // Some kind of simplification occurred: check whether the operand of the + // salvaged debug expression can be encoded in this DAG. + if (handleDebugValue(V, Var, Expr, dl, SDOrder)) { + LLVM_DEBUG(dbgs() << "Salvaged debug location info for:\n " + << DDI.getDI() << "\nBy stripping back to:\n " << V); + return; + } + } + + // This was the final opportunity to salvage this debug information, and it + // couldn't be done. Place an undef DBG_VALUE at this location to terminate + // any earlier variable location. + auto Undef = UndefValue::get(Type::getInt32Ty(DDI.getDI()->getContext())); + auto SDV = DAG.getConstantDbgValue(Var, Expr, Undef, dl, SDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); + + LLVM_DEBUG(dbgs() << "Dropping debug location info for:\n " << DDI.getDI() + << "\n"); + LLVM_DEBUG(dbgs() << " Last seen at:\n " << *DDI.getDI()->getOperand(0) + << "\n"); +} + bool SelectionDAGBuilder::handleDebugValue(const Value *V, DILocalVariable *Var, DIExpression *Expr, DebugLoc dl, unsigned Order) { @@ -1271,6 +1339,14 @@ return false; } +void SelectionDAGBuilder::resolveOrClearDbgInfo() { + // Try to fixup any remaining dangling debug info -- and drop it if we can't. + for (auto &Pair : DanglingDebugInfoMap) + for (auto &DDI : Pair.getSecond()) + finalDebugFixup(DDI); + clearDanglingDebugInfo(); +} + /// getCopyFromRegs - If there was virtual register allocated for the value V /// emit CopyFromReg of the specified type Ty. Return empty SDValue() otherwise. SDValue SelectionDAGBuilder::getCopyFromRegs(const Value *V, Type *Ty) { @@ -5407,21 +5483,7 @@ if (handleDebugValue(V, Variable, Expression, dl, SDNodeOrder)) return nullptr; - // TODO: When we get here we will either drop the dbg.value completely, or - // we try to move it forward by letting it dangle for awhile. So we should - // probably add an extra DbgValue to the DAG here, with a reference to - // "noreg", to indicate that we have lost the debug location for the - // variable. - - if (!V->use_empty() ) { - // Do not call getValue(V) yet, as we don't want to generate code. - // Remember it for later. - DanglingDebugInfoMap[V].emplace_back(&DI, dl, SDNodeOrder); - return nullptr; - } - - LLVM_DEBUG(dbgs() << "Dropping debug location info for:\n " << DI << "\n"); - LLVM_DEBUG(dbgs() << " Last seen at:\n " << *V << "\n"); + DanglingDebugInfoMap[V].emplace_back(&DI, dl, SDNodeOrder); return nullptr; } Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -691,6 +691,7 @@ // Make sure the root of the DAG is up-to-date. CurDAG->setRoot(SDB->getControlRoot()); HadTailCall = SDB->HasTailCall; + SDB->resolveOrClearDbgInfo(); SDB->clear(); // Final step, emit the lowered DAG as machine code. Index: test/DebugInfo/X86/sdag-dangling-dbgvalue.ll =================================================================== --- test/DebugInfo/X86/sdag-dangling-dbgvalue.ll +++ test/DebugInfo/X86/sdag-dangling-dbgvalue.ll @@ -101,6 +101,7 @@ ; Verify that the def comes before the for bar4. define i32 @test4() local_unnamed_addr #0 !dbg !40 { ; CHECK-LABEL: bb.0.entry4 +; CHECK-NEXT: DBG_VALUE $noreg, $noreg, ![[FOO4]], !DIExpression() ; CHECK-NEXT: DBG_VALUE 0, $noreg, ![[FOO4]], !DIExpression() ; CHECK-NEXT: [[REG4:%[0-9]+]]:gr64 = ; CHECK-NEXT: DBG_VALUE [[REG4]], $noreg, ![[BAR4]], !DIExpression() @@ -114,6 +115,7 @@ ; Verify that we do not get a DBG_VALUE that maps foo5 to @S here. define i32 @test5() local_unnamed_addr #0 !dbg !47 { ; CHECK-LABEL: bb.0.entry5: +; CHECK-NEXT: DBG_VALUE $noreg, $noreg, ![[FOO5]], !DIExpression() ; CHECK-NEXT: DBG_VALUE 0, $noreg, ![[FOO5]], !DIExpression() ; CHECK-NEXT: [[REG5:%[0-9]+]]:gr64 = ; CHECK-NEXT: DBG_VALUE [[REG5]], $noreg, ![[BAR5]], !DIExpression() Index: test/DebugInfo/X86/sdag-ir-salvage.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/sdag-ir-salvage.ll @@ -0,0 +1,55 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown -start-after=codegenprepare -stop-before expand-isel-pseudos %s -o - | FileCheck %s + +; Test that the dbg.value for %baz, which doesn't exist in the 'next' bb, +; can be salvaged back to the underlying argument vreg. + +; CHECK: ![[AAAVAR:.*]] = !DILocalVariable(name: "aaa", +; CHECK: DBG_VALUE %{{[0-9]+}}, $noreg, ![[AAAVAR]] + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-linux-gnu" + +define i8 @f(i32* %foo) local_unnamed_addr !dbg !6 { +entry: + %bar = getelementptr i32, i32* %foo, i32 4 + %baz = bitcast i32* %bar to i8* + %quux = load i8, i8* %baz + br label %next + +next: ; preds = %entry + tail call void @llvm.dbg.value(metadata i8* %baz, metadata !15, metadata !DIExpression()), !dbg !30 + %xyzzy = add i8 %quux, 123 + br label %fin + +fin: ; preds = %next + %trains = getelementptr i32, i32* %foo, i32 3 + %planes = bitcast i32* %trains to i8* + %cars = load i8, i8* %planes + %ret = add i8 %xyzzy, %cars + ret i8 %ret +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!25, !26, !27, !28} +!llvm.ident = !{!29} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "test.c", directory: ".") +!2 = !{} +!6 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 18, type: !7, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14) +!7 = !DISubroutineType(types: !8) +!8 = !{!13} +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_unsigned) +!14 = !{!15} +!15 = !DILocalVariable(name: "aaa", scope: !6, file: !1, line: 18, type: !13) +!25 = !{i32 2, !"Dwarf Version", i32 4} +!26 = !{i32 2, !"Debug Info Version", i32 3} +!27 = !{i32 1, !"wchar_size", i32 4} +!28 = !{i32 7, !"PIC Level", i32 2} +!29 = !{!"clang"} +!30 = !DILocation(line: 18, column: 14, scope: !6)