Skip to content

Commit c45e4c1

Browse files
author
Chris Jackson
committed
[Debuginfo][LSR] Add salvaging variadic dbg.value intrinsics [1/2] [NFC]
First of two patches that extends SCEV-based salvaging to enable salvaging of dbg.value instrinsics that have multiple locations ops before the Loop Strength Reduction pass. The existing single-op SCEV-based salvaging can generate variadic dbg.value intrinsics in order to salvage a dbg.value that has a single location op. If a dbg.value has multiple location ops before LSR, and LSR optimises away one or more of the location operands, then currently no salvaging will be attempted. Salvaging can now be added, but first this patch cleans up consistency in both the code and comments, and applies some refactoring to make application of the new salvaging implementation more straightforward. - Use SCEVDbgValueBuilder for both types of recovery expressions: IV-offset based and iteration count based. - Combine the functions that write the final DIExpression. - Move some static functions into member functions. Reviewers: @orlando Differential Revision: https://reviews.llvm.org/D120168
1 parent c10bbc2 commit c45e4c1

File tree

1 file changed

+115
-127
lines changed

1 file changed

+115
-127
lines changed

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp

Lines changed: 115 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -5914,15 +5914,17 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const {
59145914
namespace {
59155915
struct SCEVDbgValueBuilder {
59165916
SCEVDbgValueBuilder() = default;
5917-
SCEVDbgValueBuilder(const SCEVDbgValueBuilder &Base) {
5917+
SCEVDbgValueBuilder(const SCEVDbgValueBuilder &Base) { clone(Base); }
5918+
5919+
void clone(const SCEVDbgValueBuilder &Base) {
59185920
Values = Base.Values;
59195921
Expr = Base.Expr;
59205922
}
59215923

59225924
/// The DIExpression as we translate the SCEV.
59235925
SmallVector<uint64_t, 6> Expr;
59245926
/// The location ops of the DIExpression.
5925-
SmallVector<llvm::ValueAsMetadata *, 2> Values;
5927+
SmallVector<Value *, 2> Values;
59265928

59275929
void pushOperator(uint64_t Op) { Expr.push_back(Op); }
59285930
void pushUInt(uint64_t Operand) { Expr.push_back(Operand); }
@@ -5931,14 +5933,13 @@ struct SCEVDbgValueBuilder {
59315933
/// in the set of values referenced by the expression.
59325934
void pushValue(llvm::Value *V) {
59335935
Expr.push_back(llvm::dwarf::DW_OP_LLVM_arg);
5934-
auto *It =
5935-
std::find(Values.begin(), Values.end(), llvm::ValueAsMetadata::get(V));
5936+
auto *It = std::find(Values.begin(), Values.end(), V);
59365937
unsigned ArgIndex = 0;
59375938
if (It != Values.end()) {
59385939
ArgIndex = std::distance(Values.begin(), It);
59395940
} else {
59405941
ArgIndex = Values.size();
5941-
Values.push_back(llvm::ValueAsMetadata::get(V));
5942+
Values.push_back(V);
59425943
}
59435944
Expr.push_back(ArgIndex);
59445945
}
@@ -6028,52 +6029,6 @@ struct SCEVDbgValueBuilder {
60286029
return Success;
60296030
}
60306031

6031-
void setFinalExpression(llvm::DbgValueInst &DI, const DIExpression *OldExpr) {
6032-
// Re-state assumption that this dbg.value is not variadic. Any remaining
6033-
// opcodes in its expression operate on a single value already on the
6034-
// expression stack. Prepend our operations, which will re-compute and
6035-
// place that value on the expression stack.
6036-
assert(!DI.hasArgList());
6037-
auto *NewExpr =
6038-
DIExpression::prependOpcodes(OldExpr, Expr, /*StackValue*/ true);
6039-
DI.setExpression(NewExpr);
6040-
6041-
auto ValArrayRef = llvm::ArrayRef<llvm::ValueAsMetadata *>(Values);
6042-
DI.setRawLocation(llvm::DIArgList::get(DI.getContext(), ValArrayRef));
6043-
}
6044-
6045-
/// If a DVI can be emitted without a DIArgList, omit DW_OP_llvm_arg and the
6046-
/// location op index 0.
6047-
void setShortFinalExpression(llvm::DbgValueInst &DI,
6048-
const DIExpression *OldExpr) {
6049-
assert((Expr[0] == llvm::dwarf::DW_OP_LLVM_arg && Expr[1] == 0) &&
6050-
"Expected DW_OP_llvm_arg and 0.");
6051-
DI.replaceVariableLocationOp(
6052-
0u, llvm::MetadataAsValue::get(DI.getContext(), Values[0]));
6053-
6054-
// See setFinalExpression: prepend our opcodes on the start of any old
6055-
// expression opcodes.
6056-
assert(!DI.hasArgList());
6057-
llvm::SmallVector<uint64_t, 6> FinalExpr(llvm::drop_begin(Expr, 2));
6058-
auto *NewExpr =
6059-
DIExpression::prependOpcodes(OldExpr, FinalExpr, /*StackValue*/ true);
6060-
DI.setExpression(NewExpr);
6061-
}
6062-
6063-
/// Once the IV and variable SCEV translation is complete, write it to the
6064-
/// source DVI.
6065-
void applyExprToDbgValue(llvm::DbgValueInst &DI,
6066-
const DIExpression *OldExpr) {
6067-
assert(!Expr.empty() && "Unexpected empty expression.");
6068-
// Emit a simpler form if only a single location is referenced.
6069-
if (Values.size() == 1 && Expr[0] == llvm::dwarf::DW_OP_LLVM_arg &&
6070-
Expr[1] == 0) {
6071-
setShortFinalExpression(DI, OldExpr);
6072-
} else {
6073-
setFinalExpression(DI, OldExpr);
6074-
}
6075-
}
6076-
60776032
/// Return true if the combination of arithmetic operator and underlying
60786033
/// SCEV constant value is an identity function.
60796034
bool isIdentityFunction(uint64_t Op, const SCEV *S) {
@@ -6122,6 +6077,44 @@ struct SCEVDbgValueBuilder {
61226077
return true;
61236078
}
61246079

6080+
/// Create an expression that is an offset from a value (usually the IV).
6081+
void createOffsetExpr(int64_t Offset, Value *OffsetValue) {
6082+
pushValue(OffsetValue);
6083+
DIExpression::appendOffset(Expr, Offset);
6084+
LLVM_DEBUG(
6085+
dbgs() << "scev-salvage: Generated IV offset expression. Offset: "
6086+
<< std::to_string(Offset) << "\n");
6087+
}
6088+
6089+
/// Combine a translation of the SCEV and the IV to create an expression that
6090+
/// recovers a location's value.
6091+
void createIterCountExpr(const SCEV *S,
6092+
const SCEVDbgValueBuilder &IterationCount,
6093+
ScalarEvolution &SE) {
6094+
// SCEVs for SSA values are most frquently of the form
6095+
// {start,+,stride}, but sometimes they are ({start,+,stride} + %a + ..).
6096+
// This is because %a is a PHI node that is not the IV. However, these
6097+
// SCEVs have not been observed to result in debuginfo-lossy optimisations,
6098+
// so its not expected this point will be reached.
6099+
if (!isa<SCEVAddRecExpr>(S))
6100+
return;
6101+
6102+
LLVM_DEBUG(dbgs() << "scev-salvage: Value to salvage SCEV: " << *S << '\n');
6103+
6104+
const auto *Rec = cast<SCEVAddRecExpr>(S);
6105+
if (!Rec->isAffine())
6106+
return;
6107+
6108+
if (S->getExpressionSize() > MaxSCEVSalvageExpressionSize)
6109+
return;
6110+
6111+
// Initialise a new builder with the iteration count expression. In
6112+
// combination with the value's SCEV this enables recovery.
6113+
clone(IterationCount);
6114+
if (!SCEVToValueExpr(*Rec, SE))
6115+
return;
6116+
}
6117+
61256118
/// Convert a SCEV of a value to a DIExpression that is pushed onto the
61266119
/// builder's expression stack. The stack should already contain an
61276120
/// expression for the iteration count, so that it can be multiplied by
@@ -6153,6 +6146,8 @@ struct SCEVDbgValueBuilder {
61536146
}
61546147
};
61556148

6149+
/// Holds all the required data to salvage a dbg.value using the pre-LSR SCEVs
6150+
/// and DIExpression.
61566151
struct DVIRecoveryRec {
61576152
DbgValueInst *DVI;
61586153
DIExpression *Expr;
@@ -6161,60 +6156,80 @@ struct DVIRecoveryRec {
61616156
};
61626157
} // namespace
61636158

6164-
static void RewriteDVIUsingIterCount(DVIRecoveryRec CachedDVI,
6165-
const SCEVDbgValueBuilder &IterationCount,
6166-
ScalarEvolution &SE) {
6167-
// LSR may add locations to previously single location-op DVIs which
6168-
// are currently not supported.
6169-
if (CachedDVI.DVI->getNumVariableLocationOps() != 1)
6170-
return;
6171-
6172-
// SCEVs for SSA values are most frquently of the form
6173-
// {start,+,stride}, but sometimes they are ({start,+,stride} + %a + ..).
6174-
// This is because %a is a PHI node that is not the IV. However, these
6175-
// SCEVs have not been observed to result in debuginfo-lossy optimisations,
6176-
// so its not expected this point will be reached.
6177-
if (!isa<SCEVAddRecExpr>(CachedDVI.SCEV))
6178-
return;
6159+
/// Write the new expression and new location ops for the dbg.value. Emit as
6160+
/// short a expression as possible based on checks of the expression length and
6161+
/// number of location ops.
6162+
static void UpdateDbgValueInst(DVIRecoveryRec &DVIRec,
6163+
SmallVectorImpl<Value *> &NewLocationOps,
6164+
SmallVectorImpl<uint64_t> &NewExpr) {
6165+
6166+
// If there is only a single location op, the {DW_OP_LLVM_arg, 0} sequence
6167+
// can be omitted from the expression. Also, DIArglist() can be ommitted from
6168+
// the first argument of the dbg.value.
6169+
if (NewLocationOps.size() == 1 && NewExpr[0] == dwarf::DW_OP_LLVM_arg &&
6170+
NewExpr[1] == 0) {
6171+
DVIRec.DVI->replaceVariableLocationOp(0u, NewLocationOps[0]);
6172+
llvm::SmallVector<uint64_t, 6> ShortExpr(llvm::drop_begin(NewExpr, 2));
6173+
auto *FinalExpr = DIExpression::prependOpcodes(DVIRec.Expr, ShortExpr,
6174+
/*StackValue*/ true);
6175+
DVIRec.DVI->setExpression(FinalExpr);
6176+
} else {
6177+
SmallVector<ValueAsMetadata *, 3> MetadataLocs;
6178+
for (Value *V : NewLocationOps)
6179+
MetadataLocs.push_back(ValueAsMetadata::get(V));
6180+
auto ValArrayRef = llvm::ArrayRef<llvm::ValueAsMetadata *>(MetadataLocs);
6181+
DVIRec.DVI->setRawLocation(
6182+
llvm::DIArgList::get(DVIRec.DVI->getContext(), ValArrayRef));
6183+
auto *FinalExpr =
6184+
DIExpression::prependOpcodes(DVIRec.Expr, NewExpr, /*StackValue*/ true);
6185+
DVIRec.DVI->setExpression(FinalExpr);
6186+
}
6187+
}
6188+
6189+
static bool SalvageDVI(llvm::Loop *L, ScalarEvolution &SE,
6190+
llvm::PHINode *LSRInductionVar, DVIRecoveryRec &DVIRec,
6191+
const SCEV *SCEVInductionVar,
6192+
SCEVDbgValueBuilder IterCountExpr) {
6193+
if (!DVIRec.DVI->isUndef())
6194+
return false;
61796195

6180-
LLVM_DEBUG(dbgs() << "scev-salvage: Value to salvage SCEV: "
6181-
<< *CachedDVI.SCEV << '\n');
6196+
// Some DVIs that were single location-op when cached are now multi-op,
6197+
// due to LSR optimisations. However, multi-op salvaging is not yet
6198+
// supported by SCEV salvaging. The expression applies to a single
6199+
// location op, so the DIAarglist must be replaced by the original location,
6200+
// which is now undef.
6201+
if (DVIRec.DVI->hasArgList()) {
6202+
if (DVIRec.DVI->getNumVariableLocationOps() == 0 ||
6203+
!DVIRec.DVI->getVariableLocationOp(0))
6204+
return false;
6205+
llvm::Type *Ty = DVIRec.DVI->getVariableLocationOp(0)->getType();
6206+
DVIRec.DVI->setRawLocation(llvm::ValueAsMetadata::get(UndefValue::get(Ty)));
6207+
DVIRec.DVI->setExpression(DVIRec.Expr);
6208+
}
61826209

6183-
const auto *Rec = cast<SCEVAddRecExpr>(CachedDVI.SCEV);
6184-
if (!Rec->isAffine())
6185-
return;
6210+
LLVM_DEBUG(dbgs() << "scev-salvage: attempt to salvage: " << *DVIRec.DVI
6211+
<< '\n');
61866212

6187-
if (CachedDVI.SCEV->getExpressionSize() > MaxSCEVSalvageExpressionSize)
6188-
return;
6213+
SCEVDbgValueBuilder SalvageExpr;
61896214

6190-
// Initialise a new builder with the iteration count expression. In
6191-
// combination with the value's SCEV this enables recovery.
6192-
SCEVDbgValueBuilder RecoverValue(IterationCount);
6193-
if (!RecoverValue.SCEVToValueExpr(*Rec, SE))
6194-
return;
6215+
// Create an offset-based salvage expression if possible, as it requires
6216+
// less DWARF ops than an iteration count-based expression.
6217+
if (Optional<APInt> Offset =
6218+
SE.computeConstantDifference(DVIRec.SCEV, SCEVInductionVar)) {
6219+
if (Offset.getValue().getMinSignedBits() <= 64)
6220+
SalvageExpr.createOffsetExpr(Offset.getValue().getSExtValue(),
6221+
LSRInductionVar);
6222+
} else
6223+
SalvageExpr.createIterCountExpr(DVIRec.SCEV, IterCountExpr, SE);
61956224

6196-
LLVM_DEBUG(dbgs() << "scev-salvage: Updating: " << *CachedDVI.DVI << '\n');
6197-
RecoverValue.applyExprToDbgValue(*CachedDVI.DVI, CachedDVI.Expr);
6198-
LLVM_DEBUG(dbgs() << "scev-salvage: to: " << *CachedDVI.DVI << '\n');
6199-
}
6225+
UpdateDbgValueInst(DVIRec, SalvageExpr.Values, SalvageExpr.Expr);
62006226

6201-
static void RewriteDVIUsingOffset(DVIRecoveryRec &DVIRec, llvm::PHINode &IV,
6202-
int64_t Offset) {
6203-
assert(!DVIRec.DVI->hasArgList() && "Expected single location-op dbg.value.");
6204-
DbgValueInst *DVI = DVIRec.DVI;
6205-
SmallVector<uint64_t, 8> Ops;
6206-
DIExpression::appendOffset(Ops, Offset);
6207-
DIExpression *Expr = DIExpression::prependOpcodes(DVIRec.Expr, Ops, true);
6208-
LLVM_DEBUG(dbgs() << "scev-salvage: Updating: " << *DVIRec.DVI << '\n');
6209-
DVI->setExpression(Expr);
6210-
llvm::Value *ValIV = dyn_cast<llvm::Value>(&IV);
6211-
DVI->replaceVariableLocationOp(
6212-
0u, llvm::MetadataAsValue::get(DVI->getContext(),
6213-
llvm::ValueAsMetadata::get(ValIV)));
6214-
LLVM_DEBUG(dbgs() << "scev-salvage: updated with offset to IV: "
6215-
<< *DVIRec.DVI << '\n');
6227+
LLVM_DEBUG(dbgs() << "scev-salvage: Updated DVI: " << *DVIRec.DVI << "\n");
6228+
return true;
62166229
}
62176230

6231+
/// Obtain an expression for the iteration count, then attempt to salvage the
6232+
/// dbg.value intrinsics.
62186233
static void
62196234
DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE,
62206235
llvm::PHINode *LSRInductionVar,
@@ -6231,6 +6246,7 @@ DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE,
62316246
if (!IVAddRec->isAffine())
62326247
return;
62336248

6249+
// Prevent translation using excessive resources.
62346250
if (IVAddRec->getExpressionSize() > MaxSCEVSalvageExpressionSize)
62356251
return;
62366252

@@ -6243,37 +6259,9 @@ DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE,
62436259
LLVM_DEBUG(dbgs() << "scev-salvage: IV SCEV: " << *SCEVInductionVar
62446260
<< '\n');
62456261

6246-
// Needn't salvage if the location op hasn't been undef'd by LSR.
62476262
for (auto &DVIRec : DVIToUpdate) {
6248-
if (!DVIRec.DVI->isUndef())
6249-
continue;
6250-
6251-
// Some DVIs that were single location-op when cached are now multi-op,
6252-
// due to LSR optimisations. However, multi-op salvaging is not yet
6253-
// supported by SCEV salvaging. But, we can attempt a salvage by restoring
6254-
// the pre-LSR single-op expression.
6255-
if (DVIRec.DVI->hasArgList()) {
6256-
if (!DVIRec.DVI->getVariableLocationOp(0))
6257-
continue;
6258-
llvm::Type *Ty = DVIRec.DVI->getVariableLocationOp(0)->getType();
6259-
DVIRec.DVI->setRawLocation(
6260-
llvm::ValueAsMetadata::get(UndefValue::get(Ty)));
6261-
DVIRec.DVI->setExpression(DVIRec.Expr);
6262-
}
6263-
6264-
LLVM_DEBUG(dbgs() << "scev-salvage: value to recover SCEV: "
6265-
<< *DVIRec.SCEV << '\n');
6266-
6267-
// Create a simple expression if the IV and value to salvage SCEVs
6268-
// start values differ by only a constant value.
6269-
if (Optional<APInt> Offset =
6270-
SE.computeConstantDifference(DVIRec.SCEV, SCEVInductionVar)) {
6271-
if (Offset.getValue().getMinSignedBits() <= 64)
6272-
RewriteDVIUsingOffset(DVIRec, *LSRInductionVar,
6273-
Offset.getValue().getSExtValue());
6274-
} else {
6275-
RewriteDVIUsingIterCount(DVIRec, IterCountExpr, SE);
6276-
}
6263+
SalvageDVI(L, SE, LSRInductionVar, DVIRec, SCEVInductionVar,
6264+
IterCountExpr);
62776265
}
62786266
}
62796267
}

0 commit comments

Comments
 (0)