c2rust_transpile/cfg/
loops.rs1#![deny(missing_docs)]
20
21use super::*;
22use indexmap::{IndexMap, IndexSet};
23
24pub fn match_loop_body(
30 mut desired_body: IndexSet<Label>,
31 strict_reachable_from: &IndexMap<Label, IndexSet<Label>>,
32 body_blocks: &mut IndexMap<Label, BasicBlock<StructureLabel<StmtOrDecl>, StmtOrDecl>>,
33 follow_blocks: &mut IndexMap<Label, BasicBlock<StructureLabel<StmtOrDecl>, StmtOrDecl>>,
34 follow_entries: &mut IndexSet<Label>,
35) -> bool {
36 let mut something_happened = true;
38 while something_happened {
39 something_happened = false;
40
41 let to_move: Vec<Label> = follow_entries
42 .intersection(&desired_body)
43 .cloned()
44 .collect();
45
46 for following in to_move {
47 let bb = if let Some(bb) = follow_blocks.swap_remove(&following) {
48 bb
49 } else {
50 continue;
51 };
52 something_happened = true;
53
54 desired_body.swap_remove(&following);
55
56 follow_entries.swap_remove(&following);
57 follow_entries.extend(bb.successors());
58 follow_entries.retain(|e| !body_blocks.contains_key(e));
59 body_blocks.insert(following, bb);
60 }
61 }
62
63 desired_body.is_empty()
64 && body_blocks.keys().all(|body_lbl| {
65 match strict_reachable_from.get(body_lbl) {
67 None => true,
68 Some(reachable_froms) => reachable_froms
69 .iter()
70 .all(|lbl| body_blocks.contains_key(lbl)),
71 }
72 })
73}
74
75pub fn heuristic_loop_body(
84 predecessor_map: &IndexMap<Label, IndexSet<Label>>,
85 body_blocks: &mut IndexMap<Label, BasicBlock<StructureLabel<StmtOrDecl>, StmtOrDecl>>,
86 follow_blocks: &mut IndexMap<Label, BasicBlock<StructureLabel<StmtOrDecl>, StmtOrDecl>>,
87 follow_entries: &mut IndexSet<Label>,
88) {
89 if follow_entries.len() > 1 {
90 for follow_entry in follow_entries.clone().iter() {
91 let mut following: Label = follow_entry.clone();
92
93 loop {
94 if predecessor_map[&following].len() != 1 {
96 break;
97 }
98
99 let bb = if let Some(bb) = follow_blocks.swap_remove(&following) {
101 bb
102 } else {
103 break;
104 };
105 let succs = bb.successors();
106
107 body_blocks.insert(following.clone(), bb);
108 follow_entries.swap_remove(&following);
109 follow_entries.extend(succs.clone());
110
111 if succs.len() != 1 {
113 break;
114 }
115
116 following = succs.iter().next().unwrap().clone();
117 }
118 }
119 }
120}
121
122#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
124pub struct LoopId(u64);
125
126impl LoopId {
127 pub fn new(id: u64) -> LoopId {
129 LoopId(id)
130 }
131
132 pub fn pretty_print(&self) -> String {
135 let &LoopId(loop_id) = self;
136 format!("l_{}", loop_id)
137 }
138}
139
140#[derive(Clone, Debug)]
142pub struct LoopInfo<Lbl: Hash + Eq> {
143 node_loops: IndexMap<Lbl, LoopId>,
145
146 loops: IndexMap<LoopId, (IndexSet<Lbl>, Option<LoopId>)>,
148}
149
150impl<Lbl: Hash + Eq> Default for LoopInfo<Lbl> {
153 fn default() -> Self {
154 Self {
155 node_loops: Default::default(),
156 loops: Default::default(),
157 }
158 }
159}
160
161impl<Lbl: Hash + Eq + Clone> LoopInfo<Lbl> {
162 #[allow(missing_docs)]
163 pub fn new() -> Self {
164 Self::default()
165 }
166
167 pub fn absorb(&mut self, other: LoopInfo<Lbl>) {
169 self.node_loops.extend(other.node_loops);
170 self.loops.extend(other.loops);
171 }
172
173 pub fn tightest_common_loop<E: Iterator<Item = Lbl>>(&self, mut entries: E) -> Option<LoopId> {
175 let first = entries.next()?;
176
177 let mut loop_id = *self.node_loops.get(&first)?;
178
179 for entry in entries {
180 loop {
182 match self.loops.get(&loop_id) {
183 Some((ref in_loop, parent_id)) => {
184 if in_loop.contains(&entry) {
185 break;
186 }
187 loop_id = if let Some(i) = parent_id {
188 *i
189 } else {
190 return None;
191 };
192 }
193
194 None => return None,
195 }
196 }
197 }
198
199 Some(loop_id)
200 }
201
202 pub fn filter_unreachable(&mut self, reachable: &IndexSet<Lbl>) {
204 self.node_loops.retain(|lbl, _| reachable.contains(lbl));
205 for (_, &mut (ref mut set, _)) in self.loops.iter_mut() {
206 set.retain(|lbl| reachable.contains(lbl));
207 }
208 }
209
210 pub fn rewrite_blocks(&mut self, rewrites: &IndexMap<Lbl, Lbl>) {
213 self.node_loops.retain(|lbl, _| rewrites.get(lbl).is_none());
214 for (_, &mut (ref mut set, _)) in self.loops.iter_mut() {
215 set.retain(|lbl| rewrites.get(lbl).is_none());
216 }
217 }
218
219 pub fn add_loop(&mut self, id: LoopId, contents: IndexSet<Lbl>, outer_id: Option<LoopId>) {
221 for elem in &contents {
222 if !self.node_loops.contains_key(elem) {
223 self.node_loops.insert(elem.clone(), id);
224 }
225 }
226
227 self.loops.insert(id, (contents, outer_id));
228 }
229
230 pub fn enclosing_loops(&self, lbl: &Lbl) -> Vec<LoopId> {
232 let mut loop_id_opt: Option<LoopId> = self.node_loops.get(lbl).cloned();
233 let mut loop_ids = vec![];
234 while let Some(loop_id) = loop_id_opt {
235 loop_ids.push(loop_id);
236 loop_id_opt = self.loops[&loop_id].1;
237 }
238 loop_ids
239 }
240
241 pub fn get_loop_contents(&self, id: LoopId) -> &IndexSet<Lbl> {
243 &self
244 .loops
245 .get(&id)
246 .unwrap_or_else(|| panic!("There is no loop with id {:?}", id))
247 .0
248 }
249}