llvm_scratch/core/function/
function.rs

1use fmt::Formatter;
2use std::fmt;
3
4use id_arena::{Arena, Id};
5
6use crate::core::{
7    basic_block::{BasicBlock, BasicBlockId, BasicBlockKind},
8    function::param_attrs::*,
9    instruction::Instruction,
10    llvm_string::*,
11    llvm_type::*,
12};
13
14pub type FunctionId = Id<Function>;
15
16/// An representation of LLVMFunction.
17/// LLVMFunction を表す構造体
18pub struct Function {
19    return_type: ReturnType,
20    name: LLVMString,
21    arg_list: ParameterSet,
22
23    entry_block: BasicBlockId,
24    bb_allocator: Arena<BasicBlock>,
25}
26
27impl fmt::Display for Function {
28    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
29        writeln!(
30            f,
31            "define {} @{} {} {{",
32            self.return_type, self.name, self.arg_list
33        )?;
34
35        let entry_bb = self.bb_allocator.get(self.entry_block).unwrap();
36
37        writeln!(f, "{}", entry_bb)?;
38
39        {
40            entry_bb.print_successors(f, &self.bb_allocator)?;
41        }
42
43        writeln!(f, "}}")?;
44
45        Ok(())
46    }
47}
48
49impl Function {
50    pub fn new(func_name: &str, ret_type: ReturnType) -> Self {
51        let mut bb_alloc = Arena::new();
52        let entry_block_id = bb_alloc.alloc(BasicBlock::new(
53            LLVMString::from("entry"),
54            None,
55            BasicBlockKind::TERMINATED,
56        ));
57        Self {
58            return_type: ret_type,
59            name: LLVMString::from(func_name),
60            arg_list: Default::default(),
61            entry_block: entry_block_id,
62            bb_allocator: bb_alloc,
63        }
64    }
65
66    pub fn entry_bb_is_empty(&self) -> bool {
67        let entry_bb = self.bb_allocator.get(self.entry_block).unwrap();
68        entry_bb.insts_empty()
69    }
70
71    pub fn insert_inst(&mut self, bb: BasicBlockId, inst: Instruction) {
72        if let Some(insert_bb) = self.bb_allocator.get_mut(bb) {
73            insert_bb.new_inst(inst);
74        }
75    }
76
77    pub fn returns_void(&self) -> bool {
78        self.return_type.is_void()
79    }
80
81    pub fn get_name_ref(&self) -> &LLVMString {
82        &self.name
83    }
84
85    pub fn get_entry_bb(&self) -> BasicBlockId {
86        self.entry_block
87    }
88
89    pub fn args_empty(&self) -> bool {
90        self.arg_list.is_empty()
91    }
92
93    pub fn new_argument(&mut self, arg: Parameter) {
94        self.arg_list.add_arg(arg);
95    }
96
97    pub fn new_basic_block(
98        &mut self,
99        l: &str,
100        pred: Option<BasicBlockId>,
101        k: BasicBlockKind,
102    ) -> BasicBlockId {
103        self.bb_allocator
104            .alloc(BasicBlock::new(LLVMString::from(l), pred, k))
105    }
106}
107
108/// each function has a type signature.
109#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
110pub struct FunctionType {
111    return_type: ReturnType,
112    arg_list: ParameterSet,
113}
114
115impl FunctionType {
116    pub fn new(ret_type: ReturnType, args: ParameterSet) -> Self {
117        Self {
118            return_type: ret_type,
119            arg_list: args,
120        }
121    }
122}
123
124impl fmt::Display for FunctionType {
125    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
126        write!(f, "{} {}", self.return_type, self.arg_list)
127    }
128}
129
130/// each llvm function must have a return type.
131/// LLVMFunctionに必ず存在する,返り値の型
132#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
133pub struct ReturnType {
134    return_type: LLVMType,
135    /// a ReturnType may have a set of Attributes
136    /// return_type は Attribute を持つ可能性がある
137    attributes: Option<ParameterAttributes>,
138}
139
140impl ReturnType {
141    pub fn new(ret_type: LLVMType, attrs: Option<ParameterAttributes>) -> Self {
142        Self {
143            return_type: ret_type,
144            attributes: attrs,
145        }
146    }
147
148    fn is_void(&self) -> bool {
149        match &self.return_type.kind {
150            LLVMTypeKind::VOID => true,
151            _ => false,
152        }
153    }
154}
155
156impl fmt::Display for ReturnType {
157    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
158        match &self.attributes {
159            Some(attrs) => write!(f, "{} {}", attrs, self.return_type),
160            None => write!(f, "{}", self.return_type),
161        }
162    }
163}
164
165/// each llvm function must have a set of Parameter.
166/// LLVMFunction が持つ引数リストの実装
167#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
168pub struct ParameterSet {
169    params: Vec<Parameter>,
170}
171
172impl Default for ParameterSet {
173    fn default() -> Self {
174        Self { params: Vec::new() }
175    }
176}
177
178impl ParameterSet {
179    pub fn new(args: Vec<Parameter>) -> Self {
180        Self { params: args }
181    }
182
183    pub fn add_arg(&mut self, arg: Parameter) {
184        self.params.push(arg);
185    }
186
187    fn is_empty(&self) -> bool {
188        self.params.is_empty()
189    }
190}
191
192impl fmt::Display for ParameterSet {
193    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
194        let fmt_string = self
195            .params
196            .iter()
197            .map(|attr| attr.to_string())
198            .collect::<Vec<String>>()
199            .join(", ");
200
201        write!(f, "({})", fmt_string)
202    }
203}
204
205/// LLVMFunction が持つ各引数
206#[derive(Eq, PartialEq, PartialOrd, Ord, Hash)]
207pub struct Parameter {
208    name: LLVMString,
209    attributes: Option<ParameterAttributes>,
210    param_type: LLVMType,
211}
212
213impl Parameter {
214    pub fn new(
215        param_name: LLVMString,
216        attrs: Option<ParameterAttributes>,
217        arg_type: LLVMType,
218    ) -> Self {
219        Self {
220            name: param_name,
221            attributes: attrs,
222            param_type: arg_type,
223        }
224    }
225}
226
227impl fmt::Display for Parameter {
228    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
229        match &self.attributes {
230            Some(attrs) => write!(f, "{} {} {}", self.param_type, attrs, self.name),
231            None => write!(f, "{} {}", self.param_type, self.name),
232        }
233    }
234}