1use rucc_mir::{Block, Func, Reg, Role};
55
56use crate::order::{Order, Point};
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub struct Range {
67 pub start: Point,
69 pub end: Point,
71}
72
73impl Range {
74 #[must_use]
76 pub fn covers(self, point: Point) -> bool {
77 self.start <= point && point <= self.end
78 }
79
80 #[must_use]
82 pub fn overlaps(self, other: Self) -> bool {
83 self.start <= other.end && other.start <= self.end
84 }
85
86 fn with(self, point: Point) -> Self {
89 Self { start: self.start.min(point), end: self.end.max(point) }
90 }
91}
92
93#[derive(Debug, Clone, Copy)]
104pub struct Area<'a> {
105 pieces: &'a [Range],
106 also: Option<Point>,
107}
108
109impl<'a> Area<'a> {
110 #[must_use]
115 pub fn with(self, point: Point) -> Self {
116 Self { also: Some(point), ..self }
117 }
118
119 #[must_use]
122 pub fn hull(self) -> Range {
123 Range { start: self.piece(0).start, end: self.pieces[self.pieces.len() - 1].end }
124 }
125
126 #[must_use]
132 pub fn covers(self, point: Point) -> bool {
133 let first = self.pieces.partition_point(|piece| piece.end < point);
134 first < self.pieces.len() && self.piece(first).covers(point)
135 }
136
137 #[must_use]
142 pub fn overlaps(self, other: Self) -> bool {
143 let (mut mine, mut theirs) = (0, 0);
144 while mine < self.pieces.len() && theirs < other.pieces.len() {
145 let (one, two) = (self.piece(mine), other.piece(theirs));
146 if one.overlaps(two) {
147 return true;
148 }
149 if one.end < two.end {
151 mine += 1;
152 } else {
153 theirs += 1;
154 }
155 }
156 false
157 }
158
159 pub fn pieces(self) -> impl Iterator<Item = Range> + 'a {
161 (0..self.pieces.len()).map(move |piece| self.piece(piece))
162 }
163
164 fn piece(self, index: usize) -> Range {
167 let piece = self.pieces[index];
168 match self.also {
169 Some(also) if also + 1 == piece.start => Range { start: also, end: piece.end },
170 _ => piece,
171 }
172 }
173}
174
175#[derive(Debug, Clone)]
177pub struct Live {
178 live_in: Rows,
179 live_out: Rows,
180 pieces: Vec<Range>,
182 spans: Vec<(usize, usize)>,
184}
185
186impl Live {
187 #[must_use]
189 pub fn of(func: &Func, order: &Order) -> Self {
190 let vregs = func.vregs();
191 let (used, defined) = exposed(func, order);
192 let (live_in, live_out) = flow(func, order, &used, &defined);
193 let (pieces, spans) = carve(func, order, &live_in, &live_out, vregs);
194 Self { live_in, live_out, pieces, spans }
195 }
196
197 #[must_use]
200 pub fn area(&self, reg: Reg) -> Option<Area<'_>> {
201 let pieces = self.pieces(reg);
202 if pieces.is_empty() {
203 return None;
204 }
205 Some(Area { pieces, also: None })
206 }
207
208 #[must_use]
210 pub fn range(&self, reg: Reg) -> Option<Range> {
211 self.area(reg).map(Area::hull)
212 }
213
214 pub fn live_in(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
219 self.live_in.iter(block.index())
220 }
221
222 pub fn live_out(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
225 self.live_out.iter(block.index())
226 }
227
228 fn pieces(&self, reg: Reg) -> &[Range] {
230 let number = reg.number().and_then(|number| usize::try_from(number).ok());
231 let Some(&(from, to)) = number.and_then(|number| self.spans.get(number)) else {
232 return &[];
233 };
234 &self.pieces[from..to]
235 }
236}
237
238fn carve(
244 func: &Func,
245 order: &Order,
246 live_in: &Rows,
247 live_out: &Rows,
248 vregs: usize,
249) -> (Vec<Range>, Vec<(usize, usize)>) {
250 let mut lists: Vec<Vec<Range>> = vec![Vec::new(); vregs];
251 let mut here: Vec<Option<Range>> = vec![None; vregs];
252 let mut touched: Vec<usize> = Vec::new();
253
254 for &block in order.blocks() {
255 for reg in live_in.iter(block.index()) {
258 note(&mut here, &mut touched, reg, order.start(block));
259 }
260 for reg in live_out.iter(block.index()) {
261 note(&mut here, &mut touched, reg, order.end(block));
262 }
263 for param in &func[block].params {
264 note(&mut here, &mut touched, param.reg, order.start(block));
265 }
266 for inst in func.insts(block) {
267 for operand in &func[func[inst].operands] {
268 match operand.role {
269 Role::Use => note(&mut here, &mut touched, operand.reg, order.early(inst)),
270 Role::Def => note(&mut here, &mut touched, operand.reg, order.late(inst)),
271 Role::EarlyDef => {
278 note(&mut here, &mut touched, operand.reg, order.early(inst));
279 note(&mut here, &mut touched, operand.reg, order.late(inst));
280 }
281 }
282 }
283 }
284 for call in &func[block].succs {
285 for &arg in &call.args {
286 note(&mut here, &mut touched, arg, order.end(block));
287 }
288 }
289
290 for &number in &touched {
291 let Some(piece) = here[number].take() else { continue };
292 match lists[number].last_mut() {
293 Some(last) if last.end + 1 == piece.start => last.end = piece.end,
297 _ => lists[number].push(piece),
298 }
299 }
300 touched.clear();
301 }
302
303 let mut pieces = Vec::new();
304 let mut spans = Vec::with_capacity(vregs);
305 for list in &lists {
306 let from = pieces.len();
307 pieces.extend_from_slice(list);
308 spans.push((from, pieces.len()));
309 }
310 (pieces, spans)
311}
312
313fn note(here: &mut [Option<Range>], touched: &mut Vec<usize>, reg: Reg, point: Point) {
315 let Some(number) = reg.number().and_then(|number| usize::try_from(number).ok()) else {
316 return;
317 };
318 let Some(slot) = here.get_mut(number) else { return };
319 match slot {
320 Some(range) => *range = range.with(point),
321 None => {
322 *slot = Some(Range { start: point, end: point });
323 touched.push(number);
324 }
325 }
326}
327
328fn exposed(func: &Func, order: &Order) -> (Rows, Rows) {
333 let vregs = func.vregs();
334 let mut used = Vec::new();
335 let mut defined = Vec::new();
336 let mut reads = Building::new(vregs);
337 let mut writes = Building::new(vregs);
338 for &block in order.blocks() {
339 let row = block.index();
340 for call in &func[block].succs {
341 for &arg in &call.args {
342 reads.insert(arg);
343 }
344 }
345 let insts: Vec<_> = func.insts(block).collect();
346 for &inst in insts.iter().rev() {
347 let operands = &func[func[inst].operands];
348 for operand in operands.iter().filter(|operand| operand.role.is_def()) {
349 reads.remove(operand.reg);
350 writes.insert(operand.reg);
351 }
352 for operand in operands.iter().filter(|operand| !operand.role.is_def()) {
353 reads.insert(operand.reg);
354 }
355 }
356 for param in &func[block].params {
357 reads.remove(param.reg);
358 writes.insert(param.reg);
359 }
360 used.extend(reads.take().into_iter().map(|number| (row_of(row), number)));
361 defined.extend(writes.take().into_iter().map(|number| (row_of(row), number)));
362 }
363 (Rows::gather(func.block_count(), &used), Rows::gather(func.block_count(), &defined))
364}
365
366fn flow(func: &Func, order: &Order, used: &Rows, defined: &Rows) -> (Rows, Rows) {
380 let count = func.block_count();
381 let vregs = func.vregs();
382 let mut preds: Vec<Vec<usize>> = vec![Vec::new(); count];
383 for &block in order.blocks() {
384 for call in &func[block].succs {
385 preds[call.block.index()].push(block.index());
386 }
387 }
388 let mut starts = vec![0usize; vregs + 1];
390 for &block in order.blocks() {
391 for &number in used.row(block.index()) {
392 starts[number as usize + 1] += 1;
393 }
394 }
395 for number in 0..vregs {
396 starts[number + 1] += starts[number];
397 }
398 let mut readers = vec![0usize; starts[vregs]];
399 let mut filled = starts.clone();
400 for &block in order.blocks() {
401 for &number in used.row(block.index()) {
402 readers[filled[number as usize]] = block.index();
403 filled[number as usize] += 1;
404 }
405 }
406 let mut ends = vec![0usize; vregs + 1];
409 for &block in order.blocks() {
410 for &number in defined.row(block.index()) {
411 ends[number as usize + 1] += 1;
412 }
413 }
414 for number in 0..vregs {
415 ends[number + 1] += ends[number];
416 }
417 let mut writers = vec![0usize; ends[vregs]];
418 let mut filled = ends.clone();
419 for &block in order.blocks() {
420 for &number in defined.row(block.index()) {
421 writers[filled[number as usize]] = block.index();
422 filled[number as usize] += 1;
423 }
424 }
425
426 let mut live_in = Vec::new();
427 let mut live_out = Vec::new();
428 let mut arrived = vec![u32::MAX; count];
431 let mut left = vec![u32::MAX; count];
432 let mut wrote = vec![u32::MAX; count];
433 let mut waiting = Vec::new();
434 for number in 0..vregs {
435 let value = u32::try_from(number).expect("a register number");
436 for &row in &writers[ends[number]..ends[number + 1]] {
437 wrote[row] = value;
438 }
439 for &row in &readers[starts[number]..starts[number + 1]] {
440 if arrived[row] != value {
441 arrived[row] = value;
442 live_in.push((row_of(row), value));
443 waiting.push(row);
444 }
445 }
446 while let Some(row) = waiting.pop() {
447 for &pred in &preds[row] {
448 if left[pred] != value {
449 left[pred] = value;
450 live_out.push((row_of(pred), value));
451 }
452 if arrived[pred] != value && wrote[pred] != value {
453 arrived[pred] = value;
454 live_in.push((row_of(pred), value));
455 waiting.push(pred);
456 }
457 }
458 }
459 }
460 (Rows::transpose(count, &live_in), Rows::transpose(count, &live_out))
461}
462
463#[derive(Debug, Clone)]
483struct Rows {
484 starts: Vec<usize>,
486 numbers: Vec<u32>,
487}
488
489impl Rows {
490 fn gather(rows: usize, pairs: &[(u32, u32)]) -> Self {
496 let (starts, mut filled) = Self::starts(rows, pairs);
497 let mut numbers = vec![0u32; pairs.len()];
498 for &(row, number) in pairs {
499 let at = &mut filled[row as usize];
500 numbers[*at] = number;
501 *at += 1;
502 }
503 Self { starts, numbers }
504 }
505
506 fn transpose(rows: usize, pairs: &[(u32, u32)]) -> Self {
515 let mut shift = 0;
516 while rows > Self::WAYS << shift {
517 shift += 1;
518 }
519 if shift == 0 {
520 return Self::gather(rows, pairs);
521 }
522 let (starts, mut filled) = Self::starts(rows, pairs);
523 let mut next: Vec<usize> =
525 (0..rows.div_ceil(1 << shift)).map(|run| starts[run << shift]).collect();
526 let mut runs = vec![(0u32, 0u32); pairs.len()];
527 for &pair in pairs {
528 let at = &mut next[(pair.0 >> shift) as usize];
529 runs[*at] = pair;
530 *at += 1;
531 }
532 let mut numbers = vec![0u32; pairs.len()];
533 for &(row, number) in &runs {
534 let at = &mut filled[row as usize];
535 numbers[*at] = number;
536 *at += 1;
537 }
538 Self { starts, numbers }
539 }
540
541 const WAYS: usize = 256;
543
544 fn starts(rows: usize, pairs: &[(u32, u32)]) -> (Vec<usize>, Vec<usize>) {
547 let mut starts = vec![0usize; rows + 1];
548 for &(row, _) in pairs {
549 starts[row as usize + 1] += 1;
550 }
551 for row in 0..rows {
552 starts[row + 1] += starts[row];
553 }
554 let filled = starts.clone();
555 (starts, filled)
556 }
557
558 fn row(&self, row: usize) -> &[u32] {
559 &self.numbers[self.starts[row]..self.starts[row + 1]]
560 }
561
562 fn iter(&self, row: usize) -> impl Iterator<Item = Reg> + '_ {
563 self.row(row).iter().copied().map(Reg::virtual_reg)
564 }
565}
566
567fn row_of(index: usize) -> u32 {
569 u32::try_from(index).expect("a block number")
570}
571
572struct Building {
582 flags: Vec<bool>,
583 touched: Vec<u32>,
587}
588
589impl Building {
590 fn new(vregs: usize) -> Self {
591 Self { flags: vec![false; vregs], touched: Vec::new() }
592 }
593
594 fn number(&self, reg: Reg) -> Option<usize> {
598 let number = usize::try_from(reg.number()?).ok()?;
599 (number < self.flags.len()).then_some(number)
600 }
601
602 fn insert(&mut self, reg: Reg) {
603 let Some(number) = self.number(reg) else { return };
604 if !self.flags[number] {
605 self.flags[number] = true;
606 self.touched.push(u32::try_from(number).expect("a register number"));
607 }
608 }
609
610 fn remove(&mut self, reg: Reg) {
611 if let Some(number) = self.number(reg) {
612 self.flags[number] = false;
613 }
614 }
615
616 fn take(&mut self) -> Vec<u32> {
618 let flags = &mut self.flags;
619 let mut out: Vec<u32> = self
620 .touched
621 .drain(..)
622 .filter(|&number| std::mem::replace(&mut flags[number as usize], false))
623 .collect();
624 out.sort_unstable();
625 out
626 }
627}
628
629#[cfg(test)]
630mod tests {
631 use rucc_base::Interner;
632 use rucc_mir::{BlockCall, Constraint, Opcode, Operand};
633 use rucc_target::x86_64::GPR;
634
635 use super::*;
636
637 fn regs(of: impl Iterator<Item = Reg>) -> Vec<u32> {
639 of.filter_map(Reg::number).collect()
640 }
641
642 #[test]
643 fn a_value_is_live_from_where_it_is_written_to_where_it_is_last_read() {
644 let mut names = Interner::new();
645 let mut func = Func::new(names.intern("f"));
646 let opcode = Opcode::new(names.intern("x64.nop"));
647 let block = func.create_block();
648 let value = func.new_vreg(GPR);
649 let other = func.new_vreg(GPR);
650 let write = func.build(block, opcode).def(value, GPR).finish();
651 let idle = func.build(block, opcode).def(other, GPR).finish();
652 let read = func.build(block, opcode).uses(value, GPR).finish();
653
654 let order = Order::of(&func);
655 let live = Live::of(&func, &order);
656 let range = live.range(value).expect("the value is live somewhere");
657 assert_eq!(range, Range { start: order.late(write), end: order.early(read) });
658 assert!(range.covers(order.early(idle)));
659 assert_eq!(
662 live.range(other),
663 Some(Range { start: order.late(idle), end: order.late(idle) })
664 );
665 assert!(!range.overlaps(Range { start: order.late(read), end: order.late(read) }));
666 assert_eq!(regs(live.live_in(block)), Vec::<u32>::new());
667 }
668
669 #[test]
670 fn a_value_read_in_another_block_is_live_between_them() {
671 let mut names = Interner::new();
672 let mut func = Func::new(names.intern("f"));
673 let opcode = Opcode::new(names.intern("x64.nop"));
674 let head = func.create_block();
675 let middle = func.create_block();
676 let tail = func.create_block();
677 let value = func.new_vreg(GPR);
678 func.build(head, opcode).def(value, GPR).finish();
679 *func.succs_mut(head) = vec![BlockCall::to(middle)];
680 *func.succs_mut(middle) = vec![BlockCall::to(tail)];
681 let read = func.build(tail, opcode).uses(value, GPR).finish();
682
683 let order = Order::of(&func);
684 let live = Live::of(&func, &order);
685 assert_eq!(regs(live.live_in(middle)), vec![0]);
688 assert_eq!(regs(live.live_out(middle)), vec![0]);
689 assert!(live.range(value).expect("live somewhere").covers(order.start(middle)));
690 assert_eq!(live.range(value).expect("live somewhere").end, order.early(read));
691 }
692
693 #[test]
694 fn a_block_the_value_never_reaches_is_a_hole_between_two_pieces() {
695 let mut names = Interner::new();
696 let mut func = Func::new(names.intern("f"));
697 let opcode = Opcode::new(names.intern("x64.nop"));
698 let entry = func.create_block();
699 let arm = func.create_block();
700 let tail = func.create_block();
701 let value = func.new_vreg(GPR);
702 let write = func.build(entry, opcode).def(value, GPR).finish();
703 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
704 let idle = func.build(arm, opcode).finish();
705 let read = func.build(tail, opcode).uses(value, GPR).finish();
706
707 let order = Order::of(&func);
708 let live = Live::of(&func, &order);
709 let area = live.area(value).expect("live somewhere");
710 assert!(live.range(value).expect("live somewhere").covers(order.early(idle)));
714 assert!(!area.covers(order.early(idle)));
715 assert_eq!(
716 area.pieces().collect::<Vec<_>>(),
717 vec![
718 Range { start: order.late(write), end: order.end(entry) },
719 Range { start: order.start(tail), end: order.early(read) },
720 ]
721 );
722 }
723
724 #[test]
725 fn a_value_in_a_hole_of_another_may_have_its_register() {
726 let mut names = Interner::new();
727 let mut func = Func::new(names.intern("f"));
728 let opcode = Opcode::new(names.intern("x64.nop"));
729 let entry = func.create_block();
730 let arm = func.create_block();
731 let tail = func.create_block();
732 let value = func.new_vreg(GPR);
733 let inside = func.new_vreg(GPR);
734 func.build(entry, opcode).def(value, GPR).finish();
735 *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
736 func.build(arm, opcode).def(inside, GPR).finish();
737 func.build(arm, opcode).uses(inside, GPR).finish();
738 func.build(tail, opcode).uses(value, GPR).finish();
739
740 let order = Order::of(&func);
741 let live = Live::of(&func, &order);
742 let value = live.area(value).expect("live somewhere");
743 let inside = live.area(inside).expect("live somewhere");
744 assert!(value.hull().overlaps(inside.hull()));
748 assert!(!value.overlaps(inside));
749 assert!(!inside.overlaps(value));
750 }
751
752 #[test]
753 fn one_point_added_in_front_of_a_piece_is_part_of_the_area() {
754 let mut names = Interner::new();
755 let mut func = Func::new(names.intern("f"));
756 let opcode = Opcode::new(names.intern("x64.nop"));
757 let block = func.create_block();
758 let first = func.new_vreg(GPR);
759 let second = func.new_vreg(GPR);
760 let write = func.build(block, opcode).def(first, GPR).finish();
761 let both = func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
762
763 let order = Order::of(&func);
764 let live = Live::of(&func, &order);
765 let first = live.area(first).expect("live somewhere");
766 let second = live.area(second).expect("live somewhere");
767 assert!(!first.overlaps(second));
772 assert!(first.overlaps(second.with(order.early(both))));
773 assert!(second.with(order.early(both)).covers(order.early(both)));
774 assert_eq!(second.with(order.early(both)).hull().start, order.early(both));
775 assert_eq!(first.hull().start, order.late(write));
776 }
777
778 #[test]
779 fn the_point_added_in_front_joins_the_piece_it_belongs_to_and_not_the_first_one() {
780 let mut names = Interner::new();
781 let mut func = Func::new(names.intern("f"));
782 let nop = Opcode::new(names.intern("x64.nop"));
783 let add = Opcode::new(names.intern("x64.add"));
784 let entry = func.create_block();
785 let head = func.create_block();
786 let arm = func.create_block();
787 let latch = func.create_block();
788 let out = func.create_block();
789 let seed = func.new_vreg(GPR);
790 let sum = func.new_vreg(GPR);
791 let inside = func.new_vreg(GPR);
792 let loaded = func.new_vreg(GPR);
793 func.build(entry, nop).def(seed, GPR).finish();
794 func.build(entry, nop).def(sum, GPR).finish();
795 *func.succs_mut(entry) = vec![BlockCall::to(head)];
796 func.build(head, nop).uses(sum, GPR).finish();
797 *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
798 func.build(arm, nop).def(inside, GPR).finish();
799 func.build(arm, nop).uses(inside, GPR).finish();
800 *func.succs_mut(arm) = vec![BlockCall::to(out)];
801 func.build(latch, nop).def(loaded, GPR).finish();
802 let carry = func
803 .build(latch, add)
804 .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
805 .uses(seed, GPR)
806 .uses(loaded, GPR)
807 .finish();
808 *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
809
810 let order = Order::of(&func);
811 let live = Live::of(&func, &order);
812 let sum = live.area(sum).expect("live somewhere");
813 let loaded = live.area(loaded).expect("live somewhere");
814 assert_eq!(sum.pieces().count(), 2);
819 assert!(!sum.covers(order.early(carry)));
820 assert!(sum.with(order.early(carry)).covers(order.early(carry)));
821 assert!(!loaded.overlaps(sum));
822 assert!(loaded.overlaps(sum.with(order.early(carry))));
823 }
824
825 #[test]
826 fn a_value_carried_round_a_loop_is_live_round_all_of_it() {
827 let mut names = Interner::new();
828 let mut func = Func::new(names.intern("f"));
829 let opcode = Opcode::new(names.intern("x64.nop"));
830 let header = func.create_block();
831 let body = func.create_block();
832 let carried = func.append_param(header, GPR);
833 let next = func.new_vreg(GPR);
834 *func.succs_mut(header) = vec![BlockCall::to(body)];
835 func.build(body, opcode).def(next, GPR).uses(carried, GPR).finish();
836 *func.succs_mut(body) = vec![BlockCall::with(header, vec![next])];
837
838 let order = Order::of(&func);
839 let live = Live::of(&func, &order);
840 assert_eq!(regs(live.live_in(header)), Vec::<u32>::new());
843 assert_eq!(regs(live.live_in(body)), vec![carried.number().expect("virtual")]);
844 let range = live.range(next).expect("live somewhere");
845 assert_eq!(range.end, order.end(body));
846 }
847
848 #[test]
849 fn two_values_that_are_never_both_wanted_do_not_overlap() {
850 let mut names = Interner::new();
851 let mut func = Func::new(names.intern("f"));
852 let opcode = Opcode::new(names.intern("x64.nop"));
853 let block = func.create_block();
854 let first = func.new_vreg(GPR);
855 let second = func.new_vreg(GPR);
856 let write = func.build(block, opcode).def(first, GPR).finish();
857 func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
858
859 let order = Order::of(&func);
860 let live = Live::of(&func, &order);
861 let first = live.range(first).expect("live somewhere");
862 let second = live.range(second).expect("live somewhere");
863 assert!(!first.overlaps(second));
867 assert!(first.start > order.start(block));
868 assert_eq!(first.start, order.late(write));
869 }
870
871 #[test]
872 fn an_operand_written_early_is_wanted_where_the_operands_are_read() {
873 let mut names = Interner::new();
874 let mut func = Func::new(names.intern("f"));
875 let opcode = Opcode::new(names.intern("x64.nop"));
876 let block = func.create_block();
877 let source = func.new_vreg(GPR);
878 let early = func.new_vreg(GPR);
879 func.build(block, opcode).def(source, GPR).finish();
880 func.build(block, opcode)
881 .operand(Operand::write_early(early, GPR))
882 .operand(Operand::read(source, GPR))
883 .finish();
884
885 let order = Order::of(&func);
886 let live = Live::of(&func, &order);
887 let source = live.range(source).expect("live somewhere");
888 let early = live.range(early).expect("live somewhere");
889 assert!(source.overlaps(early));
892 }
893
894 #[test]
895 fn a_register_a_memory_operand_names_is_read_like_any_other() {
896 use rucc_mir::Mem;
897
898 let mut names = Interner::new();
899 let mut func = Func::new(names.intern("f"));
900 let opcode = Opcode::new(names.intern("x64.nop"));
901 let block = func.create_block();
902 let address = func.new_vreg(GPR);
903 let write = func.build(block, opcode).def(address, GPR).finish();
904 let load = func.build(block, opcode).mem(Mem::at(Operand::read(address, GPR))).finish();
905
906 let order = Order::of(&func);
907 let live = Live::of(&func, &order);
908 assert_eq!(
909 live.range(address),
910 Some(Range { start: order.late(write), end: order.early(load) })
911 );
912 }
913
914 #[test]
915 fn rows_from_a_list_a_value_at_a_time_over_many_blocks_keep_the_order_the_numbers_came_in() {
916 let rows = 3000;
919 let mut pairs = Vec::new();
920 let mut seed = 7u32;
921 for number in 0..400 {
922 for _ in 0..30 {
923 seed = seed.wrapping_mul(1_103_515_245).wrapping_add(12345);
924 pairs.push(((seed >> 8) % 3000, number));
925 }
926 }
927 let gathered = Rows::transpose(rows, &pairs);
928 for row in 0..rows {
929 let wanted: Vec<u32> = pairs
930 .iter()
931 .filter(|&&(at, _)| at as usize == row)
932 .map(|&(_, number)| number)
933 .collect();
934 assert_eq!(gathered.row(row), wanted, "row {row}");
935 }
936 }
937}