Skip to content

[RemoveDIs][DebugInfo] Add support for DPValues to LoopStrengthReduce #78706

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 136 additions & 104 deletions llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6366,10 +6366,12 @@ struct SCEVDbgValueBuilder {
/// and DIExpression.
struct DVIRecoveryRec {
DVIRecoveryRec(DbgValueInst *DbgValue)
: DVI(DbgValue), Expr(DbgValue->getExpression()),
: DbgRef(DbgValue), Expr(DbgValue->getExpression()),
HadLocationArgList(false) {}
DVIRecoveryRec(DPValue *DPV)
: DbgRef(DPV), Expr(DPV->getExpression()), HadLocationArgList(false) {}

DbgValueInst *DVI;
PointerUnion<DbgValueInst *, DPValue *> DbgRef;
DIExpression *Expr;
bool HadLocationArgList;
SmallVector<WeakVH, 2> LocationOps;
Expand Down Expand Up @@ -6401,17 +6403,19 @@ static unsigned numLLVMArgOps(SmallVectorImpl<uint64_t> &Expr) {
/// Overwrites DVI with the location and Ops as the DIExpression. This will
/// create an invalid expression if Ops has any dwarf::DW_OP_llvm_arg operands,
/// because a DIArglist is not created for the first argument of the dbg.value.
static void updateDVIWithLocation(DbgValueInst &DVI, Value *Location,
template <typename T>
static void updateDVIWithLocation(T &DbgVal, Value *Location,
SmallVectorImpl<uint64_t> &Ops) {
assert(
numLLVMArgOps(Ops) == 0 &&
"Expected expression that does not contain any DW_OP_llvm_arg operands.");
DVI.setRawLocation(ValueAsMetadata::get(Location));
DVI.setExpression(DIExpression::get(DVI.getContext(), Ops));
assert(numLLVMArgOps(Ops) == 0 && "Expected expression that does not "
"contain any DW_OP_llvm_arg operands.");
DbgVal.setRawLocation(ValueAsMetadata::get(Location));
DbgVal.setExpression(DIExpression::get(DbgVal.getContext(), Ops));
DbgVal.setExpression(DIExpression::get(DbgVal.getContext(), Ops));
}

/// Overwrite DVI with locations placed into a DIArglist.
static void updateDVIWithLocations(DbgValueInst &DVI,
template <typename T>
static void updateDVIWithLocations(T &DbgVal,
SmallVectorImpl<Value *> &Locations,
SmallVectorImpl<uint64_t> &Ops) {
assert(numLLVMArgOps(Ops) != 0 &&
Expand All @@ -6421,8 +6425,8 @@ static void updateDVIWithLocations(DbgValueInst &DVI,
for (Value *V : Locations)
MetadataLocs.push_back(ValueAsMetadata::get(V));
auto ValArrayRef = llvm::ArrayRef<llvm::ValueAsMetadata *>(MetadataLocs);
DVI.setRawLocation(llvm::DIArgList::get(DVI.getContext(), ValArrayRef));
DVI.setExpression(DIExpression::get(DVI.getContext(), Ops));
DbgVal.setRawLocation(llvm::DIArgList::get(DbgVal.getContext(), ValArrayRef));
DbgVal.setExpression(DIExpression::get(DbgVal.getContext(), Ops));
}

/// Write the new expression and new location ops for the dbg.value. If possible
Expand All @@ -6433,30 +6437,37 @@ static void updateDVIWithLocations(DbgValueInst &DVI,
static void UpdateDbgValueInst(DVIRecoveryRec &DVIRec,
SmallVectorImpl<Value *> &NewLocationOps,
SmallVectorImpl<uint64_t> &NewExpr) {
unsigned NumLLVMArgs = numLLVMArgOps(NewExpr);
if (NumLLVMArgs == 0) {
// Location assumed to be on the stack.
updateDVIWithLocation(*DVIRec.DVI, NewLocationOps[0], NewExpr);
} else if (NumLLVMArgs == 1 && NewExpr[0] == dwarf::DW_OP_LLVM_arg) {
// There is only a single DW_OP_llvm_arg at the start of the expression,
// so it can be omitted along with DIArglist.
assert(NewExpr[1] == 0 &&
"Lone LLVM_arg in a DIExpression should refer to location-op 0.");
llvm::SmallVector<uint64_t, 6> ShortenedOps(llvm::drop_begin(NewExpr, 2));
updateDVIWithLocation(*DVIRec.DVI, NewLocationOps[0], ShortenedOps);
} else {
// Multiple DW_OP_llvm_arg, so DIArgList is strictly necessary.
updateDVIWithLocations(*DVIRec.DVI, NewLocationOps, NewExpr);
}
auto UpdateDbgValueInstImpl = [&](auto *DbgVal) {
unsigned NumLLVMArgs = numLLVMArgOps(NewExpr);
if (NumLLVMArgs == 0) {
// Location assumed to be on the stack.
updateDVIWithLocation(*DbgVal, NewLocationOps[0], NewExpr);
} else if (NumLLVMArgs == 1 && NewExpr[0] == dwarf::DW_OP_LLVM_arg) {
// There is only a single DW_OP_llvm_arg at the start of the expression,
// so it can be omitted along with DIArglist.
assert(NewExpr[1] == 0 &&
"Lone LLVM_arg in a DIExpression should refer to location-op 0.");
llvm::SmallVector<uint64_t, 6> ShortenedOps(llvm::drop_begin(NewExpr, 2));
updateDVIWithLocation(*DbgVal, NewLocationOps[0], ShortenedOps);
} else {
// Multiple DW_OP_llvm_arg, so DIArgList is strictly necessary.
updateDVIWithLocations(*DbgVal, NewLocationOps, NewExpr);
}

// If the DIExpression was previously empty then add the stack terminator.
// Non-empty expressions have only had elements inserted into them and so the
// terminator should already be present e.g. stack_value or fragment.
DIExpression *SalvageExpr = DVIRec.DVI->getExpression();
if (!DVIRec.Expr->isComplex() && SalvageExpr->isComplex()) {
SalvageExpr = DIExpression::append(SalvageExpr, {dwarf::DW_OP_stack_value});
DVIRec.DVI->setExpression(SalvageExpr);
}
// If the DIExpression was previously empty then add the stack terminator.
// Non-empty expressions have only had elements inserted into them and so
// the terminator should already be present e.g. stack_value or fragment.
DIExpression *SalvageExpr = DbgVal->getExpression();
if (!DVIRec.Expr->isComplex() && SalvageExpr->isComplex()) {
SalvageExpr =
DIExpression::append(SalvageExpr, {dwarf::DW_OP_stack_value});
DbgVal->setExpression(SalvageExpr);
}
};
if (isa<DbgValueInst *>(DVIRec.DbgRef))
UpdateDbgValueInstImpl(cast<DbgValueInst *>(DVIRec.DbgRef));
else
UpdateDbgValueInstImpl(cast<DPValue *>(DVIRec.DbgRef));
}

/// Cached location ops may be erased during LSR, in which case a poison is
Expand All @@ -6470,40 +6481,49 @@ static Value *getValueOrPoison(WeakVH &VH, LLVMContext &C) {

/// Restore the DVI's pre-LSR arguments. Substitute undef for any erased values.
static void restorePreTransformState(DVIRecoveryRec &DVIRec) {
LLVM_DEBUG(dbgs() << "scev-salvage: restore dbg.value to pre-LSR state\n"
<< "scev-salvage: post-LSR: " << *DVIRec.DVI << '\n');
assert(DVIRec.Expr && "Expected an expression");
DVIRec.DVI->setExpression(DVIRec.Expr);

// Even a single location-op may be inside a DIArgList and referenced with
// DW_OP_LLVM_arg, which is valid only with a DIArgList.
if (!DVIRec.HadLocationArgList) {
assert(DVIRec.LocationOps.size() == 1 &&
"Unexpected number of location ops.");
// LSR's unsuccessful salvage attempt may have added DIArgList, which in
// this case was not present before, so force the location back to a single
// uncontained Value.
Value *CachedValue =
getValueOrPoison(DVIRec.LocationOps[0], DVIRec.DVI->getContext());
DVIRec.DVI->setRawLocation(ValueAsMetadata::get(CachedValue));
} else {
SmallVector<ValueAsMetadata *, 3> MetadataLocs;
for (WeakVH VH : DVIRec.LocationOps) {
Value *CachedValue = getValueOrPoison(VH, DVIRec.DVI->getContext());
MetadataLocs.push_back(ValueAsMetadata::get(CachedValue));
auto RestorePreTransformStateImpl = [&](auto *DbgVal) {
LLVM_DEBUG(dbgs() << "scev-salvage: restore dbg.value to pre-LSR state\n"
<< "scev-salvage: post-LSR: " << *DbgVal << '\n');
assert(DVIRec.Expr && "Expected an expression");
DbgVal->setExpression(DVIRec.Expr);

// Even a single location-op may be inside a DIArgList and referenced with
// DW_OP_LLVM_arg, which is valid only with a DIArgList.
if (!DVIRec.HadLocationArgList) {
assert(DVIRec.LocationOps.size() == 1 &&
"Unexpected number of location ops.");
// LSR's unsuccessful salvage attempt may have added DIArgList, which in
// this case was not present before, so force the location back to a
// single uncontained Value.
Value *CachedValue =
getValueOrPoison(DVIRec.LocationOps[0], DbgVal->getContext());
DbgVal->setRawLocation(ValueAsMetadata::get(CachedValue));
} else {
SmallVector<ValueAsMetadata *, 3> MetadataLocs;
for (WeakVH VH : DVIRec.LocationOps) {
Value *CachedValue = getValueOrPoison(VH, DbgVal->getContext());
MetadataLocs.push_back(ValueAsMetadata::get(CachedValue));
}
auto ValArrayRef = llvm::ArrayRef<llvm::ValueAsMetadata *>(MetadataLocs);
DbgVal->setRawLocation(
llvm::DIArgList::get(DbgVal->getContext(), ValArrayRef));
}
auto ValArrayRef = llvm::ArrayRef<llvm::ValueAsMetadata *>(MetadataLocs);
DVIRec.DVI->setRawLocation(
llvm::DIArgList::get(DVIRec.DVI->getContext(), ValArrayRef));
}
LLVM_DEBUG(dbgs() << "scev-salvage: pre-LSR: " << *DVIRec.DVI << '\n');
LLVM_DEBUG(dbgs() << "scev-salvage: pre-LSR: " << *DbgVal << '\n');
};
if (isa<DbgValueInst *>(DVIRec.DbgRef))
RestorePreTransformStateImpl(cast<DbgValueInst *>(DVIRec.DbgRef));
else
RestorePreTransformStateImpl(cast<DPValue *>(DVIRec.DbgRef));
}

static bool SalvageDVI(llvm::Loop *L, ScalarEvolution &SE,
llvm::PHINode *LSRInductionVar, DVIRecoveryRec &DVIRec,
const SCEV *SCEVInductionVar,
SCEVDbgValueBuilder IterCountExpr) {
if (!DVIRec.DVI->isKillLocation())

if (isa<DbgValueInst *>(DVIRec.DbgRef)
? !cast<DbgValueInst *>(DVIRec.DbgRef)->isKillLocation()
: !cast<DPValue *>(DVIRec.DbgRef)->isKillLocation())
return false;

// LSR may have caused several changes to the dbg.value in the failed salvage
Expand Down Expand Up @@ -6596,16 +6616,20 @@ static bool SalvageDVI(llvm::Loop *L, ScalarEvolution &SE,
}

UpdateDbgValueInst(DVIRec, NewLocationOps, NewExpr);
LLVM_DEBUG(dbgs() << "scev-salvage: Updated DVI: " << *DVIRec.DVI << "\n");
if (isa<DbgValueInst *>(DVIRec.DbgRef))
LLVM_DEBUG(dbgs() << "scev-salvage: Updated DVI: "
<< *cast<DbgValueInst *>(DVIRec.DbgRef) << "\n");
else
LLVM_DEBUG(dbgs() << "scev-salvage: Updated DVI: "
<< *cast<DPValue *>(DVIRec.DbgRef) << "\n");
return true;
}

/// Obtain an expression for the iteration count, then attempt to salvage the
/// dbg.value intrinsics.
static void
DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE,
llvm::PHINode *LSRInductionVar,
SmallVector<std::unique_ptr<DVIRecoveryRec>, 2> &DVIToUpdate) {
static void DbgRewriteSalvageableDVIs(
llvm::Loop *L, ScalarEvolution &SE, llvm::PHINode *LSRInductionVar,
SmallVector<std::unique_ptr<DVIRecoveryRec>, 2> &DVIToUpdate) {
if (DVIToUpdate.empty())
return;

Expand Down Expand Up @@ -6647,48 +6671,56 @@ static void DbgGatherSalvagableDVI(
SmallSet<AssertingVH<DbgValueInst>, 2> &DVIHandles) {
for (const auto &B : L->getBlocks()) {
for (auto &I : *B) {
auto DVI = dyn_cast<DbgValueInst>(&I);
if (!DVI)
continue;
// Ensure that if any location op is undef that the dbg.vlue is not
// cached.
if (DVI->isKillLocation())
continue;

// Check that the location op SCEVs are suitable for translation to
// DIExpression.
const auto &HasTranslatableLocationOps =
[&](const DbgValueInst *DVI) -> bool {
for (const auto LocOp : DVI->location_ops()) {
if (!LocOp)
return false;

if (!SE.isSCEVable(LocOp->getType()))
return false;

const SCEV *S = SE.getSCEV(LocOp);
if (SE.containsUndefs(S))
return false;
auto ProcessDbgValue = [&](auto *DbgVal) -> bool {
// Ensure that if any location op is undef that the dbg.vlue is not
// cached.
if (DbgVal->isKillLocation())
return false;

// Check that the location op SCEVs are suitable for translation to
// DIExpression.
const auto &HasTranslatableLocationOps =
[&](const auto *DbgValToTranslate) -> bool {
for (const auto LocOp : DbgValToTranslate->location_ops()) {
if (!LocOp)
return false;

if (!SE.isSCEVable(LocOp->getType()))
return false;

const SCEV *S = SE.getSCEV(LocOp);
if (SE.containsUndefs(S))
return false;
}
return true;
};

if (!HasTranslatableLocationOps(DbgVal))
return false;

std::unique_ptr<DVIRecoveryRec> NewRec =
std::make_unique<DVIRecoveryRec>(DbgVal);
// Each location Op may need a SCEVDbgValueBuilder in order to recover
// it. Pre-allocating a vector will enable quick lookups of the builder
// later during the salvage.
NewRec->RecoveryExprs.resize(DbgVal->getNumVariableLocationOps());
for (const auto LocOp : DbgVal->location_ops()) {
NewRec->SCEVs.push_back(SE.getSCEV(LocOp));
NewRec->LocationOps.push_back(LocOp);
NewRec->HadLocationArgList = DbgVal->hasArgList();
}
SalvageableDVISCEVs.push_back(std::move(NewRec));
return true;
};

if (!HasTranslatableLocationOps(DVI))
continue;

std::unique_ptr<DVIRecoveryRec> NewRec =
std::make_unique<DVIRecoveryRec>(DVI);
// Each location Op may need a SCEVDbgValueBuilder in order to recover it.
// Pre-allocating a vector will enable quick lookups of the builder later
// during the salvage.
NewRec->RecoveryExprs.resize(DVI->getNumVariableLocationOps());
for (const auto LocOp : DVI->location_ops()) {
NewRec->SCEVs.push_back(SE.getSCEV(LocOp));
NewRec->LocationOps.push_back(LocOp);
NewRec->HadLocationArgList = DVI->hasArgList();
for (auto &DPV : I.getDbgValueRange()) {
if (DPV.isDbgValue() || DPV.isDbgAssign())
ProcessDbgValue(&DPV);
}
SalvageableDVISCEVs.push_back(std::move(NewRec));
DVIHandles.insert(DVI);
auto DVI = dyn_cast<DbgValueInst>(&I);
if (!DVI)
continue;
if (ProcessDbgValue(DVI))
DVIHandles.insert(DVI);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce < %s | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce < %s | FileCheck %s

; During Loop Strength Reduce, if the terminating condition for the loop is not
; immediately adjacent to the terminating branch and it has more than one use,
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -loop-reduce -S %s | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -loop-reduce -S %s | FileCheck %s

;; Test that LSR preserves debug-info for induction variables and scev-based
;; salvaging produces short DIExpressions that use a constant offset from the
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-1.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt < %s -loop-reduce -S | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators < %s -loop-reduce -S | FileCheck %s
;
; Test that LSR avoids crashing on very large integer inputs. It should
; discard the variable location by creating an undef dbg.value.
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt < %s -loop-reduce -S | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators < %s -loop-reduce -S | FileCheck %s

; Test that LSR does not produce invalid debug info when a debug value is
; salvaged during LSR by adding additional location operands, then becomes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s -o - | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s -o - | FileCheck %s
; REQUIRES: x86-registered-target

;; Ensure that we retain debuginfo for the induction variable and dependant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s -o - | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s -o - | FileCheck %s
; REQUIRES: x86-registered-target

;; Ensure that we retain debuginfo for the induction variable and dependant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s -o - | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s -o - | FileCheck %s
; REQUIRES: x86-registered-target

;; Ensure that we retain debuginfo for the induction variable and dependant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s -o - | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s -o - | FileCheck %s
; REQUIRES: x86-registered-target

;; Ensure that we retain debuginfo for the induction variable and dependant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s -o - | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s -o - | FileCheck %s
; REQUIRES: x86-registered-target

;; Ensure that we retain debuginfo for the induction variable and dependant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s | FileCheck %s
; REQUIRES: x86-registered-target

;; Ensure that SCEV-based salvaging in Loop Strength Reduction can salvage
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt < %s -loop-reduce -S 2>&1 | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators < %s -loop-reduce -S 2>&1 | FileCheck %s
;; This test case checks that whether the new icmp instruction preserves
;; the debug location of the original instruction for %exitcond
; CHECK: icmp uge i32 %indvar.next, %n, !dbg ![[DBGLOC:[0-9]+]]
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopStrengthReduce/pr12018.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt < %s -loop-reduce
; RUN: opt --try-experimental-debuginfo-iterators < %s -loop-reduce

target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128"

Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopStrengthReduce/pr51329.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S -loop-reduce %s | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -S -loop-reduce %s | FileCheck %s
;
; Test that LSR SCEV-based salvaging does not crash when translating SCEVs
; that contain integers with binary representations greater than 64-bits.
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopStrengthReduce/pr51656.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -loop-reduce -S %s | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators -loop-reduce -S %s | FileCheck %s

;; This test ensures that no attempt is made to translate long SCEVs into
;; DIExpressions. Attempting the translation can use excessive resources and
Expand Down
Loading