duskphantom_middle/ir/
function.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 std::ops::{Deref, DerefMut};
18
19use super::*;
20use crate::define_graph_iterator;
21
22pub type FunPtr = ObjPtr<Function>;
23
24pub struct Function {
25    pub mem_pool: ObjPtr<IRBuilder>,
26
27    pub name: String,
28
29    /// Entry of function, if it is a function that is not defined in this module, it will be None.
30    /// Such as library function.
31    pub entry: Option<BBPtr>,
32
33    /// Exit of function, if it is a function that is not defined in this module, it will be None.
34    /// Such as library function.
35    pub exit: Option<BBPtr>,
36
37    pub return_type: ValueType,
38
39    /// BasicBlock of function parameters
40    pub params: Vec<ParaPtr>,
41}
42
43impl Function {
44    /// Return true if it is a function that is not defined in this module.
45    pub fn is_lib(&self) -> bool {
46        self.entry.is_none()
47    }
48
49    /// Return true if it is main function.
50    pub fn is_main(&self) -> bool {
51        self.name == "main"
52    }
53
54    /// Create a depth-first iterator to traverse the graph structure of basicblocks.
55    /// Traverse in the direction of data flow with the function entry as the starting point.
56    /// Do not change the graph structure during traversal, which may cause unknown errors
57    pub fn dfs_iter(&self) -> DFSIterator {
58        DFSIterator::from(self.entry.unwrap())
59    }
60
61    /// Create a breadth-first iterator to traverse the graph structure of basicblocks.
62    /// Traverse in the direction of data flow with the function entry as the starting point.
63    /// Do not change the graph structure during traversal, which may cause unknown errors
64    pub fn bfs_iter(&self) -> BFSIterator {
65        BFSIterator::from(self.entry.unwrap())
66    }
67
68    /// Create a depth-first iterator to traverse the graph structure of basicblocks.
69    /// Traverse in the reverse direction of data flow with the function exit as the starting point.
70    /// Do not change the graph structure during traversal, which may cause unknown errors
71    pub fn dfs_iter_rev(&self) -> DFSIteratorRev {
72        DFSIteratorRev::from(self.exit.unwrap())
73    }
74
75    /// Create a breadth-first iterator to traverse the graph structure of basicblocks.
76    /// Traverse in the reverse direction of data flow with the function exit as the starting point.
77    /// Do not change the graph structure during traversal, which may cause unknown errors
78    pub fn bfs_iter_rev(&self) -> BFSIteratorRev {
79        BFSIteratorRev::from(self.exit.unwrap())
80    }
81
82    /// Create a postorder iterator to traverse the graph structure of basicblocks.
83    pub fn po_iter(&self) -> POIterator {
84        POIterator::from(self.entry.unwrap())
85    }
86
87    /// Create a reverse postorder iterator to traverse the graph structure of basicblocks.
88    pub fn rpo_iter(&self) -> RPOIterator {
89        RPOIterator::from(self.entry.unwrap())
90    }
91
92    pub fn gen_llvm_ir(&self) -> String {
93        let header = if self.is_lib() { "declare" } else { "define" };
94        let mut ir = format!("{} {} @{}(", header, self.return_type, self.name);
95        if !self.params.is_empty() {
96            for param in self.params.iter() {
97                ir += &format!("{}, ", param.as_ref());
98            }
99            let _ = ir.split_off(ir.len() - 2);
100        }
101        ir += ")";
102
103        // If it is a library function, there is no need to generate the body
104        if self.is_lib() {
105            ir += "\n";
106            return ir;
107        }
108
109        // Otherwise, generate the body of the function
110        ir += " {\n";
111        self.bfs_iter().for_each(|bb| {
112            ir += &bb.gen_llvm_ir();
113        });
114        ir + "\n}\n"
115    }
116}
117
118define_graph_iterator!(BFSIterator, VecDeque<BBPtr>, pop_front, get_succ_bb);
119define_graph_iterator!(BFSIteratorRev, VecDeque<BBPtr>, pop_front, get_pred_bb);
120define_graph_iterator!(DFSIterator, Vec<BBPtr>, pop, get_succ_bb);
121define_graph_iterator!(DFSIteratorRev, Vec<BBPtr>, pop, get_pred_bb);
122
123/// Postorder iterator.
124pub struct POIterator {
125    container: VecDeque<BBPtr>,
126}
127
128impl Iterator for POIterator {
129    type Item = BBPtr;
130    fn next(&mut self) -> Option<Self::Item> {
131        self.container.pop_front()
132    }
133}
134
135impl From<BBPtr> for POIterator {
136    fn from(bb: BBPtr) -> Self {
137        // Run postorder traversal
138        let mut container = Vec::new();
139        let mut visited = HashSet::new();
140        run_postorder(bb, &mut visited, &mut container);
141
142        // Wrap in iterator
143        Self {
144            container: container.into(),
145        }
146    }
147}
148
149/// Reverse postorder iterator.
150pub struct RPOIterator {
151    container: Vec<BBPtr>,
152}
153
154impl Iterator for RPOIterator {
155    type Item = BBPtr;
156    fn next(&mut self) -> Option<Self::Item> {
157        self.container.pop()
158    }
159}
160
161impl From<BBPtr> for RPOIterator {
162    fn from(bb: BBPtr) -> Self {
163        // Run postorder traversal
164        let mut container = Vec::new();
165        let mut visited = HashSet::new();
166        run_postorder(bb, &mut visited, &mut container);
167
168        // Wrap in iterator
169        Self { container }
170    }
171}
172
173/// Run a complete post order traversal.
174fn run_postorder(bb: BBPtr, visited: &mut HashSet<BBPtr>, container: &mut Vec<BBPtr>) {
175    if visited.contains(&bb) {
176        return;
177    }
178    visited.insert(bb);
179    for succ in bb.get_succ_bb() {
180        run_postorder(*succ, visited, container);
181    }
182    container.push(bb);
183}
184
185#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
186pub struct ParaPtr(ObjPtr<Parameter>);
187impl Display for ParaPtr {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        write!(f, "%{}", self.0.name)
190    }
191}
192impl Deref for ParaPtr {
193    type Target = Parameter;
194    fn deref(&self) -> &Parameter {
195        self.0.as_ref()
196    }
197}
198impl DerefMut for ParaPtr {
199    fn deref_mut(&mut self) -> &mut Self::Target {
200        self.0.as_mut()
201    }
202}
203impl AsRef<Parameter> for ParaPtr {
204    fn as_ref(&self) -> &Parameter {
205        self.0.as_ref()
206    }
207}
208impl From<ObjPtr<Parameter>> for ParaPtr {
209    fn from(ptr: ObjPtr<Parameter>) -> Self {
210        Self(ptr)
211    }
212}
213
214#[derive(Clone)]
215pub struct Parameter {
216    pub name: String,
217    pub value_type: ValueType,
218    user: Vec<InstPtr>,
219}
220
221impl Display for Parameter {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        write!(f, "{} %{}", self.value_type, self.name)
224    }
225}
226
227impl Parameter {
228    pub fn new(name: String, value_type: ValueType) -> Self {
229        Self {
230            name,
231            value_type,
232            user: Vec::new(),
233        }
234    }
235
236    pub fn get_user(&self) -> &[InstPtr] {
237        &self.user
238    }
239    pub fn get_user_mut(&mut self) -> &mut Vec<InstPtr> {
240        &mut self.user
241    }
242    /// # Safety
243    /// FIXME: explain why it is unsafe,and describe the safety requirements
244    pub unsafe fn add_user(&mut self, inst: InstPtr) {
245        self.user.push(inst);
246    }
247    /// # Safety
248    /// FIXME: explain why it is unsafe,and describe the safety requirements
249    pub unsafe fn remove_user(&mut self, inst: InstPtr) {
250        self.user
251            .iter()
252            .position(|x| *x == inst)
253            .map(|i| self.user.swap_remove(i));
254    }
255}