Skip to content

Commit 2a6782b

Browse files
committed
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
1 parent 2664f5d commit 2a6782b

File tree

4 files changed

+149
-10
lines changed

4 files changed

+149
-10
lines changed

llvm/include/llvm/Analysis/ScalarEvolution.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,15 @@ class ScalarEvolution {
11631163
const SCEV *S, const Loop *L,
11641164
SmallPtrSetImpl<const SCEVPredicate *> &Preds);
11651165

1166+
/// Compute \p LHS - \p RHS and returns the result as an APInt if it is a
1167+
/// constant, and None if it isn't.
1168+
///
1169+
/// This is intended to be a cheaper version of getMinusSCEV. We can be
1170+
/// frugal here since we just bail out of actually constructing and
1171+
/// canonicalizing an expression in the cases where the result isn't going
1172+
/// to be a constant.
1173+
Optional<APInt> computeConstantDifference(const SCEV *LHS, const SCEV *RHS);
1174+
11661175
/// Update no-wrap flags of an AddRec. This may drop the cached info about
11671176
/// this AddRec (such as range info) in case if new flags may potentially
11681177
/// sharpen it.
@@ -1884,15 +1893,6 @@ class ScalarEvolution {
18841893
bool splitBinaryAdd(const SCEV *Expr, const SCEV *&L, const SCEV *&R,
18851894
SCEV::NoWrapFlags &Flags);
18861895

1887-
/// Compute \p LHS - \p RHS and returns the result as an APInt if it is a
1888-
/// constant, and None if it isn't.
1889-
///
1890-
/// This is intended to be a cheaper version of getMinusSCEV. We can be
1891-
/// frugal here since we just bail out of actually constructing and
1892-
/// canonicalizing an expression in the cases where the result isn't going
1893-
/// to be a constant.
1894-
Optional<APInt> computeConstantDifference(const SCEV *LHS, const SCEV *RHS);
1895-
18961896
/// Drop memoized information computed for S.
18971897
void forgetMemoizedResults(const SCEV *S);
18981898

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#include "llvm/IR/BasicBlock.h"
8282
#include "llvm/IR/Constant.h"
8383
#include "llvm/IR/Constants.h"
84+
#include "llvm/IR/DebugInfoMetadata.h"
8485
#include "llvm/IR/DerivedTypes.h"
8586
#include "llvm/IR/Dominators.h"
8687
#include "llvm/IR/GlobalValue.h"
@@ -5774,6 +5775,62 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const {
57745775
AU.addPreserved<MemorySSAWrapperPass>();
57755776
}
57765777

5778+
using EqualValues = SmallVector<std::tuple<WeakVH, int64_t, DIExpression *>, 4>;
5779+
using EqualValuesMap = DenseMap<DbgValueInst *, EqualValues>;
5780+
5781+
static void DbgGatherEqualValues(Loop *L, ScalarEvolution &SE,
5782+
EqualValuesMap &DbgValueToEqualSet) {
5783+
for (auto &B : L->getBlocks()) {
5784+
for (auto &I : *B) {
5785+
auto DVI = dyn_cast<DbgValueInst>(&I);
5786+
if (!DVI)
5787+
continue;
5788+
auto V = DVI->getVariableLocation();
5789+
if (!V || !SE.isSCEVable(V->getType()))
5790+
continue;
5791+
auto DbgValueSCEV = SE.getSCEV(V);
5792+
EqualValues EqSet;
5793+
for (PHINode &Phi : L->getHeader()->phis()) {
5794+
if (V->getType() != Phi.getType())
5795+
continue;
5796+
if (!SE.isSCEVable(Phi.getType()))
5797+
continue;
5798+
auto PhiSCEV = SE.getSCEV(&Phi);
5799+
if (Optional<APInt> Offset =
5800+
SE.computeConstantDifference(DbgValueSCEV, PhiSCEV))
5801+
EqSet.emplace_back(std::make_tuple(
5802+
&Phi, Offset.getValue().getSExtValue(), DVI->getExpression()));
5803+
}
5804+
DbgValueToEqualSet[DVI] = std::move(EqSet);
5805+
}
5806+
}
5807+
}
5808+
5809+
static void DbgApplyEqualValues(EqualValuesMap &DbgValueToEqualSet) {
5810+
for (auto A : DbgValueToEqualSet) {
5811+
auto DVI = A.first;
5812+
// Only update those that are now undef.
5813+
if (!isa_and_nonnull<UndefValue>(DVI->getVariableLocation()))
5814+
continue;
5815+
for (auto EV : A.second) {
5816+
auto V = std::get<WeakVH>(EV);
5817+
if (!V)
5818+
continue;
5819+
auto DbgDIExpr = std::get<DIExpression *>(EV);
5820+
auto Offset = std::get<int64_t>(EV);
5821+
auto &Ctx = DVI->getContext();
5822+
DVI->setOperand(0, MetadataAsValue::get(Ctx, ValueAsMetadata::get(V)));
5823+
if (Offset) {
5824+
SmallVector<uint64_t, 8> Ops;
5825+
DIExpression::appendOffset(Ops, Offset);
5826+
DbgDIExpr = DIExpression::prependOpcodes(DbgDIExpr, Ops, true);
5827+
}
5828+
DVI->setOperand(2, MetadataAsValue::get(Ctx, DbgDIExpr));
5829+
break;
5830+
}
5831+
}
5832+
}
5833+
57775834
static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
57785835
DominatorTree &DT, LoopInfo &LI,
57795836
const TargetTransformInfo &TTI,
@@ -5789,6 +5846,11 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
57895846
Changed |=
57905847
LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get()).getChanged();
57915848

5849+
// Debug preservation - before we start removing anything create equivalence
5850+
// sets for the llvm.dbg.value intrinsics.
5851+
EqualValuesMap DbgValueToEqualSet;
5852+
DbgGatherEqualValues(L, SE, DbgValueToEqualSet);
5853+
57925854
// Remove any extra phis created by processing inner loops.
57935855
Changed |= DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get());
57945856
if (EnablePhiElim && L->isLoopSimplifyForm()) {
@@ -5806,6 +5868,9 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
58065868
DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get());
58075869
}
58085870
}
5871+
5872+
DbgApplyEqualValues(DbgValueToEqualSet);
5873+
58095874
return Changed;
58105875
}
58115876

llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
; ASM: popl %ebx
3434
; ASM: [[EPILOGUE]]: # %return
3535
; ASM: retl $8
36-
; ASM: Ltmp10:
36+
; ASM: Ltmp11:
3737
; ASM: .cv_fpo_endproc
3838

3939
; Note how RvaStart advances 7 bytes to skip the shrink-wrapped portion.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
; RUN: opt < %s -loop-reduce -S | FileCheck %s
2+
3+
; Test that LSR preserves debug-info for induction variables.
4+
5+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
6+
7+
define dso_local void @foo(i8* nocapture %p) local_unnamed_addr !dbg !7 {
8+
; CHECK-LABEL: @foo(
9+
entry:
10+
call void @llvm.dbg.value(metadata i8* %p, metadata !13, metadata !DIExpression()), !dbg !16
11+
call void @llvm.dbg.value(metadata i8 0, metadata !14, metadata !DIExpression()), !dbg !17
12+
br label %for.body, !dbg !18
13+
14+
for.cond.cleanup: ; preds = %for.body
15+
ret void, !dbg !19
16+
17+
for.body: ; preds = %entry, %for.body
18+
; CHECK-LABEL: for.body:
19+
%i.06 = phi i8 [ 0, %entry ], [ %inc, %for.body ]
20+
%p.addr.05 = phi i8* [ %p, %entry ], [ %add.ptr, %for.body ]
21+
call void @llvm.dbg.value(metadata i8 %i.06, metadata !14, metadata !DIExpression()), !dbg !17
22+
call void @llvm.dbg.value(metadata i8* %p.addr.05, metadata !13, metadata !DIExpression()), !dbg !16
23+
; CHECK-NOT: call void @llvm.dbg.value(metadata i8* undef
24+
; 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
25+
%add.ptr = getelementptr inbounds i8, i8* %p.addr.05, i64 3, !dbg !20
26+
call void @llvm.dbg.value(metadata i8* %add.ptr, metadata !13, metadata !DIExpression()), !dbg !16
27+
; CHECK-NOT: call void @llvm.dbg.value(metadata i8* undef
28+
; CHECK: call void @llvm.dbg.value(metadata i8* %lsr.iv, metadata ![[MID_p]], metadata !DIExpression()), !dbg !16
29+
store i8 %i.06, i8* %add.ptr, align 1, !dbg !23, !tbaa !24
30+
%inc = add nuw nsw i8 %i.06, 1, !dbg !27
31+
call void @llvm.dbg.value(metadata i8 %inc, metadata !14, metadata !DIExpression()), !dbg !17
32+
%exitcond.not = icmp eq i8 %inc, 32, !dbg !28
33+
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !dbg !18, !llvm.loop !29
34+
}
35+
36+
declare void @llvm.dbg.value(metadata, metadata, metadata)
37+
38+
!llvm.dbg.cu = !{!0}
39+
!llvm.module.flags = !{!3, !4, !5}
40+
!llvm.ident = !{!6}
41+
42+
!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)
43+
!1 = !DIFile(filename: "lsrdbg.c", directory: "/")
44+
!2 = !{}
45+
!3 = !{i32 7, !"Dwarf Version", i32 4}
46+
!4 = !{i32 2, !"Debug Info Version", i32 3}
47+
!5 = !{i32 1, !"wchar_size", i32 4}
48+
!6 = !{!"clang version 12.0.0"}
49+
!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)
50+
!8 = !DISubroutineType(types: !9)
51+
!9 = !{null, !10}
52+
!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
53+
!11 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
54+
!12 = !{!13, !14}
55+
!13 = !DILocalVariable(name: "p", arg: 1, scope: !7, file: !1, line: 2, type: !10)
56+
; CHECK: ![[MID_p]] = !DILocalVariable(name: "p", arg: 1, scope: !7, file: !1, line: 2, type: !10)
57+
!14 = !DILocalVariable(name: "i", scope: !15, file: !1, line: 4, type: !11)
58+
!15 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 3)
59+
!16 = !DILocation(line: 0, scope: !7)
60+
!17 = !DILocation(line: 0, scope: !15)
61+
!18 = !DILocation(line: 4, column: 3, scope: !15)
62+
!19 = !DILocation(line: 8, column: 1, scope: !7)
63+
!20 = !DILocation(line: 5, column: 7, scope: !21)
64+
!21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 4, column: 42)
65+
!22 = distinct !DILexicalBlock(scope: !15, file: !1, line: 4, column: 3)
66+
!23 = !DILocation(line: 6, column: 8, scope: !21)
67+
!24 = !{!25, !25, i64 0}
68+
!25 = !{!"omnipotent char", !26, i64 0}
69+
!26 = !{!"Simple C/C++ TBAA"}
70+
!27 = !DILocation(line: 4, column: 38, scope: !22)
71+
!28 = !DILocation(line: 4, column: 31, scope: !22)
72+
!29 = distinct !{!29, !18, !30, !31}
73+
!30 = !DILocation(line: 7, column: 3, scope: !15)
74+
!31 = !{!"llvm.loop.unroll.disable"}

0 commit comments

Comments
 (0)