Skip to content

Keep track of how scopes and locals are duplicated during inlining so that they can be correctly de-duplicated when emitting debug info #115455

Open
@dpaoliello

Description

@dpaoliello

Background

Original issue

The call to panic within a function like Option::unwrap is translated to LLVM as a tail call (as it will never return), when multiple calls to the same function like this are inlined LLVM will notice the common tail call block (i.e., loading the same panic string + location info and then calling panic) and merge them together.

When merging these instructions together, LLVM will also attempt to merge the debug locations as well, but this fails (i.e., debug info is dropped) as Rust emits a new DISubprogram at each inline site thus LLVM doesn't recognize that these are actually the same function and so thinks that there isn't a common debug location.

As an example of this, consider the following program:

#[no_mangle]
fn add_numbers(x: &Option<i32>, y: &Option<i32>) -> i32 {
    let x1 = x.unwrap();
    let y1 = y.unwrap();

    x1 + y1
}

When building for x86_64 Windows using 1.72 it generates (note the lack of .cv_loc before the call to panic, thus it will be attributed to the same line at the addq instruction):

	.cv_loc	0 1 3 0                        # src\lib.rs:3:0
	addq	$40, %rsp
	retq
	leaq	.Lalloc_f570dea0a53168780ce9a91e67646421(%rip), %rcx
	leaq	.Lalloc_629ace53b7e5b76aaa810d549cc84ea3(%rip), %r8
	movl	$43, %edx
	callq	_ZN4core9panicking5panic17h12e60b9063f6dee8E
	int3

Ideally, we would generate debug information that would allow LLVM to (partially) merge the locations together and thus maintain the correct inlining information and partial line info (since the inlined function was de-duplicated, we can't give the exact line number as that is ambiguous between the two inline sites, but we also shouldn't show an incorrect line number).

For example, we could generate something like below (which shows the panic! was inlined from unwrap in option.rs at line 935 into the current function in lib.rs at line 0):

	.cv_loc	0 1 3 0                        # src\lib.rs:3:0
	addq	$40, %rsp
	retq
	.cv_inline_site_id 6 within 0 inlined_at 1 0 0
	.cv_loc	6 2 935 0                       # library\core\src\option.rs:935:0
	leaq	.Lalloc_5f55955de67e57c79064b537689facea(%rip), %rcx
	leaq	.Lalloc_e741d4de8cb5801e1fd7a6c6795c1559(%rip), %r8
	movl	$43, %edx
	callq	_ZN4core9panicking5panic17hde1558f32d5b1c04E
	int3

New issue

I attempted to fix this by deduplicating sub-program, lexical block and variable debug info in #114643 however this resulted in asserts in LLVM when attempting to build for Linux (see #115156).

The root cause of those asserts is that Rust was generating overlapping DW_OP_LLVM_fragment info for the same local variable in two different @llvm.dbg.declare calls (i.e., that two different stack allocations represented the same part ("fragment") of the same local variable).

My current plan (#115417) is to work around this by not deduplicating lexical scopes and variables, but instead create a new lexical scope every time that a function is inlined so that subsequent lexical scopes and variables do not appear to be duplicates (from LLVM's perspective).

Long-term fix

Given that LLVM relies on exact matching to merge together debug locations, and that Clang appears to do this deduplicating in its debug information, it seems that the correct long-term fix is for Rust to also do this deduplicating.

However, to do this Rust needs to keep careful track of how locals and scopes are duplicated while inlining - either to avoid the duplication at the point of inlining or to be able to deduplicate them when emitting debug information.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.WG-debuggingWorking group: Bad Rust debugging experiences

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions