inside_baseball/script/
control.rs

1use crate::script::{
2    ast::{get_script_config, WriteCx},
3    basic::{basic_block_get_exact, basic_blocks_get_index_by_end, BasicBlock},
4};
5use indexmap::IndexMap;
6use std::{
7    fmt,
8    ops::{Range, RangeInclusive},
9    slice,
10};
11use tracing::{debug, instrument};
12
13#[derive(Debug)]
14pub struct ControlBlock {
15    pub start: usize,
16    pub end: usize,
17    pub control: Control,
18}
19
20#[derive(Debug)]
21pub enum Control {
22    CodeRange,
23    Sequence(Vec<usize>),
24    If(If),
25    Do(Do),
26}
27
28#[derive(Debug)]
29pub struct If {
30    pub condition: usize,
31    pub true_: usize,
32    pub false_: Option<usize>,
33}
34
35#[derive(Debug)]
36pub struct While {
37    pub condition: usize,
38    pub body: usize,
39}
40
41#[derive(Debug)]
42pub struct Do {
43    pub body: usize,
44    pub condition: usize,
45    pub condition_kind: ConditionKind,
46}
47
48#[derive(Debug)]
49pub enum ConditionKind {
50    Always,
51    Until,
52}
53
54#[instrument(level = "debug", skip(basics, cx))]
55pub fn build_control_structures(
56    basics: &IndexMap<usize, BasicBlock>,
57    cx: &WriteCx,
58) -> Vec<ControlBlock> {
59    // Build the initial root block -- a flat sequence with every basic block in
60    // order.
61
62    let mut controls = Vec::with_capacity(basics.len() + 1);
63
64    controls.push(ControlBlock {
65        start: 0,
66        end: basics[basics.len() - 1].end,
67        control: Control::Sequence(Vec::new()),
68    });
69
70    let mut seq = Vec::with_capacity(basics.len());
71    for basic in basics.values() {
72        let block = controls.len();
73        controls.push(ControlBlock {
74            start: basic.start,
75            end: basic.end,
76            control: Control::CodeRange,
77        });
78        seq.push(block);
79    }
80
81    let root_seq = match &mut controls[0].control {
82        Control::Sequence(root_seq) => root_seq,
83        _ => unreachable!(),
84    };
85    *root_seq = seq;
86
87    // Run structuring passes one by one.
88
89    let mut work = Vec::with_capacity(16);
90    work.push(0);
91    while let Some(index) = work.pop() {
92        scan_forward_jumps(index, basics, &mut controls, &mut work);
93    }
94    check_control_invariants(0, &controls, basics);
95
96    let skip_do_blocks = get_script_config(cx).map_or(false, |c| c.skip_do_blocks);
97    if !skip_do_blocks {
98        work.push(0);
99        while let Some(index) = work.pop() {
100            scan_loops(index, basics, &mut controls, &mut work);
101        }
102        check_control_invariants(0, &controls, basics);
103    }
104
105    work.push(0);
106    while let Some(index) = work.pop() {
107        scan_elses(index, basics, &mut controls, &mut work);
108    }
109    check_control_invariants(0, &controls, basics);
110
111    controls
112}
113
114fn scan_forward_jumps(
115    index: usize,
116    basics: &IndexMap<usize, BasicBlock>,
117    controls: &mut Vec<ControlBlock>,
118    work: &mut Vec<usize>,
119) {
120    match &controls[index].control {
121        Control::CodeRange => {}
122        Control::Sequence(_) => {
123            scan_forward_jumps_in_sequence(index, basics, controls, work);
124        }
125        Control::If(b) => {
126            work.push(b.condition);
127            work.push(b.true_);
128            work.extend(b.false_);
129        }
130        Control::Do(b) => {
131            work.push(b.body);
132            work.push(b.condition);
133        }
134    }
135}
136
137fn scan_forward_jumps_in_sequence(
138    parent_index: usize,
139    basics: &IndexMap<usize, BasicBlock>,
140    controls: &mut Vec<ControlBlock>,
141    work: &mut Vec<usize>,
142) {
143    let children = match &controls[parent_index].control {
144        Control::Sequence(blocks) => blocks,
145        _ => unreachable!(),
146    };
147
148    for i in 0..children.len() {
149        match &controls[children[i]].control {
150            Control::CodeRange => {
151                if let Some(payload) = scan_forward_jump(parent_index, i, controls, basics) {
152                    build_forward_jump(parent_index, i, payload, controls);
153                    check_control_invariants(parent_index, controls, basics);
154                    work.push(parent_index); // Come back later for the rest
155                    return;
156                }
157            }
158            Control::Sequence(_) => unreachable!(),
159            Control::If(b) => {
160                work.push(b.condition);
161                work.push(b.true_);
162                work.extend(b.false_);
163            }
164            Control::Do(b) => {
165                work.push(b.body);
166                work.push(b.condition);
167            }
168        }
169    }
170}
171
172fn scan_forward_jump(
173    parent_index: usize,
174    seq_index: usize,
175    controls: &[ControlBlock],
176    basics: &IndexMap<usize, BasicBlock>,
177) -> Option<BuildForwardJump> {
178    let parent = &controls[parent_index];
179    let children = match &parent.control {
180        Control::Sequence(blocks) => blocks,
181        _ => unreachable!(),
182    };
183    let cond_ctrl = &controls[children[seq_index]];
184    let cond_block = basic_block_get_exact(basics, cond_ctrl.start, cond_ctrl.end);
185
186    // Require conditional forward jump, still within parent block
187    if !(cond_block.exits.len() == 2
188        && cond_block.exits[0] == cond_block.end
189        && cond_block.exits[1] >= cond_block.end
190        && cond_block.exits[1] <= parent.end)
191    {
192        return None;
193    }
194
195    let body_end = cond_block.exits[1];
196    // Check for a paired jump back to the start of the block
197    let is_loop = {
198        let body_end_block_index = basic_blocks_get_index_by_end(basics, body_end);
199        let body_end_block = &basics[body_end_block_index];
200        body_end_block.exits.len() == 1 && body_end_block.exits[0] == cond_block.start
201    };
202    Some(BuildForwardJump {
203        start: cond_block.start,
204        body_end,
205        is_loop,
206    })
207}
208
209#[derive(Copy, Clone)]
210struct BuildForwardJump {
211    start: usize,
212    body_end: usize,
213    is_loop: bool,
214}
215
216fn build_forward_jump(
217    parent_index: usize,
218    cond_seq: usize,
219    build: BuildForwardJump,
220    controls: &mut Vec<ControlBlock>,
221) {
222    if build.is_loop {
223        build_do(
224            parent_index,
225            BuildDo {
226                start: build.start,
227                end: build.body_end,
228                condition_kind: ConditionKind::Always,
229            },
230            controls,
231        );
232    } else {
233        build_if(parent_index, cond_seq, build.body_end, controls);
234    }
235}
236
237fn build_if(
238    parent_index: usize,
239    cond_seq: usize,
240    body_end: usize,
241    controls: &mut Vec<ControlBlock>,
242) {
243    let body_seq_end = seq_index_ending_at_addr(parent_index, body_end, controls);
244    debug!(
245        parent = %Block(parent_index, controls),
246        cond = %SeqBlock(parent_index, cond_seq, controls),
247        body = %SeqRange(parent_index, (cond_seq + 1)..=body_seq_end, controls),
248        "building if",
249    );
250
251    // Drain the range of blocks which will form the body.
252
253    let seq_blocks = match &mut controls[parent_index].control {
254        Control::Sequence(blocks) => blocks,
255        _ => unreachable!(),
256    };
257    let mut drain = seq_blocks.drain(cond_seq..=body_seq_end);
258    let condition = drain.next().unwrap();
259    let body_blocks: Vec<_> = drain.collect();
260
261    let cond_start = controls[condition].start;
262    let body_start = controls[condition].end;
263
264    // Combine the list of body blocks into one.
265
266    let body = match body_blocks.len() {
267        0 => {
268            // If there are none, synthesize a zero-length block.
269            let body = controls.len();
270            controls.push(ControlBlock {
271                start: body_start,
272                end: body_start,
273                control: Control::CodeRange,
274            });
275            body
276        }
277        1 => body_blocks[0],
278        _ => {
279            let body = controls.len();
280            controls.push(ControlBlock {
281                start: body_start,
282                end: body_end,
283                control: Control::Sequence(body_blocks),
284            });
285            body
286        }
287    };
288
289    // Create the if block, then insert it back into the parent sequence.
290
291    let result = controls.len();
292    controls.push(ControlBlock {
293        start: cond_start,
294        end: body_end,
295        control: Control::If(If {
296            condition,
297            true_: body,
298            false_: None,
299        }),
300    });
301
302    let seq_blocks = match &mut controls[parent_index].control {
303        Control::Sequence(blocks) => blocks,
304        _ => unreachable!(),
305    };
306    seq_blocks.insert(cond_seq, result);
307}
308
309fn scan_elses(
310    index: usize,
311    basics: &IndexMap<usize, BasicBlock>,
312    controls: &mut Vec<ControlBlock>,
313    work: &mut Vec<usize>,
314) {
315    match &controls[index].control {
316        Control::CodeRange => {}
317        Control::Sequence(_) => {
318            scan_elses_in_sequence(index, basics, controls, work);
319        }
320        Control::If(b) => {
321            work.push(b.condition);
322            work.push(b.true_);
323            work.extend(b.false_);
324        }
325        Control::Do(b) => {
326            work.push(b.body);
327            work.push(b.condition);
328        }
329    }
330}
331
332fn scan_elses_in_sequence(
333    parent_index: usize,
334    basics: &IndexMap<usize, BasicBlock>,
335    controls: &mut Vec<ControlBlock>,
336    work: &mut Vec<usize>,
337) {
338    let children = match &controls[parent_index].control {
339        Control::Sequence(blocks) => blocks,
340        _ => unreachable!(),
341    };
342
343    for i in 0..children.len() {
344        match &controls[children[i]].control {
345            Control::CodeRange => {}
346            Control::Sequence(_) => unreachable!(),
347            Control::If(b) => {
348                if let Some(else_end) = scan_else(parent_index, i, basics, controls) {
349                    build_else(parent_index, i, else_end, controls);
350                    work.push(parent_index); // Come back later for the rest of the elses
351                    return;
352                }
353
354                work.push(b.condition);
355                work.push(b.true_);
356                work.extend(b.false_);
357            }
358            Control::Do(b) => {
359                work.push(b.body);
360                work.push(b.condition);
361            }
362        }
363    }
364}
365
366fn scan_else(
367    parent_index: usize,
368    if_seq_index: usize,
369    basics: &IndexMap<usize, BasicBlock>,
370    controls: &[ControlBlock],
371) -> Option<usize> {
372    let parent = &controls[parent_index];
373    let parent_blocks = match &controls[parent_index].control {
374        Control::Sequence(blocks) => blocks,
375        _ => unreachable!(),
376    };
377    let if_index = parent_blocks[if_seq_index];
378    let if_ = match &controls[if_index].control {
379        Control::If(b) => b,
380        _ => return None,
381    };
382
383    // An if can only have one else, of course
384    if if_.false_.is_some() {
385        return None;
386    }
387
388    let true_end_index = basic_blocks_get_index_by_end(basics, controls[if_.true_].end);
389    let true_end = &basics[true_end_index];
390
391    // Require an unconditional jump over a code range within the same parent, which
392    // will form the else.
393    if !(true_end.exits.len() == 1
394        && true_end.exits[0] > true_end.end
395        && true_end.exits[0] <= parent.end)
396    {
397        return None;
398    }
399
400    let else_end = true_end.exits[0];
401
402    // Require the end to be on a block boundary or within a splittable block
403    match seq_end_boundary(parent_index, else_end, controls) {
404        (_, SeqBoundary::Exact | SeqBoundary::CanSplit) => {}
405        (_, SeqBoundary::CanNotSplit) => return None,
406    }
407
408    Some(else_end)
409}
410
411fn build_else(
412    parent_index: usize,
413    if_seq_index: usize,
414    else_end: usize,
415    controls: &mut Vec<ControlBlock>,
416) {
417    let children = match &mut controls[parent_index].control {
418        Control::Sequence(blocks) => blocks,
419        _ => unreachable!(),
420    };
421    let if_index = children[if_seq_index];
422    let if_ctrl = &controls[if_index];
423    let else_start = if_ctrl.end;
424    debug!(
425        if_ = %AddrRange(if_ctrl.start..if_ctrl.end),
426        "else" = %AddrRange(else_start..else_end),
427        "building else, parent=#{parent_index}",
428    );
429
430    // Drain the range of blocks which will form the else.
431
432    let else_seq_start = if_seq_index + 1;
433    let else_seq_end = seq_index_ending_at_addr(parent_index, else_end, controls);
434
435    let seq_blocks = match &mut controls[parent_index].control {
436        Control::Sequence(blocks) => blocks,
437        _ => unreachable!(),
438    };
439    let else_blocks: Vec<_> = seq_blocks.drain(else_seq_start..=else_seq_end).collect();
440
441    // Combine the list of else blocks into one.
442
443    let else_ = match else_blocks.len() {
444        0 => todo!(),
445        1 => else_blocks[0],
446        _ => {
447            let else_ = controls.len();
448            controls.push(ControlBlock {
449                start: else_start,
450                end: else_end,
451                control: Control::Sequence(else_blocks),
452            });
453            else_
454        }
455    };
456
457    // Grow the if block to contain the new else block.
458
459    controls[if_index].end = else_end;
460    let mut if_ = match &mut controls[if_index].control {
461        Control::If(if_) => if_,
462        _ => unreachable!(),
463    };
464    if_.false_ = Some(else_);
465}
466
467fn scan_loops(
468    index: usize,
469    basics: &IndexMap<usize, BasicBlock>,
470    controls: &mut Vec<ControlBlock>,
471    work: &mut Vec<usize>,
472) {
473    match &controls[index].control {
474        Control::CodeRange | Control::Sequence(_) => {
475            scan_loops_in_sequence(index, basics, controls, work);
476        }
477        Control::If(b) => {
478            work.push(b.condition);
479            work.push(b.true_);
480            work.extend(b.false_);
481        }
482        Control::Do(b) => {
483            work.push(b.body);
484            // Ignore the condition since its jump was already handled.
485        }
486    }
487}
488
489fn scan_loops_in_sequence(
490    index: usize,
491    basics: &IndexMap<usize, BasicBlock>,
492    controls: &mut Vec<ControlBlock>,
493    work: &mut Vec<usize>,
494) {
495    let blocks = match &controls[index].control {
496        Control::CodeRange => slice::from_ref(&index),
497        Control::Sequence(blocks) => blocks,
498        _ => unreachable!(),
499    };
500
501    for &block in blocks {
502        match &controls[block].control {
503            Control::CodeRange => {
504                if controls[block].start == controls[block].end {
505                    continue;
506                }
507                let basic_start = basics.get_index_of(&controls[block].start).unwrap();
508                let basic_end = basic_blocks_get_index_by_end(basics, controls[block].end);
509                for i in basic_start..=basic_end {
510                    if let Some(build) = scan_do(index, i, controls, basics) {
511                        build_do(index, build, controls);
512                        work.push(index); // Scan for later loops in same sequence
513                        return;
514                    }
515                }
516            }
517            Control::Sequence(_) => unreachable!(),
518            Control::If(b) => {
519                work.push(b.condition);
520                work.push(b.true_);
521                work.extend(b.false_);
522            }
523            Control::Do(b) => {
524                work.push(b.body);
525                // Ignore the condition since its jump was already handled.
526            }
527        }
528    }
529}
530
531fn scan_do(
532    parent_index: usize,
533    basic_index: usize,
534    controls: &[ControlBlock],
535    basics: &IndexMap<usize, BasicBlock>,
536) -> Option<BuildDo> {
537    let parent = &controls[parent_index];
538
539    let end_block = &basics[basic_index];
540    let condition_kind = match end_block.exits.len() {
541        1 => ConditionKind::Always,
542        2 => ConditionKind::Until,
543        _ => unreachable!(),
544    };
545    let start = *end_block.exits.last().unwrap();
546    let end = end_block.end;
547
548    // Require backward jump within parent sequence
549    if !(start < end && start >= parent.start) {
550        return None;
551    }
552
553    // Require the start/end to be on block boundaries or within splittable blocks
554    match &controls[parent_index].control {
555        Control::CodeRange => {}
556        Control::Sequence(_) => {
557            match seq_start_boundary(parent_index, start, controls) {
558                (_, SeqBoundary::Exact | SeqBoundary::CanSplit) => {}
559                (_, SeqBoundary::CanNotSplit) => return None,
560            }
561            match seq_end_boundary(parent_index, end, controls) {
562                (_, SeqBoundary::Exact | SeqBoundary::CanSplit) => {}
563                (_, SeqBoundary::CanNotSplit) => return None,
564            }
565        }
566        _ => unreachable!(),
567    }
568
569    Some(BuildDo {
570        start,
571        end,
572        condition_kind,
573    })
574}
575
576struct BuildDo {
577    start: usize,
578    end: usize,
579    condition_kind: ConditionKind,
580}
581
582fn build_do(
583    parent_index: usize,
584    BuildDo {
585        start,
586        end,
587        condition_kind,
588    }: BuildDo,
589    controls: &mut Vec<ControlBlock>,
590) {
591    debug!(
592        parent = %Block(parent_index, controls),
593        addr = %AddrRange(start..end),
594        ?condition_kind,
595        "building do",
596    );
597
598    // Ensure the blocks have boundaries at the start/end addresses
599
600    let seq_start_index = seq_index_starting_at_addr(parent_index, start, controls);
601    let seq_end_index = seq_index_ending_at_addr(parent_index, end, controls);
602
603    // Drain the range of blocks which will form the loop.
604
605    let seq_blocks = match &mut controls[parent_index].control {
606        Control::Sequence(blocks) => blocks,
607        _ => unreachable!(),
608    };
609    let mut drain = seq_blocks.drain(seq_start_index..=seq_end_index);
610    let body_blocks: Vec<_> = drain
611        .by_ref()
612        .take(seq_end_index - seq_start_index)
613        .collect();
614    let condition = drain.next().unwrap();
615    debug_assert!(drain.next().is_none());
616    drop(drain);
617
618    // Combine the list of body blocks into one.
619
620    let body = match body_blocks.len() {
621        0 => {
622            // If there are none, synthesize a zero-length block.
623            debug_assert!(start == controls[condition].start);
624            let body = controls.len();
625            controls.push(ControlBlock {
626                start,
627                end: start,
628                control: Control::CodeRange,
629            });
630            body
631        }
632        1 => body_blocks[0],
633        _ => {
634            let body = controls.len();
635            controls.push(ControlBlock {
636                start,
637                end: controls[*body_blocks.last().unwrap()].end,
638                control: Control::Sequence(body_blocks),
639            });
640            body
641        }
642    };
643
644    // Create the do block, then insert it back into the parent sequence.
645
646    let do_ = controls.len();
647    controls.push(ControlBlock {
648        start,
649        end,
650        control: Control::Do(Do {
651            body,
652            condition,
653            condition_kind,
654        }),
655    });
656
657    let seq_blocks = match &mut controls[parent_index].control {
658        Control::Sequence(blocks) => blocks,
659        _ => unreachable!(),
660    };
661    seq_blocks.insert(seq_start_index, do_);
662}
663
664fn seq_start_boundary(
665    parent_index: usize,
666    addr: usize,
667    controls: &[ControlBlock],
668) -> (usize, SeqBoundary) {
669    debug_assert!(controls[parent_index].start <= addr && addr <= controls[parent_index].end);
670    let seq_blocks = match &controls[parent_index].control {
671        Control::Sequence(seq_blocks) => seq_blocks,
672        _ => unreachable!(),
673    };
674    let i = seq_blocks
675        .iter()
676        .position(|&b| controls[b].end > addr)
677        .unwrap();
678    let split = if addr == controls[seq_blocks[i]].start {
679        SeqBoundary::Exact
680    } else if matches!(controls[seq_blocks[i]].control, Control::CodeRange) {
681        SeqBoundary::CanSplit
682    } else {
683        SeqBoundary::CanNotSplit
684    };
685    (i, split)
686}
687
688fn seq_end_boundary(
689    parent_index: usize,
690    addr: usize,
691    controls: &[ControlBlock],
692) -> (usize, SeqBoundary) {
693    debug_assert!(controls[parent_index].start <= addr && addr <= controls[parent_index].end);
694    let seq_blocks = match &controls[parent_index].control {
695        Control::Sequence(seq_blocks) => seq_blocks,
696        _ => unreachable!(),
697    };
698    let i = seq_blocks
699        .iter()
700        .rposition(|&b| controls[b].start < addr)
701        .unwrap();
702    let split = if addr == controls[seq_blocks[i]].end {
703        SeqBoundary::Exact
704    } else if matches!(controls[seq_blocks[i]].control, Control::CodeRange) {
705        SeqBoundary::CanSplit
706    } else {
707        SeqBoundary::CanNotSplit
708    };
709    (i, split)
710}
711
712enum SeqBoundary {
713    Exact,
714    CanSplit,
715    CanNotSplit,
716}
717
718fn seq_index_starting_at_addr(
719    parent_index: usize,
720    addr: usize,
721    controls: &[ControlBlock],
722) -> usize {
723    debug_assert!(controls[parent_index].start <= addr && addr <= controls[parent_index].end);
724
725    match seq_start_boundary(parent_index, addr, controls) {
726        (i, SeqBoundary::Exact) => i,
727        _ => unreachable!(),
728    }
729}
730
731fn seq_index_ending_at_addr(parent_index: usize, addr: usize, controls: &[ControlBlock]) -> usize {
732    debug_assert!(controls[parent_index].start <= addr && addr <= controls[parent_index].end);
733
734    match seq_end_boundary(parent_index, addr, controls) {
735        (i, SeqBoundary::Exact) => i,
736        _ => unreachable!(),
737    }
738}
739
740fn check_control_invariants(
741    root: usize,
742    controls: &[ControlBlock],
743    basics: &IndexMap<usize, BasicBlock>,
744) {
745    #[cfg(not(debug_assertions))]
746    return;
747
748    macro_rules! asrt {
749        ($cond:expr) => {
750            assert!($cond, "{} invariant violation in #{}", Dump(controls), root);
751        };
752    }
753
754    let ctrl = &controls[root];
755    asrt!(ctrl.start <= ctrl.end);
756
757    match &ctrl.control {
758        Control::CodeRange => {
759            asrt!(basics[&ctrl.start].start == ctrl.start);
760            let _ = &basics[&ctrl.start]; // Ensure it starts exactly on a basic block
761            // Zero-length starting blocks are okay. All others must have end exactly on
762            // a basic block
763            if !(ctrl.start == 0 && ctrl.end == 0) {
764                let end_index = basic_blocks_get_index_by_end(basics, ctrl.end);
765                asrt!(basics[end_index].end == ctrl.end);
766            }
767        }
768        Control::Sequence(xs) => {
769            asrt!(!xs.is_empty());
770            asrt!(controls[*xs.first().unwrap()].start == ctrl.start);
771            asrt!(controls[*xs.last().unwrap()].end == ctrl.end);
772            for i in 0..xs.len() - 1 {
773                asrt!(controls[xs[i]].end == controls[xs[i + 1]].start);
774            }
775            for &child in xs {
776                check_control_invariants(child, controls, basics);
777            }
778        }
779        Control::If(b) => {
780            asrt!(ctrl.start == controls[b.condition].start);
781            asrt!(controls[b.condition].end == controls[b.true_].start);
782            check_control_invariants(b.condition, controls, basics);
783            check_control_invariants(b.true_, controls, basics);
784            match b.false_ {
785                None => {
786                    asrt!(ctrl.end == controls[b.true_].end);
787                }
788                Some(false_) => {
789                    asrt!(ctrl.end == controls[false_].end);
790                    asrt!(controls[b.true_].end == controls[false_].start);
791                    check_control_invariants(false_, controls, basics);
792                }
793            }
794        }
795        Control::Do(b) => {
796            asrt!(ctrl.start == controls[b.body].start);
797            asrt!(ctrl.end == controls[b.condition].end);
798            asrt!(controls[b.body].end == controls[b.condition].start);
799            check_control_invariants(b.body, controls, basics);
800            check_control_invariants(b.condition, controls, basics);
801
802            let cond_block = &basics[&controls[b.condition].start];
803            match b.condition_kind {
804                ConditionKind::Always => {
805                    asrt!(cond_block.exits.len() == 1);
806                    asrt!(cond_block.exits[0] == ctrl.start);
807                }
808                ConditionKind::Until => {
809                    asrt!(cond_block.exits.len() == 2);
810                    asrt!(cond_block.exits[0] == ctrl.end);
811                    asrt!(cond_block.exits[1] == ctrl.start);
812                }
813            }
814        }
815    }
816}
817
818struct AddrRange(Range<usize>);
819
820impl fmt::Display for AddrRange {
821    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822        write!(f, "0x{:x}..0x{:x}", self.0.start, self.0.end)
823    }
824}
825
826struct Block<'a>(usize, &'a [ControlBlock]);
827
828impl fmt::Display for Block<'_> {
829    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
830        let &Self(index, controls) = self;
831        let block = &controls[index];
832        write!(f, "#{}(0x{:x}..0x{:x})", index, block.start, block.end)
833    }
834}
835
836struct SeqBlock<'a>(usize, usize, &'a [ControlBlock]);
837
838impl fmt::Display for SeqBlock<'_> {
839    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
840        let &Self(parent_index, seq_index, controls) = self;
841        let children = match &controls[parent_index].control {
842            Control::Sequence(blocks) => blocks,
843            _ => unreachable!(),
844        };
845        let block = children[seq_index];
846        let ctrl = &controls[block];
847        write!(
848            f,
849            "#{}[{}]->#{}(0x{:x}..0x{:x})",
850            parent_index, seq_index, block, ctrl.start, ctrl.end,
851        )
852    }
853}
854
855struct SeqRange<'a>(usize, RangeInclusive<usize>, &'a [ControlBlock]);
856
857impl fmt::Display for SeqRange<'_> {
858    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859        let &Self(parent_index, ref seq_range, controls) = self;
860        let seq_start = *seq_range.start();
861        let seq_end = *seq_range.end();
862        let children = match &controls[parent_index].control {
863            Control::Sequence(blocks) => blocks,
864            _ => unreachable!(),
865        };
866        let start = controls[children[seq_start]].start;
867        let end = controls[children[seq_end]].end;
868        write!(
869            f,
870            "#{}[{}..={}](0x{:x}..0x{:x})",
871            parent_index, seq_start, seq_end, start, end,
872        )
873    }
874}
875
876struct Dump<'a>(&'a [ControlBlock]);
877
878impl fmt::Display for Dump<'_> {
879    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880        for (i, block) in self.0.iter().enumerate() {
881            writeln!(
882                f,
883                "#{} {} {:?}",
884                i,
885                AddrRange(block.start..block.end),
886                block.control,
887            )?;
888        }
889        Ok(())
890    }
891}