vicis_core/ir/function/
parser.rs

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
29// define [linkage] [PreemptionSpecifier] [visibility] [DLLStorageClass]
30//        [cconv] [ret attrs]
31//        <ResultType> @<FunctionName> ([argument list])
32//        [(unnamed_addr|local_unnamed_addr)] [AddrSpace] [fn Attrs]
33//        [section "name"] [comdat [($name)]] [align N] [gc] [prefix Constant]
34//        [prologue Constant] [personality Constant] (!name !N)* { ... }
35
36pub 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    // Parse each block
121    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        // Parse label
138        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            // is_prototype,
224            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}