From: Jeremy Morse Date: Wed, 13 Feb 2019 16:33:05 +0000 (+0000) Subject: [DebugInfo][DAG] Either salvage dangling debug info or emit Undef DBG_VALUEs X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=826e231bb6f77b2f066d73393e9ce66733266d15;p=llvm [DebugInfo][DAG] Either salvage dangling debug info or emit Undef DBG_VALUEs In this patch SelectionDAG tries to salvage any dbg.values that are going to be dropped, in case they can be recovered from Values in the current BB. It also strengthens SelectionDAGs handling of dangling debug data, so that dbg.values are *always* emitted (as Undef or otherwise) instead of dangling forever. The motivation behind this patch exists in the new test case: a memory address (here a bitcast and GEP) exist in one basic block, and a dbg.value referring to the address is left in the 'next' block. The base pointer is live across all basic blocks. In current llvm trunk the dbg.value cannot be encoded, and it isn't even emitted as an Undef DBG_VALUE. The change is simply: if we're definitely going to drop a dbg.value, repeatedly apply salvageDebugInfo to its operand until either we find something that can be encoded, or we can't salvage any further in which case we produce an Undef DBG_VALUE. To know when we're "definitely going to drop a dbg.value", SelectionDAG signals SelectionDAGBuilder when all IR instructions have been encoded to force salvaging. This ensures that any dbg.value that's dangling after DAG creation will have a corresponding DBG_VALUE encoded. Differential Revision: https://reviews.llvm.org/D57694 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353954 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 23655a87dbf..5b62a568197 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/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 @@ void SelectionDAGBuilder::dropDanglingDebugInfo(const DILocalVariable *Variable, 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)) + salvageUnresolvedDbgValue(DDI); + DDIV.erase(remove_if(DDIV, isMatchingDbgValue), DDIV.end()); } } @@ -1179,12 +1187,73 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V, } 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(DDI.getDI()->getVariableLocation()->getType()); + auto SDV = + DAG.getConstantDbgValue(Variable, Expr, Undef, dl, DbgSDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); + } } DDIV.clear(); } +void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) { + Value *V = DDI.getDI()->getValue(); + DILocalVariable *Var = DDI.getDI()->getVariable(); + DIExpression *Expr = DDI.getDI()->getExpression(); + DebugLoc DL = DDI.getdl(); + DebugLoc InstDL = DDI.getDI()->getDebugLoc(); + 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, InstDL, 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) + 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, InstDL, 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(DDI.getDI()->getVariableLocation()->getType()); + auto SDV = DAG.getConstantDbgValue(Var, Expr, Undef, DL, SDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); + + LLVM_DEBUG(dbgs() << "Dropping debug value 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, DebugLoc InstDL, unsigned Order) { @@ -1277,6 +1346,14 @@ bool SelectionDAGBuilder::handleDebugValue(const Value *V, DILocalVariable *Var, 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()) + salvageUnresolvedDbgValue(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) { @@ -5552,21 +5629,12 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { 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; - } + // TODO: Dangling debug info will eventually either be resolved or produce + // an Undef DBG_VALUE. However in the resolution case, a gap may appear + // between the original dbg.value location and its resolved DBG_VALUE, which + // we should ideally fill with an extra Undef DBG_VALUE. - 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; } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 2b0a5f891c0..e84214dbf5e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -676,16 +676,24 @@ public: void dropDanglingDebugInfo(const DILocalVariable *Variable, const DIExpression *Expr); - // If we saw an earlier dbg_value referring to V, generate the debug data - // structures now that we've seen its definition. + /// If we saw an earlier dbg_value referring to V, generate the debug data + /// structures now that we've seen its definition. void resolveDanglingDebugInfo(const Value *V, SDValue Val); - // For a given Value, attempt to create and record a SDDbgValue in the - // SelectionDAG. + /// 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 salvageUnresolvedDbgValue(DanglingDebugInfo &DDI); + + /// For a given Value, attempt to create and record a SDDbgValue in the + /// SelectionDAG. bool handleDebugValue(const Value *V, DILocalVariable *Var, DIExpression *Expr, DebugLoc CurDL, DebugLoc InstDL, 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; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 4eabab45e28..173919378ae 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -691,6 +691,7 @@ void SelectionDAGISel::SelectBasicBlock(BasicBlock::const_iterator Begin, // 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. diff --git a/test/DebugInfo/X86/sdag-dangling-dbgvalue.ll b/test/DebugInfo/X86/sdag-dangling-dbgvalue.ll index ca7cfb82571..34c97f7a4c0 100644 --- a/test/DebugInfo/X86/sdag-dangling-dbgvalue.ll +++ b/test/DebugInfo/X86/sdag-dangling-dbgvalue.ll @@ -101,6 +101,7 @@ entry3: ; 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 @@ entry4: ; 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() diff --git a/test/DebugInfo/X86/sdag-ir-salvage.ll b/test/DebugInfo/X86/sdag-ir-salvage.ll new file mode 100644 index 00000000000..0bd5f18dd17 --- /dev/null +++ b/test/DebugInfo/X86/sdag-ir-salvage.ll @@ -0,0 +1,56 @@ +; 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-LABEL: bb.1.next: +; 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)