1use crate::basic_block::BasicBlock;
4use crate::context::{ArgId, BlockId, InstrId, TypeId, ValueRef};
5use crate::instruction::Instruction;
6use crate::value::{Argument, Linkage};
7use std::collections::HashMap;
8
9pub struct Function {
11 pub name: String,
13 pub ty: TypeId,
15 pub args: Vec<Argument>,
17 pub blocks: Vec<BasicBlock>,
19 pub instructions: Vec<Instruction>,
21 pub instr_dbg_locs: HashMap<InstrId, u32>,
23 pub instr_metadata: HashMap<InstrId, Vec<(String, String)>>,
25 pub value_names: HashMap<String, InstrId>,
27 pub arg_names: HashMap<String, ArgId>,
29 pub is_declaration: bool,
31 pub linkage: Linkage,
33 next_name_id: u32,
35}
36
37impl Function {
38 pub fn new(name: impl Into<String>, ty: TypeId, args: Vec<Argument>, linkage: Linkage) -> Self {
40 let mut f = Function {
41 name: name.into(),
42 ty,
43 args: Vec::new(),
44 blocks: Vec::new(),
45 instructions: Vec::new(),
46 instr_dbg_locs: HashMap::new(),
47 instr_metadata: HashMap::new(),
48 value_names: HashMap::new(),
49 arg_names: HashMap::new(),
50 is_declaration: false,
51 linkage,
52 next_name_id: 0,
53 };
54 for arg in args {
55 let idx = ArgId(f.args.len() as u32);
56 if !arg.name.is_empty() {
57 f.arg_names.insert(arg.name.clone(), idx);
58 }
59 f.args.push(arg);
60 }
61 f
62 }
63
64 pub fn new_declaration(
66 name: impl Into<String>,
67 ty: TypeId,
68 args: Vec<Argument>,
69 linkage: Linkage,
70 ) -> Self {
71 let mut f = Self::new(name, ty, args, linkage);
72 f.is_declaration = true;
73 f
74 }
75
76 pub fn add_block(&mut self, bb: BasicBlock) -> BlockId {
82 let id = BlockId(self.blocks.len() as u32);
83 self.blocks.push(bb);
84 id
85 }
86
87 pub fn block(&self, id: BlockId) -> &BasicBlock {
89 &self.blocks[id.0 as usize]
90 }
91
92 pub fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock {
94 &mut self.blocks[id.0 as usize]
95 }
96
97 pub fn num_blocks(&self) -> usize {
99 self.blocks.len()
100 }
101
102 pub fn alloc_instr(&mut self, mut instr: Instruction) -> InstrId {
109 if instr.name.as_deref() == Some("") {
111 let name = self.fresh_name();
112 instr.name = Some(name);
113 }
114 let id = InstrId(self.instructions.len() as u32);
115 if let Some(ref n) = instr.name {
116 if !n.is_empty() {
117 self.value_names.insert(n.clone(), id);
118 }
119 }
120 self.instructions.push(instr);
121 id
122 }
123
124 pub fn instr(&self, id: InstrId) -> &Instruction {
126 &self.instructions[id.0 as usize]
127 }
128
129 pub fn instr_mut(&mut self, id: InstrId) -> &mut Instruction {
131 &mut self.instructions[id.0 as usize]
132 }
133
134 pub fn num_instrs(&self) -> usize {
136 self.instructions.len()
137 }
138
139 pub fn set_instr_dbg_loc(&mut self, id: InstrId, loc_id: u32) {
141 self.instr_dbg_locs.insert(id, loc_id);
142 }
143
144 pub fn instr_dbg_loc(&self, id: InstrId) -> Option<u32> {
146 self.instr_dbg_locs.get(&id).copied()
147 }
148
149 pub fn add_instr_metadata(&mut self, id: InstrId, key: impl Into<String>, value: impl Into<String>) {
151 self.instr_metadata
152 .entry(id)
153 .or_default()
154 .push((key.into(), value.into()));
155 }
156
157 pub fn instr_metadata(&self, id: InstrId) -> Option<&[(String, String)]> {
159 self.instr_metadata.get(&id).map(Vec::as_slice)
160 }
161
162 pub fn arg(&self, id: ArgId) -> &Argument {
168 &self.args[id.0 as usize]
169 }
170
171 pub fn num_args(&self) -> usize {
173 self.args.len()
174 }
175
176 pub fn lookup_value(&self, name: &str) -> Option<ValueRef> {
182 if let Some(&iid) = self.value_names.get(name) {
183 return Some(ValueRef::Instruction(iid));
184 }
185 if let Some(&aid) = self.arg_names.get(name) {
186 return Some(ValueRef::Argument(aid));
187 }
188 None
189 }
190
191 pub fn lookup_block(&self, name: &str) -> Option<BlockId> {
193 self.blocks
194 .iter()
195 .enumerate()
196 .find(|(_, bb)| bb.name == name)
197 .map(|(i, _)| BlockId(i as u32))
198 }
199
200 pub fn type_of_value(&self, vref: ValueRef) -> Option<TypeId> {
206 match vref {
207 ValueRef::Instruction(id) => Some(self.instructions[id.0 as usize].ty),
208 ValueRef::Argument(id) => Some(self.args[id.0 as usize].ty),
209 ValueRef::Constant(_) | ValueRef::Global(_) => None, }
211 }
212
213 pub fn fresh_name(&mut self) -> String {
219 let n = self.next_name_id;
220 self.next_name_id += 1;
221 format!("v{n}")
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232 use crate::context::Context;
233
234 #[test]
235 fn function_fresh_names() {
236 let mut ctx = Context::new();
237 let fn_ty = ctx.mk_fn_type(ctx.void_ty, vec![], false);
238 let mut f = Function::new("test", fn_ty, vec![], Linkage::External);
239 assert_eq!(f.fresh_name(), "v0");
240 assert_eq!(f.fresh_name(), "v1");
241 assert_eq!(f.fresh_name(), "v2");
242 }
243
244 #[test]
245 fn function_add_block() {
246 let mut ctx = Context::new();
247 let fn_ty = ctx.mk_fn_type(ctx.void_ty, vec![], false);
248 let mut f = Function::new("test", fn_ty, vec![], Linkage::External);
249 let bb = BasicBlock::new("entry");
250 let bid = f.add_block(bb);
251 assert_eq!(bid, BlockId(0));
252 assert_eq!(f.block(bid).name, "entry");
253 }
254}