From 052e9b430651f5cb89b511d131d1d7a47a28d215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sun, 26 Jan 2025 21:13:32 +0000 Subject: [PATCH] add NLL SCCs to polonius MIR dump --- compiler/rustc_borrowck/src/polonius/dump.rs | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 11b00fdd44aa..944b5b1d4a7d 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -1,6 +1,7 @@ use std::io; use rustc_data_structures::fx::FxHashSet; +use rustc_index::IndexVec; use rustc_middle::mir::pretty::{ PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, }; @@ -54,6 +55,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( /// - the list of polonius localized constraints /// - a mermaid graph of the CFG /// - a mermaid graph of the NLL regions and the constraints between them +/// - a mermaid graph of the NLL SCCs and the constraints between them fn emit_polonius_dump<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -101,6 +103,14 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "")?; writeln!(out, "")?; + // Section 4: mermaid visualization of the NLL SCC graph. + writeln!(out, "
")?; + writeln!(out, "NLL SCCs")?; + writeln!(out, "
")?;
+    emit_mermaid_nll_sccs(regioncx, out)?;
+    writeln!(out, "
")?; + writeln!(out, "
")?; + // Finalize the dump with the HTML epilogue. writeln!( out, @@ -343,3 +353,42 @@ fn emit_mermaid_nll_regions<'tcx>( } Ok(()) } + +/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar +/// to the graphviz version. +fn emit_mermaid_nll_sccs<'tcx>( + regioncx: &RegionInferenceContext<'tcx>, + out: &mut dyn io::Write, +) -> io::Result<()> { + // The mermaid chart type: a top-down flowchart. + writeln!(out, "flowchart TD")?; + + // Gather and emit the SCC nodes. + let mut nodes_per_scc: IndexVec<_, _> = + regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect(); + for region in regioncx.var_infos.indices() { + let scc = regioncx.constraint_sccs().scc(region); + nodes_per_scc[scc].push(region); + } + for (scc, regions) in nodes_per_scc.iter_enumerated() { + // The node label: the regions contained in the SCC. + write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?; + for (idx, ®ion) in regions.iter().enumerate() { + render_region(region, regioncx, out)?; + if idx < regions.len() - 1 { + write!(out, ",")?; + } + } + writeln!(out, "}}\"]")?; + } + + // Emit the edges between SCCs. + let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| { + regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target)) + }); + for (source, target) in edges { + writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?; + } + + Ok(()) +}