From 2a6782bb9f1d6843ab6e147765c1cdd7ee5eb90a Mon Sep 17 00:00:00 2001 From: Markus Lavin Date: Mon, 14 Dec 2020 15:37:34 +0100 Subject: [PATCH] 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 --- llvm/include/llvm/Analysis/ScalarEvolution.h | 18 ++--- .../Transforms/Scalar/LoopStrengthReduce.cpp | 65 ++++++++++++++++ llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll | 2 +- .../LoopStrengthReduce/dbg-preserve-0.ll | 74 +++++++++++++++++++ 4 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 35e569710cab..a7a24f086fbe 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1163,6 +1163,15 @@ public: const SCEV *S, const Loop *L, SmallPtrSetImpl &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 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 computeConstantDifference(const SCEV *LHS, const SCEV *RHS); - /// Drop memoized information computed for S. void forgetMemoizedResults(const SCEV *S); diff --git a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp index ddd8856e92c5..0f82e196602f 100644 --- a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -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(); } +using EqualValues = SmallVector, 4>; +using EqualValuesMap = DenseMap; + +static void DbgGatherEqualValues(Loop *L, ScalarEvolution &SE, + EqualValuesMap &DbgValueToEqualSet) { + for (auto &B : L->getBlocks()) { + for (auto &I : *B) { + auto DVI = dyn_cast(&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 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(DVI->getVariableLocation())) + continue; + for (auto EV : A.second) { + auto V = std::get(EV); + if (!V) + continue; + auto DbgDIExpr = std::get(EV); + auto Offset = std::get(EV); + auto &Ctx = DVI->getContext(); + DVI->setOperand(0, MetadataAsValue::get(Ctx, ValueAsMetadata::get(V))); + if (Offset) { + SmallVector 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; } diff --git a/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll b/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll index 08aecdac5b79..e8f37a370666 100644 --- a/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll +++ b/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll @@ -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. diff --git a/llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll b/llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll new file mode 100644 index 000000000000..71031aabb95b --- /dev/null +++ b/llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll @@ -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"}