flycatcherc_clif/
lib.rs

1//! A Cranelift backend for Flycatcher's compiler.
2
3use cranelift::prelude::*;
4use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
5use cranelift_codegen::settings::{self, Configurable};
6use cranelift_module::{default_libcall_names, Linkage, Module};
7use cranelift_object::{ObjectBuilder, ObjectModule};
8use flycatcherc::{FlycatcherFrontend, FlycatcherType, VariableType};
9use std::io::prelude::*;
10use std::path::Path;
11pub use target_lexicon::{self, Triple};
12
13/// A Cranelift backend for Flycatcher's compiler.
14pub struct CraneliftBackend {
15
16    /// The target triple that the CraneliftBackend will compile to.
17    pub target: Triple,
18
19    /// The path to output an object file.
20    pub out_file: String,
21
22    /// A list of variables declared in the module.
23    variables: Vec<String>,
24
25}
26
27impl CraneliftBackend {
28
29    /// Initializes a CraneliftBackend instance.
30    pub fn new(target: Triple, out_file: String) -> Self {
31        Self {
32            target,
33            out_file,
34            variables: vec![]
35        }
36    }
37
38    /// Converts a FlycatcherType to a Cranelift type.
39    fn convert_fctype(&self, t: FlycatcherType) -> Type {
40        match t {
41            FlycatcherType::Boolean => types::B1,
42            FlycatcherType::Size => types::I64,
43            FlycatcherType::Float64 => types::F64,
44            _ => panic!("This type is unsupported by the Cranelift backend.")
45        }
46    }
47
48    /// Compiles HIR from a FlycatcherFrontend into an object file.
49    pub fn compile(&mut 
50        self, frontend: FlycatcherFrontend) -> bool {
51        // Initialize a flag builder.
52        let mut flag_builder = settings::builder();
53        flag_builder.set("use_colocated_libcalls", "false").unwrap();
54        flag_builder.set("is_pic", "false").unwrap();
55
56        let isa = cranelift_codegen::isa::lookup(self.target.clone())
57            .unwrap()
58            .finish(settings::Flags::new(flag_builder));
59        
60        let mut module = ObjectModule::new(ObjectBuilder::new(
61            isa,
62            [1, 2, 3, 4, 5, 6, 7, 8],
63            default_libcall_names()
64        ).unwrap());
65
66        let mut ctx = module.make_context();
67        let mut func_ctx = FunctionBuilderContext::new();
68
69        let sig_main = module.make_signature();
70        let func_main = module
71            .declare_function("WinMain", Linkage::Export, &sig_main)
72            .unwrap();
73
74        ctx.func.signature = sig_main;
75        ctx.func.name = ExternalName::user(0, func_main.as_u32());
76
77        {
78            let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
79            
80            // Declare variables from the frontend
81            for item in frontend.symbols {
82                let v = Variable::new(self.variables.len());
83                
84                let fctype = match item.1 {
85                    VariableType::Declared(t) => t,
86                    VariableType::Defined(t, ..) => t
87                };
88
89                bcx.declare_var(v, self.convert_fctype(fctype));
90                self.variables.push(item.0);
91            }
92
93            let block0 = bcx.create_block();
94            bcx.switch_to_block(block0);
95
96            bcx.ins().return_(&[]);
97            bcx.seal_all_blocks();
98        }
99
100        let mut trap_sink = NullTrapSink {};
101        let mut stack_map_sink = NullStackMapSink {};
102
103        module
104            .define_function(func_main, &mut ctx, &mut trap_sink, &mut stack_map_sink)
105            .unwrap();
106        
107        module.clear_context(&mut ctx);
108
109        let o = module.finish();
110        let res = o.emit().unwrap();
111
112        //std::fs::write(self.out_file.clone(), res).unwrap();
113        let mut f = std::fs::File::create(self.out_file.clone()).unwrap();
114        f.write_all(&res).unwrap();
115        
116        true
117    }
118
119}