Skip to content

Commit

Permalink
[DebugInfo][RemoveDIs] Instrument loop-deletion for DPValues (#73042)
Browse files Browse the repository at this point in the history
Loop deletion identifies dbg.value intrinsics in the loop, sets them to
undef/poison, and sinks them to the exit of the loop, to ensure that any
variable assignments that happen in a deleted loop are "optimised out".
This needs to be replicated for DPValues, the non-instruction
replacement for dbg.value intrinsics.

The movement API for DPValues is (deliberately) more limited than
dbg.values, which is tricky because inserting the collection of
dbg.values at an arbitrary iterator can insert a dbg.value in the middle
of a sequence of dbg.values. A big no-no for DPValues. This patch
replicates the order by inserting DPValues in reverse at the
head-iterator of the block, to ensure the same output as dbg.value mode.
Technically the order isn't important, but we're trying to ensure
identical outputs from optimisation passes right now.

Add more CHECK lines for dbg.values in diundef.ll to ensure that we
don't create any spurious dbg.values, and to ensure that sequences of
dbg.values come out of the optimisation in the correct order.
  • Loading branch information
jmorse committed Nov 23, 2023
1 parent 6248c24 commit ce1b243
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
35 changes: 32 additions & 3 deletions llvm/lib/Transforms/Utils/LoopUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
// Use a map to unique and a vector to guarantee deterministic ordering.
llvm::SmallDenseSet<DebugVariable, 4> DeadDebugSet;
llvm::SmallVector<DbgVariableIntrinsic *, 4> DeadDebugInst;
llvm::SmallVector<DPValue *, 4> DeadDPValues;

if (ExitBlock) {
// Given LCSSA form is satisfied, we should not have users of instructions
Expand All @@ -628,6 +629,24 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
"Unexpected user in reachable block");
U.set(Poison);
}

// RemoveDIs: do the same as below for DPValues.
if (Block->IsNewDbgInfoFormat) {
for (DPValue &DPV :
llvm::make_early_inc_range(I.getDbgValueRange())) {
DebugVariable Key(DPV.getVariable(), DPV.getExpression(),
DPV.getDebugLoc().get());
if (!DeadDebugSet.insert(Key).second)
continue;
// Unlinks the DPV from it's container, for later insertion.
DPV.removeFromParent();
DeadDPValues.push_back(&DPV);
}
}

// For one of each variable encountered, preserve a debug intrinsic (set
// to Poison) and transfer it to the loop exit. This terminates any
// variable locations that were set during the loop.
auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I);
if (!DVI)
continue;
Expand All @@ -642,12 +661,22 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
// be be replaced with undef. Loop invariant values will still be available.
// Move dbg.values out the loop so that earlier location ranges are still
// terminated and loop invariant assignments are preserved.
Instruction *InsertDbgValueBefore = ExitBlock->getFirstNonPHI();
assert(InsertDbgValueBefore &&
DIBuilder DIB(*ExitBlock->getModule());
BasicBlock::iterator InsertDbgValueBefore =
ExitBlock->getFirstInsertionPt();
assert(InsertDbgValueBefore != ExitBlock->end() &&
"There should be a non-PHI instruction in exit block, else these "
"instructions will have no parent.");

for (auto *DVI : DeadDebugInst)
DVI->moveBefore(InsertDbgValueBefore);
DVI->moveBefore(*ExitBlock, InsertDbgValueBefore);

// Due to the "head" bit in BasicBlock::iterator, we're going to insert
// each DPValue right at the start of the block, wheras dbg.values would be
// repeatedly inserted before the first instruction. To replicate this
// behaviour, do it backwards.
for (DPValue *DPV : llvm::reverse(DeadDPValues))
ExitBlock->insertDPValueBefore(DPV, InsertDbgValueBefore);
}

// Remove the block from the reference counting scheme, so that we can
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/LoopDeletion/crashbc.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
; Make sure we don't crash when writing bitcode.
; RUN: opt < %s -passes=loop-deletion -o /dev/null
; RUN: opt < %s -passes=loop-deletion -o /dev/null --try-experimental-debuginfo-iterators

define void @f() {
br label %bb1
Expand Down
18 changes: 15 additions & 3 deletions llvm/test/Transforms/LoopDeletion/diundef.ll
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
; RUN: opt %s -passes=loop-deletion -S | FileCheck %s
; RUN: opt %s -passes=loop-deletion -S | FileCheck %s --implicit-check-not=dbg.value
; RUN: opt %s -passes=loop-deletion -S --try-experimental-debuginfo-iterators | FileCheck %s --implicit-check-not=dbg.value

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

@a = common local_unnamed_addr global i32 0, align 4, !dbg !0

define i32 @b() local_unnamed_addr !dbg !12 {
; CHECK-LABEL: entry
; CHECK: call void @llvm.dbg.value(metadata i32 0, metadata ![[IVAR:[0-9]+]],
; CHECK-LABEL: for.end:
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata ![[IVAR]], metadata !DIExpression()), !dbg !17
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata ![[JVAR:[0-9]+]], metadata !DIExpression()), !dbg !17
; CHECK-NEXT: %call = tail call i32 {{.*}} @patatino()
entry:
call void @llvm.dbg.value(metadata i32 0, metadata !16, metadata !DIExpression()), !dbg !17
br label %for.cond, !dbg !18
Expand All @@ -15,11 +22,10 @@ for.cond: ; preds = %for.cond, %entry
call void @llvm.dbg.value(metadata i32 %i.0, metadata !16, metadata !DIExpression()), !dbg !17
%inc = add nuw nsw i32 %i.0, 1, !dbg !21
call void @llvm.dbg.value(metadata i32 %inc, metadata !16, metadata !DIExpression()), !dbg !17
call void @llvm.dbg.value(metadata i32 %inc, metadata !37, metadata !DIExpression()), !dbg !17
%exitcond = icmp ne i32 %inc, 3, !dbg !23
br i1 %exitcond, label %for.cond, label %for.end, !dbg !24, !llvm.loop !25

; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata !16, metadata !DIExpression()), !dbg !17
; CHECK-NEXT: %call = tail call i32 {{.*}} @patatino()
for.end: ; preds = %for.cond
%call = tail call i32 (...) @patatino() #3, !dbg !27
%0 = load i32, ptr @a, align 4, !dbg !28
Expand All @@ -34,6 +40,11 @@ entry:
ret i32 0, !dbg !36
}

; CHECK: declare void @llvm.dbg.value(metadata,

; CHECK: ![[IVAR]] = !DILocalVariable(name: "i",
; CHECK: ![[JVAR]] = !DILocalVariable(name: "j",

declare void @llvm.dbg.value(metadata, metadata, metadata)

!llvm.dbg.cu = !{!2}
Expand Down Expand Up @@ -73,3 +84,4 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
!34 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 9, type: !13, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4)
!35 = !DILocation(line: 9, column: 14, scope: !34)
!36 = !DILocation(line: 9, column: 19, scope: !34)
!37 = !DILocalVariable(name: "j", scope: !12, file: !3, line: 3, type: !6)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt -S %s -passes=loop-deletion | FileCheck %s
; RUN: opt -S %s -passes=loop-deletion --try-experimental-debuginfo-iterators | FileCheck %s

;; static int foo(int Param) __attribute__((always_inline));
;; static int foo(int Param) { return Param * Param * 2; }
Expand Down

0 comments on commit ce1b243

Please sign in to comment.