/// Configuration options for the dot backend #[derive(Clone, Default)] pubstruct Options { /// Only emit function bodies pub cfg_only: bool,
}
/// Identifier used to address a graph node type NodeId = usize;
/// Stores the target nodes for control flow statements #[derive(Default, Clone, Copy)] struct Targets { /// The node, if some, where continue operations will land
continue_target: Option<usize>, /// The node, if some, where break operations will land
break_target: Option<usize>,
}
/// Stores information about the graph of statements #[derive(Default)] struct StatementGraph { /// List of node names
nodes: Vec<&'static str>, /// List of edges of the control flow, the items are defined as /// (from, to, label)
flow: Vec<(NodeId, NodeId, &'static str)>, /// List of implicit edges of the control flow, used for jump /// operations such as continue or break, the items are defined as /// (from, to, label, color_id)
jumps: Vec<(NodeId, NodeId, &'static str, usize)>, /// List of dependency relationships between a statement node and /// expressions
dependencies: Vec<(NodeId, Handle<crate::Expression>, &'static str)>, /// List of expression emitted by statement node
emits: Vec<(NodeId, Handle<crate::Expression>)>, /// List of function call by statement node
calls: Vec<(NodeId, Handle<crate::Function>)>,
}
impl StatementGraph { /// Adds a new block to the statement graph, returning the first and last node, respectively fn add(&mutself, block: &[crate::Statement], targets: Targets) -> (NodeId, NodeId) { usecrate::Statement as S;
// The first node of the block isn't a statement but a virtual node let root = self.nodes.len(); self.nodes.push(if root == 0 { "Root" } else { "Node" }); // Track the last placed node, this will be returned to the caller and // will also be used to generate the control flow edges letmut last_node = root; for statement in block { // Reserve a new node for the current statement and link it to the // node of the previous statement let id = self.nodes.len(); self.flow.push((last_node, id, "")); self.nodes.push(""); // reserve space
// Track the node identifier for the merge node, the merge node is // the last node of a statement, normally this is the node itself, // but for control flow statements such as `if`s and `switch`s this // is a virtual node where all branches merge back. letmut merge_id = id;
self.nodes[id] = match *statement {
S::Emit(ref range) => { for handle in range.clone() { self.emits.push((id, handle));
} "Emit"
}
S::Kill => "Kill", //TODO: link to the beginning
S::Break => { // Try to link to the break target, otherwise produce // a broken connection iflet Some(target) = targets.break_target { self.jumps.push((id, target, "Break", 5))
} else { self.jumps.push((id, root, "Broken", 7))
} "Break"
}
S::Continue => { // Try to link to the continue target, otherwise produce // a broken connection iflet Some(target) = targets.continue_target { self.jumps.push((id, target, "Continue", 5))
} else { self.jumps.push((id, root, "Broken", 7))
} "Continue"
}
S::ControlBarrier(_flags) => "ControlBarrier",
S::MemoryBarrier(_flags) => "MemoryBarrier",
S::Block(ref b) => { let (other, last) = self.add(b, targets); self.flow.push((id, other, "")); // All following nodes should connect to the end of the block // statement so change the merge id to it.
merge_id = last; "Block"
}
S::If {
condition, ref accept, ref reject,
} => { self.dependencies.push((id, condition, "condition")); let (accept_id, accept_last) = self.add(accept, targets); self.flow.push((id, accept_id, "accept")); let (reject_id, reject_last) = self.add(reject, targets); self.flow.push((id, reject_id, "reject"));
// Create a merge node, link the branches to it and set it // as the merge node to make the next statement node link to it
merge_id = self.nodes.len(); self.nodes.push("Merge"); self.flow.push((accept_last, merge_id, "")); self.flow.push((reject_last, merge_id, ""));
// Create a merge node and set it as the merge node to make // the next statement node link to it
merge_id = self.nodes.len(); self.nodes.push("Merge");
// Create a new targets structure and set the break target // to the merge node letmut targets = targets;
targets.break_target = Some(merge_id);
for case in cases { let (case_id, case_last) = self.add(&case.body, targets); let label = match case.value { crate::SwitchValue::Default => "default",
_ => "case",
}; self.flow.push((id, case_id, label)); // Link the last node of the branch to the merge node self.flow.push((case_last, merge_id, ""));
} "Switch"
}
S::Loop { ref body, ref continuing,
break_if,
} => { // Create a new targets structure and set the break target // to the merge node, this must happen before generating the // continuing block since it can break. letmut targets = targets;
targets.break_target = Some(id);
let (continuing_id, continuing_last) = self.add(continuing, targets);
// Set the the continue target to the beginning // of the newly generated continuing block
targets.continue_target = Some(continuing_id);
let (body_id, body_last) = self.add(body, targets);
self.flow.push((id, body_id, "body"));
// Link the last node of the body to the continuing block self.flow.push((body_last, continuing_id, "continuing")); // Link the last node of the continuing block back to the // beginning of the loop body self.flow.push((continuing_last, body_id, "continuing"));
for (handle, fun) in module.functions.iter() { let prefix = Prefixed(handle).to_string();
writeln!(output, "\tsubgraph cluster_{prefix} {{")?;
writeln!(
output, "\t\tlabel=\"Function{:?}/'{}'\"",
handle,
name(&fun.name)
)?; let info = mod_info.map(|a| &a[handle]);
write_fun(&mut output, prefix, fun, info, &options)?;
writeln!(output, "\t}}")?;
} for (ep_index, ep) in module.entry_points.iter().enumerate() { let prefix = format!("ep{ep_index}");
writeln!(output, "\tsubgraph cluster_{prefix} {{")?;
writeln!(output, "\t\tlabel=\"{:?}/'{}'\"", ep.stage, ep.name)?; let info = mod_info.map(|a| a.get_entry_point(ep_index));
write_fun(&mut output, prefix, &ep.function, info, &options)?;
writeln!(output, "\t}}")?;
}
output += "}\n";
Ok(output)
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.69Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.