Skip to main content

vicis_core/ir/module/
parser.rs

1use super::super::function;
2use super::Module;
3use super::{
4    attributes::{parser::parse_attributes, Attribute},
5    global_variable, metadata, name,
6};
7use crate::ir::{
8    types,
9    util::{spaces, string_literal},
10};
11use nom;
12use nom::{
13    bytes::complete::tag,
14    character::complete::{char, digit1},
15    error::VerboseError,
16    sequence::{preceded, tuple},
17    IResult,
18};
19
20fn parse_source_filename(source: &str) -> IResult<&str, String, VerboseError<&str>> {
21    tuple((
22        tag("source_filename"),
23        preceded(spaces, char('=')),
24        preceded(spaces, string_literal),
25    ))(source)
26    .map(|(i, (_, _, name))| (i, name))
27}
28
29fn parse_target_datalayout(source: &str) -> IResult<&str, String, VerboseError<&str>> {
30    tuple((
31        tag("target"),
32        preceded(spaces, tag("datalayout")),
33        preceded(spaces, char('=')),
34        preceded(spaces, string_literal),
35    ))(source)
36    .map(|(i, (_, _, _, datalayout))| (i, datalayout))
37}
38
39fn parse_target_triple(source: &str) -> IResult<&str, String, VerboseError<&str>> {
40    tuple((
41        tag("target"),
42        preceded(spaces, tag("triple")),
43        preceded(spaces, char('=')),
44        preceded(spaces, string_literal),
45    ))(source)
46    .map(|(i, (_, _, _, triple))| (i, triple))
47}
48
49fn parse_attribute_group(source: &str) -> IResult<&str, (u32, Vec<Attribute>), VerboseError<&str>> {
50    tuple((
51        tag("attributes"),
52        preceded(spaces, char('#')),
53        digit1,
54        preceded(spaces, char('=')),
55        preceded(spaces, char('{')),
56        preceded(spaces, parse_attributes),
57        preceded(spaces, char('}')),
58    ))(source)
59    .map(|(i, (_, _, id, _, _, attrs, _))| (i, (id.parse().unwrap(), attrs)))
60}
61
62fn parse_local_type<'a>(
63    source: &'a str,
64    types: &types::Types,
65) -> IResult<&'a str, (), VerboseError<&'a str>> {
66    let (source, name) = preceded(spaces, preceded(char('%'), name::parse))(source)?;
67    types.base_mut().empty_named_type(name.clone()); // register a named type
68    let (source, _) = preceded(spaces, preceded(char('='), preceded(spaces, tag("type"))))(source)?;
69    let (source, ty) = types::parse(source, types)?;
70    types.base_mut().change_to_named_type(ty, name);
71    Ok((source, ()))
72}
73
74pub fn parse(mut source: &str) -> Result<Module, nom::Err<VerboseError<&str>>> {
75    let mut module = Module::new();
76    loop {
77        source = spaces(source)?.0;
78
79        if source.is_empty() {
80            break;
81        }
82
83        if let Ok((source_, source_filename)) = parse_source_filename(source) {
84            module.source_filename = source_filename;
85            source = source_;
86            continue;
87        }
88
89        if let Ok((source_, target_datalayout)) = parse_target_datalayout(source) {
90            module.target.datalayout = target_datalayout.to_string();
91            source = source_;
92            continue;
93        }
94
95        if let Ok((source_, target_triple)) = parse_target_triple(source) {
96            module.target.triple = target_triple.to_string();
97            source = source_;
98            continue;
99        }
100
101        if let Ok((source_, (id, attrs))) = parse_attribute_group(source) {
102            module.attributes.insert(id, attrs);
103            source = source_;
104            continue;
105        }
106
107        if let Ok((source_, _)) = parse_local_type(source, &module.types) {
108            source = source_;
109            continue;
110        }
111
112        if let Ok((source_, gv)) = global_variable::parse(source, &module.types) {
113            module.global_variables.insert(gv.name.clone(), gv);
114            source = source_;
115            continue;
116        }
117
118        if let Ok((source_, func)) = function::parse(source, module.types.clone()) {
119            module.functions.alloc(func);
120            source = source_;
121            continue;
122        }
123        if let Ok((source_, (name_, meta))) = metadata::parse(&module.types)(source) {
124            module.metas.insert(name_, meta);
125            source = source_;
126            continue;
127        }
128
129        todo!("unsupported syntax at {:?}", source)
130    }
131
132    Ok(module)
133}
134
135macro_rules! generate_test {
136    ($fname:ident, $name:literal) => {
137        #[test]
138        fn $fname() {
139            use nom::error::convert_error;
140            use std::fs;
141            let source = fs::read_to_string(concat!("./examples/", $name)).unwrap();
142            let module = match parse(&source) {
143                Ok(ok) => ok,
144                Err(nom::Err::Error(e)) => {
145                    println!("{}", convert_error(source.as_str(), e));
146                    panic!()
147                }
148                Err(e) => panic!("{:?}", e),
149            };
150            insta::assert_debug_snapshot!(module);
151        }
152    };
153}
154
155generate_test!(parse_example_addsubmul, "addsubmul.ll");
156generate_test!(parse_example_ary, "ary.ll");
157generate_test!(parse_example_br, "br.ll");
158generate_test!(parse_example_call, "call.ll");
159generate_test!(parse_example_cast, "cast.ll");
160generate_test!(parse_example_cgep, "cgep.ll");
161generate_test!(parse_example_dce, "dce.ll");
162generate_test!(parse_example_gblvar, "gblvar.ll");
163generate_test!(parse_example_icmp, "icmp.ll");
164generate_test!(parse_example_load, "load.ll");
165generate_test!(parse_example_loop, "loop.ll");
166generate_test!(parse_example_loop2, "loop2.ll");
167generate_test!(parse_example_manyargs, "manyargs.ll");
168generate_test!(parse_example_metadata, "metadata.ll");
169generate_test!(parse_example_node, "node.ll");
170generate_test!(parse_example_phi, "phi.ll");
171generate_test!(parse_example_phi_loop, "phi_loop.ll");
172generate_test!(parse_example_printf, "printf.ll");
173generate_test!(parse_example_puts, "puts.ll");
174generate_test!(parse_example_ret42, "ret42.ll");
175generate_test!(parse_example_rustc_fn_call, "rustc_fn_call.ll");
176generate_test!(parse_example_rustc_hello, "rustc_hello.ll");
177generate_test!(parse_example_rustc_minimum, "rustc_minimum.ll");
178generate_test!(parse_example_struct, "struct.ll");
179
180#[test]
181fn parse_module1() {
182    let result = parse(
183        r#"
184            source_filename = "c.c"
185            target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
186            ; comments
187            ; bluh bluh
188            target triple = "x86_64-pc-linux-gnu" ; hogehoge
189            !0 = !{}
190            define dso_local i32 @main(i32 %0, i32 %1) #0 {
191                ret void
192            }
193            attributes #0 = { noinline "abcde" = ;fff
194            ;ff
195                                            "ff" "xxx"}
196        "#,
197    );
198    assert!(result.is_ok());
199    let result = result.unwrap();
200    assert_eq!(result.source_filename, "c.c");
201    assert_eq!(
202        result.target.datalayout,
203        "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
204    );
205    assert_eq!(result.target.triple, "x86_64-pc-linux-gnu");
206    println!("{:?}", result);
207}
208
209#[test]
210#[rustfmt::skip]
211fn parse_module2() {
212    use rustc_hash::FxHashMap;
213    let result = parse(include_str!("../../../examples/ret42.ll"));
214    assert!(result.is_ok());
215    let result = result.unwrap();
216    assert_eq!(result.source_filename, "c.c");
217    assert_eq!(
218        result.target.datalayout,
219        "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
220    );
221    assert_eq!(result.target.triple, "x86_64-pc-linux-gnu");
222    let attrs = vec![(
223        0u32,
224        vec![
225            Attribute::NoInline,
226            Attribute::NoUnwind,
227            Attribute::OptNone,
228            Attribute::UWTable, 
229            Attribute::StringAttribute {kind: "correctly-rounded-divide-sqrt-fp-math".to_string(), value: "false"                     .to_string()},
230            Attribute::StringAttribute {kind: "disable-tail-calls"                   .to_string(), value: "false"                     .to_string()},
231            Attribute::StringAttribute {kind: "frame-pointer"                        .to_string(), value: "all"                       .to_string()},
232            Attribute::StringAttribute {kind: "less-precise-fpmad"                   .to_string(), value: "false"                     .to_string()},
233            Attribute::StringAttribute {kind: "min-legal-vector-width"               .to_string(), value: "0"                         .to_string()},
234            Attribute::StringAttribute {kind: "no-infs-fp-math"                      .to_string(), value: "false"                     .to_string()},
235            Attribute::StringAttribute {kind: "no-jump-tables"                       .to_string(), value: "false"                     .to_string()},
236            Attribute::StringAttribute {kind: "no-nans-fp-math"                      .to_string(), value: "false"                     .to_string()},
237            Attribute::StringAttribute {kind: "no-signed-zeros-fp-math"              .to_string(), value: "false"                     .to_string()},
238            Attribute::StringAttribute {kind: "no-trapping-math"                     .to_string(), value: "false"                     .to_string()},
239            Attribute::StringAttribute {kind: "stack-protector-buffer-size"          .to_string(), value: "8"                         .to_string()},
240            Attribute::StringAttribute {kind: "target-cpu"                           .to_string(), value: "x86-64"                    .to_string()},
241            Attribute::StringAttribute {kind: "target-features"                      .to_string(), value: "+fxsr,+mmx,+sse,+sse2,+x87".to_string()},
242            Attribute::StringAttribute {kind: "unsafe-fp-math"                       .to_string(), value: "false"                     .to_string()},
243            Attribute::StringAttribute {kind: "use-soft-float"                       .to_string(), value: "false"                     .to_string()},
244        ],
245    )]
246    .into_iter()
247    .collect::<FxHashMap<u32, Vec<Attribute>>>();
248    for (key1, val1) in &result.attributes {
249        assert!(&attrs[key1] == val1)
250    }
251    println!("{:?}", result);
252}