Skip to content

Commit c727056

Browse files
committed
Partial Reapply "[DebugInfo] Use variadic debug values to salvage BinOps and GEP instrs with non-const operands"
This is a partial reapply of the original commit and the followup commit that were previously reverted; this reapply also includes a small fix for a potential source of non-determinism, but also has a small change to turn off variadic debug value salvaging, to ensure that any future revert/reapply steps to disable and renable this feature do not risk causing conflicts. Differential Revision: https://reviews.llvm.org/D91722 This reverts commit 386b66b.
1 parent 2daf117 commit c727056

File tree

18 files changed

+471
-138
lines changed

18 files changed

+471
-138
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2592,6 +2592,16 @@ class DIExpression : public MDNode {
25922592
// return it's sign information.
25932593
llvm::Optional<SignedOrUnsignedConstant> isConstant() const;
25942594

2595+
/// Return the number of unique location operands referred to (via
2596+
/// DW_OP_LLVM_arg) in this expression; this is not necessarily the number of
2597+
/// instances of DW_OP_LLVM_arg within the expression.
2598+
/// For example, for the expression:
2599+
/// (DW_OP_LLVM_arg 0, DW_OP_LLVM_arg 1, DW_OP_plus,
2600+
/// DW_OP_LLVM_arg 0, DW_OP_mul)
2601+
/// This function would return 2, as there are two unique location operands
2602+
/// (0 and 1).
2603+
uint64_t getNumLocationOperands() const;
2604+
25952605
using element_iterator = ArrayRef<uint64_t>::iterator;
25962606

25972607
element_iterator elements_begin() const { return getElements().begin(); }
@@ -2739,6 +2749,10 @@ class DIExpression : public MDNode {
27392749
/// return true with an offset of zero.
27402750
bool extractIfOffset(int64_t &Offset) const;
27412751

2752+
/// Returns true iff this DIExpression contains at least one instance of
2753+
/// `DW_OP_LLVM_arg, n` for all n in [0, N).
2754+
bool hasAllLocationOps(unsigned N) const;
2755+
27422756
/// Checks if the last 4 elements of the expression are DW_OP_constu <DWARF
27432757
/// Address Space> DW_OP_swap DW_OP_xderef and extracts the <DWARF Address
27442758
/// Space>.

llvm/include/llvm/IR/Instructions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "llvm/ADT/ArrayRef.h"
1919
#include "llvm/ADT/Bitfields.h"
20+
#include "llvm/ADT/MapVector.h"
2021
#include "llvm/ADT/None.h"
2122
#include "llvm/ADT/STLExtras.h"
2223
#include "llvm/ADT/SmallVector.h"
@@ -1152,7 +1153,9 @@ class GetElementPtrInst : public Instruction {
11521153
/// must be at least as wide as the IntPtr type for the address space of
11531154
/// the base GEP pointer.
11541155
bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const;
1155-
1156+
bool collectOffset(const DataLayout &DL, unsigned BitWidth,
1157+
MapVector<Value *, APInt> &VariableOffsets,
1158+
APInt &ConstantOffset) const;
11561159
// Methods for support type inquiry through isa, cast, and dyn_cast:
11571160
static bool classof(const Instruction *I) {
11581161
return (I->getOpcode() == Instruction::GetElementPtr);

llvm/include/llvm/IR/IntrinsicInst.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ class DbgVariableIntrinsic : public DbgInfoIntrinsic {
204204

205205
void replaceVariableLocationOp(Value *OldValue, Value *NewValue);
206206
void replaceVariableLocationOp(unsigned OpIdx, Value *NewValue);
207+
/// Adding a new location operand will always result in this intrinsic using
208+
/// an ArgList, and must always be accompanied by a new expression that uses
209+
/// the new operand.
210+
void addVariableLocationOps(ArrayRef<Value *> NewValues,
211+
DIExpression *NewExpr);
207212

208213
void setVariable(DILocalVariable *NewVar) {
209214
setArgOperand(1, MetadataAsValue::get(NewVar->getContext(), NewVar));

llvm/include/llvm/IR/Operator.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_IR_OPERATOR_H
1515
#define LLVM_IR_OPERATOR_H
1616

17+
#include "llvm/ADT/MapVector.h"
1718
#include "llvm/ADT/None.h"
1819
#include "llvm/ADT/Optional.h"
1920
#include "llvm/IR/Constants.h"
@@ -576,6 +577,12 @@ class GEPOperator
576577
Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
577578
APInt &Offset,
578579
function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
580+
581+
/// Collect the offset of this GEP as a map of Values to their associated
582+
/// APInt multipliers, as well as a total Constant Offset.
583+
bool collectOffset(const DataLayout &DL, unsigned BitWidth,
584+
MapVector<Value *, APInt> &VariableOffsets,
585+
APInt &ConstantOffset) const;
579586
};
580587

581588
class PtrToIntOperator

llvm/include/llvm/Transforms/Utils/Local.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ void salvageDebugInfoForDbgValues(Instruction &I,
298298
/// appended to the expression. \p LocNo: the index of the location operand to
299299
/// which \p I applies, should be 0 for debug info without a DIArgList.
300300
DIExpression *salvageDebugInfoImpl(Instruction &I, DIExpression *DIExpr,
301-
bool StackVal, unsigned LocNo);
301+
bool StackVal, unsigned LocNo,
302+
SmallVectorImpl<Value *> &AdditionalValues);
302303

303304
/// Point debug users of \p From to \p To or salvage them. Use this function
304305
/// only when replacing all uses of \p From with \p To, with a guarantee that

llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,6 @@ class DbgValueLoc {
121121
// Currently, DBG_VALUE_VAR expressions must use stack_value.
122122
assert(Expr && Expr->isValid() &&
123123
is_contained(Locs, dwarf::DW_OP_stack_value));
124-
for (DbgValueLocEntry &Entry : ValueLocEntries) {
125-
assert(!Entry.isConstantFP() && !Entry.isConstantInt() &&
126-
"Constant values should only be present in non-variadic "
127-
"DBG_VALUEs.");
128-
}
129124
#endif
130125
}
131126

@@ -142,11 +137,6 @@ class DbgValueLoc {
142137
// Currently, DBG_VALUE_VAR expressions must use stack_value.
143138
assert(Expr && Expr->isValid() &&
144139
is_contained(Expr->getElements(), dwarf::DW_OP_stack_value));
145-
for (DbgValueLocEntry &Entry : ValueLocEntries) {
146-
assert(!Entry.isConstantFP() && !Entry.isConstantInt() &&
147-
"Constant values should only be present in non-variadic "
148-
"DBG_VALUEs.");
149-
}
150140
}
151141
#endif
152142
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,10 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
12481248
}
12491249

12501250
void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
1251+
// TODO: For the variadic implementation, instead of only checking the fail
1252+
// state of `handleDebugValue`, we need know specifically which values were
1253+
// invalid, so that we attempt to salvage only those values when processing
1254+
// a DIArgList.
12511255
assert(!DDI.getDI()->hasArgList() &&
12521256
"Not implemented for variadic dbg_values");
12531257
Value *V = DDI.getDI()->getValue(0);
@@ -1271,16 +1275,21 @@ void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
12711275
while (isa<Instruction>(V)) {
12721276
Instruction &VAsInst = *cast<Instruction>(V);
12731277
// Temporary "0", awaiting real implementation.
1274-
DIExpression *NewExpr = salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0);
1278+
SmallVector<Value *, 4> AdditionalValues;
1279+
DIExpression *SalvagedExpr =
1280+
salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0, AdditionalValues);
12751281

12761282
// If we cannot salvage any further, and haven't yet found a suitable debug
12771283
// expression, bail out.
1278-
if (!NewExpr)
1284+
// TODO: If AdditionalValues isn't empty, then the salvage can only be
1285+
// represented with a DBG_VALUE_LIST, so we give up. When we have support
1286+
// here for variadic dbg_values, remove that condition.
1287+
if (!SalvagedExpr || !AdditionalValues.empty())
12791288
break;
12801289

12811290
// New value and expr now represent this debuginfo.
12821291
V = VAsInst.getOperand(0);
1283-
Expr = NewExpr;
1292+
Expr = SalvagedExpr;
12841293

12851294
// Some kind of simplification occurred: check whether the operand of the
12861295
// salvaged debug expression can be encoded in this DAG.

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,17 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
12511251
return false;
12521252
}
12531253

1254+
bool DIExpression::hasAllLocationOps(unsigned N) const {
1255+
SmallDenseSet<uint64_t, 4> SeenOps;
1256+
for (auto ExprOp : expr_ops())
1257+
if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
1258+
SeenOps.insert(ExprOp.getArg(0));
1259+
for (uint64_t Idx = 0; Idx < N; ++Idx)
1260+
if (!is_contained(SeenOps, Idx))
1261+
return false;
1262+
return true;
1263+
}
1264+
12541265
const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
12551266
unsigned &AddrClass) {
12561267
// FIXME: This seems fragile. Nothing that verifies that these elements
@@ -1465,6 +1476,16 @@ Optional<DIExpression *> DIExpression::createFragmentExpression(
14651476
return DIExpression::get(Expr->getContext(), Ops);
14661477
}
14671478

1479+
uint64_t DIExpression::getNumLocationOperands() const {
1480+
uint64_t Result = 0;
1481+
for (auto ExprOp : expr_ops())
1482+
if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
1483+
Result = std::max(Result, ExprOp.getArg(0) + 1);
1484+
assert(hasAllLocationOps(Result) &&
1485+
"Expression is missing one or more location operands.");
1486+
return Result;
1487+
}
1488+
14681489
llvm::Optional<DIExpression::SignedOrUnsignedConstant>
14691490
DIExpression::isConstant() const {
14701491

llvm/lib/IR/Instructions.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,6 +1804,15 @@ bool GetElementPtrInst::accumulateConstantOffset(const DataLayout &DL,
18041804
return cast<GEPOperator>(this)->accumulateConstantOffset(DL, Offset);
18051805
}
18061806

1807+
bool GetElementPtrInst::collectOffset(
1808+
const DataLayout &DL, unsigned BitWidth,
1809+
MapVector<Value *, APInt> &VariableOffsets,
1810+
APInt &ConstantOffset) const {
1811+
// Delegate to the generic GEPOperator implementation.
1812+
return cast<GEPOperator>(this)->collectOffset(DL, BitWidth, VariableOffsets,
1813+
ConstantOffset);
1814+
}
1815+
18071816
//===----------------------------------------------------------------------===//
18081817
// ExtractElementInst Implementation
18091818
//===----------------------------------------------------------------------===//

llvm/lib/IR/IntrinsicInst.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ void DbgVariableIntrinsic::replaceVariableLocationOp(unsigned OpIdx,
118118
0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
119119
}
120120

121+
void DbgVariableIntrinsic::addVariableLocationOps(ArrayRef<Value *> NewValues,
122+
DIExpression *NewExpr) {
123+
assert(NewExpr->hasAllLocationOps(getNumVariableLocationOps() +
124+
NewValues.size()) &&
125+
"NewExpr for debug variable intrinsic does not reference every "
126+
"location operand.");
127+
assert(!is_contained(NewValues, nullptr) && "New values must be non-null");
128+
setArgOperand(2, MetadataAsValue::get(getContext(), NewExpr));
129+
SmallVector<ValueAsMetadata *, 4> MDs;
130+
for (auto *VMD : location_ops())
131+
MDs.push_back(getAsMetadata(VMD));
132+
for (auto *VMD : NewValues)
133+
MDs.push_back(getAsMetadata(VMD));
134+
setArgOperand(
135+
0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
136+
}
137+
121138
Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
122139
if (auto Fragment = getExpression()->getFragmentInfo())
123140
return Fragment->SizeInBits;

llvm/lib/IR/Operator.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,61 @@ bool GEPOperator::accumulateConstantOffset(
142142
}
143143
return true;
144144
}
145+
146+
bool GEPOperator::collectOffset(
147+
const DataLayout &DL, unsigned BitWidth,
148+
MapVector<Value *, APInt> &VariableOffsets,
149+
APInt &ConstantOffset) const {
150+
assert(BitWidth == DL.getIndexSizeInBits(getPointerAddressSpace()) &&
151+
"The offset bit width does not match DL specification.");
152+
153+
auto CollectConstantOffset = [&](APInt Index, uint64_t Size) {
154+
Index = Index.sextOrTrunc(BitWidth);
155+
APInt IndexedSize = APInt(BitWidth, Size);
156+
ConstantOffset += Index * IndexedSize;
157+
};
158+
159+
for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this);
160+
GTI != GTE; ++GTI) {
161+
// Scalable vectors are multiplied by a runtime constant.
162+
bool ScalableType = isa<ScalableVectorType>(GTI.getIndexedType());
163+
164+
Value *V = GTI.getOperand();
165+
StructType *STy = GTI.getStructTypeOrNull();
166+
// Handle ConstantInt if possible.
167+
if (auto ConstOffset = dyn_cast<ConstantInt>(V)) {
168+
if (ConstOffset->isZero())
169+
continue;
170+
// If the type is scalable and the constant is not zero (vscale * n * 0 =
171+
// 0) bailout.
172+
// TODO: If the runtime value is accessible at any point before DWARF
173+
// emission, then we could potentially keep a forward reference to it
174+
// in the debug value to be filled in later.
175+
if (ScalableType)
176+
return false;
177+
// Handle a struct index, which adds its field offset to the pointer.
178+
if (STy) {
179+
unsigned ElementIdx = ConstOffset->getZExtValue();
180+
const StructLayout *SL = DL.getStructLayout(STy);
181+
// Element offset is in bytes.
182+
CollectConstantOffset(APInt(BitWidth, SL->getElementOffset(ElementIdx)),
183+
1);
184+
continue;
185+
}
186+
CollectConstantOffset(ConstOffset->getValue(),
187+
DL.getTypeAllocSize(GTI.getIndexedType()));
188+
continue;
189+
}
190+
191+
if (STy || ScalableType)
192+
return false;
193+
// Insert an initial offset of 0 for V iff none exists already, then
194+
// increment the offset by IndexedSize.
195+
VariableOffsets.insert({V, APInt(BitWidth, 0)});
196+
APInt IndexedSize =
197+
APInt(BitWidth, DL.getTypeAllocSize(GTI.getIndexedType()));
198+
VariableOffsets[V] += IndexedSize;
199+
}
200+
return true;
201+
}
145202
} // namespace llvm

llvm/lib/Transforms/Coroutines/CoroFrame.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,10 +2488,15 @@ void coro::salvageDebugInfo(
24882488
} else if (auto *StInst = dyn_cast<StoreInst>(Storage)) {
24892489
Storage = StInst->getOperand(0);
24902490
} else if (auto *GEPInst = dyn_cast<GetElementPtrInst>(Storage)) {
2491-
Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr,
2492-
/*WithStackValue=*/false, 0);
2493-
if (!Expr)
2494-
return;
2491+
SmallVector<Value *> AdditionalValues;
2492+
DIExpression *SalvagedExpr = llvm::salvageDebugInfoImpl(
2493+
*GEPInst, Expr,
2494+
/*WithStackValue=*/false, 0, AdditionalValues);
2495+
// Debug declares cannot currently handle additional location
2496+
// operands.
2497+
if (!SalvagedExpr || !AdditionalValues.empty())
2498+
break;
2499+
Expr = SalvagedExpr;
24952500
Storage = GEPInst->getOperand(0);
24962501
} else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
24972502
Storage = BCInst->getOperand(0);

0 commit comments

Comments
 (0)