Fork of daniellemaywood.uk/gleam — Wasm codegen work
9.7 kB
258 lines
1use std::collections::HashMap;
2
3use cranelift::{codegen::ir::BlockArg, prelude::*};
4use cranelift_jit::{JITBuilder, JITModule};
5use cranelift_module::{FuncOrDataId, Linkage, Module, default_libcall_names};
6use ecow::EcoString;
7use num_bigint::BigInt;
8
9pub mod mir;
10
11pub fn compile(m: mir::Module) {
12 let mut flag_builder = settings::builder();
13
14 flag_builder
15 .set("is_pic", "false")
16 .expect("unable to set `is_pic` to false");
17
18 let isa = cranelift_native::builder()
19 .unwrap_or_else(|reason| panic!("host machine not support: {reason}"))
20 .finish(settings::Flags::new(flag_builder))
21 .expect("unable to build isa target");
22
23 let mut module = JITModule::new(JITBuilder::with_isa(isa, default_libcall_names()));
24 let mut context = module.make_context();
25 let mut function_context = FunctionBuilderContext::new();
26
27 for function in m.functions {
28 let sig = &mut context.func.signature;
29
30 for _ in &function.parameters {
31 sig.params.push(AbiParam::new(types::I64));
32 }
33
34 sig.returns.push(AbiParam::new(types::I64));
35
36 let mut builder = FunctionBuilder::new(&mut context.func, &mut function_context);
37
38 let entry = builder.create_block();
39 builder.append_block_params_for_function_params(entry);
40 builder.switch_to_block(entry);
41 builder.seal_block(entry);
42
43 let mut translator = FunctionTranslator {
44 builder,
45 module: &mut module,
46 variables: HashMap::new(),
47 };
48
49 for (index, parameter) in function.parameters.into_iter().enumerate() {
50 if let Some(name) = parameter.name {
51 let var = translator.make_var(name);
52 let val = translator.builder.block_params(entry)[index];
53
54 translator.builder.def_var(var, val);
55 }
56 }
57
58 let output = translator.translate_expression(function.body);
59
60 _ = translator.builder.ins().return_(&[output]);
61 translator.builder.finalize();
62
63 let id = module
64 .declare_function(&function.name, Linkage::Export, &context.func.signature)
65 .expect("unable to declare function");
66
67 module
68 .define_function(id, &mut context)
69 .expect("unable to define function");
70
71 module.clear_context(&mut context);
72 }
73
74 module
75 .finalize_definitions()
76 .expect("unable to finalize definitions");
77
78 let FuncOrDataId::Func(main) = module.get_name("main").expect("expected a main function")
79 else {
80 panic!("expected main to be a function")
81 };
82
83 let code = module.get_finalized_function(main);
84 #[allow(unsafe_code)]
85 let main = unsafe { std::mem::transmute::<_, extern "C" fn() -> i64>(code) };
86
87 println!("{}", main());
88}
89
90struct FunctionTranslator<'a, M: Module> {
91 builder: FunctionBuilder<'a>,
92 module: &'a mut M,
93 variables: HashMap<EcoString, Variable>,
94}
95
96impl<'a, M: Module> FunctionTranslator<'a, M> {
97 fn make_var(&mut self, name: EcoString) -> Variable {
98 let variable = self.builder.declare_var(types::I64);
99 _ = self.variables.insert(name, variable);
100 variable
101 }
102
103 fn get_var(&mut self, name: &EcoString) -> Variable {
104 self.variables
105 .get(name)
106 .cloned()
107 .unwrap_or_else(|| panic!("variable '{}' not found", name))
108 }
109
110 fn make_int(&mut self, value: BigInt) -> Value {
111 let value: i64 = value.try_into().expect("bigint out of representable range");
112
113 self.builder.ins().iconst(types::I64, value)
114 }
115
116 fn translate_expression(&mut self, expression: mir::Expression) -> Value {
117 _ = self.module;
118
119 match expression {
120 mir::Expression::Block(expressions) => expressions
121 .into_iter()
122 .map(|expression| self.translate_expression(expression))
123 .last()
124 .expect("block shouldn't be empty"),
125 mir::Expression::FunctionRef {
126 module: _,
127 name,
128 arity,
129 } => {
130 let mut signature = self.module.make_signature();
131
132 for _ in 0..arity {
133 signature.params.push(AbiParam::new(types::I64));
134 }
135 signature.returns.push(AbiParam::new(types::I64));
136
137 let id = self
138 .module
139 .declare_function(&name, Linkage::Import, &signature)
140 .expect("unable to declare function for import");
141
142 let func = self.module.declare_func_in_func(id, self.builder.func);
143
144 self.builder.ins().func_addr(types::I64, func)
145 }
146 mir::Expression::Var(var) => {
147 let var = self.get_var(&var.name);
148
149 self.builder.use_var(var)
150 }
151 mir::Expression::Int { value } => self.make_int(value),
152 mir::Expression::Float { value: _ } => todo!(),
153 mir::Expression::Bool { value: _ } => todo!(),
154 mir::Expression::String { value: _ } => todo!(),
155 mir::Expression::Equals { lhs, rhs } => {
156 let lhs = self.translate_expression(*lhs);
157 let rhs = self.translate_expression(*rhs);
158
159 self.builder.ins().icmp(IntCC::Equal, lhs, rhs)
160 }
161 mir::Expression::NotEquals { lhs: _, rhs: _ } => todo!(),
162 mir::Expression::IntGt { lhs: _, rhs: _ } => todo!(),
163 mir::Expression::IntGtEq { lhs: _, rhs: _ } => todo!(),
164 mir::Expression::IntLt { lhs: _, rhs: _ } => todo!(),
165 mir::Expression::IntLtEq { lhs: _, rhs: _ } => todo!(),
166 mir::Expression::IntAdd { lhs, rhs } => {
167 let lhs = self.translate_expression(*lhs);
168 let rhs = self.translate_expression(*rhs);
169
170 self.builder.ins().iadd(lhs, rhs)
171 }
172 mir::Expression::IntSub { lhs, rhs } => {
173 let lhs = self.translate_expression(*lhs);
174 let rhs = self.translate_expression(*rhs);
175
176 self.builder.ins().isub(lhs, rhs)
177 }
178 mir::Expression::IntMul { lhs: _, rhs: _ } => todo!(),
179 mir::Expression::IntDiv { lhs: _, rhs: _ } => todo!(),
180 mir::Expression::IntRem { lhs: _, rhs: _ } => todo!(),
181 mir::Expression::FloatGt { lhs: _, rhs: _ } => todo!(),
182 mir::Expression::FloatGtEq { lhs: _, rhs: _ } => todo!(),
183 mir::Expression::FloatLt { lhs: _, rhs: _ } => todo!(),
184 mir::Expression::FloatLtEq { lhs: _, rhs: _ } => todo!(),
185 mir::Expression::FloatAdd { lhs: _, rhs: _ } => todo!(),
186 mir::Expression::FloatSub { lhs: _, rhs: _ } => todo!(),
187 mir::Expression::FloatMul { lhs: _, rhs: _ } => todo!(),
188 mir::Expression::FloatDiv { lhs: _, rhs: _ } => todo!(),
189 mir::Expression::StringConcat { lhs: _, rhs: _ } => todo!(),
190 mir::Expression::List { items: _, tail: _ } => todo!(),
191 mir::Expression::Struct { tag: _, items: _ } => todo!(),
192 mir::Expression::StructAccess { value: _, index: _ } => todo!(),
193 mir::Expression::Set { name, value } => {
194 let var = self.make_var(name.name);
195 let val = self.translate_expression(*value);
196
197 self.builder.def_var(var, val);
198 self.builder.use_var(var)
199 }
200 mir::Expression::If { cond, then, else_ } => {
201 let cond = self.translate_expression(*cond);
202
203 let then_block = self.builder.create_block();
204 let else_block = self.builder.create_block();
205 let merge_block = self.builder.create_block();
206
207 _ = self.builder.append_block_param(merge_block, types::I64);
208
209 _ = self
210 .builder
211 .ins()
212 .brif(cond, then_block, &[], else_block, &[]);
213
214 self.builder.switch_to_block(then_block);
215 self.builder.seal_block(then_block);
216
217 let then_return = self.translate_expression(*then);
218 _ = self
219 .builder
220 .ins()
221 .jump(merge_block, &[BlockArg::Value(then_return)]);
222
223 self.builder.switch_to_block(else_block);
224 self.builder.seal_block(else_block);
225
226 let else_return = self.translate_expression(*else_);
227 _ = self
228 .builder
229 .ins()
230 .jump(merge_block, &[BlockArg::Value(else_return)]);
231
232 self.builder.switch_to_block(merge_block);
233 self.builder.seal_block(merge_block);
234
235 self.builder.block_params(merge_block)[0]
236 }
237 mir::Expression::Call { target, args } => {
238 let mut signature = self.module.make_signature();
239
240 for _ in 0..args.len() {
241 signature.params.push(AbiParam::new(types::I64));
242 }
243 signature.returns.push(AbiParam::new(types::I64));
244
245 let target = self.translate_expression(*target);
246 let args: Vec<_> = args
247 .into_iter()
248 .map(|arg| self.translate_expression(arg))
249 .collect();
250
251 let sig = self.builder.import_signature(signature);
252 let call = self.builder.ins().call_indirect(sig, target, &args);
253
254 self.builder.inst_results(call)[0]
255 }
256 }
257 }
258}