duskphantom_middle/ir/basic_block.rs
1// Copyright 2024 Duskphantom Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17use instruction::{downcast_mut, misc_inst::Phi, InstType};
18
19use super::*;
20
21pub type BBPtr = ObjPtr<BasicBlock>;
22
23/// The organization structure of the instructions inside the basic block is a double linked list.
24/// the last instruction must be br or ret.
25pub struct BasicBlock {
26 pub ir_builder: ObjPtr<IRBuilder>,
27
28 pub name: String,
29
30 pub id: usize,
31
32 pub depth: usize,
33
34 /// The head instruction of the `BasicBlock`,
35 /// which is used to unify the insertion operation and has no actual meaning.
36 /// Logical structure of the `BasicBlock` is a two-way non-circular linked list,
37 /// but in actual implementation, it is a two-way circular linked list.
38 head_inst: InstPtr,
39
40 /// The predecessor `BasicBlock` of the `BasicBlock`.
41 /// The number of predecessor `BasicBlocks` can theoretically be 0 to infinity.
42 /// When the number of predecessor `BasicBlocks` is 0,
43 /// the `BasicBlock` is the function entry `BasicBlock` or an unreachable `BasicBlock`.
44 pred_bbs: Vec<BBPtr>,
45
46 /// The successor `BasicBlock` of the `BasicBlock`.
47 /// The number of successor `BasicBlocks` can theoretically be 0, 1, and 2:
48 /// 1. When the number of successor `BasicBlocks` is 0, the `BasicBlock` is the function exit `BasicBlock`.
49 /// 2. When the number of successor `BasicBlocks` is 1, the last instruction of the `BasicBlock` is an unconditional jump instruction.
50 /// 3. When the number of successor `BasicBlocks` is 2, the last instruction of the `BasicBlock` is a conditional jump instruction.
51 /// + The `BasicBlock` with index 0 is the `BasicBlock` to jump to when the condition is true.
52 /// + The `BasicBlock` with index 1 is the `BasicBlock` to jump to when the condition is false.
53 succ_bbs: Vec<BBPtr>,
54}
55
56impl BasicBlock {
57 pub fn new(name: String, mut ir_builder: ObjPtr<IRBuilder>) -> Self {
58 let head_inst = ir_builder.new_head();
59 Self {
60 ir_builder,
61 name,
62 id: 0,
63 depth: 0,
64 head_inst,
65 pred_bbs: Vec::new(),
66 succ_bbs: Vec::new(),
67 }
68 }
69
70 /// # Safety
71 ///
72 /// Inits `BasicBlock` after memory allocation.
73 ///
74 /// This is an ugly code that is a compromise in design. You should not call this function.
75 pub unsafe fn init_bb(mut bb: BBPtr, id: usize) {
76 let mut head = bb.head_inst;
77 bb.head_inst.set_prev(head);
78 bb.head_inst.set_next(head);
79 head.set_parent_bb(bb);
80 bb.id = id;
81 }
82
83 /// Returns `True` if the `BasicBlock` is empty.
84 #[inline]
85 pub fn is_empty(&self) -> bool {
86 self.head_inst.is_last()
87 }
88
89 /// Gets first instruction in the `BasicBlock`.
90 ///
91 /// # Panics
92 /// Please make sure the current basic block is not empty, otherwise it will panic.
93 #[inline]
94 pub fn get_first_inst(&self) -> InstPtr {
95 self.head_inst.get_next().unwrap()
96 }
97
98 /// Gets the last instruction in the `BasicBlock`.
99 ///
100 /// # Panics
101 /// Please make sure the current basic block is not empty, otherwise it will panic.
102 #[inline]
103 pub fn get_last_inst(&self) -> InstPtr {
104 self.head_inst.get_prev().unwrap()
105 }
106
107 /// Appends a new instruction to the end of the `BasicBlock`.
108 #[inline]
109 pub fn push_back(&mut self, inst: InstPtr) {
110 self.head_inst.insert_before(inst);
111 }
112
113 /// Appends a new instruction to the beginning of the `BasicBlock`.
114 #[inline]
115 pub fn push_front(&mut self, inst: InstPtr) {
116 self.head_inst.insert_after(inst);
117 }
118
119 /// Returns `True` if the `BasicBlock` is the function entry `BasicBlock`.
120 #[inline]
121 pub fn is_entry(&self) -> bool {
122 self.pred_bbs.is_empty()
123 }
124
125 /// Returns `True` if the `BasicBlock` is the function exit `BasicBlock`.
126 #[inline]
127 pub fn is_exit(&self) -> bool {
128 self.succ_bbs.is_empty()
129 }
130
131 /// Gets the predecessor `BasicBlock` of the `BasicBlock`.
132 #[inline]
133 pub fn get_pred_bb(&self) -> &Vec<BBPtr> {
134 &self.pred_bbs
135 }
136
137 /// Gets the successor `BasicBlock` of the `BasicBlock`.
138 #[inline]
139 pub fn get_succ_bb(&self) -> &Vec<BBPtr> {
140 &self.succ_bbs
141 }
142
143 /// Remove current block.
144 /// This removes self from successor's predecessor list and phi operand.
145 ///
146 /// # Panics
147 /// Please make sure this block is unreachable!
148 pub fn remove_self(&mut self) {
149 for succ in self.succ_bbs.iter() {
150 succ.clone().remove_pred_bb(ObjPtr::new(self));
151 }
152 }
153
154 /// Replace `preds => [ self -> ... ] => succs` with `preds => [ entry -> ... ] => succs`. This:
155 /// - add preds to entry's predecessor list
156 /// - remove preds from self's predecessor list
157 /// - replaces self to entry in predecessor's successor list
158 /// - replaces self to entry in function entry
159 ///
160 /// # Safety
161 /// Entry should be different from self, and contain no "phi" instructions.
162 pub fn replace_entry(&mut self, mut entry: BBPtr, mut func: FunPtr) {
163 for pred in self.pred_bbs.iter_mut() {
164 entry.pred_bbs.push(*pred);
165 for pred_succ in pred.succ_bbs.iter_mut() {
166 if pred_succ.id == self.id {
167 *pred_succ = entry;
168 }
169 }
170 }
171 self.pred_bbs.clear();
172 if func.entry.is_some() && func.entry.unwrap().id == self.id {
173 func.entry = Some(entry);
174 }
175 }
176
177 /// Replace `preds => [ ... -> self ] => succs` with `preds => [ ... -> exit ] => succs`. This:
178 /// - add succs to exit's successor list
179 /// - remove succs from self's successor list
180 /// - replaces self -> exit in successor's predecessor list
181 /// - replaces self -> exit in successor's phi operand
182 ///
183 /// # Safety
184 /// Exit should be different from self.
185 pub fn replace_exit(&mut self, mut exit: BBPtr) {
186 for succ in self.succ_bbs.iter() {
187 exit.succ_bbs.push(*succ);
188 succ.clone().replace_pred_bb(ObjPtr::new(self), exit);
189 }
190 self.succ_bbs.clear();
191 }
192
193 /// Remove a predecessor of this block.
194 pub fn remove_pred_bb(&mut self, pred: BBPtr) {
195 // Remove pred bb
196 self.pred_bbs.retain(|x| x.id != pred.id);
197
198 // Remove phi operand
199 for mut inst in self.iter() {
200 if inst.get_type() == InstType::Phi {
201 let inst = downcast_mut::<Phi>(inst.as_mut());
202 inst.remove_incoming_value(pred.id);
203
204 // If phi has only one operand, replace with the operand
205 if inst.get_incoming_values().len() == 1 {
206 let only_op = inst.get_incoming_values()[0].0.clone();
207 inst.replace_self(&only_op);
208 }
209 }
210 }
211 }
212
213 /// Replace a predecessor of this block.
214 pub fn replace_pred_bb(&mut self, from: BBPtr, to: BBPtr) {
215 // Replace pred bb
216 for pred in self.pred_bbs.iter_mut() {
217 if pred.id == from.id {
218 *pred = to;
219 }
220 }
221
222 // Replace phi operand
223 for mut inst in self.iter() {
224 if inst.get_type() == InstType::Phi {
225 let inst = downcast_mut::<Phi>(inst.as_mut());
226 inst.replace_incoming_value(from, to);
227 }
228 }
229 }
230
231 /// Replace successor with given mapping.
232 /// TODO: rename me
233 pub fn replace_succ_bb_only(&mut self, mut from: BBPtr, mut to: BBPtr) {
234 if let Some(index) = self.succ_bbs.iter().enumerate().find_map(|(index, bb)| {
235 if bb.id == from.id {
236 Some(index)
237 } else {
238 None
239 }
240 }) {
241 from.pred_bbs.retain(|x| x.id != self.id);
242 self.succ_bbs[index] = to;
243 to.pred_bbs.push(ObjPtr::new(self))
244 }
245 }
246
247 /// Sets which `BasicBlock` to jump to when the condition is true.
248 ///
249 /// # Panics
250 /// Don't replace existing true `BasicBlock` with this method.
251 pub fn set_true_bb(&mut self, mut bb: BBPtr) {
252 let self_ptr = ObjPtr::new(self);
253 if self.succ_bbs.is_empty() {
254 self.succ_bbs.push(bb);
255 } else {
256 panic!("The true bb already exists");
257 }
258 bb.pred_bbs.push(self_ptr);
259 }
260
261 /// Sets which `BasicBlock` to jump to when the condition is false.
262 ///
263 /// # Panics
264 /// You should set the true `BasicBlock` before use this method.
265 /// Don't replace existing false `BasicBlock` with this method.
266 pub fn set_false_bb(&mut self, mut bb: BBPtr) {
267 let self_ptr = ObjPtr::new(self);
268 if self.succ_bbs.len() == 1 {
269 self.succ_bbs.push(bb);
270 } else {
271 panic!("The false bb already exists");
272 }
273 bb.pred_bbs.push(self_ptr);
274 }
275
276 /// Remove basic block to jump to when the condition is false.
277 /// This will only execute when false bb exists.
278 pub fn remove_false_bb(&mut self) {
279 let self_ptr = ObjPtr::new(self);
280 if self.succ_bbs.len() == 2 {
281 let mut next = self.succ_bbs[1];
282 next.remove_pred_bb(self_ptr);
283 self.succ_bbs.pop();
284 }
285 }
286
287 /// Remove basic block to jump to when the condition is true.
288 /// This will only execute when false bb exists.
289 pub fn remove_true_bb(&mut self) {
290 let self_ptr = ObjPtr::new(self);
291 if self.succ_bbs.len() == 2 {
292 let mut next = self.succ_bbs[0];
293 next.remove_pred_bb(self_ptr);
294 self.succ_bbs.remove(0);
295 }
296 }
297
298 /// Returns a iterator of the `BasicBlock`.
299 /// The iterator yields the `InstPtr` of the `BasicBlock` except the head instruction.
300 pub fn iter(&self) -> BasicBlockIterator {
301 BasicBlockIterator {
302 cur: self.head_inst,
303 next: self.head_inst.get_next(),
304 }
305 }
306
307 /// Returns a reverse iterator of the `BasicBlock`.
308 /// The iterator yields the `InstPtr` of the `BasicBlock` except the head instruction.
309 pub fn iter_rev(&self) -> BasicBlockIteratorRev {
310 BasicBlockIteratorRev {
311 cur: self.head_inst,
312 prev: self.head_inst.get_prev(),
313 }
314 }
315
316 pub fn gen_llvm_ir(&self) -> String {
317 let mut ir = String::new();
318 ir += &format!("{}:\n", self.name);
319 for inst in self.iter() {
320 ir += &inst.gen_llvm_ir();
321 ir += "\n";
322 }
323 ir + "\n"
324 }
325}
326
327impl Display for BasicBlock {
328 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
329 write!(f, "%{}", self.name)
330 }
331}
332
333impl Extend<InstPtr> for BasicBlock {
334 fn extend<T: IntoIterator<Item = InstPtr>>(&mut self, iter: T) {
335 iter.into_iter().for_each(|inst| {
336 self.push_back(inst);
337 });
338 }
339}
340
341impl PartialEq for BasicBlock {
342 fn eq(&self, other: &Self) -> bool {
343 self.name == other.name
344 }
345}
346
347impl PartialOrd for BasicBlock {
348 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
349 Some(self.cmp(other))
350 }
351}
352
353impl Eq for BasicBlock {}
354
355impl Ord for BasicBlock {
356 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
357 self.name.cmp(&other.name)
358 }
359}
360
361pub struct BasicBlockIterator {
362 cur: InstPtr,
363 next: Option<InstPtr>,
364}
365
366impl Iterator for BasicBlockIterator {
367 type Item = InstPtr;
368 fn next(&mut self) -> Option<Self::Item> {
369 self.cur = self.next?;
370 self.next = self.cur.get_next();
371 Some(self.cur)
372 }
373}
374
375pub struct BasicBlockIteratorRev {
376 cur: InstPtr,
377 prev: Option<InstPtr>,
378}
379
380impl Iterator for BasicBlockIteratorRev {
381 type Item = InstPtr;
382 fn next(&mut self) -> Option<Self::Item> {
383 self.cur = self.prev?;
384 self.prev = self.cur.get_prev();
385 Some(self.cur)
386 }
387}