-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
llvm: Fix line number information to prevent spurious breakpoint hits #20543
base: master
Are you sure you want to change the base?
Conversation
3ed994c
to
28f87ae
Compare
Is patching Builder really the correct solution here? I think the usage code, if anything, should be updated. Also I'm not convinced the order of basic blocks is the problem. |
If you move the placeBlock so that we get the same order of blocks again as we have in status quo: --- /tmp/llvm.zig 2024-07-21 18:02:01.645028639 +0200
+++ src/codegen/llvm.zig 2024-07-21 18:01:12.664540800 +0200
@@ -5962,10 +5962,10 @@
.breaks = &breaks,
});
defer assert(self.blocks.remove(inst));
+ try self.wip.placeBlock(parent_bb);
try self.genBodyDebugScope(maybe_inline_func, body);
- try self.wip.placeBlock(parent_bb);
self.wip.cursor = .{ .block = parent_bb };
// Create a phi node only if the block returns a value. an then, for example, try stepping through a for loop—this is my test code: export fn foo() u8 {
const s = [3]u32{4,5,6};
var x: u8 = 1;
for (s) |c| {
if (c == 5)
x = 2;
x = 3;
}
return x;
} —then you can see that GDB doesn't stop on the with correct block orderdefine dso_local zeroext i8 @foo() #0 !dbg !6 {
Entry:
%0 = alloca i32, align 4
%1 = alloca [8 x i8], align 8
%2 = alloca [1 x i8], align 1
call void @llvm.dbg.declare(metadata ptr @0, metadata !8, metadata !DIExpression()), !dbg !7
store i8 1, ptr %2, align 1, !dbg !9
call void @llvm.dbg.declare(metadata ptr %2, metadata !10, metadata !DIExpression()), !dbg !9
store i64 0, ptr %1, align 8, !dbg !9
br label %Loop, !dbg !11
Loop:
%3 = load i64, ptr %1, align 8, !dbg !12
%4 = icmp ult i64 %3, 3, !dbg !13
br i1 %4, label %Then, label %Else, !dbg !13
Then:
%5 = getelementptr inbounds [3 x i32], ptr @0, i64 0, i64 %3, !dbg !14
%6 = load i32, ptr %5, !dbg !14
store i32 %6, ptr %0, align 4, !dbg !14
call void @llvm.dbg.declare(metadata ptr %0, metadata !15, metadata !DIExpression()), !dbg !14
%7 = icmp eq i32 %6, 5, !dbg !16
br i1 %7, label %Then1, label %Else1, !dbg !16
Else:
br label %Block2, !dbg !14
Then1:
store i8 2, ptr %2, align 1, !dbg !17
br label %Block, !dbg !17
Else1:
br label %Block, !dbg !18
Block:
store i8 3, ptr %2, align 1, !dbg !19
br label %Block1, !dbg !19
Block1:
%8 = add nuw i64 %3, 1, !dbg !12
store i64 %8, ptr %1, align 8, !dbg !12
br label %Loop, !dbg !11
Block2:
%9 = load i8, ptr %2, align 1, !dbg !20
ret i8 %9, !dbg !20
}
and withoutdefine dso_local zeroext i8 @foo() #0 !dbg !6 {
Entry:
%0 = alloca i32, align 4
%1 = alloca [8 x i8], align 8
%2 = alloca [1 x i8], align 1
call void @llvm.dbg.declare(metadata ptr @0, metadata !8, metadata !DIExpression()), !dbg !7
store i8 1, ptr %2, align 1, !dbg !9
call void @llvm.dbg.declare(metadata ptr %2, metadata !10, metadata !DIExpression()), !dbg !9
store i64 0, ptr %1, align 8, !dbg !9
br label %Loop, !dbg !11
Block:
%3 = load i8, ptr %2, align 1, !dbg !12
ret i8 %3, !dbg !12
Loop:
%4 = load i64, ptr %1, align 8, !dbg !13
%5 = icmp ult i64 %4, 3, !dbg !14
br i1 %5, label %Then, label %Else, !dbg !14
Block1:
%6 = add nuw i64 %4, 1, !dbg !13
store i64 %6, ptr %1, align 8, !dbg !13
br label %Loop, !dbg !11
Then:
%7 = getelementptr inbounds [3 x i32], ptr @0, i64 0, i64 %4, !dbg !15
%8 = load i32, ptr %7, !dbg !15
store i32 %8, ptr %0, align 4, !dbg !15
call void @llvm.dbg.declare(metadata ptr %0, metadata !16, metadata !DIExpression()), !dbg !15
%9 = icmp eq i32 %8, 5, !dbg !17
br i1 %9, label %Then1, label %Else1, !dbg !17
Else:
br label %Block, !dbg !15
Block2:
store i8 3, ptr %2, align 1, !dbg !18
br label %Block1, !dbg !18
Then1:
store i8 2, ptr %2, align 1, !dbg !19
br label %Block2, !dbg !19
Else1:
br label %Block2, !dbg !20
}
to GDB's stepping logic, which only stops on the first instruction of a new line. Took me some head-scratching to figure that one out : ) How could I influence the block ordering without touching the Builder? |
28f87ae
to
0ec103b
Compare
I think it would be informative to look at it in terms of the LLVM IR that is being generated. |
The LLVM is the same, differing only in the order of the blocks. Hang on a sec, I can show you too... |
Updated the details tags in my previous comment. |
0ec103b
to
af84823
Compare
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
af84823
to
ca8b0a5
Compare
Fixes #19443.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not leak inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether (see comments for some more details). So we reorder some basic blocks too.