qcode_passes/
terminator.rs1use qcode::value::{
4 BlockId, FunctionBody, QCodeView, ValueId,
5 insn::{Branch, Mnemonic},
6 util::base_ref::BaseRef,
7};
8
9use crate::PassCtx;
10
11pub fn replace_terminator_with_branch<'a, 'str>(
12 body: &'a mut FunctionBody<'str>,
13 cx: PassCtx<'a, 'str>,
14 block: BlockId,
15 target: BlockId,
16 args: Vec<ValueId>,
17) {
18 let mut old_successors = cx
19 .body_view(body)
20 .block_ref(block)
21 .successors()
22 .map(|(edge, _)| edge)
23 .collect::<Vec<_>>();
24 old_successors.sort_unstable();
25 old_successors.dedup();
26 for edge in old_successors {
27 body.remove_cfg_edge(edge);
28 }
29
30 let term_id = cx
37 .body_view(body)
38 .block_ref(block)
39 .instruction_ids()
40 .last()
41 .copied()
42 .filter(|&id| cx.body_view(body).insn_ref(id).mnemonic().is_terminator());
43 let local_target = target.localize(block.func);
44 let args: Vec<_> = args
45 .into_iter()
46 .map(|arg| arg.localize(block.func))
47 .collect();
48 if let Some(term_id) = term_id {
49 body.replace_instruction_mnemonic(
50 term_id,
51 Mnemonic::Branch(Branch {
52 target: local_target,
53 args,
54 }),
55 );
56 } else {
57 let branch = body.push_mnemonic(
58 cx.shr(),
59 Mnemonic::Branch(Branch {
60 target: local_target,
61 args,
62 }),
63 0,
64 );
65 let end = cx.body_view(body).block_ref(block).instruction_ids().len();
66 {
67 let mut host = cx.host(body);
70 BaseRef::new(host.reborrow(), block).insert_insn_at_index(end, branch);
71 }
72 }
73 body.add_cfg_edge(block, target);
74}