luaur_bytecode/methods/
call_inliner_split_block_on_op.rs1use crate::enums::bc_block_edge_kind::BcBlockEdgeKind;
2use crate::enums::bc_op_kind::BcOpKind;
3use crate::records::bc_block::BcBlock;
4use crate::records::bc_block_edge::BcBlockEdge;
5use crate::records::bc_op::BcOp;
6use crate::records::bc_ref::BcRef;
7use crate::records::call_inliner::CallInliner;
8use alloc::vec::Vec;
9use luaur_common::macros::luau_assert::LUAU_ASSERT;
10
11impl<'a> CallInliner<'a> {
12 pub fn split_block_on_op(
13 &mut self,
14 split_op: BcOp,
15 ) -> (BcRef<'a, BcBlock>, BcRef<'a, BcBlock>) {
16 let prev_block_op = self.caller.instructions[split_op.index as usize].block;
17 LUAU_ASSERT!(prev_block_op.kind == BcOpKind::Block);
18 LUAU_ASSERT!(self.caller.blocks[prev_block_op.index as usize]
19 .ops
20 .iter()
21 .any(|op| *op == split_op));
22
23 let insn_block_op = self.caller.add_block();
24 let prev_block_sortkey = self.caller.blocks[prev_block_op.index as usize].sortkey;
25 let prev_block_chainkey = self.caller.blocks[prev_block_op.index as usize].chainkey;
26 self.caller.blocks[insn_block_op.index as usize].sortkey = prev_block_sortkey;
27 self.caller.blocks[insn_block_op.index as usize].chainkey = prev_block_chainkey + 1;
28
29 let next_block_op = self.caller.add_block();
30 self.caller.blocks[next_block_op.index as usize].sortkey =
31 self.caller.blocks[insn_block_op.index as usize].sortkey;
32 self.caller.blocks[next_block_op.index as usize].chainkey =
33 self.caller.blocks[insn_block_op.index as usize].chainkey + 1;
34
35 while *self.caller.blocks[prev_block_op.index as usize]
36 .ops
37 .back()
38 .unwrap()
39 != split_op
40 {
41 let back_op = *self.caller.blocks[prev_block_op.index as usize]
42 .ops
43 .back()
44 .unwrap();
45 self.caller.blocks[prev_block_op.index as usize]
46 .ops
47 .pop_back();
48 self.caller.blocks[next_block_op.index as usize]
49 .ops
50 .push_front(back_op);
51 self.caller.instructions[back_op.index as usize].block = next_block_op;
52 }
53
54 let prev_successors = self.caller.blocks[prev_block_op.index as usize]
55 .successors
56 .clone();
57 for e in &prev_successors {
58 let succ = e.target;
59 for pred in self.caller.blocks[succ.index as usize]
60 .predecessors
61 .iter_mut()
62 {
63 if pred.target == prev_block_op {
64 pred.target = next_block_op;
65 }
66 }
67 }
68 self.caller.blocks[next_block_op.index as usize].successors = prev_successors;
69 self.caller.blocks[prev_block_op.index as usize]
70 .successors
71 .clear();
72
73 self.caller.blocks[prev_block_op.index as usize]
74 .successors
75 .push_back(BcBlockEdge {
76 kind: BcBlockEdgeKind::Fallthrough,
77 target: insn_block_op,
78 });
79 self.caller.blocks[insn_block_op.index as usize]
80 .predecessors
81 .push_back(BcBlockEdge {
82 kind: BcBlockEdgeKind::Fallthrough,
83 target: prev_block_op,
84 });
85 self.caller.blocks[insn_block_op.index as usize]
86 .successors
87 .push_back(BcBlockEdge {
88 kind: BcBlockEdgeKind::Fallthrough,
89 target: next_block_op,
90 });
91 self.caller.blocks[next_block_op.index as usize]
92 .predecessors
93 .push_back(BcBlockEdge {
94 kind: BcBlockEdgeKind::Fallthrough,
95 target: insn_block_op,
96 });
97
98 LUAU_ASSERT!(
99 *self.caller.blocks[prev_block_op.index as usize]
100 .ops
101 .back()
102 .unwrap()
103 == split_op
104 );
105 self.caller.blocks[prev_block_op.index as usize]
106 .ops
107 .pop_back();
108 self.caller.blocks[insn_block_op.index as usize]
109 .ops
110 .push_back(split_op);
111 self.caller.instructions[split_op.index as usize].block = insn_block_op;
112
113 let vec_ptr: *const Vec<BcBlock> = &self.caller.blocks;
114 let vec_ref: &'a Vec<BcBlock> = unsafe { &*vec_ptr };
115 (
116 BcRef {
117 vec: vec_ref,
118 op: prev_block_op,
119 },
120 BcRef {
121 vec: vec_ref,
122 op: next_block_op,
123 },
124 )
125 }
126}