vicis_core/ir/function/data/
mod.rs1use crate::ir::{
2 function::{
3 basic_block::{BasicBlock, BasicBlockId},
4 instruction::{Instruction, InstructionId},
5 },
6 value::{Value, ValueId},
7};
8use id_arena::Arena;
9use rustc_hash::{FxHashMap, FxHashSet};
10
11pub struct Data {
12 pub values: Arena<Value>,
13 pub instructions: Arena<Instruction>,
14 pub basic_blocks: Arena<BasicBlock>,
15 pub users_map: FxHashMap<InstructionId, FxHashSet<InstructionId>>,
16}
17
18impl Default for Data {
19 fn default() -> Self {
20 Self {
21 values: Arena::new(),
22 instructions: Arena::new(),
23 basic_blocks: Arena::new(),
24 users_map: FxHashMap::default(),
25 }
26 }
27}
28
29impl Data {
30 pub fn new() -> Self {
31 Self::default()
32 }
33
34 pub fn create_block(&mut self) -> BasicBlockId {
35 self.basic_blocks.alloc(BasicBlock::new())
36 }
37
38 pub fn create_inst(&mut self, mut inst: Instruction) -> InstructionId {
39 let id = self.instructions.alloc_with_id(|id| {
40 inst.id = Some(id);
41 inst
42 });
43 self.users_map.insert(id, FxHashSet::default());
44 self.validate_inst_uses(id);
45 id
46 }
47
48 pub fn create_value(&mut self, inst: Value) -> ValueId {
49 self.values.alloc(inst)
50 }
51
52 pub fn replace_inst(&mut self, from: InstructionId, to: Instruction) {
53 self.instructions[from].replace(to);
54 self.validate_inst_uses(from)
55 }
56
57 pub fn block_ref(&self, id: BasicBlockId) -> &BasicBlock {
58 &self.basic_blocks[id]
59 }
60
61 pub fn block_ref_mut(&mut self, id: BasicBlockId) -> &mut BasicBlock {
62 &mut self.basic_blocks[id]
63 }
64
65 pub fn remove_block_pred(&mut self, id: BasicBlockId, pred: BasicBlockId) -> bool {
66 self.basic_blocks[id].preds.remove(&pred)
67 }
68
69 pub fn remove_block_succ(&mut self, id: BasicBlockId, succ: BasicBlockId) -> bool {
70 self.basic_blocks[id].succs.remove(&succ)
71 }
72
73 pub fn inst_ref(&self, id: InstructionId) -> &Instruction {
74 &self.instructions[id]
75 }
76
77 pub fn inst_ref_mut(&mut self, id: InstructionId) -> &mut Instruction {
78 &mut self.instructions[id]
79 }
80
81 pub fn value_ref(&self, id: ValueId) -> &Value {
82 &self.values[id]
83 }
84
85 pub fn value_ref_mut(&mut self, id: ValueId) -> &mut Value {
86 &mut self.values[id]
87 }
88
89 pub fn users_of(&self, id: InstructionId) -> &FxHashSet<InstructionId> {
90 &self.users_map[&id]
91 }
92
93 pub fn only_one_user_of(&self, id: InstructionId) -> Option<InstructionId> {
96 if self.users_of(id).len() != 1 {
97 return None;
98 }
99 self.users_of(id).iter().next().copied()
100 }
101
102 pub fn replace_inst_arg(&mut self, inst_id: InstructionId, from: InstructionId, to: ValueId) {
103 let inst = &mut self.instructions[inst_id];
104 let mut replaced = false;
105
106 for arg_id in inst.operand.args_mut() {
108 let arg = &self.values[*arg_id];
109 if matches!(arg, Value::Instruction(i) if i == &from) {
110 *arg_id = to;
111 replaced = true;
112 }
113 continue;
114 }
115
116 if !replaced {
118 return;
119 }
120
121 if let Some(map) = self.users_map.get_mut(&from) {
124 assert!(map.remove(&inst_id));
125 }
126
127 if let Value::Instruction(to) = self.values[to] {
128 self.users_map
129 .entry(to)
130 .or_insert_with(FxHashSet::default)
131 .insert(inst_id);
132 }
133 }
134
135 pub fn replace_all_uses(&mut self, inst_id: InstructionId, to: ValueId) {
136 for user_id in self.users_map[&inst_id].clone() {
137 self.replace_inst_arg(user_id, inst_id, to);
138 }
139 }
140
141 pub fn validate_inst_uses(&mut self, id: InstructionId) {
142 let args = self.instructions[id]
143 .operand
144 .args()
145 .iter()
146 .filter_map(|&arg| match &self.values[arg] {
147 Value::Instruction(id) => Some(*id),
148 _ => None,
149 })
150 .collect::<Vec<InstructionId>>();
151 for arg in args {
152 self.users_map
153 .entry(arg)
154 .or_insert_with(FxHashSet::default)
155 .insert(id);
156 }
157 }
158
159 pub fn remove_uses(&mut self, id: InstructionId) {
160 let args = self.instructions[id]
161 .operand
162 .args()
163 .iter()
164 .filter_map(|&arg| match &self.values[arg] {
165 Value::Instruction(id) => Some(*id),
166 _ => None,
167 })
168 .collect::<Vec<InstructionId>>();
169 for arg in args {
170 if let Some(users) = self.users_map.get_mut(&arg) {
171 users.remove(&id);
172 }
173 }
174 }
175}