luaur_bytecode/methods/
bytecode_graph_parser_find_producer_bytecode_graph_parser.rs1use crate::enums::bc_block_edge_kind::BcBlockEdgeKind;
2use crate::enums::bc_op_kind::BcOpKind;
3use crate::records::bc_op::BcOp;
4use crate::records::bc_op_hash::BcOpHash;
5use crate::records::bytecode_graph_parser::BytecodeGraphParser;
6use crate::type_aliases::reg::Reg;
7use alloc::collections::BTreeSet;
8use alloc::vec::Vec;
9use luaur_common::macros::luau_assert::LUAU_ASSERT;
10use std::collections::HashSet;
11
12impl<'a> BytecodeGraphParser<'a> {
13 pub fn find_producer_bc_op_reg_unordered_set_bc_op_bc_op_hash(
14 &mut self,
15 block: BcOp,
16 reg: Reg,
17 visited: &mut HashSet<BcOp, BcOpHash>,
18 ) -> Option<BcOp> {
19 visited.insert(block);
20 LUAU_ASSERT!(block.index < self.producers.len() as u32);
21 let block_producers = &self.producers[block.index as usize];
22
23 if (reg as i32) > block_producers.invalidAfter {
24 return None;
25 }
26
27 if let Some(local) = block_producers.own.get(®) {
28 return Some(*local);
29 }
30
31 if let Some(cached) = block_producers.cached.get(®) {
32 return Some(*cached);
33 }
34
35 if block_producers.multiReturn.kind != BcOpKind::None
36 && reg >= block_producers.multiReturnStart
37 {
38 return Some(self.func.add_proj(
39 block_producers.multiReturn,
40 (reg - block_producers.multiReturnStart) as u32,
41 ));
42 }
43
44 let mut results: Vec<BcOp> = Vec::new();
47 let bl = self.func.block_op(block);
48 let predecessors = bl.predecessors.clone();
49
50 for edge in &predecessors {
51 let ctrl = edge.kind;
52 let pred = edge.target;
53
54 if ctrl == BcBlockEdgeKind::Loop || visited.contains(&pred) {
55 continue;
56 }
57 LUAU_ASSERT!(block != pred);
58
59 if let Some(op) =
60 self.find_producer_bc_op_reg_unordered_set_bc_op_bc_op_hash(pred, reg, visited)
61 {
62 if op.kind == BcOpKind::Phi {
63 let phi = self.func.phi_op(op);
64 for &proj in &phi.ops {
65 if !results.contains(&proj) {
66 results.push(proj);
67 }
68 }
69 } else {
70 if !results.contains(&op) {
71 results.push(op);
72 }
73 }
74 }
75 }
76
77 if results.is_empty() {
78 return None;
79 }
80
81 let res = if results.len() == 1 {
82 results[0]
83 } else {
84 let res = self.func.add_phi();
85 let phi = self.func.phi_op(res);
86 for op in results {
87 phi.ops.push_back(op);
88 }
89 res
90 };
91
92 let block_producers = &mut self.producers[block.index as usize];
93 block_producers.cached.insert(reg, res);
94 Some(res)
95 }
96}