-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Transforms] Debug values are not remapped when cloning. #87747
[Transforms] Debug values are not remapped when cloning. #87747
Conversation
When cloning instructions from one basic block to another, the debug values are not remapped, in the same was as the normal instructions.
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-llvm-transforms Author: Carlos Alberto Enciso (CarlosAlbertoEnciso) ChangesWhen cloning instructions from one basic block to another, Full diff: https://github.com/llvm/llvm-project/pull/87747.diff 5 Files Affected:
diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index 4f22720f1c558d..e74bf15a21b9a2 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -311,7 +311,8 @@ class DbgVariableIntrinsic : public DbgInfoIntrinsic {
Value *getVariableLocationOp(unsigned OpIdx) const;
- void replaceVariableLocationOp(Value *OldValue, Value *NewValue);
+ void replaceVariableLocationOp(Value *OldValue, Value *NewValue,
+ bool AllowEmpty = false);
void replaceVariableLocationOp(unsigned OpIdx, Value *NewValue);
/// Adding a new location operand will always result in this intrinsic using
/// an ArgList, and must always be accompanied by a new expression that uses
diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index 89403e1d7fcb4d..cff716a8430992 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -119,7 +119,8 @@ static ValueAsMetadata *getAsMetadata(Value *V) {
}
void DbgVariableIntrinsic::replaceVariableLocationOp(Value *OldValue,
- Value *NewValue) {
+ Value *NewValue,
+ bool AllowEmpty) {
// If OldValue is used as the address part of a dbg.assign intrinsic replace
// it with NewValue and return true.
auto ReplaceDbgAssignAddress = [this, OldValue, NewValue]() -> bool {
@@ -136,6 +137,8 @@ void DbgVariableIntrinsic::replaceVariableLocationOp(Value *OldValue,
auto Locations = location_ops();
auto OldIt = find(Locations, OldValue);
if (OldIt == Locations.end()) {
+ if (AllowEmpty)
+ return;
assert(DbgAssignAddrReplaced &&
"OldValue must be dbg.assign addr if unused in DIArgList");
return;
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index ffcb511e6a8312..d7936969011e66 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -2694,6 +2694,35 @@ bool JumpThreadingPass::duplicateCondBranchOnPHIIntoPred(
New->setOperand(i, I->second);
}
+ // Remap debug variable operands.
+ auto RemapDebugVariable = [](auto &Mapping, auto *Inst) {
+ auto RemapDebugOperands = [&Mapping](auto *DV, auto Set) {
+ for (auto *Op : Set)
+ if (Instruction *InstOp = dyn_cast<Instruction>(Op)) {
+ auto I = Mapping.find(InstOp);
+ if (I != Mapping.end())
+ DV->replaceVariableLocationOp(Op, I->second, /*AllowEmpty=*/true);
+ }
+ };
+ auto RemapAssignAddress = [&Mapping](auto *DA) {
+ if (Instruction *Addr = dyn_cast<Instruction>(DA->getAddress())) {
+ auto I = Mapping.find(Addr);
+ if (I != Mapping.end())
+ DA->setAddress(I->second);
+ }
+ };
+ if (auto DVI = dyn_cast<DbgVariableIntrinsic>(Inst))
+ RemapDebugOperands(DVI, DVI->location_ops());
+ if (auto DAI = dyn_cast<DbgAssignIntrinsic>(Inst))
+ RemapAssignAddress(DAI);
+ for (DbgVariableRecord &DVR : filterDbgVars(Inst->getDbgRecordRange())) {
+ RemapDebugOperands(&DVR, DVR.location_ops());
+ if (DVR.isDbgAssign())
+ RemapAssignAddress(&DVR);
+ }
+ };
+ RemapDebugVariable(ValueMapping, New);
+
// If this instruction can be simplified after the operands are updated,
// just use the simplified value instead. This frequently happens due to
// phi translation.
diff --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp
index 3eac726994ae13..de58e1b759f96b 100644
--- a/llvm/lib/Transforms/Utils/CloneFunction.cpp
+++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp
@@ -1131,6 +1131,35 @@ BasicBlock *llvm::DuplicateInstructionsInSplitBetween(
if (I != ValueMapping.end())
New->setOperand(i, I->second);
}
+
+ // Remap debug variable operands.
+ auto RemapDebugVariable = [](auto &Mapping, auto *Inst) {
+ auto RemapDebugOperands = [&Mapping](auto *DV, auto Set) {
+ for (auto *Op : Set)
+ if (Instruction *InstOp = dyn_cast<Instruction>(Op)) {
+ auto I = Mapping.find(InstOp);
+ if (I != Mapping.end())
+ DV->replaceVariableLocationOp(Op, I->second, /*AllowEmpty=*/true);
+ }
+ };
+ auto RemapAssignAddress = [&Mapping](auto *DA) {
+ if (Instruction *Addr = dyn_cast<Instruction>(DA->getAddress())) {
+ auto I = Mapping.find(Addr);
+ if (I != Mapping.end())
+ DA->setAddress(I->second);
+ }
+ };
+ if (auto DVI = dyn_cast<DbgVariableIntrinsic>(Inst))
+ RemapDebugOperands(DVI, DVI->location_ops());
+ if (auto DAI = dyn_cast<DbgAssignIntrinsic>(Inst))
+ RemapAssignAddress(DAI);
+ for (DbgVariableRecord &DVR : filterDbgVars(Inst->getDbgRecordRange())) {
+ RemapDebugOperands(&DVR, DVR.location_ops());
+ if (DVR.isDbgAssign())
+ RemapAssignAddress(&DVR);
+ }
+ };
+ RemapDebugVariable(ValueMapping, New);
}
return NewBB;
diff --git a/llvm/test/Transforms/CallSiteSplitting/callsite-split-debug.ll b/llvm/test/Transforms/CallSiteSplitting/callsite-split-debug.ll
index 8f10dcb30d7bfd..68c906d616c92d 100644
--- a/llvm/test/Transforms/CallSiteSplitting/callsite-split-debug.ll
+++ b/llvm/test/Transforms/CallSiteSplitting/callsite-split-debug.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=callsite-splitting -o - < %s | FileCheck %s
+; RUN: opt -S -passes=callsite-splitting -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-DEBUG
; RUN: opt -S -strip-debug -passes=callsite-splitting -o - < %s | FileCheck %s
define internal i16 @bar(i16 %p1, i16 %p2) {
@@ -8,6 +8,9 @@ define internal i16 @bar(i16 %p1, i16 %p2) {
define i16 @foo(i16 %in) {
bb0:
+ %a = alloca i16, align 4, !DIAssignID !12
+ call void @llvm.dbg.assign(metadata i1 undef, metadata !11, metadata !DIExpression(), metadata !12, metadata ptr %a, metadata !DIExpression()), !dbg !8
+ store i16 7, ptr %a, align 4, !DIAssignID !13
br label %bb1
bb1:
@@ -20,13 +23,21 @@ bb2:
CallsiteBB:
%1 = phi i16 [ 0, %bb1 ], [ 1, %bb2 ]
%c = phi i16 [ 2, %bb1 ], [ 3, %bb2 ]
+ %p = phi ptr [ %a, %bb1 ], [ %a, %bb2 ]
+ call void @llvm.dbg.value(metadata i16 %1, metadata !7, metadata !DIExpression()), !dbg !8
call void @llvm.dbg.value(metadata i16 %c, metadata !7, metadata !DIExpression()), !dbg !8
+ call void @llvm.dbg.value(metadata !DIArgList(i16 %1, i16 %c), metadata !7, metadata !DIExpression()), !dbg !8
+ call void @llvm.dbg.value(metadata !DIArgList(i16 %c, i16 %c), metadata !7, metadata !DIExpression()), !dbg !8
+ call void @llvm.dbg.assign(metadata i16 %1, metadata !11, metadata !DIExpression(), metadata !13, metadata ptr %a, metadata !DIExpression()), !dbg !8
+ call void @llvm.dbg.assign(metadata i16 %c, metadata !11, metadata !DIExpression(), metadata !13, metadata ptr %a, metadata !DIExpression()), !dbg !8
+ call void @llvm.dbg.assign(metadata i16 %1, metadata !11, metadata !DIExpression(), metadata !13, metadata ptr %p, metadata !DIExpression()), !dbg !8
%2 = call i16 @bar(i16 %1, i16 5)
ret i16 %2
}
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
attributes #0 = { nounwind readnone speculatable }
@@ -43,14 +54,37 @@ attributes #0 = { nounwind readnone speculatable }
!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, unit: !0)
!7 = !DILocalVariable(name: "c", scope: !6, line: 5, type: !5)
!8 = !DILocation(line: 5, column: 7, scope: !6)
+!11 = !DILocalVariable(name: "a", scope: !6, line: 6, type: !5)
+!12 = distinct !DIAssignID()
+!13 = distinct !DIAssignID()
; The optimization should trigger even in the presence of the dbg.value in
; CallSiteBB.
; CHECK-LABEL: @foo
; CHECK-LABEL: bb1.split:
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata i16 0, metadata ![[DBG_1:[0-9]+]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata i16 2, metadata ![[DBG_1]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata !DIArgList(i16 0, i16 2), {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata !DIArgList(i16 2, i16 2), {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.assign(metadata i16 0, metadata ![[DBG_2:[0-9]+]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.assign(metadata i16 2, metadata ![[DBG_2]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.assign(metadata i16 0, metadata ![[DBG_2]], metadata !DIExpression(), metadata ![[ID_1:[0-9]+]], metadata ptr %a, {{.*}}
; CHECK: [[TMP1:%[0-9]+]] = call i16 @bar(i16 0, i16 5)
+
; CHECK-LABEL: bb2.split:
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata i16 1, metadata ![[DBG_1]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata i16 3, metadata ![[DBG_1]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata !DIArgList(i16 1, i16 3), {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.value(metadata !DIArgList(i16 3, i16 3), {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.assign(metadata i16 1, metadata ![[DBG_2]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.assign(metadata i16 3, metadata ![[DBG_2]], {{.*}}
+; CHECK-DEBUG: call void @llvm.dbg.assign(metadata i16 1, metadata ![[DBG_2]], metadata !DIExpression(), metadata ![[ID_1:[0-9]+]], metadata ptr %a, {{.*}}
; CHECK: [[TMP2:%[0-9]+]] = call i16 @bar(i16 1, i16 5)
+
; CHECK-LABEL: CallsiteBB
; CHECK: %phi.call = phi i16 [ [[TMP2]], %bb2.split ], [ [[TMP1]], %bb1.split
+
+; CHECK-DEBUG-DAG: ![[DBG_1]] = !DILocalVariable(name: "c"{{.*}})
+; CHECK-DEBUG-DAG: ![[DBG_2]] = !DILocalVariable(name: "a"{{.*}})
+; CHECK-DEBUG-DAG: ![[ID_1]] = distinct !DIAssignID()
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes all look good, with one inline question.
llvm/lib/IR/IntrinsicInst.cpp
Outdated
if (AllowEmpty) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this needed now (can you point to a test that fails without it)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The included test fails:
llvm/test/Transforms/CallSiteSplitting/callsite-split-debug.ll
This is the line that triggers the assertion:
call void @llvm.dbg.value(metadata !DIArgList(i16 %c, i16 %c), metadata !7, metadata !DIExpression()), !dbg !8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, looking at the DbgVariableRecord::replaceVariableLocationOp
the condition should be:
if (AllowEmpty || DbgAssignAddrReplaced)
return;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, yeah that makes sense. Thanks!
When cloning instructions from one basic block to another, the debug values are not remapped, in the same was as the normal instructions. Missing condition '|| DbgAssignAddrReplaced' to account for any 'dbg.assign' replacement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
When cloning instructions from one basic block to another, the debug values are not remapped, in the same was as the normal instructions. - Make 'RemapDebugVariable' a general function by moving it to 'Transform/Utils/Local'. - Change in 'JumpThreading' parameters, return values and local instances: DenseMap<Instruction *, Value *> to ValueToValueMapTy.
@OCHyams Thanks for your review. |
void JumpThreadingPass::cloneInstructions(ValueToValueMapTy &ValueMapping, | ||
BasicBlock::iterator BI, | ||
BasicBlock::iterator BE, | ||
BasicBlock *NewBB, | ||
BasicBlock *PredBB) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it necessary to change the return value to an out-parameter here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to the compilation error: use of deleted function
// ValueMap can't be copied nor moved, because the callbacks store pointer to
// it.
ValueMap(const ValueMap &) = delete;
ValueMap(ValueMap &&) = delete;
ValueMap &operator=(const ValueMap &) = delete;
ValueMap &operator=(ValueMap &&) = delete;
using ValueToValueMapTy = ValueMap<const Value *, WeakTrackingVH>;
ValueMap
can't be copied nor moved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two small things, then this LGTM. Thanks!
llvm/lib/Transforms/Utils/Local.cpp
Outdated
void llvm::remapDebugVariable(ValueToValueMapTy &Mapping, Instruction *Inst) { | ||
auto RemapDebugOperands = [&Mapping](auto *DV, auto Set) { | ||
for (auto *Op : Set) | ||
if (Instruction *InstOp = dyn_cast<Instruction>(Op)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that we need the dyn_cast
checks now that you're passing in a ValueToValueMapTy
given that the key is a Value *
. Could you remove them please?
/// Remap the debug intrinsic instructions in the \p Mapping using the | ||
/// \p Inst as a criteria. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the wording of this comment is slightly unclear. What do you think of this instead?
"Remap the operands of the debug records attached to \p Inst, and the operands of \p Inst itself if it's a debug intrinsic."
When cloning instructions from one basic block to another, the debug values are not remapped, in the same was as the normal instructions. - Rewording a comment to add more clarity. - Remove not required 'dyn_cast.
@OCHyams Thanks for your review. |
llvm/lib/Transforms/Utils/Local.cpp
Outdated
void llvm::remapDebugVariable(ValueToValueMapTy &Mapping, Instruction *Inst) { | ||
auto RemapDebugOperands = [&Mapping](auto *DV, auto Set) { | ||
for (auto *Op : Set) | ||
if (auto *InstOp = Op) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You still have the if
statements, but they're not needed either. Please can you remove those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same again below - I don't think if (Instruction *Addr = dyn_cast<Instruction>(DA->getAddress())) {
is needed on line 3661.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@OCHyams Reworked the patch to remove those if
s. Thanks.
When cloning instructions from one basic block to another, the debug values are not remapped, in the same was as the normal instructions. - After removing the 'dyn_cast' checks, the following 'if's are not required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments look sufficiently addressed, LGTM
@SLTozer Thanks. |
When cloning instructions from one basic block to another,
the debug values are not remapped, in the same was as the
normal instructions.