1use rucc_mir::{Block, Func, Inst};
26
27pub type Point = u32;
29
30#[derive(Debug, Clone)]
32pub struct Order {
33 blocks: Vec<Block>,
34 start: Vec<Point>,
36 end: Vec<Point>,
38 early: Vec<Point>,
40 points: Point,
41}
42
43impl Order {
44 #[must_use]
46 pub fn of(func: &Func) -> Self {
47 let mut order = Self {
48 blocks: Vec::with_capacity(func.block_count()),
49 start: vec![0; func.block_count()],
50 end: vec![0; func.block_count()],
51 early: vec![0; func.inst_count()],
52 points: 0,
53 };
54 let mut point = 0;
55 for block in func.blocks() {
56 order.blocks.push(block);
57 order.start[block.index()] = point;
58 point += 1;
59 for inst in func.insts(block) {
60 order.early[inst.index()] = point;
61 point += 2;
62 }
63 order.end[block.index()] = point;
64 point += 1;
65 }
66 order.points = point;
67 order
68 }
69
70 #[must_use]
72 pub fn blocks(&self) -> &[Block] {
73 &self.blocks
74 }
75
76 #[must_use]
79 pub fn points(&self) -> Point {
80 self.points
81 }
82
83 #[must_use]
85 pub fn start(&self, block: Block) -> Point {
86 self.start[block.index()]
87 }
88
89 #[must_use]
91 pub fn end(&self, block: Block) -> Point {
92 self.end[block.index()]
93 }
94
95 #[must_use]
97 pub fn early(&self, inst: Inst) -> Point {
98 self.early[inst.index()]
99 }
100
101 #[must_use]
103 pub fn late(&self, inst: Inst) -> Point {
104 self.early[inst.index()] + 1
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use rucc_base::Interner;
111 use rucc_mir::{BlockCall, Opcode};
112
113 use super::*;
114
115 fn func() -> (Func, Vec<Block>, Vec<Inst>) {
117 let mut names = Interner::new();
118 let mut func = Func::new(names.intern("f"));
119 let opcode = Opcode::new(names.intern("x64.nop"));
120 let head = func.create_block();
121 let tail = func.create_block();
122 let first = func.build(head, opcode).finish();
123 let second = func.build(head, opcode).finish();
124 *func.succs_mut(head) = vec![BlockCall::to(tail)];
125 let third = func.build(tail, opcode).finish();
126 (func, vec![head, tail], vec![first, second, third])
127 }
128
129 #[test]
130 fn the_order_is_the_one_the_function_is_written_in() {
131 let (func, blocks, _) = func();
132 assert_eq!(Order::of(&func).blocks(), blocks);
133 }
134
135 #[test]
136 fn an_instruction_reads_before_it_writes() {
137 let (func, _, insts) = func();
138 let order = Order::of(&func);
139 for &inst in &insts {
140 assert!(order.early(inst) < order.late(inst));
141 }
142 }
143
144 #[test]
145 fn nothing_in_a_function_shares_a_point_with_anything_else() {
146 let (func, blocks, insts) = func();
147 let order = Order::of(&func);
148 let mut points: Vec<Point> = Vec::new();
149 for &block in &blocks {
150 points.push(order.start(block));
151 points.push(order.end(block));
152 }
153 for &inst in &insts {
154 points.push(order.early(inst));
155 points.push(order.late(inst));
156 }
157 points.sort_unstable();
158 let count = points.len();
159 points.dedup();
160 assert_eq!(points.len(), count);
161 assert_eq!(order.points(), Point::try_from(count).expect("a small function"));
162 }
163
164 #[test]
165 fn a_block_holds_everything_in_it() {
166 let (func, blocks, insts) = func();
167 let order = Order::of(&func);
168 for &block in &blocks {
169 for inst in func.insts(block) {
170 assert!(order.start(block) < order.early(inst));
171 assert!(order.late(inst) < order.end(block));
172 }
173 }
174 assert!(order.end(blocks[0]) < order.start(blocks[1]));
176 assert!(order.late(insts[1]) < order.early(insts[2]));
177 }
178}