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}