Skip to content

Commit f49ee00

Browse files
authored
[DebugInfo][ConstraintElimination] Fix debug value loss in replacing comparisons with the speculated constants (#136839)
Fix #135736
1 parent 45d96df commit f49ee00

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
2525
#include "llvm/Analysis/ValueTracking.h"
2626
#include "llvm/IR/DataLayout.h"
27+
#include "llvm/IR/DebugInfo.h"
2728
#include "llvm/IR/Dominators.h"
2829
#include "llvm/IR/Function.h"
2930
#include "llvm/IR/IRBuilder.h"
@@ -1457,8 +1458,29 @@ static bool checkAndReplaceCondition(
14571458
return ShouldReplace;
14581459
});
14591460
NumCondsRemoved++;
1461+
1462+
// Update the debug value records that satisfy the same condition used
1463+
// in replaceUsesWithIf.
1464+
SmallVector<DbgVariableIntrinsic *> DbgUsers;
1465+
SmallVector<DbgVariableRecord *> DVRUsers;
1466+
findDbgUsers(DbgUsers, Cmp, &DVRUsers);
1467+
1468+
for (auto *DVR : DVRUsers) {
1469+
auto *DTN = DT.getNode(DVR->getParent());
1470+
if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut)
1471+
continue;
1472+
1473+
auto *MarkedI = DVR->getInstruction();
1474+
if (MarkedI->getParent() == ContextInst->getParent() &&
1475+
MarkedI->comesBefore(ContextInst))
1476+
continue;
1477+
1478+
DVR->replaceVariableLocationOp(Cmp, ConstantC);
1479+
}
1480+
14601481
if (Cmp->use_empty())
14611482
ToRemove.push_back(Cmp);
1483+
14621484
return Changed;
14631485
};
14641486

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
; RUN: opt < %s -passes=constraint-elimination -S | FileCheck %s
2+
3+
; Check that checkAndReplaceCondition() salvages the debug value information after replacing
4+
; the conditions (`%c.1` and `%t.2` in this test) with the speculated constants (GitHub Issue
5+
; #135736).
6+
; In particular, the debug value record uses should not be replaced if they come before the
7+
; context instrtuction (e.g., `%t.2` in this example).
8+
9+
declare void @llvm.assume(i1 noundef) #0
10+
11+
declare void @may_unwind()
12+
13+
declare void @use(i1)
14+
15+
define i1 @assume_single_bb_conditions_after_assume(i8 %a, i8 %b, i1 %c) !dbg !5 {
16+
; CHECK-LABEL: define i1 @assume_single_bb_conditions_after_assume(
17+
; CHECK: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1:%.*]], [[B:%.*]], !dbg [[DBG12:![0-9]+]]
18+
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]], !dbg [[DBG13:![0-9]+]]
19+
; CHECK-NEXT: #dbg_value(i1 [[C_1]], [[META9:![0-9]+]], !DIExpression(), [[META14:![0-9]+]])
20+
; CHECK-NEXT: call void @use(i1 [[C_1]]), !dbg [[DBG15:![0-9]+]]
21+
; CHECK-NEXT: #dbg_value(i1 [[C_1]], [[META9]], !DIExpression(), [[META14]])
22+
; CHECK-NEXT: call void @may_unwind(), !dbg [[DBG16:![0-9]+]]
23+
; CHECK-NEXT: #dbg_value(i1 [[C_1]], [[META9]], !DIExpression(), [[META14]])
24+
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]), !dbg [[DBG17:![0-9]+]]
25+
; CHECK-NEXT: #dbg_value(i1 [[C_1]], [[META9]], !DIExpression(), [[META14]])
26+
; CHECK-NEXT: #dbg_value(i1 true, [[META9]], !DIExpression(), [[META14]])
27+
; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true, !dbg [[DBG18:![0-9]+]]
28+
;
29+
%add.1 = add nuw nsw i8 %a, 1, !dbg !11
30+
%cmp.1 = icmp ule i8 %add.1, %b, !dbg !12
31+
%c.1 = icmp ule i8 %add.1, %b, !dbg !13
32+
#dbg_value(i1 %c.1, !9, !DIExpression(), !14)
33+
call void @use(i1 %c.1), !dbg !15
34+
#dbg_value(i1 %c.1, !9, !DIExpression(), !14)
35+
call void @may_unwind(), !dbg !16
36+
#dbg_value(i1 %c.1, !9, !DIExpression(), !14)
37+
call void @llvm.assume(i1 %cmp.1), !dbg !17
38+
#dbg_value(i1 %c.1, !9, !DIExpression(), !14)
39+
%t.2 = icmp ule i8 %a, %b, !dbg !14
40+
#dbg_value(i1 %c.1, !9, !DIExpression(), !14)
41+
%res.1 = xor i1 %c.1, %t.2, !dbg !18
42+
%add.2 = add nuw nsw i8 %a, 2, !dbg !19
43+
%c.2 = icmp ule i8 %add.2, %b, !dbg !20
44+
%res.2 = xor i1 %res.1, %c.2, !dbg !21
45+
ret i1 %res.2, !dbg !22
46+
}
47+
48+
attributes #0 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
49+
50+
!llvm.dbg.cu = !{!0}
51+
!llvm.debugify = !{!2, !3}
52+
!llvm.module.flags = !{!4}
53+
54+
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
55+
!1 = !DIFile(filename: "/app/example.ll", directory: "/")
56+
!2 = !{i32 12}
57+
!3 = !{i32 8}
58+
!4 = !{i32 2, !"Debug Info Version", i32 3}
59+
!5 = distinct !DISubprogram(name: "assume_single_bb_conditions_after_assume", linkageName: "assume_single_bb_conditions_after_assume", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
60+
!6 = !DISubroutineType(types: !7)
61+
!7 = !{}
62+
!8 = !{!9}
63+
!9 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 7, type: !10)
64+
!10 = !DIBasicType(name: "ty8", size: 8, encoding: DW_ATE_unsigned)
65+
!11 = !DILocation(line: 1, column: 1, scope: !5)
66+
!12 = !DILocation(line: 2, column: 1, scope: !5)
67+
!13 = !DILocation(line: 3, column: 1, scope: !5)
68+
!14 = !DILocation(line: 7, column: 1, scope: !5)
69+
!15 = !DILocation(line: 4, column: 1, scope: !5)
70+
!16 = !DILocation(line: 5, column: 1, scope: !5)
71+
!17 = !DILocation(line: 6, column: 1, scope: !5)
72+
!18 = !DILocation(line: 8, column: 1, scope: !5)
73+
!19 = !DILocation(line: 9, column: 1, scope: !5)
74+
!20 = !DILocation(line: 10, column: 1, scope: !5)
75+
!21 = !DILocation(line: 11, column: 1, scope: !5)
76+
!22 = !DILocation(line: 12, column: 1, scope: !5)
77+
78+
; CHECK: [[META9]] = !DILocalVariable(name: "4",
79+
; CHECK: [[DBG12]] = !DILocation(line: 2, column: 1,
80+
; CHECK: [[DBG13]] = !DILocation(line: 3, column: 1,
81+
; CHECK: [[META14]] = !DILocation(line: 7, column: 1,
82+
; CHECK: [[DBG18]] = !DILocation(line: 8, column: 1,
83+
;.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
; RUN: opt < %s -passes=constraint-elimination -S | FileCheck %s
2+
3+
; Check that checkAndReplaceCondition() salvages the debug value information after replacing
4+
; the conditions (`%t.1` in this test) with the speculated constants (GitHub Issue #135736).
5+
; In particular, debug uses are replaced if the debug record is dominated by the condition fact.
6+
7+
define i1 @test_and_ule(i4 %x, i4 %y, i4 %z) !dbg !5 {
8+
; CHECK-LABEL: define i1 @test_and_ule(
9+
; CHECK-SAME: i4 [[X:%.*]], i4 [[Y:%.*]], i4 [[Z:%.*]])
10+
; CHECK: [[T_1:%.*]] = icmp ule i4 [[X]], [[Z]], !dbg [[DBG13:![0-9]+]]
11+
;
12+
entry:
13+
%c.1 = icmp ule i4 %x, %y, !dbg !11
14+
%c.2 = icmp ule i4 %y, %z, !dbg !12
15+
%t.1 = icmp ule i4 %x, %z, !dbg !13
16+
%and = and i1 %c.1, %c.2, !dbg !14
17+
br i1 %and, label %then, label %exit, !dbg !15
18+
19+
; CHECK: [[THEN:.*]]:
20+
; CHECK-NEXT: #dbg_value(i1 true, [[META9:![0-9]+]], !DIExpression(), [[DBG13]])
21+
; CHECK-NEXT: [[R_1:%.*]] = xor i1 true, true, !dbg [[DBG16:![0-9]+]]
22+
then: ; preds = %entry
23+
#dbg_value(i1 %t.1, !9, !DIExpression(), !13)
24+
%r.1 = xor i1 %t.1, %t.1, !dbg !16
25+
br label %exit
26+
27+
; CHECK: [[EXIT:.*]]:
28+
; CHECK-NEXT: #dbg_value(i1 [[T_1]], [[META17:![0-9]+]], !DIExpression(), [[DBG13]])
29+
; CHECK-NEXT: ret i1 [[T_1]], !dbg [[DBG18:![0-9]+]]
30+
exit: ; preds = %bb1, %entry
31+
#dbg_value(i1 %t.1, !17, !DIExpression(), !13)
32+
ret i1 %t.1, !dbg !18
33+
}
34+
35+
!llvm.dbg.cu = !{!0}
36+
!llvm.debugify = !{!2, !3}
37+
!llvm.module.flags = !{!4}
38+
39+
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
40+
!1 = !DIFile(filename: "temp.ll", directory: "/")
41+
!2 = !{i32 20}
42+
!3 = !{i32 17}
43+
!4 = !{i32 2, !"Debug Info Version", i32 3}
44+
!5 = distinct !DISubprogram(name: "test_and_ule", linkageName: "test_and_ule", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
45+
!6 = !DISubroutineType(types: !7)
46+
!7 = !{}
47+
!8 = !{!9}
48+
!9 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
49+
!10 = !DIBasicType(name: "ty8", size: 8, encoding: DW_ATE_unsigned)
50+
!11 = !DILocation(line: 1, column: 1, scope: !5)
51+
!12 = !DILocation(line: 2, column: 1, scope: !5)
52+
!13 = !DILocation(line: 5, column: 1, scope: !5)
53+
!14 = !DILocation(line: 3, column: 1, scope: !5)
54+
!15 = !DILocation(line: 4, column: 1, scope: !5)
55+
!16 = !DILocation(line: 7, column: 1, scope: !5)
56+
!17 = !DILocalVariable(name: "6", scope: !5, file: !1, line: 7, type: !10)
57+
!18 = !DILocation(line: 20, column: 1, scope: !5)
58+
59+
; CHECK: [[META9]] = !DILocalVariable(name: "4",
60+
; CHECK: [[DBG13]] = !DILocation(line: 5, column: 1,
61+
; CHECK: [[DBG16]] = !DILocation(line: 7, column: 1,
62+
; CHECK: [[META17]] = !DILocalVariable(name: "6",
63+
; CHECK: [[DBG18]] = !DILocation(line: 20, column: 1,
64+
;.

0 commit comments

Comments
 (0)