Rollup merge of #152474 - sgasho:opt-bisect-limit-mir, r=saethlin
Implement opt-bisect-limit for MIR closes: rust-lang/rust#150910 Enable bisecting MIR optimization passes to enhance debuggability. discussions on zulip: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/MIR.20dump.20the.20pass.20names/with/573219207 ### Check it works #### Sample code ```rust fn abs(num: isize) -> usize { if num < 0 { -num as usize } else { num as usize } } fn main() { println!("{}", abs(-10)); } ``` #### Output ```shell rustc +mir -Zmir-opt-bisect-limit=30 src/main.rs BISECT: running pass (1) CheckAlignment on main[89d5]::main BISECT: running pass (2) CheckNull on main[89d5]::main BISECT: running pass (3) CheckEnums on main[89d5]::main BISECT: running pass (4) LowerSliceLenCalls on main[89d5]::main BISECT: running pass (5) InstSimplify-before-inline on main[89d5]::main BISECT: running pass (6) ForceInline on main[89d5]::main BISECT: running pass (7) RemoveStorageMarkers on main[89d5]::main BISECT: running pass (8) RemoveZsts on main[89d5]::main BISECT: running pass (9) RemoveUnneededDrops on main[89d5]::main BISECT: running pass (10) UnreachableEnumBranching on main[89d5]::main BISECT: running pass (11) SimplifyCfg-after-unreachable-enum-branching on main[89d5]::main BISECT: running pass (12) InstSimplify-after-simplifycfg on main[89d5]::main BISECT: running pass (13) SimplifyConstCondition-after-inst-simplify on main[89d5]::main BISECT: running pass (14) SimplifyLocals-before-const-prop on main[89d5]::main BISECT: running pass (15) SimplifyLocals-after-value-numbering on main[89d5]::main BISECT: running pass (16) MatchBranchSimplification on main[89d5]::main BISECT: running pass (17) SingleUseConsts on main[89d5]::main BISECT: running pass (18) SimplifyConstCondition-after-const-prop on main[89d5]::main BISECT: running pass (19) SimplifyConstCondition-final on main[89d5]::main BISECT: running pass (20) RemoveNoopLandingPads on main[89d5]::main BISECT: running pass (21) SimplifyCfg-final on main[89d5]::main BISECT: running pass (22) CopyProp on main[89d5]::main BISECT: running pass (23) SimplifyLocals-final on main[89d5]::main BISECT: running pass (24) AddCallGuards on main[89d5]::main BISECT: running pass (25) PreCodegen on main[89d5]::main BISECT: running pass (26) CheckAlignment on main[89d5]::abs BISECT: running pass (27) CheckNull on main[89d5]::abs BISECT: running pass (28) CheckEnums on main[89d5]::abs BISECT: running pass (29) LowerSliceLenCalls on main[89d5]::abs BISECT: running pass (30) InstSimplify-before-inline on main[89d5]::abs BISECT: NOT running pass (31) ForceInline on main[89d5]::abs BISECT: NOT running pass (32) RemoveStorageMarkers on main[89d5]::abs BISECT: NOT running pass (33) RemoveZsts on main[89d5]::abs BISECT: NOT running pass (34) RemoveUnneededDrops on main[89d5]::abs BISECT: NOT running pass (35) UnreachableEnumBranching on main[89d5]::abs BISECT: NOT running pass (36) SimplifyCfg-after-unreachable-enum-branching on main[89d5]::abs BISECT: NOT running pass (37) InstSimplify-after-simplifycfg on main[89d5]::abs BISECT: NOT running pass (38) SimplifyConstCondition-after-inst-simplify on main[89d5]::abs BISECT: NOT running pass (39) SimplifyLocals-before-const-prop on main[89d5]::abs BISECT: NOT running pass (40) SimplifyLocals-after-value-numbering on main[89d5]::abs BISECT: NOT running pass (41) MatchBranchSimplification on main[89d5]::abs BISECT: NOT running pass (42) SingleUseConsts on main[89d5]::abs BISECT: NOT running pass (43) SimplifyConstCondition-after-const-prop on main[89d5]::abs BISECT: NOT running pass (44) SimplifyConstCondition-final on main[89d5]::abs BISECT: NOT running pass (45) RemoveNoopLandingPads on main[89d5]::abs BISECT: NOT running pass (46) SimplifyCfg-final on main[89d5]::abs BISECT: NOT running pass (47) CopyProp on main[89d5]::abs BISECT: NOT running pass (48) SimplifyLocals-final on main[89d5]::abs BISECT: NOT running pass (49) AddCallGuards on main[89d5]::abs BISECT: NOT running pass (50) PreCodegen on main[89d5]::abs ``` r? @saethlin
This commit is contained in:
commit
544462ad8b
5 changed files with 198 additions and 1 deletions
11
tests/run-make/mir-opt-bisect-limit/main.rs
Normal file
11
tests/run-make/mir-opt-bisect-limit/main.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![crate_type = "lib"]
|
||||
#![no_std]
|
||||
|
||||
#[inline(never)]
|
||||
pub fn callee(x: u64) -> u64 {
|
||||
x.wrapping_mul(3).wrapping_add(7)
|
||||
}
|
||||
|
||||
pub fn caller(a: u64, b: u64) -> u64 {
|
||||
callee(a) + callee(b)
|
||||
}
|
||||
119
tests/run-make/mir-opt-bisect-limit/rmake.rs
Normal file
119
tests/run-make/mir-opt-bisect-limit/rmake.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
use std::path::Path;
|
||||
|
||||
use run_make_support::{CompletedProcess, rfs, rustc};
|
||||
|
||||
struct Case {
|
||||
name: &'static str,
|
||||
flags: &'static [&'static str],
|
||||
expect_inline_dump: bool,
|
||||
expect_running: ExpectedCount,
|
||||
expect_not_running: ExpectedCount,
|
||||
}
|
||||
|
||||
enum ExpectedCount {
|
||||
Exactly(usize),
|
||||
AtLeastOne,
|
||||
Zero,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cases = [
|
||||
Case {
|
||||
name: "limit0",
|
||||
flags: &["-Zmir-opt-bisect-limit=0"],
|
||||
expect_inline_dump: false,
|
||||
expect_running: ExpectedCount::Exactly(0),
|
||||
expect_not_running: ExpectedCount::AtLeastOne,
|
||||
},
|
||||
Case {
|
||||
name: "limit1",
|
||||
flags: &["-Zmir-opt-bisect-limit=1"],
|
||||
expect_inline_dump: false,
|
||||
expect_running: ExpectedCount::Exactly(1),
|
||||
expect_not_running: ExpectedCount::AtLeastOne,
|
||||
},
|
||||
Case {
|
||||
name: "huge_limit",
|
||||
flags: &["-Zmir-opt-bisect-limit=1000000000"],
|
||||
expect_inline_dump: true,
|
||||
expect_running: ExpectedCount::AtLeastOne,
|
||||
expect_not_running: ExpectedCount::Zero,
|
||||
},
|
||||
Case {
|
||||
name: "limit0_with_force_enable_inline",
|
||||
flags: &["-Zmir-opt-bisect-limit=0", "-Zmir-enable-passes=+Inline"],
|
||||
expect_inline_dump: false,
|
||||
expect_running: ExpectedCount::Exactly(0),
|
||||
expect_not_running: ExpectedCount::AtLeastOne,
|
||||
},
|
||||
];
|
||||
|
||||
for case in cases {
|
||||
let (inline_dumped, running_count, not_running_count, output) =
|
||||
compile_case(case.name, case.flags);
|
||||
|
||||
assert_eq!(
|
||||
inline_dumped, case.expect_inline_dump,
|
||||
"{}: unexpected Inline dump presence",
|
||||
case.name
|
||||
);
|
||||
|
||||
assert_expected_count(
|
||||
running_count,
|
||||
case.expect_running,
|
||||
&format!("{}: running count", case.name),
|
||||
);
|
||||
assert_expected_count(
|
||||
not_running_count,
|
||||
case.expect_not_running,
|
||||
&format!("{}: NOT running count", case.name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_case(dump_dir: &str, extra_flags: &[&str]) -> (bool, usize, usize, CompletedProcess) {
|
||||
if Path::new(dump_dir).exists() {
|
||||
rfs::remove_dir_all(dump_dir);
|
||||
}
|
||||
rfs::create_dir_all(dump_dir);
|
||||
|
||||
let mut cmd = rustc();
|
||||
cmd.input("main.rs")
|
||||
.arg("--emit=mir")
|
||||
.arg("-Zmir-opt-level=2")
|
||||
.arg("-Copt-level=2")
|
||||
.arg("-Zthreads=1")
|
||||
.arg("-Zdump-mir=Inline")
|
||||
.arg(format!("-Zdump-mir-dir={dump_dir}"));
|
||||
|
||||
for &flag in extra_flags {
|
||||
cmd.arg(flag);
|
||||
}
|
||||
|
||||
let output = cmd.run();
|
||||
let (running_count, not_running_count) = bisect_line_counts(&output);
|
||||
(has_inline_dump_file(dump_dir), running_count, not_running_count, output)
|
||||
}
|
||||
|
||||
fn assert_expected_count(actual: usize, expected: ExpectedCount, context: &str) {
|
||||
match expected {
|
||||
ExpectedCount::Exactly(n) => assert_eq!(actual, n, "{context}"),
|
||||
ExpectedCount::AtLeastOne => assert!(actual > 0, "{context}"),
|
||||
ExpectedCount::Zero => assert_eq!(actual, 0, "{context}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_inline_dump_file(dir: &str) -> bool {
|
||||
rfs::read_dir(dir)
|
||||
.flatten()
|
||||
.any(|entry| entry.file_name().to_string_lossy().contains(".Inline."))
|
||||
}
|
||||
|
||||
fn bisect_line_counts(output: &CompletedProcess) -> (usize, usize) {
|
||||
let stderr = output.stderr_utf8();
|
||||
let running_count =
|
||||
stderr.lines().filter(|line| line.starts_with("BISECT: running pass (")).count();
|
||||
let not_running_count =
|
||||
stderr.lines().filter(|line| line.starts_with("BISECT: NOT running pass (")).count();
|
||||
(running_count, not_running_count)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue