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 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 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); 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 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 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 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 let body = match body_blocks.len() {
267 0 => {
268 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 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); 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 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 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 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 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 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 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 }
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); 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 }
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 if !(start < end && start >= parent.start) {
550 return None;
551 }
552
553 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 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 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 let body = match body_blocks.len() {
621 0 => {
622 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 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]; 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}