Skip to content

Commit 59fab22

Browse files
committed
[DebugInfo][RemoveDIs] Support cloning and remapping DPValues (#72546)
This patch adds support for CloneBasicBlock duplicating the DPValues attached to instructions, and adds facilities to remap them into their new context. The plumbing to achieve this is fairly straightforwards and mechanical. I've also added illustrative uses to LoopUnrollRuntime, SimpleLoopUnswitch and SimplifyCFG. The former only updates for the epilogue right now so I've added CHECK lines just for the end of an unrolled loop (further updates coming later). SimpleLoopUnswitch had no debug-info tests so I've added a new one. The two modified parts of SimplifyCFG are covered by the two modified SimplifyCFG tests. These are scenarios where we have to do extra cloning for copying of DPValues because they're no longer instructions, and remap them too.
1 parent 2f7c050 commit 59fab22

File tree

10 files changed

+326
-1
lines changed

10 files changed

+326
-1
lines changed

llvm/include/llvm/Transforms/Utils/ValueMapper.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,26 @@
1515
#define LLVM_TRANSFORMS_UTILS_VALUEMAPPER_H
1616

1717
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/simple_ilist.h"
1819
#include "llvm/IR/ValueHandle.h"
1920
#include "llvm/IR/ValueMap.h"
2021

2122
namespace llvm {
2223

2324
class Constant;
25+
class DIBuilder;
26+
class DPValue;
2427
class Function;
2528
class GlobalVariable;
2629
class Instruction;
2730
class MDNode;
2831
class Metadata;
32+
class Module;
2933
class Type;
3034
class Value;
3135

3236
using ValueToValueMapTy = ValueMap<const Value *, WeakTrackingVH>;
37+
using DPValueIterator = simple_ilist<DPValue>::iterator;
3338

3439
/// This is a class that can be implemented by clients to remap types when
3540
/// cloning constants and instructions.
@@ -175,6 +180,8 @@ class ValueMapper {
175180
Constant *mapConstant(const Constant &C);
176181

177182
void remapInstruction(Instruction &I);
183+
void remapDPValue(Module *M, DPValue &V);
184+
void remapDPValueRange(Module *M, iterator_range<DPValueIterator> Range);
178185
void remapFunction(Function &F);
179186
void remapGlobalObjectMetadata(GlobalObject &GO);
180187

@@ -260,6 +267,22 @@ inline void RemapInstruction(Instruction *I, ValueToValueMapTy &VM,
260267
ValueMapper(VM, Flags, TypeMapper, Materializer).remapInstruction(*I);
261268
}
262269

270+
/// Remap the Values used in the DPValue \a V using the value map \a VM.
271+
inline void RemapDPValue(Module *M, DPValue *V, ValueToValueMapTy &VM,
272+
RemapFlags Flags = RF_None,
273+
ValueMapTypeRemapper *TypeMapper = nullptr,
274+
ValueMaterializer *Materializer = nullptr) {
275+
ValueMapper(VM, Flags, TypeMapper, Materializer).remapDPValue(M, *V);
276+
}
277+
278+
/// Remap the Values used in the DPValue \a V using the value map \a VM.
279+
inline void RemapDPValueRange(Module *M, iterator_range<DPValueIterator> Range,
280+
ValueToValueMapTy &VM, RemapFlags Flags = RF_None,
281+
ValueMapTypeRemapper *TypeMapper = nullptr,
282+
ValueMaterializer *Materializer = nullptr) {
283+
ValueMapper(VM, Flags, TypeMapper, Materializer).remapDPValueRange(M, Range);
284+
}
285+
263286
/// Remap the operands, metadata, arguments, and instructions of a function.
264287
///
265288
/// Calls \a MapValue() on prefix data, prologue data, and personality

llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,8 +1257,11 @@ static BasicBlock *buildClonedLoopBlocks(
12571257
// everything available. Also, we have inserted new instructions which may
12581258
// include assume intrinsics, so we update the assumption cache while
12591259
// processing this.
1260+
Module *M = ClonedPH->getParent()->getParent();
12601261
for (auto *ClonedBB : NewBlocks)
12611262
for (Instruction &I : *ClonedBB) {
1263+
RemapDPValueRange(M, I.getDbgValueRange(), VMap,
1264+
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
12621265
RemapInstruction(&I, VMap,
12631266
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
12641267
if (auto *II = dyn_cast<AssumeInst>(&I))

llvm/lib/Transforms/Utils/CloneFunction.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap,
5959
Instruction *NewInst = I.clone();
6060
if (I.hasName())
6161
NewInst->setName(I.getName() + NameSuffix);
62-
NewInst->insertInto(NewBB, NewBB->end());
62+
63+
NewInst->insertBefore(*NewBB, NewBB->end());
64+
NewInst->cloneDebugInfoFrom(&I);
65+
6366
VMap[&I] = NewInst; // Add instruction map to value.
6467

6568
if (isa<CallInst>(I) && !I.isDebugOrPseudoInst()) {

llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,9 +913,12 @@ bool llvm::UnrollRuntimeLoopRemainder(
913913
// Rewrite the cloned instruction operands to use the values created when the
914914
// clone is created.
915915
for (BasicBlock *BB : NewBlocks) {
916+
Module *M = BB->getModule();
916917
for (Instruction &I : *BB) {
917918
RemapInstruction(&I, VMap,
918919
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
920+
RemapDPValueRange(M, I.getDbgValueRange(), VMap,
921+
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
919922
}
920923
}
921924

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,9 @@ static void CloneInstructionsIntoPredecessorBlockAndUpdateSSAUses(
11261126
NewBonusInst->dropUBImplyingAttrsAndMetadata();
11271127

11281128
NewBonusInst->insertInto(PredBlock, PTI->getIterator());
1129+
auto Range = NewBonusInst->cloneDebugInfoFrom(&BonusInst);
1130+
RemapDPValueRange(NewBonusInst->getModule(), Range, VMap,
1131+
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
11291132

11301133
if (isa<DbgInfoIntrinsic>(BonusInst))
11311134
continue;
@@ -3303,6 +3306,10 @@ FoldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
33033306
BasicBlock::iterator InsertPt = EdgeBB->getFirstInsertionPt();
33043307
DenseMap<Value *, Value *> TranslateMap; // Track translated values.
33053308
TranslateMap[Cond] = CB;
3309+
3310+
// RemoveDIs: track instructions that we optimise away while folding, so
3311+
// that we can copy DPValues from them later.
3312+
BasicBlock::iterator SrcDbgCursor = BB->begin();
33063313
for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) {
33073314
if (PHINode *PN = dyn_cast<PHINode>(BBI)) {
33083315
TranslateMap[PN] = PN->getIncomingValueForBlock(EdgeBB);
@@ -3337,13 +3344,26 @@ FoldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
33373344
TranslateMap[&*BBI] = N;
33383345
}
33393346
if (N) {
3347+
// Copy all debug-info attached to instructions from the last we
3348+
// successfully clone, up to this instruction (they might have been
3349+
// folded away).
3350+
for (; SrcDbgCursor != BBI; ++SrcDbgCursor)
3351+
N->cloneDebugInfoFrom(&*SrcDbgCursor);
3352+
SrcDbgCursor = std::next(BBI);
3353+
// Clone debug-info on this instruction too.
3354+
N->cloneDebugInfoFrom(&*BBI);
3355+
33403356
// Register the new instruction with the assumption cache if necessary.
33413357
if (auto *Assume = dyn_cast<AssumeInst>(N))
33423358
if (AC)
33433359
AC->registerAssumption(Assume);
33443360
}
33453361
}
33463362

3363+
for (; &*SrcDbgCursor != BI; ++SrcDbgCursor)
3364+
InsertPt->cloneDebugInfoFrom(&*SrcDbgCursor);
3365+
InsertPt->cloneDebugInfoFrom(BI);
3366+
33473367
BB->removePredecessor(EdgeBB);
33483368
BranchInst *EdgeBI = cast<BranchInst>(EdgeBB->getTerminator());
33493369
EdgeBI->setSuccessor(0, RealDest);
@@ -3748,6 +3768,16 @@ static bool performBranchToCommonDestFolding(BranchInst *BI, BranchInst *PBI,
37483768
ValueToValueMapTy VMap; // maps original values to cloned values
37493769
CloneInstructionsIntoPredecessorBlockAndUpdateSSAUses(BB, PredBlock, VMap);
37503770

3771+
Module *M = BB->getModule();
3772+
3773+
if (PredBlock->IsNewDbgInfoFormat) {
3774+
PredBlock->getTerminator()->cloneDebugInfoFrom(BB->getTerminator());
3775+
for (DPValue &DPV : PredBlock->getTerminator()->getDbgValueRange()) {
3776+
RemapDPValue(M, &DPV, VMap,
3777+
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
3778+
}
3779+
}
3780+
37513781
// Now that the Cond was cloned into the predecessor basic block,
37523782
// or/and the two conditions together.
37533783
Value *BICond = VMap[BI->getCondition()];

llvm/lib/Transforms/Utils/ValueMapper.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "llvm/IR/InlineAsm.h"
3232
#include "llvm/IR/Instruction.h"
3333
#include "llvm/IR/Instructions.h"
34+
#include "llvm/IR/IntrinsicInst.h"
3435
#include "llvm/IR/Metadata.h"
3536
#include "llvm/IR/Operator.h"
3637
#include "llvm/IR/Type.h"
@@ -145,6 +146,7 @@ class Mapper {
145146
Value *mapValue(const Value *V);
146147
void remapInstruction(Instruction *I);
147148
void remapFunction(Function &F);
149+
void remapDPValue(DPValue &DPV);
148150

149151
Constant *mapConstant(const Constant *C) {
150152
return cast_or_null<Constant>(mapValue(C));
@@ -535,6 +537,39 @@ Value *Mapper::mapValue(const Value *V) {
535537
return getVM()[V] = ConstantPointerNull::get(cast<PointerType>(NewTy));
536538
}
537539

540+
void Mapper::remapDPValue(DPValue &V) {
541+
// Remap variables and DILocations.
542+
auto *MappedVar = mapMetadata(V.getVariable());
543+
auto *MappedDILoc = mapMetadata(V.getDebugLoc());
544+
V.setVariable(cast<DILocalVariable>(MappedVar));
545+
V.setDebugLoc(DebugLoc(cast<DILocation>(MappedDILoc)));
546+
547+
// Find Value operands and remap those.
548+
SmallVector<Value *, 4> Vals, NewVals;
549+
for (Value *Val : V.location_ops())
550+
Vals.push_back(Val);
551+
for (Value *Val : Vals)
552+
NewVals.push_back(mapValue(Val));
553+
554+
// If there are no changes to the Value operands, finished.
555+
if (Vals == NewVals)
556+
return;
557+
558+
bool IgnoreMissingLocals = Flags & RF_IgnoreMissingLocals;
559+
560+
// Otherwise, do some replacement.
561+
if (!IgnoreMissingLocals &&
562+
llvm::any_of(NewVals, [&](Value *V) { return V == nullptr; })) {
563+
V.setKillLocation();
564+
} else {
565+
// Either we have all non-empty NewVals, or we're permitted to ignore
566+
// missing locals.
567+
for (unsigned int I = 0; I < Vals.size(); ++I)
568+
if (NewVals[I])
569+
V.replaceVariableLocationOp(I, NewVals[I]);
570+
}
571+
}
572+
538573
Value *Mapper::mapBlockAddress(const BlockAddress &BA) {
539574
Function *F = cast<Function>(mapValue(BA.getFunction()));
540575

@@ -1179,6 +1214,17 @@ void ValueMapper::remapInstruction(Instruction &I) {
11791214
FlushingMapper(pImpl)->remapInstruction(&I);
11801215
}
11811216

1217+
void ValueMapper::remapDPValue(Module *M, DPValue &V) {
1218+
FlushingMapper(pImpl)->remapDPValue(V);
1219+
}
1220+
1221+
void ValueMapper::remapDPValueRange(
1222+
Module *M, iterator_range<DPValue::self_iterator> Range) {
1223+
for (DPValue &DPV : Range) {
1224+
remapDPValue(M, DPV);
1225+
}
1226+
}
1227+
11821228
void ValueMapper::remapFunction(Function &F) {
11831229
FlushingMapper(pImpl)->remapFunction(F);
11841230
}

llvm/test/Transforms/LoopUnroll/runtime-epilog-debuginfo.ll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
; RUN: opt -passes=loop-unroll -unroll-runtime -unroll-runtime-epilog -S %s | FileCheck %s
2+
; RUN: opt -passes=loop-unroll -unroll-runtime -unroll-runtime-epilog -S %s --try-experimental-debuginfo-iterators | FileCheck %s
23

34
; Test that epilogue is tagged with the same debug information as original loop body rather than original loop exit.
45

@@ -11,6 +12,18 @@
1112
; CHECK: br i1 %lcmp.mod, label %for.body.i.epil.preheader, label %lee1.exit.loopexit, !dbg ![[LOOP_LOC]]
1213
; CHECK: for.body.i.epil.preheader:
1314
; CHECK: br label %for.body.i.epil, !dbg ![[LOOP_LOC]]
15+
; CHECK: for.body.i.epil:
16+
;; Ensure that when we clone the div/add/add and its following dbg.values,
17+
;; those dbg.values are remapped to the duplicated adds, not the originals.
18+
; CHECK: %div.i.epil = sdiv i32 %t.08.i.epil, 2,
19+
; CHECK-NEXT: %add.i.epil = add i32 %t.08.i.epil, %a,
20+
; CHECK-NEXT: %add1.i.epil = add i32 %add.i.epil, %div.i.epil,
21+
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %add1.i.epil,
22+
; CHECK-NEXT: %inc.i.epil = add nuw i32 %i.09.i.epil, 1, !dbg !36
23+
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %inc.i.epil,
24+
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %inc.i.epil,
25+
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %add1.i.epil,
26+
1427
; CHECK: lee1.exit.loopexit:
1528
; CHECK: br label %lee1.exit, !dbg ![[EXIT_LOC:[0-9]+]]
1629

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>),verify<loops>' -S < %s | FileCheck %s
3+
; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>),verify<loops>' -S < %s --try-experimental-debuginfo-iterators | FileCheck %s
4+
;
5+
;; Check that when we duplicate the load in the loop header, we also duplicate
6+
;; the corresponding dbg.value.
7+
;; FIXME: the hoisted load dominates the duplicated dbg.value, however as it's
8+
;; not subsequently used in the loop, so it doesn't get remapped into the
9+
;; debug user and we get a undef/poison dbg.value. This is suboptimal, but it's
10+
;; important that the dbg.value gets duplicated nonetheless.
11+
12+
declare void @clobber()
13+
declare void @llvm.dbg.value(metadata, metadata, metadata)
14+
15+
define i32 @partial_unswitch_true_successor(ptr %ptr, i32 %N) {
16+
; CHECK-LABEL: @partial_unswitch_true_successor(
17+
; CHECK-NEXT: entry:
18+
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR:%.*]], align 4
19+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 100
20+
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
21+
; CHECK: entry.split.us:
22+
; CHECK-NEXT: br label [[LOOP_HEADER_US:%.*]]
23+
; CHECK: loop.header.us:
24+
; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ], [ [[IV_NEXT_US:%.*]], [[LOOP_LATCH_US:%.*]] ]
25+
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 poison, metadata [[META3:![0-9]+]], metadata !DIExpression()), !dbg [[DBG8:![0-9]+]]
26+
; CHECK-NEXT: br label [[NOCLOBBER_US:%.*]]
27+
; CHECK: noclobber.us:
28+
; CHECK-NEXT: br label [[LOOP_LATCH_US]]
29+
; CHECK: loop.latch.us:
30+
; CHECK-NEXT: [[C_US:%.*]] = icmp ult i32 [[IV_US]], [[N:%.*]]
31+
; CHECK-NEXT: [[IV_NEXT_US]] = add i32 [[IV_US]], 1
32+
; CHECK-NEXT: br i1 [[C_US]], label [[LOOP_HEADER_US]], label [[EXIT_SPLIT_US:%.*]]
33+
; CHECK: exit.split.us:
34+
; CHECK-NEXT: br label [[EXIT:%.*]]
35+
; CHECK: entry.split:
36+
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
37+
; CHECK: loop.header:
38+
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
39+
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr [[PTR]], align 4
40+
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[LV]], metadata [[META3]], metadata !DIExpression()), !dbg [[DBG8]]
41+
; CHECK-NEXT: [[SC:%.*]] = icmp eq i32 [[LV]], 100
42+
; CHECK-NEXT: br i1 [[SC]], label [[NOCLOBBER:%.*]], label [[CLOBBER:%.*]]
43+
; CHECK: noclobber:
44+
; CHECK-NEXT: br label [[LOOP_LATCH]]
45+
; CHECK: clobber:
46+
; CHECK-NEXT: call void @clobber()
47+
; CHECK-NEXT: br label [[LOOP_LATCH]]
48+
; CHECK: loop.latch:
49+
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], [[N]]
50+
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
51+
; CHECK-NEXT: br i1 [[C]], label [[LOOP_HEADER]], label [[EXIT_SPLIT:%.*]], !llvm.loop [[LOOP9:![0-9]+]]
52+
; CHECK: exit.split:
53+
; CHECK-NEXT: br label [[EXIT]]
54+
; CHECK: exit:
55+
; CHECK-NEXT: ret i32 10
56+
;
57+
entry:
58+
br label %loop.header
59+
60+
loop.header:
61+
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
62+
%lv = load i32, ptr %ptr
63+
call void @llvm.dbg.value(metadata i32 %lv, metadata !6, metadata !DIExpression()), !dbg !7
64+
%sc = icmp eq i32 %lv, 100
65+
br i1 %sc, label %noclobber, label %clobber
66+
67+
noclobber:
68+
br label %loop.latch
69+
70+
clobber:
71+
call void @clobber()
72+
br label %loop.latch
73+
74+
loop.latch:
75+
%c = icmp ult i32 %iv, %N
76+
%iv.next = add i32 %iv, 1
77+
br i1 %c, label %loop.header, label %exit
78+
79+
exit:
80+
ret i32 10
81+
}
82+
83+
!llvm.module.flags = !{!21}
84+
!llvm.dbg.cu = !{!2}
85+
86+
!0 = distinct !DISubprogram(name: "foo", line: 2, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !20, scope: !1, type: !3)
87+
!1 = !DIFile(filename: "b.c", directory: "/private/tmp")
88+
!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", isOptimized: true, emissionKind: FullDebug, file: !20)
89+
!3 = !DISubroutineType(types: !4)
90+
!4 = !{!5}
91+
!5 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
92+
!6 = !DILocalVariable(name: "i", line: 2, arg: 1, scope: !0, file: !1, type: !5)
93+
!7 = !DILocation(line: 2, column: 13, scope: !0)
94+
!9 = !DILocalVariable(name: "k", line: 3, scope: !10, file: !1, type: !5)
95+
!10 = distinct !DILexicalBlock(line: 2, column: 16, file: !20, scope: !0)
96+
!11 = !DILocation(line: 3, column: 12, scope: !10)
97+
!12 = !DILocation(line: 4, column: 3, scope: !10)
98+
!13 = !DILocation(line: 5, column: 5, scope: !14)
99+
!14 = distinct !DILexicalBlock(line: 4, column: 10, file: !20, scope: !10)
100+
!15 = !DILocation(line: 6, column: 3, scope: !14)
101+
!16 = !DILocation(line: 7, column: 5, scope: !17)
102+
!17 = distinct !DILexicalBlock(line: 6, column: 10, file: !20, scope: !10)
103+
!18 = !DILocation(line: 8, column: 3, scope: !17)
104+
!19 = !DILocation(line: 9, column: 3, scope: !10)
105+
!20 = !DIFile(filename: "b.c", directory: "/private/tmp")
106+
!21 = !{i32 1, !"Debug Info Version", i32 3}
107+
108+

llvm/test/Transforms/SimplifyCFG/branch-fold-dbg.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s
3+
; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s --try-experimental-debuginfo-iterators | FileCheck %s
34

45
%0 = type { ptr, ptr }
56

0 commit comments

Comments
 (0)