diff --git a/Cargo.lock b/Cargo.lock index 7a380e2ad8..0e48061e34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,40 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "datafrog" version = "2.0.1" @@ -20,12 +48,38 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "fixedbitset" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + [[package]] name = "log" version = "0.4.14" @@ -35,12 +89,69 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + [[package]] name = "ordermap" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" +[[package]] +name = "pest" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.4.13" @@ -63,6 +174,8 @@ version = "0.7.0" dependencies = [ "diff", "log", + "pest", + "pest_derive", "petgraph", "pico-args", "polonius-engine", @@ -83,8 +196,92 @@ dependencies = [ name = "polonius-parser" version = "0.5.0" +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/Cargo.toml b/Cargo.toml index a5123f12c9..74e6679702 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,5 +19,7 @@ polonius-engine = { path = "./polonius-engine" } log = "0.4" petgraph = "0.4.13" pico-args = "0.2" +pest = "2.7.4" +pest_derive = "2.7.4" [workspace] diff --git a/src/cli.rs b/src/cli.rs index 2d1e23ce94..c400219f23 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -13,6 +13,7 @@ use crate::dump; use crate::dump::Output; use crate::facts::AllFacts; use crate::intern; +use crate::mir_parser; use crate::tab_delim; const PKG_NAME: &str = env!("CARGO_PKG_NAME"); @@ -29,6 +30,7 @@ pub struct Options { output_directory: Option<String>, fact_dirs: Vec<String>, liveness_graph_file: Option<String>, + mir_file: Option<String>, } #[derive(Debug)] @@ -86,7 +88,11 @@ pub fn main(opt: Options) -> Result<(), Error> { .expect("Failed to write output"); } if let Some(ref graphviz_file) = graphviz_file { - dump::graphviz(&output, &all_facts, graphviz_file, tables) + let mir = opt + .mir_file + .as_ref() + .map(|x| mir_parser::parse(Path::new(&x))); + dump::graphviz(&output, &all_facts, graphviz_file, tables, &mir) .expect("Failed to write GraphViz"); } if let Some(ref liveness_graph_file) = liveness_graph_file { @@ -169,6 +175,7 @@ ARGS: graphviz_file: arg_from_str(&mut args, "--graphviz-file")?, output_directory: arg_from_str(&mut args, "-o")?.or(arg_from_str(&mut args, "--output")?), liveness_graph_file: arg_from_str(&mut args, "--dump-liveness-graph")?, + mir_file: arg_from_str(&mut args, "--mir-file")?, fact_dirs: args.free().map_err(readable_pico_error)?, }; diff --git a/src/dump.rs b/src/dump.rs index cf7120b917..a5c1bb0b1b 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -504,6 +504,7 @@ pub(crate) fn graphviz( all_facts: &AllFacts, output_file: &PathBuf, intern: &InternerTables, + mir: &Option<HashMap<String, Vec<String>>>, ) -> io::Result<()> { let mut file = File::create(output_file)?; let mut output_fragments: Vec<String> = Vec::new(); @@ -522,6 +523,7 @@ pub(crate) fn graphviz( &inputs_by_point, &outputs_by_point, intern, + mir, ) .into_iter(); output_fragments.extend(graphviz_code); @@ -540,6 +542,7 @@ fn graphviz_for_edge( inputs_by_point: &[HashMap<Point, String>], outputs_by_point: &[HashMap<Point, String>], intern: &InternerTables, + mir: &Option<HashMap<String, Vec<String>>>, ) -> Vec<String> { let mut ret = Vec::new(); maybe_render_point( @@ -549,6 +552,7 @@ fn graphviz_for_edge( outputs_by_point, &mut ret, intern, + mir, ); maybe_render_point( point2, @@ -557,6 +561,7 @@ fn graphviz_for_edge( outputs_by_point, &mut ret, intern, + mir, ); ret.push(format!( "\"node{0}\" -> \"node{1}\":f0 [\n id = {2}\n];\n", @@ -574,6 +579,7 @@ fn maybe_render_point( outputs_by_point: &[HashMap<Point, String>], render_vec: &mut Vec<String>, intern: &InternerTables, + mir: &Option<HashMap<String, Vec<String>>>, ) { if seen_points.contains(&point.index()) { return; @@ -592,11 +598,24 @@ fn maybe_render_point( .collect::<Vec<_>>() .join(" | "); - render_vec.push(format!("\"node{0}\" [\n label = \"{{ <f0> {1} | INPUTS | {2} | OUTPUTS | {3} }}\"\n shape = \"record\"\n];\n", + let point_str = escape_for_graphviz(Point::table(intern).untern(point)); + let (bb_name, offset) = extract(&point_str); + let instr: String = mir + .as_ref() + .and_then(|hm| Some(format!("| {}", escape_for_graphviz(&hm[bb_name][offset])))) + .unwrap_or_default(); + render_vec.push(format!("\"node{0}\" [\n label = \"{{ <f0> {point_str} {instr} | INPUTS | {input_tuples} | OUTPUTS | {output_tuples} }}\"\n shape = \"record\"\n];\n", point.index(), - escape_for_graphviz(Point::table(intern).untern(point)), - &input_tuples, - &output_tuples)); + )); +} + +fn extract(x: &str) -> (&str, usize) { + let a = x.find('(').unwrap(); + let b = x.find('[').unwrap(); + let c = x.find(']').unwrap(); + let bb_name = &x[a + 1..b]; + let offset = &x[b + 1..c]; + (bb_name, offset.parse().unwrap()) } fn escape_for_graphviz(s: &str) -> String { diff --git a/src/lib.rs b/src/lib.rs index 3ca862b083..f606b3fc50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ mod dump; mod facts; mod intern; +mod mir_parser; mod program; mod tab_delim; mod test; diff --git a/src/mir.pest b/src/mir.pest new file mode 100644 index 0000000000..3faca012b0 --- /dev/null +++ b/src/mir.pest @@ -0,0 +1,19 @@ +// no \n . = +char2 = _{ 'a'..'z' | 'A'..'Z' | '0'..'9' | "_" | "-" | "(" | ")" | "[" | "]" | ":" | " " | "<" | ">" | "&" | "'" | "?" | "," } + +block_name = { (!"{" ~ ANY)+ } + +// not started with } +instruction = { (!(NEWLINE | "}") ~ ANY) ~ (! NEWLINE ~ ANY)+ ~ NEWLINE } + +header = _{ (scope | instruction) * } + +scope = _{ "scope" ~ ASCII_ALPHANUMERIC+ ~ "{" ~ NEWLINE ~ header ~ "}" ~ NEWLINE } + +block = { block_name ~ "{" ~ NEWLINE ~ instruction+ ~ "}" ~ NEWLINE* } + +func = { SOI ~ "fn" ~ char2+ ~ "{" ~ NEWLINE ~ header ~ NEWLINE* ~ block+ ~ "}" ~ NEWLINE* ~ EOI } + +COMMENT = _{ ("//" | "|") ~ (!NEWLINE ~ ANY)* ~ NEWLINE* } +WHITESPACE = _{ " " | "\t" } + diff --git a/src/mir_parser.rs b/src/mir_parser.rs new file mode 100644 index 0000000000..78203ff4be --- /dev/null +++ b/src/mir_parser.rs @@ -0,0 +1,64 @@ +use pest::Parser; +use pest_derive::Parser; +use std::collections::HashMap; +use std::io::Read; +use std::path::Path; + +#[derive(Parser)] +#[grammar = "mir.pest"] +struct MirParser; + +pub fn parse(path: &Path) -> HashMap<String, Vec<String>> { + let mut file = std::fs::File::open(&path).unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + + let mut pairs = MirParser::parse(Rule::func, &contents).unwrap_or_else(|e| panic!("{}", e)); + let func_pair = pairs.next().unwrap(); + + let mut hm = HashMap::new(); + for pair in func_pair.into_inner() { + match pair.as_rule() { + Rule::block => { + let mut iter = pair.into_inner(); + let bb = iter.next().unwrap(); + assert_eq!(bb.as_rule(), Rule::block_name); + let bb_name = bb.as_str().replace("(cleanup):", "").replace(':', ""); + let bb_name = bb_name.trim(); + let mut v: Vec<String> = Vec::new(); + for instr in iter { + assert_eq!(instr.as_rule(), Rule::instruction); + v.push(instr.as_str().trim().to_owned()); + } + let None = hm.insert(bb_name.to_owned(), v) else { + unreachable!() + }; + } + _ => {} + } + } + hm +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let path = Path::new(env!("HOME")) + .join("rust") + .join("tests") + .join("mir-opt") + .join("nll") + .join("named_lifetimes_basic.use_x.nll.0.mir"); + let _ = parse(&path); + + let path = Path::new(env!("HOME")) + .join("rust") + .join("tests") + .join("mir-opt") + .join("storage_ranges.main.nll.0.mir"); + let _ = parse(&path); + } +}