1use std::collections::{HashMap, VecDeque};
19
20use rucc_ir::{Block, Def, Func, Inst, Value};
21
22#[must_use]
28pub fn on_entry(func: &Func) -> Vec<(u32, Block, Value)> {
29 let mut assigned: HashMap<u32, Vec<(Block, Option<Inst>, Value)>> = HashMap::new();
30 for value in func.values() {
31 let place = match func[value].def {
32 Def::Result { inst, .. } => func.block_of(inst).map(|block| (block, Some(inst))),
33 Def::Param { block, index } => {
34 let param = usize::try_from(index)
35 .ok()
36 .and_then(|index| func[block].params.get(index).copied());
37 (func.is_placed(block) && param == Some(value)).then_some((block, None))
38 }
39 };
40 if let Some((block, after)) = place {
41 for decl in func.value_decls(value) {
42 assigned.entry(decl).or_default().push((block, after, value));
43 }
44 }
45 for start in func.value_starts(value) {
46 if let Some((block, after)) = func.start_place(start) {
47 assigned.entry(start.decl).or_default().push((block, after, value));
48 }
49 }
50 }
51 assigned.retain(|_, all| all.iter().any(|&(_, _, value)| value != all[0].2));
52 if assigned.is_empty() {
53 return Vec::new();
54 }
55
56 let blocks: Vec<Block> = func.blocks().collect();
57 let count = func.counts().blocks;
58 let mut position = vec![0usize; func.counts().insts];
60 let mut succs: Vec<Vec<Block>> = vec![Vec::new(); count];
61 for &block in &blocks {
62 for (at, inst) in func.insts(block).enumerate() {
63 position[inst.index()] = at + 1;
64 }
65 if let Some(terminator) = func.terminator(block) {
66 succs[block.index()].extend(func.successors(terminator).map(|call| call.block));
67 }
68 }
69 let entry = func.entry();
70
71 let mut decls: Vec<u32> = assigned.keys().copied().collect();
72 decls.sort_unstable();
73 let mut out = Vec::new();
74 for decl in decls {
75 let mut last: Vec<Option<(usize, Held)>> = vec![None; count];
79 let mut top: Vec<Option<Held>> = vec![None; count];
80 for &(block, after, value) in &assigned[&decl] {
81 let at = after.map_or(0, |inst| position[inst.index()]);
82 let slot = &mut last[block.index()];
83 *slot = match *slot {
84 Some((have, _)) if have > at => *slot,
85 Some((have, held)) if have == at => Some((at, held.meet(Held::Known(value)))),
86 _ => Some((at, Held::Known(value))),
87 };
88 if at == 0 {
89 let slot = &mut top[block.index()];
90 *slot = Some(slot.map_or(Held::Known(value), |held| held.meet(Held::Known(value))));
91 }
92 }
93 let mut into: Vec<Held> = vec![Held::Unvisited; count];
102 let mut queued = vec![false; count];
103 let mut waiting = VecDeque::new();
104 if let Some(entry) = entry {
105 into[entry.index()] = Held::Unknown;
106 queued[entry.index()] = true;
107 waiting.push_back(entry);
108 }
109 for &(block, _, _) in &assigned[&decl] {
110 if !queued[block.index()] {
111 queued[block.index()] = true;
112 waiting.push_back(block);
113 }
114 }
115 while let Some(block) = waiting.pop_front() {
116 queued[block.index()] = false;
117 let out = last[block.index()].map_or(into[block.index()], |(_, held)| held);
118 for &succ in &succs[block.index()] {
119 if Some(succ) == entry {
120 continue;
121 }
122 let now = into[succ.index()].meet(out);
123 if now != into[succ.index()] {
124 into[succ.index()] = now;
125 if !queued[succ.index()] {
126 queued[succ.index()] = true;
127 waiting.push_back(succ);
128 }
129 }
130 }
131 }
132 for &block in &blocks {
133 let held = top[block.index()].unwrap_or(into[block.index()]);
134 if let Held::Known(value) = held {
135 out.push((decl, block, value));
136 }
137 }
138 }
139 out
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144enum Held {
145 Unvisited,
147 Known(Value),
149 Unknown,
151}
152
153impl Held {
154 fn meet(self, other: Held) -> Held {
156 match (self, other) {
157 (Held::Unvisited, held) | (held, Held::Unvisited) => held,
158 (Held::Known(one), Held::Known(two)) if one == two => self,
159 _ => Held::Unknown,
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use rucc_base::Symbol;
167 use rucc_ir::{Builder, Signature, Start, Type};
168
169 use super::*;
170
171 #[test]
178 fn a_value_computed_on_this_trip_is_what_the_blocks_after_it_hold() {
179 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
180 let entry = func.create_block();
181 let head = func.create_block();
182 let body = func.create_block();
183 let after = func.create_block();
184 let exit = func.create_block();
185 let i = func.append_param(head, Type::int(32));
186 let mut build = Builder::new(&mut func, entry);
187 let zero = build.iconst(Type::int(32), 0);
188 build.jump(head, &[zero]);
189 Builder::new(&mut func, head).jump(body, &[]);
190 let mut build = Builder::new(&mut func, body);
191 let one = build.iconst(Type::int(32), 1);
192 let next = build.binary(rucc_ir::Opcode::Add, i, one, rucc_ir::Flags::NONE);
193 build.jump(after, &[]);
194 let mut build = Builder::new(&mut func, after);
195 let done = build.icmp(rucc_ir::IntPred::Eq, i, next);
196 build.br_if(done, exit, &[], head, &[next]);
197 Builder::new(&mut func, exit).ret(&[]);
198 for value in [zero, i, next] {
199 func.declare_value(value, 3);
200 }
201
202 let held = on_entry(&func);
203 assert!(held.contains(&(3, head, i)), "{held:?}");
204 assert!(held.contains(&(3, body, i)), "{held:?}");
205 assert!(held.contains(&(3, after, next)), "{held:?}");
206 assert!(held.contains(&(3, exit, next)), "{held:?}");
207 assert!(!held.iter().any(|&(_, block, _)| block == entry), "{held:?}");
208 }
209
210 #[test]
213 fn arms_that_disagree_say_nothing_and_a_start_says_what_it_gave() {
214 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
215 let entry = func.create_block();
216 let left = func.create_block();
217 let right = func.create_block();
218 let join = func.create_block();
219 let flag = func.append_param(entry, Type::I1);
220 let mut build = Builder::new(&mut func, entry);
221 let first = build.iconst(Type::int(32), 1);
222 build.br_if(flag, left, &[], right, &[]);
223 let mut build = Builder::new(&mut func, left);
224 let second = build.iconst(Type::int(32), 2);
225 let saved = build.iconst(Type::int(32), 3);
226 build.jump(join, &[]);
227 Builder::new(&mut func, right).jump(join, &[]);
228 Builder::new(&mut func, join).ret(&[]);
229 func.declare_value(first, 5);
230 func.declare_value(second, 5);
231
232 let held = on_entry(&func);
233 assert!(held.contains(&(5, left, first)), "{held:?}");
234 assert!(held.contains(&(5, right, first)), "{held:?}");
235 assert!(!held.iter().any(|&(_, block, _)| block == join), "{held:?}");
236
237 let Def::Result { inst: loaded, .. } = func[saved].def else { unreachable!() };
240 func.declare_value_from(first, Start { decl: 5, block: left, after: Some(loaded) });
241 func.declare_value_from(second, Start { decl: 6, block: left, after: None });
242 let held = on_entry(&func);
243 assert!(held.contains(&(5, join, first)), "{held:?}");
244 assert!(held.contains(&(5, left, first)), "{held:?}");
245 assert!(!held.iter().any(|&(decl, _, _)| decl == 6), "{held:?}");
246 }
247}