-
Notifications
You must be signed in to change notification settings - Fork 4
Filter std::rt::lang_start from graphs
#119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| //! D2 diagram format output for MIR graphs. | ||
|
|
||
| use std::collections::HashSet; | ||
|
|
||
| extern crate stable_mir; | ||
| use stable_mir::mir::TerminatorKind; | ||
|
|
||
|
|
@@ -10,11 +12,22 @@ use crate::mk_graph::context::GraphContext; | |
| use crate::mk_graph::util::{ | ||
| escape_d2, is_unqualified, name_lines, short_name, terminator_targets, | ||
| }; | ||
| use crate::mk_graph::{compute_lang_start_exclusions, skip_lang_start}; | ||
|
|
||
| impl SmirJson<'_> { | ||
| /// Convert the MIR to D2 diagram format | ||
| pub fn to_d2_file(self) -> String { | ||
| pub fn to_d2_file(mut self) -> String { | ||
| let ctx = GraphContext::from_smir(&self); | ||
|
|
||
| // Optionally filter out lang_start items and their unique descendants | ||
| let excluded: HashSet<String> = if skip_lang_start() { | ||
| let excluded = compute_lang_start_exclusions(&self.items, &ctx); | ||
| self.items.retain(|i| !excluded.contains(&i.symbol_name)); | ||
| excluded | ||
| } else { | ||
| HashSet::new() | ||
| }; | ||
|
|
||
| let mut output = String::new(); | ||
|
|
||
| output.push_str("direction: right\n\n"); | ||
|
|
@@ -23,7 +36,7 @@ impl SmirJson<'_> { | |
| for item in self.items { | ||
| match item.mono_item_kind { | ||
| MonoItemKind::MonoItemFn { name, body, .. } => { | ||
| render_d2_function(&name, body.as_ref(), &ctx, &mut output); | ||
| render_d2_function(&name, body.as_ref(), &ctx, &excluded, &mut output); | ||
| } | ||
| MonoItemKind::MonoItemGlobalAsm { asm } => { | ||
| render_d2_asm(&asm, &mut output); | ||
|
|
@@ -61,6 +74,7 @@ fn render_d2_function( | |
| name: &str, | ||
| body: Option<&stable_mir::mir::Body>, | ||
| ctx: &GraphContext, | ||
| excluded: &HashSet<String>, | ||
| out: &mut String, | ||
| ) { | ||
| let fn_id = short_name(name); | ||
|
|
@@ -80,7 +94,7 @@ fn render_d2_function( | |
|
|
||
| // Call edges (must be outside the container) | ||
| if let Some(body) = body { | ||
| render_d2_call_edges(&fn_id, body, ctx, out); | ||
| render_d2_call_edges(&fn_id, body, ctx, excluded, out); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -115,6 +129,7 @@ fn render_d2_call_edges( | |
| fn_id: &str, | ||
| body: &stable_mir::mir::Body, | ||
| ctx: &GraphContext, | ||
| excluded: &HashSet<String>, | ||
| out: &mut String, | ||
| ) { | ||
| for (idx, block) in body.blocks.iter().enumerate() { | ||
|
|
@@ -124,7 +139,7 @@ fn render_d2_call_edges( | |
| let Some(callee_name) = ctx.resolve_call_target(func) else { | ||
| continue; | ||
| }; | ||
| if !is_unqualified(&callee_name) { | ||
| if !is_unqualified(&callee_name) || excluded.contains(&callee_name) { | ||
| continue; | ||
| } | ||
|
Comment on lines
139
to
144
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Want to point out that we have to thread Right now the flow is:
If instead, step 3 also did: ctx.functions.retain(|_, name| !excluded.contains(name));then let Some(callee_name) = ctx.resolve_call_target(func) else {
continue; // already skips when resolve returns None
};
// no need for: || excluded.contains(&callee_name)
if !is_unqualified(&callee_name) {
continue;
}That would also eliminate the need to compute (locally) and thread |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,15 +12,25 @@ use crate::MonoItemKind; | |
|
|
||
| use crate::mk_graph::context::GraphContext; | ||
| use crate::mk_graph::util::{block_name, is_unqualified, name_lines, short_name, GraphLabelString}; | ||
| use crate::mk_graph::{compute_lang_start_exclusions, skip_lang_start}; | ||
|
|
||
| impl SmirJson<'_> { | ||
| /// Convert the MIR to DOT (Graphviz) format | ||
| pub fn to_dot_file(self) -> String { | ||
| pub fn to_dot_file(mut self) -> String { | ||
| let mut bytes = Vec::new(); | ||
|
|
||
| // Build context BEFORE consuming self | ||
| let ctx = GraphContext::from_smir(&self); | ||
|
|
||
| // Optionally filter out lang_start items and their unique descendants | ||
| let excluded: HashSet<String> = if skip_lang_start() { | ||
| let excluded = compute_lang_start_exclusions(&self.items, &ctx); | ||
| self.items.retain(|i| !excluded.contains(&i.symbol_name)); | ||
| excluded | ||
| } else { | ||
| HashSet::new() | ||
| }; | ||
|
Comment on lines
+26
to
+32
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aha! Good ole copy-and-paste inheritance (or composition in this case). This supports the filter refaction. |
||
|
|
||
| { | ||
| let mut writer = DotWriter::from(&mut bytes); | ||
|
|
||
|
|
@@ -57,7 +67,7 @@ impl SmirJson<'_> { | |
|
|
||
| // first create all nodes for functions not in the items list | ||
| for f in ctx.functions.values() { | ||
| if !item_names.contains(f) { | ||
| if !item_names.contains(f) && !excluded.contains(f) { | ||
| graph | ||
| .node_named(block_name(f, 0)) | ||
| .set_label(&name_lines(f)) | ||
|
|
@@ -245,6 +255,20 @@ impl SmirJson<'_> { | |
|
|
||
| match &b.terminator.kind { | ||
| TerminatorKind::Call { func, args, .. } => { | ||
| // Skip call edges to excluded nodes | ||
| if let Operand::Constant(ConstOperand { | ||
| const_, .. | ||
| }) = func | ||
| { | ||
| if ctx | ||
| .functions | ||
| .get(&const_.ty()) | ||
| .is_some_and(|c| excluded.contains(c)) | ||
| { | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| let e = match func { | ||
| Operand::Constant(ConstOperand { | ||
| const_, .. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a useful filter op. I recommend moving it; could be a free fn in the mk_graph mod.