[SelectionDAG] Improve handling of dangling debug info
Summary:
1) Make sure to discard dangling debug info if the variable (or
variable fragment) is mapped to something new before we had a
chance to resolve the dangling debug info.
2) When resolving debug info, make sure to bump the associated
SDNodeOrder to ensure that the DBG_VALUE is emitted after the
instruction that defines the value used in the DBG_VALUE.
This will avoid a debug-use before def scenario as seen in
https://bugs.llvm.org/show_bug.cgi?id=36417.
The new test case, test/DebugInfo/X86/sdag-dangling-dbgvalue.ll,
show some other limitations in how dangling debug info is
handled in the SelectionDAG. Since we currently only support
having one dangling dbg.value per Value, we will end up dropping
debug info when there are more than one variable that is described
by the same "dangling value".
Reviewers: aprantl
Reviewed By: aprantl
Subscribers: aprantl, eraman, llvm-commits, JDevlieghere
Tags: #debug-info
Differential Revision: https://reviews.llvm.org/D44369
llvm-svn: 327303
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index f05f0be2..df6b101 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "SelectionDAGBuilder.h"
+#include "SDNodeDbgValue.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
@@ -1077,29 +1078,64 @@
}
}
+void SelectionDAGBuilder::dropDanglingDebugInfo(const DILocalVariable *Variable,
+ const DIExpression *Expr) {
+ SmallVector<const Value *, 4> ToRemove;
+ for (auto &DMI : DanglingDebugInfoMap) {
+ DanglingDebugInfo &DDI = DMI.second;
+ if (DDI.getDI()) {
+ const DbgValueInst *DI = DDI.getDI();
+ DIVariable *DanglingVariable = DI->getVariable();
+ DIExpression *DanglingExpr = DI->getExpression();
+ if (DanglingVariable == Variable &&
+ Expr->fragmentsOverlap(DanglingExpr)) {
+ DEBUG(dbgs() << "Dropping dangling debug info for " << *DI << "\n");
+ ToRemove.push_back(DMI.first);
+ }
+ }
+ }
+
+ for (auto V : ToRemove)
+ DanglingDebugInfoMap[V] = DanglingDebugInfo();
+}
+
// resolveDanglingDebugInfo - if we saw an earlier dbg_value referring to V,
// generate the debug data structures now that we've seen its definition.
void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
SDValue Val) {
DanglingDebugInfo &DDI = DanglingDebugInfoMap[V];
- if (DDI.getDI()) {
- const DbgValueInst *DI = DDI.getDI();
- DebugLoc dl = DDI.getdl();
- unsigned DbgSDNodeOrder = DDI.getSDNodeOrder();
- DILocalVariable *Variable = DI->getVariable();
- DIExpression *Expr = DI->getExpression();
- assert(Variable->isValidLocationForIntrinsic(dl) &&
- "Expected inlined-at fields to agree");
- SDDbgValue *SDV;
- if (Val.getNode()) {
- if (!EmitFuncArgumentDbgValue(V, Variable, Expr, dl, false, Val)) {
- SDV = getDbgValue(Val, Variable, Expr, dl, DbgSDNodeOrder);
- DAG.AddDbgValue(SDV, Val.getNode(), false);
- }
+ if (!DDI.getDI())
+ return;
+ const DbgValueInst *DI = DDI.getDI();
+ DebugLoc dl = DDI.getdl();
+ unsigned ValSDNodeOrder = Val.getNode()->getIROrder();
+ unsigned DbgSDNodeOrder = DDI.getSDNodeOrder();
+ DILocalVariable *Variable = DI->getVariable();
+ DIExpression *Expr = DI->getExpression();
+ assert(Variable->isValidLocationForIntrinsic(dl) &&
+ "Expected inlined-at fields to agree");
+ SDDbgValue *SDV;
+ if (Val.getNode()) {
+ if (!EmitFuncArgumentDbgValue(V, Variable, Expr, dl, false, Val)) {
+ DEBUG(dbgs() << "Resolve dangling debug info [order=" << DbgSDNodeOrder
+ << "] for:\n " << *DI << "\n");
+ DEBUG(dbgs() << " By mapping to:\n "; Val.dump());
+ // Increase the SDNodeOrder for the DbgValue here to make sure it is
+ // inserted after the definition of Val when emitting the instructions
+ // after ISel. An alternative could be to teach
+ // ScheduleDAGSDNodes::EmitSchedule to delay the insertion properly.
+ DEBUG(if (ValSDNodeOrder > DbgSDNodeOrder)
+ dbgs() << "changing SDNodeOrder from " << DbgSDNodeOrder
+ << " to " << ValSDNodeOrder << "\n");
+ SDV = getDbgValue(Val, Variable, Expr, dl,
+ std::max(DbgSDNodeOrder, ValSDNodeOrder));
+ DAG.AddDbgValue(SDV, Val.getNode(), false);
} else
- DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n");
- DanglingDebugInfoMap[V] = DanglingDebugInfo();
- }
+ DEBUG(dbgs() << "Resolved dangling debug info for " << *DI
+ << "in EmitFuncArgumentDbgValue\n");
+ } else
+ DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n");
+ DanglingDebugInfoMap[V] = DanglingDebugInfo();
}
/// getCopyFromRegs - If there was virtual register allocated for the value V
@@ -5178,6 +5214,7 @@
const DbgInfoIntrinsic &DI = cast<DbgInfoIntrinsic>(I);
DILocalVariable *Variable = DI.getVariable();
DIExpression *Expression = DI.getExpression();
+ dropDanglingDebugInfo(Variable, Expression);
assert(Variable && "Missing variable");
// Check if address has undef value.
@@ -5209,10 +5246,11 @@
// DBG_VALUE instructions. llvm.dbg.declare is handled as a frame index in
// the MachineFunction variable table.
if (FI != std::numeric_limits<int>::max()) {
- if (Intrinsic == Intrinsic::dbg_addr)
- DAG.AddDbgValue(DAG.getFrameIndexDbgValue(Variable, Expression, FI, dl,
- SDNodeOrder),
- getRoot().getNode(), isParameter);
+ if (Intrinsic == Intrinsic::dbg_addr) {
+ SDDbgValue *SDV = DAG.getFrameIndexDbgValue(Variable, Expression,
+ FI, dl, SDNodeOrder);
+ DAG.AddDbgValue(SDV, getRoot().getNode(), isParameter);
+ }
return nullptr;
}
@@ -5256,6 +5294,7 @@
DILocalVariable *Variable = DI.getVariable();
DIExpression *Expression = DI.getExpression();
+ dropDanglingDebugInfo(Variable, Expression);
const Value *V = DI.getValue();
if (!V)
return nullptr;
@@ -5280,6 +5319,12 @@
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.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index 9e7c2bc..3d58a04 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -671,6 +671,12 @@
/// emit CopyFromReg of the specified type Ty. Return empty SDValue() otherwise.
SDValue getCopyFromRegs(const Value *V, Type *Ty);
+ /// If we have dangling debug info that describes \p Variable, or an
+ /// overlapping part of variable considering the \p Expr, then this method
+ /// weill drop that debug info as it isn't valid any longer.
+ void dropDanglingDebugInfo(const DILocalVariable *Variable,
+ const DIExpression *Expr);
+
// resolveDanglingDebugInfo - 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);