1use crate::entity::SecondaryMap;
7use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
8use crate::ir::{Block, Function, Layout, ProgramPoint};
9use crate::packed_option::PackedOption;
10use crate::timing;
11use crate::traversals::Dfs;
12use alloc::vec::Vec;
13use core::cmp::Ordering;
14
15const STRIDE: u32 = 4;
18
19#[derive(Clone, Default)]
21struct DomNode {
22 rpo_number: u32,
27
28 idom: PackedOption<Block>,
33}
34
35pub struct SimpleDominatorTree {
37 nodes: SecondaryMap<Block, DomNode>,
38
39 postorder: Vec<Block>,
41
42 dfs: Dfs,
44
45 valid: bool,
46}
47
48impl SimpleDominatorTree {
50 pub fn is_reachable(&self, block: Block) -> bool {
52 self.nodes[block].rpo_number != 0
53 }
54
55 pub fn cfg_postorder(&self) -> &[Block] {
60 debug_assert!(self.is_valid());
61 &self.postorder
62 }
63
64 pub fn idom(&self, block: Block) -> Option<Block> {
75 self.nodes[block].idom.into()
76 }
77
78 pub fn rpo_cmp_block(&self, a: Block, b: Block) -> Ordering {
80 self.nodes[a].rpo_number.cmp(&self.nodes[b].rpo_number)
81 }
82
83 pub fn rpo_cmp<A, B>(&self, a: A, b: B, layout: &Layout) -> Ordering
90 where
91 A: Into<ProgramPoint>,
92 B: Into<ProgramPoint>,
93 {
94 let a = a.into();
95 let b = b.into();
96 self.rpo_cmp_block(layout.pp_block(a), layout.pp_block(b))
97 .then_with(|| layout.pp_cmp(a, b))
98 }
99
100 pub fn dominates<A, B>(&self, a: A, b: B, layout: &Layout) -> bool
111 where
112 A: Into<ProgramPoint>,
113 B: Into<ProgramPoint>,
114 {
115 let a = a.into();
116 let b = b.into();
117 match a {
118 ProgramPoint::Block(block_a) => match b {
119 ProgramPoint::Block(block_b) => self.block_dominates(block_a, block_b),
120 ProgramPoint::Inst(inst_b) => {
121 let block_b = layout
122 .inst_block(inst_b)
123 .expect("Instruction not in layout.");
124 self.block_dominates(block_a, block_b)
125 }
126 },
127 ProgramPoint::Inst(inst_a) => {
128 let block_a: Block = layout
129 .inst_block(inst_a)
130 .expect("Instruction not in layout.");
131 match b {
132 ProgramPoint::Block(block_b) => {
133 block_a != block_b && self.block_dominates(block_a, block_b)
134 }
135 ProgramPoint::Inst(inst_b) => {
136 let block_b = layout
137 .inst_block(inst_b)
138 .expect("Instruction not in layout.");
139 if block_a == block_b {
140 layout.pp_cmp(a, b) != Ordering::Greater
141 } else {
142 self.block_dominates(block_a, block_b)
143 }
144 }
145 }
146 }
147 }
148 }
149
150 fn block_dominates(&self, block_a: Block, mut block_b: Block) -> bool {
154 let rpo_a = self.nodes[block_a].rpo_number;
155
156 while rpo_a < self.nodes[block_b].rpo_number {
159 let idom = match self.idom(block_b) {
160 Some(idom) => idom,
161 None => return false, };
163 block_b = idom;
164 }
165
166 block_a == block_b
167 }
168
169 fn common_dominator(&self, mut a: Block, mut b: Block) -> Block {
173 loop {
174 match self.rpo_cmp_block(a, b) {
175 Ordering::Less => {
176 let idom = self.nodes[b].idom.expect("Unreachable basic block?");
178 b = idom;
179 }
180 Ordering::Greater => {
181 let idom = self.nodes[a].idom.expect("Unreachable basic block?");
183 a = idom;
184 }
185 Ordering::Equal => break,
186 }
187 }
188
189 debug_assert_eq!(a, b, "Unreachable block passed to common_dominator?");
190
191 a
192 }
193}
194
195impl SimpleDominatorTree {
196 pub fn new() -> Self {
199 Self {
200 nodes: SecondaryMap::new(),
201 postorder: Vec::new(),
202 dfs: Dfs::new(),
203 valid: false,
204 }
205 }
206
207 pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self {
209 let block_capacity = func.layout.block_capacity();
210 let mut domtree = Self {
211 nodes: SecondaryMap::with_capacity(block_capacity),
212 postorder: Vec::with_capacity(block_capacity),
213 dfs: Dfs::new(),
214 valid: false,
215 };
216 domtree.compute(func, cfg);
217 domtree
218 }
219
220 pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) {
222 let _tt = timing::domtree();
223 debug_assert!(cfg.is_valid());
224 self.compute_postorder(func);
225 self.compute_domtree(func, cfg);
226 self.valid = true;
227 }
228
229 pub fn clear(&mut self) {
232 self.nodes.clear();
233 self.postorder.clear();
234 self.valid = false;
235 }
236
237 pub fn is_valid(&self) -> bool {
243 self.valid
244 }
245
246 fn compute_postorder(&mut self, func: &Function) {
250 self.clear();
251 self.nodes.resize(func.dfg.num_blocks());
252 self.postorder.extend(self.dfs.post_order_iter(func));
253 }
254
255 fn compute_domtree(&mut self, func: &Function, cfg: &ControlFlowGraph) {
258 let (entry_block, postorder) = match self.postorder.as_slice().split_last() {
267 Some((&eb, rest)) => (eb, rest),
268 None => return,
269 };
270 debug_assert_eq!(Some(entry_block), func.layout.entry_block());
271
272 self.nodes[entry_block].rpo_number = 2 * STRIDE;
274 for (rpo_idx, &block) in postorder.iter().rev().enumerate() {
275 self.nodes[block] = DomNode {
285 idom: self.compute_idom(block, cfg).into(),
286 rpo_number: (rpo_idx as u32 + 3) * STRIDE,
287 }
288 }
289
290 let mut changed = true;
295 while changed {
296 changed = false;
297 for &block in postorder.iter().rev() {
298 let idom = self.compute_idom(block, cfg).into();
299 if self.nodes[block].idom != idom {
300 self.nodes[block].idom = idom;
301 changed = true;
302 }
303 }
304 }
305 }
306
307 fn compute_idom(&self, block: Block, cfg: &ControlFlowGraph) -> Block {
310 let mut reachable_preds = cfg
314 .pred_iter(block)
315 .filter(|&BlockPredecessor { block: pred, .. }| self.nodes[pred].rpo_number > 1)
316 .map(|pred| pred.block);
317
318 let mut idom = reachable_preds
320 .next()
321 .expect("block node must have one reachable predecessor");
322
323 for pred in reachable_preds {
324 idom = self.common_dominator(idom, pred);
325 }
326
327 idom
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use crate::cursor::{Cursor, FuncCursor};
335 use crate::ir::types::*;
336 use crate::ir::{InstBuilder, TrapCode};
337
338 #[test]
339 fn empty() {
340 let func = Function::new();
341 let cfg = ControlFlowGraph::with_function(&func);
342 debug_assert!(cfg.is_valid());
343 let dtree = SimpleDominatorTree::with_function(&func, &cfg);
344 assert_eq!(0, dtree.nodes.keys().count());
345 assert_eq!(dtree.cfg_postorder(), &[]);
346 }
347
348 #[test]
349 fn unreachable_node() {
350 let mut func = Function::new();
351 let block0 = func.dfg.make_block();
352 let v0 = func.dfg.append_block_param(block0, I32);
353 let block1 = func.dfg.make_block();
354 let block2 = func.dfg.make_block();
355 let trap_block = func.dfg.make_block();
356
357 let mut cur = FuncCursor::new(&mut func);
358
359 cur.insert_block(block0);
360 cur.ins().brif(v0, block2, &[], trap_block, &[]);
361
362 cur.insert_block(trap_block);
363 cur.ins().trap(TrapCode::unwrap_user(1));
364
365 cur.insert_block(block1);
366 let v1 = cur.ins().iconst(I32, 1);
367 let v2 = cur.ins().iadd(v0, v1);
368 cur.ins().jump(block0, &[v2]);
369
370 cur.insert_block(block2);
371 cur.ins().return_(&[v0]);
372
373 let cfg = ControlFlowGraph::with_function(cur.func);
374 let dt = SimpleDominatorTree::with_function(cur.func, &cfg);
375
376 assert_eq!(dt.cfg_postorder(), &[block2, trap_block, block0]);
386
387 let v2_def = cur.func.dfg.value_def(v2).unwrap_inst();
388 assert!(!dt.dominates(v2_def, block0, &cur.func.layout));
389 assert!(!dt.dominates(block0, v2_def, &cur.func.layout));
390
391 assert!(dt.dominates(block0, block0, &cur.func.layout));
392 assert!(!dt.dominates(block0, block1, &cur.func.layout));
393 assert!(dt.dominates(block0, block2, &cur.func.layout));
394 assert!(!dt.dominates(block1, block0, &cur.func.layout));
395 assert!(dt.dominates(block1, block1, &cur.func.layout));
396 assert!(!dt.dominates(block1, block2, &cur.func.layout));
397 assert!(!dt.dominates(block2, block0, &cur.func.layout));
398 assert!(!dt.dominates(block2, block1, &cur.func.layout));
399 assert!(dt.dominates(block2, block2, &cur.func.layout));
400 }
401
402 #[test]
403 fn non_zero_entry_block() {
404 let mut func = Function::new();
405 let block0 = func.dfg.make_block();
406 let block1 = func.dfg.make_block();
407 let block2 = func.dfg.make_block();
408 let block3 = func.dfg.make_block();
409 let cond = func.dfg.append_block_param(block3, I32);
410
411 let mut cur = FuncCursor::new(&mut func);
412
413 cur.insert_block(block3);
414 let jmp_block3_block1 = cur.ins().jump(block1, &[]);
415
416 cur.insert_block(block1);
417 let br_block1_block0_block2 = cur.ins().brif(cond, block0, &[], block2, &[]);
418
419 cur.insert_block(block2);
420 cur.ins().jump(block0, &[]);
421
422 cur.insert_block(block0);
423
424 let cfg = ControlFlowGraph::with_function(cur.func);
425 let dt = SimpleDominatorTree::with_function(cur.func, &cfg);
426
427 assert_eq!(dt.cfg_postorder(), &[block0, block2, block1, block3]);
446
447 assert_eq!(cur.func.layout.entry_block().unwrap(), block3);
448 assert_eq!(dt.idom(block3), None);
449 assert_eq!(dt.idom(block1).unwrap(), block3);
450 assert_eq!(dt.idom(block2).unwrap(), block1);
451 assert_eq!(dt.idom(block0).unwrap(), block1);
452
453 assert!(dt.dominates(
454 br_block1_block0_block2,
455 br_block1_block0_block2,
456 &cur.func.layout
457 ));
458 assert!(!dt.dominates(br_block1_block0_block2, jmp_block3_block1, &cur.func.layout));
459 assert!(dt.dominates(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout));
460
461 assert_eq!(
462 dt.rpo_cmp(block3, block3, &cur.func.layout),
463 Ordering::Equal
464 );
465 assert_eq!(dt.rpo_cmp(block3, block1, &cur.func.layout), Ordering::Less);
466 assert_eq!(
467 dt.rpo_cmp(block3, jmp_block3_block1, &cur.func.layout),
468 Ordering::Less
469 );
470 assert_eq!(
471 dt.rpo_cmp(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout),
472 Ordering::Less
473 );
474 }
475
476 #[test]
477 fn backwards_layout() {
478 let mut func = Function::new();
479 let block0 = func.dfg.make_block();
480 let block1 = func.dfg.make_block();
481 let block2 = func.dfg.make_block();
482
483 let mut cur = FuncCursor::new(&mut func);
484
485 cur.insert_block(block0);
486 let jmp02 = cur.ins().jump(block2, &[]);
487
488 cur.insert_block(block1);
489 let trap = cur.ins().trap(TrapCode::unwrap_user(5));
490
491 cur.insert_block(block2);
492 let jmp21 = cur.ins().jump(block1, &[]);
493
494 let cfg = ControlFlowGraph::with_function(cur.func);
495 let dt = SimpleDominatorTree::with_function(cur.func, &cfg);
496
497 assert_eq!(cur.func.layout.entry_block(), Some(block0));
498 assert_eq!(dt.idom(block0), None);
499 assert_eq!(dt.idom(block1), Some(block2));
500 assert_eq!(dt.idom(block2), Some(block0));
501
502 assert!(dt.dominates(block0, block0, &cur.func.layout));
503 assert!(dt.dominates(block0, jmp02, &cur.func.layout));
504 assert!(dt.dominates(block0, block1, &cur.func.layout));
505 assert!(dt.dominates(block0, trap, &cur.func.layout));
506 assert!(dt.dominates(block0, block2, &cur.func.layout));
507 assert!(dt.dominates(block0, jmp21, &cur.func.layout));
508
509 assert!(!dt.dominates(jmp02, block0, &cur.func.layout));
510 assert!(dt.dominates(jmp02, jmp02, &cur.func.layout));
511 assert!(dt.dominates(jmp02, block1, &cur.func.layout));
512 assert!(dt.dominates(jmp02, trap, &cur.func.layout));
513 assert!(dt.dominates(jmp02, block2, &cur.func.layout));
514 assert!(dt.dominates(jmp02, jmp21, &cur.func.layout));
515
516 assert!(!dt.dominates(block1, block0, &cur.func.layout));
517 assert!(!dt.dominates(block1, jmp02, &cur.func.layout));
518 assert!(dt.dominates(block1, block1, &cur.func.layout));
519 assert!(dt.dominates(block1, trap, &cur.func.layout));
520 assert!(!dt.dominates(block1, block2, &cur.func.layout));
521 assert!(!dt.dominates(block1, jmp21, &cur.func.layout));
522
523 assert!(!dt.dominates(trap, block0, &cur.func.layout));
524 assert!(!dt.dominates(trap, jmp02, &cur.func.layout));
525 assert!(!dt.dominates(trap, block1, &cur.func.layout));
526 assert!(dt.dominates(trap, trap, &cur.func.layout));
527 assert!(!dt.dominates(trap, block2, &cur.func.layout));
528 assert!(!dt.dominates(trap, jmp21, &cur.func.layout));
529
530 assert!(!dt.dominates(block2, block0, &cur.func.layout));
531 assert!(!dt.dominates(block2, jmp02, &cur.func.layout));
532 assert!(dt.dominates(block2, block1, &cur.func.layout));
533 assert!(dt.dominates(block2, trap, &cur.func.layout));
534 assert!(dt.dominates(block2, block2, &cur.func.layout));
535 assert!(dt.dominates(block2, jmp21, &cur.func.layout));
536
537 assert!(!dt.dominates(jmp21, block0, &cur.func.layout));
538 assert!(!dt.dominates(jmp21, jmp02, &cur.func.layout));
539 assert!(dt.dominates(jmp21, block1, &cur.func.layout));
540 assert!(dt.dominates(jmp21, trap, &cur.func.layout));
541 assert!(!dt.dominates(jmp21, block2, &cur.func.layout));
542 assert!(dt.dominates(jmp21, jmp21, &cur.func.layout));
543 }
544
545 #[test]
546 fn insts_same_block() {
547 let mut func = Function::new();
548 let block0 = func.dfg.make_block();
549
550 let mut cur = FuncCursor::new(&mut func);
551
552 cur.insert_block(block0);
553 let v1 = cur.ins().iconst(I32, 1);
554 let v2 = cur.ins().iadd(v1, v1);
555 let v3 = cur.ins().iadd(v2, v2);
556 cur.ins().return_(&[]);
557
558 let cfg = ControlFlowGraph::with_function(cur.func);
559 let dt = SimpleDominatorTree::with_function(cur.func, &cfg);
560
561 let v1_def = cur.func.dfg.value_def(v1).unwrap_inst();
562 let v2_def = cur.func.dfg.value_def(v2).unwrap_inst();
563 let v3_def = cur.func.dfg.value_def(v3).unwrap_inst();
564
565 assert!(dt.dominates(v1_def, v2_def, &cur.func.layout));
566 assert!(dt.dominates(v2_def, v3_def, &cur.func.layout));
567 assert!(dt.dominates(v1_def, v3_def, &cur.func.layout));
568
569 assert!(!dt.dominates(v2_def, v1_def, &cur.func.layout));
570 assert!(!dt.dominates(v3_def, v2_def, &cur.func.layout));
571 assert!(!dt.dominates(v3_def, v1_def, &cur.func.layout));
572
573 assert!(dt.dominates(v2_def, v2_def, &cur.func.layout));
574 assert!(dt.dominates(block0, block0, &cur.func.layout));
575
576 assert!(dt.dominates(block0, v1_def, &cur.func.layout));
577 assert!(dt.dominates(block0, v2_def, &cur.func.layout));
578 assert!(dt.dominates(block0, v3_def, &cur.func.layout));
579
580 assert!(!dt.dominates(v1_def, block0, &cur.func.layout));
581 assert!(!dt.dominates(v2_def, block0, &cur.func.layout));
582 assert!(!dt.dominates(v3_def, block0, &cur.func.layout));
583 }
584}