Remove reachable coverage without counters
Remove reachable coverage without counters to maintain invariant that either there is no coverage at all or there is a live coverage counter left that provides the function source hash. The motivating example would be a following closure: ```rust let f = |x: bool| { debug_assert!(x); }; ``` Which, with span changes from #93967, with disabled debug assertions, after the final CFG simplifications but before removal of dead blocks, gives rise to MIR: ```rust fn main::{closure#0}(_1: &[closure@a.rs:2:13: 2:22], _2: bool) -> () { debug x => _2; let mut _0: (); bb0: { Coverage::Expression(4294967295) = 1 - 2; return; } ... } ```
This commit is contained in:
parent
2f320a224e
commit
5f40a4f7a0
3 changed files with 42 additions and 18 deletions
|
@ -315,7 +315,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
/// with `0` executions.
|
/// with `0` executions.
|
||||||
///
|
///
|
||||||
/// If there are no live `Counter` `Coverage` statements remaining, we remove
|
/// If there are no live `Counter` `Coverage` statements remaining, we remove
|
||||||
/// dead `Coverage` statements along with the dead blocks. Since at least one
|
/// `Coverage` statements along with the dead blocks. Since at least one
|
||||||
/// counter per function is required by LLVM (and necessary, to add the
|
/// counter per function is required by LLVM (and necessary, to add the
|
||||||
/// `function_hash` to the counter's call to the LLVM intrinsic
|
/// `function_hash` to the counter's call to the LLVM intrinsic
|
||||||
/// `instrprof.increment()`).
|
/// `instrprof.increment()`).
|
||||||
|
@ -342,6 +342,16 @@ fn save_unreachable_coverage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for block in &mut basic_blocks.raw[..first_dead_block] {
|
||||||
|
for statement in &mut block.statements {
|
||||||
|
let StatementKind::Coverage(_) = &statement.kind else { continue };
|
||||||
|
let instance = statement.source_info.scope.inlined_instance(source_scopes);
|
||||||
|
if !live.contains(&instance) {
|
||||||
|
statement.make_nop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if live.is_empty() {
|
if live.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
1| |// Regression test for issue #98833.
|
1| |// Regression test for issue #98833.
|
||||||
2| |// compile-flags: -Zinline-mir
|
2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off
|
||||||
3| |
|
3| |
|
||||||
4| 1|fn main() {
|
4| 1|fn main() {
|
||||||
5| 1| println!("{}", live::<false>());
|
5| 1| println!("{}", live::<false>());
|
||||||
6| 1|}
|
6| 1|
|
||||||
7| |
|
7| 1| let f = |x: bool| {
|
||||||
8| |#[inline]
|
8| | debug_assert!(
|
||||||
9| 1|fn live<const B: bool>() -> u32 {
|
9| | x
|
||||||
10| 1| if B {
|
10| | );
|
||||||
11| 0| dead()
|
11| 1| };
|
||||||
12| | } else {
|
12| 1| f(false);
|
||||||
13| 1| 0
|
13| 1|}
|
||||||
14| | }
|
14| |
|
||||||
15| 1|}
|
15| |#[inline]
|
||||||
16| |
|
16| 1|fn live<const B: bool>() -> u32 {
|
||||||
17| |#[inline]
|
17| 1| if B {
|
||||||
18| 0|fn dead() -> u32 {
|
18| 0| dead()
|
||||||
19| 0| 42
|
19| | } else {
|
||||||
20| 0|}
|
20| 1| 0
|
||||||
|
21| | }
|
||||||
|
22| 1|}
|
||||||
|
23| |
|
||||||
|
24| |#[inline]
|
||||||
|
25| 0|fn dead() -> u32 {
|
||||||
|
26| 0| 42
|
||||||
|
27| 0|}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
// Regression test for issue #98833.
|
// Regression test for issue #98833.
|
||||||
// compile-flags: -Zinline-mir
|
// compile-flags: -Zinline-mir -Cdebug-assertions=off
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{}", live::<false>());
|
println!("{}", live::<false>());
|
||||||
|
|
||||||
|
let f = |x: bool| {
|
||||||
|
debug_assert!(
|
||||||
|
x
|
||||||
|
);
|
||||||
|
};
|
||||||
|
f(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue