1use crate::ir::{
2 function::{
3 basic_block::BasicBlockId,
4 data::Data,
5 instruction::{self, Br, CondBr, Opcode, Operand},
6 layout::Layout,
7 param_attrs::parser::parse_param_attrs,
8 Function, Parameter, PersonalityFunc,
9 },
10 module::{
11 attributes, global_variable, linkage, name, preemption_specifier, unnamed_addr, visibility,
12 },
13 types,
14 types::Types,
15 util::spaces,
16 value::{Value, ValueId},
17};
18use nom::{
19 branch::alt,
20 bytes::complete::tag,
21 character::complete::char,
22 combinator::opt,
23 error::VerboseError,
24 sequence::{preceded, terminated, tuple},
25 IResult,
26};
27use rustc_hash::FxHashMap;
28
29pub struct ParserContext<'a> {
37 pub types: &'a Types,
38 pub data: &'a mut Data,
39 pub layout: &'a mut Layout,
40 pub name_to_value: &'a mut FxHashMap<name::Name, ValueId>,
41 pub name_to_block: &'a mut FxHashMap<name::Name, BasicBlockId>,
42 pub cur_block: BasicBlockId,
43}
44
45pub fn parse_argument<'a>(
46 source: &'a str,
47 types: &Types,
48 index: &mut usize,
49) -> IResult<&'a str, Parameter, VerboseError<&'a str>> {
50 let (source, ty) = types::parse(source, types)?;
51 let (source, attrs) = parse_param_attrs(source, types)?;
52 let (source, name) = opt(preceded(spaces, preceded(char('%'), name::parse)))(source)?;
53 Ok((
54 source,
55 Parameter {
56 name: name.unwrap_or(name::Name::Number({
57 *index += 1;
58 *index
59 })),
60 ty,
61 attrs,
62 },
63 ))
64}
65
66pub fn parse_argument_list<'a>(
67 source: &'a str,
68 types: &Types,
69) -> IResult<&'a str, (Vec<Parameter>, bool), VerboseError<&'a str>> {
70 let (mut source, _) = tuple((spaces, char('(')))(source)?;
71
72 if let Ok((source, _)) = tuple((spaces, char(')')))(source) {
73 return Ok((source, (vec![], false)));
74 }
75
76 let mut params = vec![];
77 let mut is_var_arg = false;
78 let mut index = 0;
79
80 loop {
81 if let Ok((source_, _)) = tuple((spaces, tag("...")))(source) {
82 is_var_arg = true;
83 source = source_;
84 break;
85 }
86
87 let (source_, param) = parse_argument(source, types, &mut index)?;
88 source = source_;
89 params.push(param);
90
91 if let Ok((source_, _)) = tuple((spaces, char(',')))(source_) {
92 source = source_;
93 continue;
94 }
95
96 break;
97 }
98
99 let (source, _) = tuple((spaces, char(')')))(source)?;
100 Ok((source, (params, is_var_arg)))
101}
102
103pub fn parse_body<'a, 'b>(
104 source: &'a str,
105 ctx: &mut ParserContext<'b>,
106 num_args: usize,
107) -> IResult<&'a str, (), VerboseError<&'a str>> {
108 let (source, _) = tuple((spaces, char('{')))(source)?;
109
110 if let Ok((source, _)) = tuple((spaces, char('}')))(source) {
111 return Ok((source, ()));
112 }
113
114 let (mut source, entry) = opt(preceded(
115 spaces,
116 terminated(name::parse, preceded(spaces, char(':'))),
117 ))(source)?;
118 let mut label = entry.unwrap_or(name::Name::Number(num_args));
119
120 loop {
122 let block = ctx.get_or_create_named_block(label);
123
124 ctx.layout.append_block(block);
125 ctx.cur_block = block;
126
127 while let Ok((source_, inst)) = instruction::parse(source, ctx) {
128 ctx.layout.append_inst(inst, ctx.cur_block);
129 source = source_
130 }
131
132 if let Ok((source, _)) = tuple((spaces, char('}')))(source) {
133 ctx.set_blocks_info();
134 return Ok((source, ()));
135 }
136
137 if let Ok((source_, label_)) =
139 preceded(spaces, terminated(name::parse, preceded(spaces, char(':'))))(source)
140 {
141 label = label_;
142 source = source_;
143 continue;
144 }
145
146 todo!("unsupported syntax at {:?}", source)
147 }
148}
149
150pub fn parse_personality<'a>(
151 source: &'a str,
152 types: &Types,
153) -> IResult<&'a str, Option<PersonalityFunc>, VerboseError<&'a str>> {
154 if let Ok((source, _)) = preceded(spaces, tag("personality"))(source) {
155 let (source, (ty, konst)) = global_variable::parse_global_type_and_const(source, types)?;
156 return Ok((source, Some((ty, konst))));
157 }
158
159 Ok((source, None))
160}
161
162pub fn parse(source: &str, types: Types) -> IResult<&str, Function, VerboseError<&str>> {
163 let (source, define_or_declare) =
164 preceded(spaces, alt((tag("define"), tag("declare"))))(source)?;
165 let is_prototype = define_or_declare == "declare";
166 let (source, linkage) = opt(preceded(spaces, linkage::parse))(source)?;
167 let (source, preemption_specifier) =
168 opt(preceded(spaces, preemption_specifier::parse))(source)?;
169 let (source, visibility) = opt(preceded(spaces, visibility::parse))(source)?;
170 let (source, ret_attrs) = parse_param_attrs(source, &types)?;
171 let (source, result_ty) = types::parse(source, &types)?;
172 let (source, (_, _, _, name)) = tuple((spaces, char('@'), spaces, name::parse))(source)?;
173 let name = name.to_string().cloned().unwrap();
174 let (source, (params, is_var_arg)) = parse_argument_list(source, &types)?;
175 let (source, unnamed_addr) = opt(preceded(spaces, unnamed_addr::parse))(source)?;
176 let (source, func_attrs) = attributes::parser::parse_attributes(source)?;
177 let (mut source, personality) = parse_personality(source, &types)?;
178
179 let mut data = Data::new();
180 let mut layout = Layout::new();
181 let mut name_to_value = FxHashMap::default();
182 let mut name_to_block = FxHashMap::default();
183 let dummy_block = data.create_block();
184
185 for (i, param) in params.iter().enumerate() {
186 let arg = data.create_value(Value::Argument(i));
187 name_to_value.insert(param.name.clone(), arg);
188 }
189
190 if !is_prototype {
191 source = parse_body(
192 source,
193 &mut ParserContext {
194 types: &types,
195 data: &mut data,
196 layout: &mut layout,
197 name_to_value: &mut name_to_value,
198 name_to_block: &mut name_to_block,
199 cur_block: dummy_block,
200 },
201 params.len(),
202 )?
203 .0;
204 }
205
206 Ok((
207 source,
208 Function {
209 name,
210 is_var_arg,
211 result_ty,
212 linkage: linkage.unwrap_or(linkage::Linkage::External),
213 preemption_specifier: preemption_specifier
214 .unwrap_or(preemption_specifier::PreemptionSpecifier::DsoPreemptable),
215 visibility: visibility.unwrap_or(visibility::Visibility::Default),
216 unnamed_addr,
217 ret_attrs,
218 func_attrs,
219 params,
220 data,
221 layout,
222 types,
223 personality,
225 },
226 ))
227}
228
229impl<'a> ParserContext<'a> {
230 pub fn get_or_create_named_value(&mut self, name: name::Name) -> ValueId {
231 if let Some(value) = self.name_to_value.get(&name) {
232 return *value;
233 }
234 let dummy = self
235 .data
236 .create_inst(Opcode::Invalid.with_block(self.cur_block));
237 let id = self.data.create_value(Value::Instruction(dummy));
238 self.name_to_value.insert(name, id);
239 id
240 }
241
242 pub fn get_or_create_named_block(&mut self, name: name::Name) -> BasicBlockId {
243 if let Some(block) = self.name_to_block.get(&name) {
244 return *block;
245 }
246 let block = self.data.create_block();
247 self.data.block_ref_mut(block).name = Some(name.clone());
248 self.name_to_block.insert(name, block);
249 block
250 }
251
252 fn set_blocks_info(&mut self) {
253 for block_id in self.layout.block_iter() {
254 let maybe_br = self.layout.block_node(block_id).last_inst();
255 let maybe_br = match maybe_br {
256 Some(maybe_br) => *maybe_br,
257 None => continue,
258 };
259 let maybe_br = &self.data.instructions[maybe_br];
260 if !maybe_br.opcode.is_terminator() {
261 continue;
262 }
263 let br = maybe_br;
264 match br.operand {
265 Operand::Br(Br { block }) => {
266 self.data.basic_blocks[br.parent].succs.insert(block);
267 self.data.basic_blocks[block].preds.insert(br.parent);
268 }
269 Operand::CondBr(CondBr { blocks, .. }) => {
270 for &block in blocks.iter() {
271 self.data.basic_blocks[br.parent].succs.insert(block);
272 self.data.basic_blocks[block].preds.insert(br.parent);
273 }
274 }
275 _ => continue,
276 }
277 }
278 }
279}
280
281#[test]
282fn test_parse_function1() {
283 let types = Types::new();
284 let result = parse(
285 r#"
286 define dso_local i32 @main(i32 %0, i32 %1) {
287 ret i32 0
288 }
289 "#,
290 types,
291 );
292 assert!(result.is_ok());
293 let result = result.unwrap().1;
294 assert_eq!(result.name, "main");
295 assert_eq!(
296 result.preemption_specifier,
297 preemption_specifier::PreemptionSpecifier::DsoLocal
298 );
299 println!("{:?}", result);
300}
301
302#[test]
303fn test_parse_function2() {
304 let types = Types::new();
305 let result = parse(
306 r#"
307 define dso_local i32 @main() #0 noinline {
308 entry:
309 %1 = alloca i32, align 4
310 store i32 1, i32* %1
311 ret i32 0
312 }
313 "#,
314 types,
315 );
316 assert!(result.is_ok());
317 let result = result.unwrap().1;
318 assert_eq!(result.name, "main");
319 assert_eq!(
320 result.preemption_specifier,
321 preemption_specifier::PreemptionSpecifier::DsoLocal
322 );
323 println!("{:?}", result);
324}