1#![allow(clippy::similar_names)]
9
10use crate::analysis::data_flow::framework::{
11 DataFlowGraph, Engine, Forward, GenKillAnalysis, GenKillEngine, GenKillSet,
12};
13use crate::analysis::DependencyHandler;
14
15use crate::cfg::*;
16use crate::data_structures::BitSet;
17use crate::ir::hir::DisciplineAccess;
18use crate::ir::{
19 BranchId, ParameterId, PortId, RealExpressionId, StatementId, StringExpressionId,
20 SystemFunctionCall, VariableId,
21};
22use crate::mir::Mir;
23use crate::mir::Statement;
24use crate::ControlFlowGraph;
25use index_vec::*;
26
27#[derive(Debug, Clone)]
28pub struct UseDefGraph {
29 pub stmt_use_def_chains: IndexVec<StatementId, BitSet<StatementId>>,
30 pub terminator_use_def_chains: IndexVec<BasicBlockId, BitSet<StatementId>>,
31 pub assignments: IndexVec<VariableId, BitSet<StatementId>>,
32}
33
34impl UseDefGraph {
35 pub fn new(mir: &Mir, cfg: &ControlFlowGraph) -> Self {
36 let statement_count = mir.statements.len();
37 let var_count = mir.variables.len();
38
39 Self {
40 stmt_use_def_chains: index_vec![BitSet::new_empty(statement_count.into());statement_count],
41 terminator_use_def_chains: index_vec![BitSet::new_empty(statement_count.into());cfg.blocks.len()],
42 assignments: index_vec![BitSet::new_empty(statement_count.into());var_count],
43 }
44 }
45
46 pub fn stmt_count(&self) -> u32 {
47 self.stmt_use_def_chains.len() as u32
48 }
49
50 pub fn len_stmd_idx(&self) -> StatementId {
51 self.stmt_use_def_chains.len_idx()
52 }
53}
54
55pub struct ReachableDefinitionsAnalysis<'lt> {
56 graph: UseDefGraph,
57 mir: &'lt Mir,
58}
59
60impl<'lt> ReachableDefinitionsAnalysis<'lt> {
61 pub fn new(mir: &'lt Mir, cfg: &ControlFlowGraph) -> Self {
62 let mut graph = UseDefGraph::new(mir, cfg);
63
64 for (id, stmt) in mir.statements.iter_enumerated() {
65 match stmt {
66 Statement::Assignment(_, var, _) => graph.assignments[*var].insert(id),
67
68 Statement::Contribute(_, _, _, _) => (),
69 }
70 }
71
72 Self { graph, mir }
73 }
74
75 pub fn run(mut self, cfg: &ControlFlowGraph) -> (UseDefGraph, DataFlowGraph<StatementId>) {
76 let mut genkill_engine = GenKillEngine::new(cfg, &mut self);
77 let engine = Engine::new(cfg, &mut genkill_engine);
78 let dfg = engine.iterate_to_fixpoint();
79
80 let mut reachable = BitSet::new_empty(self.graph.stmt_use_def_chains.len_idx());
81
82 for (id, bb) in cfg.blocks.iter_enumerated() {
83 reachable.union_with(&dfg.in_sets[id]);
84 for stmt in bb.statements.iter().copied() {
85
86
87 match self.mir[stmt] {
88 Statement::Assignment(_, var, expr) => {
89 self.mir.track_expression(
90 expr,
91 &mut UseDefBuilder {
92 graph: &mut self.graph,
93 use_stmt: stmt,
94 },
95 );
96
97 self.graph.stmt_use_def_chains[stmt].intersect_with(&reachable);
98
99 reachable.difference_with(&self.graph.assignments[var]);
100 reachable.insert(stmt);
101 }
102
103 Statement::Contribute(_, _, _, val) => {
104 self.mir.track_real_expression(
105 val,
106 &mut UseDefBuilder {
107 graph: &mut self.graph,
108 use_stmt: stmt,
109 },
110 );
111 self.graph.stmt_use_def_chains[stmt].intersect_with(&reachable);
112
113 }
115 }
116 }
117
118 if let Terminator::Split { condition, .. } = bb.terminator {
119 self.graph.terminator_use_def_chains[id]
120 .grow(self.graph.stmt_use_def_chains.len_idx());
121
122 self.mir.track_integer_expression(
123 condition,
124 &mut UseDefTerminatorBuilder {
125 graph: &mut self.graph,
126 use_terminator_block: id,
127 },
128 );
129
130 self.graph.terminator_use_def_chains[id].intersect_with(&reachable);
131 }
132
133 reachable.clear();
134 }
135
136 (self.graph, dfg)
137 }
138}
139
140impl<'lt> GenKillAnalysis<'_> for ReachableDefinitionsAnalysis<'lt> {
141 type SetType = StatementId;
142 type Direction = Forward;
143
144 fn transfer_function(
145 &mut self,
146 gen_kill_set: &mut GenKillSet<StatementId>,
147 basic_bock: BasicBlockId,
148 cfg: &ControlFlowGraph,
149 ) {
150 for stmt in cfg[basic_bock].statements.iter().copied() {
151 match self.mir[stmt] {
152 Statement::Assignment(_, var, _) => {
153 gen_kill_set.kill_all(&self.graph.assignments[var]);
154 gen_kill_set.gen(stmt);
155 }
156
157 Statement::Contribute(_, _, _, _) => {}
159 }
160 }
161 }
162
163 fn max_idx(&self) -> Self::SetType {
164 self.graph.len_stmd_idx()
165 }
166}
167
168struct UseDefBuilder<'lt> {
169 graph: &'lt mut UseDefGraph,
170 use_stmt: StatementId,
171}
172
173impl<'lt> DependencyHandler for UseDefBuilder<'lt> {
174 fn handle_variable_reference(&mut self, var: VariableId) {
175 self.graph.stmt_use_def_chains[self.use_stmt].union_with(&self.graph.assignments[var])
176 }
178
179 fn handle_parameter_reference(&mut self, _: ParameterId) {}
180
181 fn handle_branch_reference(&mut self, _: DisciplineAccess, _: BranchId, _: u8) {}
182
183 fn handle_system_function_call(
184 &mut self,
185 _: SystemFunctionCall<RealExpressionId, StringExpressionId, PortId, ParameterId>,
186 ) {
187 }
188}
189
190struct UseDefTerminatorBuilder<'lt> {
191 graph: &'lt mut UseDefGraph,
192 use_terminator_block: BasicBlockId,
193}
194
195impl<'lt> DependencyHandler for UseDefTerminatorBuilder<'lt> {
196 fn handle_variable_reference(&mut self, var: VariableId) {
197 self.graph.terminator_use_def_chains[self.use_terminator_block]
198 .union_with(&self.graph.assignments[var]);
199 }
200
201 fn handle_parameter_reference(&mut self, _: ParameterId) {}
202
203 fn handle_branch_reference(&mut self, _: DisciplineAccess, _: BranchId, _: u8) {}
204
205 fn handle_system_function_call(
206 &mut self,
207 _: SystemFunctionCall<RealExpressionId, StringExpressionId, PortId, ParameterId>,
208 ) {
209 }
210}
211
212#[cfg(feature = "graph_debug")]
213mod print {
214 use super::*;
215 use rustc_ap_graphviz as dot;
216 use rustc_ap_graphviz::LabelText::{EscStr, LabelStr};
217 use rustc_ap_graphviz::{Edges, GraphWalk, Id, LabelText, Labeller, Nodes};
218 use rustc_hash::FxHashSet;
219 use std::borrow::Cow;
220 use std::io::Write;
221
222 impl ControlFlowGraph {
223 pub fn render_data_dependence_to<W: Write>(&self, write: &mut W, udg: &UseDefGraph) {
224 dot::render(&DataDependenceGraph(self, udg), write).expect("Rendering failed")
225 }
226 }
227
228 struct DataDependenceGraph<'lt>(&'lt ControlFlowGraph, &'lt UseDefGraph);
229
230 #[derive(Copy, Clone, Eq, PartialEq)]
231 enum FlowOrDependence {
232 Flow,
233 Dependence,
234 }
235
236 impl<'a> dot::Labeller<'a> for DataDependenceGraph<'a> {
237 type Node = BasicBlockId;
238 type Edge = (FlowOrDependence, BasicBlockId, BasicBlockId);
239
240 fn graph_id(&'a self) -> Id<'a> {
241 dot::Id::new("ControlFlowGraph").unwrap()
242 }
243
244 fn node_id(&'a self, n: &Self::Node) -> Id<'a> {
245 dot::Id::new(format!("BB_{}", n.index())).unwrap()
246 }
247
248 fn node_label(&'a self, &n: &Self::Node) -> LabelText<'a> {
249 match self.0.blocks[n].terminator {
250 Terminator::End => EscStr(Cow::Owned(format!(
251 "BB_{}: {} Statements\n END",
252 n.index(),
253 self.0.blocks[n].statements.len(),
254 ))),
255 Terminator::Goto(_) => LabelStr(Cow::Owned(format!(
256 "BB_{}: {} Statements",
257 n.index(),
258 self.0.blocks[n].statements.len(),
259 ))),
260 Terminator::Split {
261 condition, merge, ..
262 } => LabelStr(Cow::Owned(format!(
263 "BB_{}: {} Statements\nSplit at {:?}\nMerge at BB_{}",
264 n.index(),
265 self.0.blocks[n].statements.len(),
266 condition,
267 merge.index(),
268 ))),
269 }
270 }
271 fn edge_label(
272 &'a self,
273 &(edge_type, start, dst): &(FlowOrDependence, BasicBlockId, BasicBlockId),
274 ) -> LabelText<'a> {
275 match edge_type {
276 FlowOrDependence::Flow => match self.0[start].terminator {
277 Terminator::Goto(_) => LabelStr(Cow::Borrowed("GOTO")),
278 Terminator::End => LabelStr(Cow::Borrowed("ILLEGAL")),
279 Terminator::Split {
280 condition,
281 true_block,
282 false_block,
283 merge,
284 } => {
285 let true_or_false = if true_block == dst {
286 "TRUE"
287 } else if false_block == dst {
288 "FALSE"
289 } else {
290 "ILLEGAL"
291 };
292 LabelStr(Cow::Borrowed(true_or_false))
293 }
294 },
295
296 FlowOrDependence::Dependence => LabelStr(Cow::Borrowed("Data dependence")),
297 }
298 }
299 }
300
301 impl<'a> dot::GraphWalk<'a> for DataDependenceGraph<'a> {
302 type Node = BasicBlockId;
303 type Edge = (FlowOrDependence, BasicBlockId, BasicBlockId);
304
305 fn nodes(&'a self) -> Nodes<'a, Self::Node> {
306 Cow::Owned(self.0.blocks.indices().collect())
307 }
308
309 fn edges(&'a self) -> Edges<'a, Self::Edge> {
310 let mut edges = Vec::new();
311 for (id, bb) in self.0.blocks.iter_enumerated() {
312 match bb.terminator {
313 Terminator::Goto(dst) => edges.push((FlowOrDependence::Flow, id, dst)),
314 Terminator::Split {
315 condition,
316 true_block,
317 false_block,
318 merge,
319 } => {
320 edges.push((FlowOrDependence::Flow, id, false_block));
321 edges.push((FlowOrDependence::Flow, id, true_block));
322 }
323 Terminator::End => (),
324 }
325 }
326 let mut processed_data_dependencies = FxHashSet::with_capacity_and_hasher(
327 self.0.blocks.len() * self.0.blocks.len(),
328 Default::default(),
329 );
330
331 for (src, data_dependencies) in self.1.stmt_use_def_chains.iter_enumerated() {
332 let src_block = self.0.containing_block(src).unwrap();
333 for dst in data_dependencies.ones() {
334 let dst_block = self.0.containing_block(dst).unwrap();
335 if processed_data_dependencies.insert((src_block, dst_block)) {
336 edges.push((FlowOrDependence::Dependence, src_block, dst_block));
337 }
338 }
339 }
340
341 for (src, data_dependencies) in self.1.terminator_use_def_chains.iter_enumerated() {
342 for dst in data_dependencies.ones() {
343 let dst_block = self.0.containing_block(dst).unwrap();
344 if processed_data_dependencies.insert((src, dst_block)) {
345 edges.push((FlowOrDependence::Dependence, src, dst_block));
346 }
347 }
348 }
349
350 Cow::Owned(edges)
351 }
352
353 fn source(&'a self, edge: &Self::Edge) -> Self::Node {
354 edge.1
355 }
356
357 fn target(&'a self, edge: &Self::Edge) -> Self::Node {
358 edge.2
359 }
360 }
361}