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