Skip to content

Commit 791930d

Browse files
committed
Re-reapply "[DebugInfo] Use variadic debug values to salvage BinOps and GEP instrs with non-const operands"
Previous build failures were caused by an error in bitcode reading and writing for DIArgList metadata, which has been fixed in e5d844b. There were also some unnecessary asserts that were being triggered on certain builds, which have been removed. This reverts commit dad5caa.
1 parent 151e244 commit 791930d

File tree

18 files changed

+399
-142
lines changed

18 files changed

+399
-142
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

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

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

25992609
element_iterator elements_begin() const { return getElements().begin(); }
@@ -2741,6 +2751,10 @@ class DIExpression : public MDNode {
27412751
/// return true with an offset of zero.
27422752
bool extractIfOffset(int64_t &Offset) const;
27432753

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

llvm/include/llvm/IR/Instructions.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,9 @@ class GetElementPtrInst : public Instruction {
11221122
/// must be at least as wide as the IntPtr type for the address space of
11231123
/// the base GEP pointer.
11241124
bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const;
1125-
1125+
bool collectOffset(const DataLayout &DL, unsigned BitWidth,
1126+
SmallDenseMap<Value *, APInt, 8> &VariableOffsets,
1127+
APInt &ConstantOffset) const;
11261128
// Methods for support type inquiry through isa, cast, and dyn_cast:
11271129
static bool classof(const Instruction *I) {
11281130
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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,12 @@ class GEPOperator
576576
Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
577577
APInt &Offset,
578578
function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
579+
580+
/// Collect the offset of this GEP as a map of Values to their associated
581+
/// APInt multipliers, as well as a total Constant Offset.
582+
bool collectOffset(const DataLayout &DL, unsigned BitWidth,
583+
SmallDenseMap<Value *, APInt, 8> &VariableOffsets,
584+
APInt &ConstantOffset) const;
579585
};
580586

581587
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
@@ -1238,6 +1238,10 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
12381238
}
12391239

12401240
void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
1241+
// TODO: For the variadic implementation, instead of only checking the fail
1242+
// state of `handleDebugValue`, we need know specifically which values were
1243+
// invalid, so that we attempt to salvage only those values when processing
1244+
// a DIArgList.
12411245
assert(!DDI.getDI()->hasArgList() &&
12421246
"Not implemented for variadic dbg_values");
12431247
Value *V = DDI.getDI()->getValue(0);
@@ -1261,16 +1265,21 @@ void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
12611265
while (isa<Instruction>(V)) {
12621266
Instruction &VAsInst = *cast<Instruction>(V);
12631267
// Temporary "0", awaiting real implementation.
1264-
DIExpression *NewExpr = salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0);
1268+
SmallVector<Value *, 4> AdditionalValues;
1269+
DIExpression *SalvagedExpr =
1270+
salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0, AdditionalValues);
12651271

12661272
// If we cannot salvage any further, and haven't yet found a suitable debug
12671273
// expression, bail out.
1268-
if (!NewExpr)
1274+
// TODO: If AdditionalValues isn't empty, then the salvage can only be
1275+
// represented with a DBG_VALUE_LIST, so we give up. When we have support
1276+
// here for variadic dbg_values, remove that condition.
1277+
if (!SalvagedExpr || !AdditionalValues.empty())
12691278
break;
12701279

12711280
// New value and expr now represent this debuginfo.
12721281
V = VAsInst.getOperand(0);
1273-
Expr = NewExpr;
1282+
Expr = SalvagedExpr;
12741283

12751284
// Some kind of simplification occurred: check whether the operand of the
12761285
// 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
@@ -1244,6 +1244,17 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
12441244
return false;
12451245
}
12461246

1247+
bool DIExpression::hasAllLocationOps(unsigned N) const {
1248+
SmallDenseSet<uint64_t, 4> SeenOps;
1249+
for (auto ExprOp : expr_ops())
1250+
if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
1251+
SeenOps.insert(ExprOp.getArg(0));
1252+
for (uint64_t Idx = 0; Idx < N; ++Idx)
1253+
if (!is_contained(SeenOps, Idx))
1254+
return false;
1255+
return true;
1256+
}
1257+
12471258
const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
12481259
unsigned &AddrClass) {
12491260
// FIXME: This seems fragile. Nothing that verifies that these elements
@@ -1458,6 +1469,16 @@ Optional<DIExpression *> DIExpression::createFragmentExpression(
14581469
return DIExpression::get(Expr->getContext(), Ops);
14591470
}
14601471

1472+
uint64_t DIExpression::getNumLocationOperands() const {
1473+
uint64_t Result = 0;
1474+
for (auto ExprOp : expr_ops())
1475+
if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
1476+
Result = std::max(Result, ExprOp.getArg(0) + 1);
1477+
assert(hasAllLocationOps(Result) &&
1478+
"Expression is missing one or more location operands.");
1479+
return Result;
1480+
}
1481+
14611482
llvm::Optional<DIExpression::SignedOrUnsignedConstant>
14621483
DIExpression::isConstant() const {
14631484

llvm/lib/IR/Instructions.cpp

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

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

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+
SmallDenseMap<Value *, APInt, 8> &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.try_emplace(V, 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
@@ -2101,10 +2101,15 @@ void coro::salvageDebugInfo(
21012101
} else if (auto *StInst = dyn_cast<StoreInst>(Storage)) {
21022102
Storage = StInst->getOperand(0);
21032103
} else if (auto *GEPInst = dyn_cast<GetElementPtrInst>(Storage)) {
2104-
Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr,
2105-
/*WithStackValue=*/false, 0);
2106-
if (!Expr)
2107-
return;
2104+
SmallVector<Value *> AdditionalValues;
2105+
DIExpression *SalvagedExpr = llvm::salvageDebugInfoImpl(
2106+
*GEPInst, Expr,
2107+
/*WithStackValue=*/false, 0, AdditionalValues);
2108+
// Debug declares cannot currently handle additional location
2109+
// operands.
2110+
if (!SalvagedExpr || !AdditionalValues.empty())
2111+
break;
2112+
Expr = SalvagedExpr;
21082113
Storage = GEPInst->getOperand(0);
21092114
} else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
21102115
Storage = BCInst->getOperand(0);

0 commit comments

Comments
 (0)