Reland [DebugInfo] Improve dbg preservation in LSR.

Use SCEV to salvage additional @llvm.dbg.value that have turned into
referencing undef after transformation (and traditional
salvageDebugInfo).  Before rewrite (but after introduction of new
induction variables) use SCEV to compute an equivalent set of values for
each @llvm.dbg.value in the loop body (among the loop header PHI-nodes).
After rewrite (and dead PHI elimination) update those @llvm.dbg.value
now referencing undef by picking a remaining value from its equivalence
set.  Allow match with offset by inserting compensation code in the
DIExpression.

Fixes : PR38815

Differential Revision: https://reviews.llvm.org/D87494
This commit is contained in:
Markus Lavin 2020-12-14 15:37:34 +01:00
parent 2664f5d436
commit 2a6782bb9f
4 changed files with 149 additions and 10 deletions

View File

@ -1163,6 +1163,15 @@ public:
const SCEV *S, const Loop *L,
SmallPtrSetImpl<const SCEVPredicate *> &Preds);
/// Compute \p LHS - \p RHS and returns the result as an APInt if it is a
/// constant, and None if it isn't.
///
/// This is intended to be a cheaper version of getMinusSCEV. We can be
/// frugal here since we just bail out of actually constructing and
/// canonicalizing an expression in the cases where the result isn't going
/// to be a constant.
Optional<APInt> computeConstantDifference(const SCEV *LHS, const SCEV *RHS);
/// Update no-wrap flags of an AddRec. This may drop the cached info about
/// this AddRec (such as range info) in case if new flags may potentially
/// sharpen it.
@ -1884,15 +1893,6 @@ private:
bool splitBinaryAdd(const SCEV *Expr, const SCEV *&L, const SCEV *&R,
SCEV::NoWrapFlags &Flags);
/// Compute \p LHS - \p RHS and returns the result as an APInt if it is a
/// constant, and None if it isn't.
///
/// This is intended to be a cheaper version of getMinusSCEV. We can be
/// frugal here since we just bail out of actually constructing and
/// canonicalizing an expression in the cases where the result isn't going
/// to be a constant.
Optional<APInt> computeConstantDifference(const SCEV *LHS, const SCEV *RHS);
/// Drop memoized information computed for S.
void forgetMemoizedResults(const SCEV *S);

View File

@ -81,6 +81,7 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/GlobalValue.h"
@ -5774,6 +5775,62 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreserved<MemorySSAWrapperPass>();
}
using EqualValues = SmallVector<std::tuple<WeakVH, int64_t, DIExpression *>, 4>;
using EqualValuesMap = DenseMap<DbgValueInst *, EqualValues>;
static void DbgGatherEqualValues(Loop *L, ScalarEvolution &SE,
EqualValuesMap &DbgValueToEqualSet) {
for (auto &B : L->getBlocks()) {
for (auto &I : *B) {
auto DVI = dyn_cast<DbgValueInst>(&I);
if (!DVI)
continue;
auto V = DVI->getVariableLocation();
if (!V || !SE.isSCEVable(V->getType()))
continue;
auto DbgValueSCEV = SE.getSCEV(V);
EqualValues EqSet;
for (PHINode &Phi : L->getHeader()->phis()) {
if (V->getType() != Phi.getType())
continue;
if (!SE.isSCEVable(Phi.getType()))
continue;
auto PhiSCEV = SE.getSCEV(&Phi);
if (Optional<APInt> Offset =
SE.computeConstantDifference(DbgValueSCEV, PhiSCEV))
EqSet.emplace_back(std::make_tuple(
&Phi, Offset.getValue().getSExtValue(), DVI->getExpression()));
}
DbgValueToEqualSet[DVI] = std::move(EqSet);
}
}
}
static void DbgApplyEqualValues(EqualValuesMap &DbgValueToEqualSet) {
for (auto A : DbgValueToEqualSet) {
auto DVI = A.first;
// Only update those that are now undef.
if (!isa_and_nonnull<UndefValue>(DVI->getVariableLocation()))
continue;
for (auto EV : A.second) {
auto V = std::get<WeakVH>(EV);
if (!V)
continue;
auto DbgDIExpr = std::get<DIExpression *>(EV);
auto Offset = std::get<int64_t>(EV);
auto &Ctx = DVI->getContext();
DVI->setOperand(0, MetadataAsValue::get(Ctx, ValueAsMetadata::get(V)));
if (Offset) {
SmallVector<uint64_t, 8> Ops;
DIExpression::appendOffset(Ops, Offset);
DbgDIExpr = DIExpression::prependOpcodes(DbgDIExpr, Ops, true);
}
DVI->setOperand(2, MetadataAsValue::get(Ctx, DbgDIExpr));
break;
}
}
}
static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
DominatorTree &DT, LoopInfo &LI,
const TargetTransformInfo &TTI,
@ -5789,6 +5846,11 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
Changed |=
LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get()).getChanged();
// Debug preservation - before we start removing anything create equivalence
// sets for the llvm.dbg.value intrinsics.
EqualValuesMap DbgValueToEqualSet;
DbgGatherEqualValues(L, SE, DbgValueToEqualSet);
// Remove any extra phis created by processing inner loops.
Changed |= DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get());
if (EnablePhiElim && L->isLoopSimplifyForm()) {
@ -5806,6 +5868,9 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get());
}
}
DbgApplyEqualValues(DbgValueToEqualSet);
return Changed;
}

View File

@ -33,7 +33,7 @@
; ASM: popl %ebx
; ASM: [[EPILOGUE]]: # %return
; ASM: retl $8
; ASM: Ltmp10:
; ASM: Ltmp11:
; ASM: .cv_fpo_endproc
; Note how RvaStart advances 7 bytes to skip the shrink-wrapped portion.

View File

@ -0,0 +1,74 @@
; RUN: opt < %s -loop-reduce -S | FileCheck %s
; Test that LSR preserves debug-info for induction variables.
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
define dso_local void @foo(i8* nocapture %p) local_unnamed_addr !dbg !7 {
; CHECK-LABEL: @foo(
entry:
call void @llvm.dbg.value(metadata i8* %p, metadata !13, metadata !DIExpression()), !dbg !16
call void @llvm.dbg.value(metadata i8 0, metadata !14, metadata !DIExpression()), !dbg !17
br label %for.body, !dbg !18
for.cond.cleanup: ; preds = %for.body
ret void, !dbg !19
for.body: ; preds = %entry, %for.body
; CHECK-LABEL: for.body:
%i.06 = phi i8 [ 0, %entry ], [ %inc, %for.body ]
%p.addr.05 = phi i8* [ %p, %entry ], [ %add.ptr, %for.body ]
call void @llvm.dbg.value(metadata i8 %i.06, metadata !14, metadata !DIExpression()), !dbg !17
call void @llvm.dbg.value(metadata i8* %p.addr.05, metadata !13, metadata !DIExpression()), !dbg !16
; CHECK-NOT: call void @llvm.dbg.value(metadata i8* undef
; CHECK: call void @llvm.dbg.value(metadata i8* %lsr.iv, metadata ![[MID_p:[0-9]+]], metadata !DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value)), !dbg !16
%add.ptr = getelementptr inbounds i8, i8* %p.addr.05, i64 3, !dbg !20
call void @llvm.dbg.value(metadata i8* %add.ptr, metadata !13, metadata !DIExpression()), !dbg !16
; CHECK-NOT: call void @llvm.dbg.value(metadata i8* undef
; CHECK: call void @llvm.dbg.value(metadata i8* %lsr.iv, metadata ![[MID_p]], metadata !DIExpression()), !dbg !16
store i8 %i.06, i8* %add.ptr, align 1, !dbg !23, !tbaa !24
%inc = add nuw nsw i8 %i.06, 1, !dbg !27
call void @llvm.dbg.value(metadata i8 %inc, metadata !14, metadata !DIExpression()), !dbg !17
%exitcond.not = icmp eq i8 %inc, 32, !dbg !28
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !dbg !18, !llvm.loop !29
}
declare void @llvm.dbg.value(metadata, metadata, metadata)
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "lsrdbg.c", directory: "/")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 12.0.0"}
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
!8 = !DISubroutineType(types: !9)
!9 = !{null, !10}
!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
!11 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
!12 = !{!13, !14}
!13 = !DILocalVariable(name: "p", arg: 1, scope: !7, file: !1, line: 2, type: !10)
; CHECK: ![[MID_p]] = !DILocalVariable(name: "p", arg: 1, scope: !7, file: !1, line: 2, type: !10)
!14 = !DILocalVariable(name: "i", scope: !15, file: !1, line: 4, type: !11)
!15 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 3)
!16 = !DILocation(line: 0, scope: !7)
!17 = !DILocation(line: 0, scope: !15)
!18 = !DILocation(line: 4, column: 3, scope: !15)
!19 = !DILocation(line: 8, column: 1, scope: !7)
!20 = !DILocation(line: 5, column: 7, scope: !21)
!21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 4, column: 42)
!22 = distinct !DILexicalBlock(scope: !15, file: !1, line: 4, column: 3)
!23 = !DILocation(line: 6, column: 8, scope: !21)
!24 = !{!25, !25, i64 0}
!25 = !{!"omnipotent char", !26, i64 0}
!26 = !{!"Simple C/C++ TBAA"}
!27 = !DILocation(line: 4, column: 38, scope: !22)
!28 = !DILocation(line: 4, column: 31, scope: !22)
!29 = distinct !{!29, !18, !30, !31}
!30 = !DILocation(line: 7, column: 3, scope: !15)
!31 = !{!"llvm.loop.unroll.disable"}