1use std::collections::HashMap;
8use std::sync::Arc;
9
10use cranelift_codegen::ir::types;
11use cranelift_codegen::ir::{AbiParam, BlockArg, InstBuilder};
12use cranelift_codegen::isa::CallConv;
13use cranelift_codegen::settings::{self, Configurable};
14use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
15use cranelift_module::{FuncId, Linkage, Module};
16use cranelift_object::{ObjectBuilder, ObjectModule};
17
18use crate::ir::{BlockId, Const, Inst, IrFunction, KnownFn, RegionAllocKind, Terminator, VarId};
19
20#[derive(Debug)]
23pub enum CodegenError {
24 Module(cranelift_module::ModuleError),
25 Codegen(String),
26}
27
28impl From<cranelift_module::ModuleError> for CodegenError {
29 fn from(e: cranelift_module::ModuleError) -> Self {
30 CodegenError::Module(e)
31 }
32}
33
34pub type CodegenResult<T> = Result<T, CodegenError>;
35
36struct RuntimeFuncs {
40 rt_safepoint: FuncId,
41 rt_const_nil: FuncId,
42 rt_const_true: FuncId,
43 rt_const_false: FuncId,
44 rt_const_long: FuncId,
45 rt_const_double: FuncId,
46 rt_const_char: FuncId,
47 rt_const_string: FuncId,
48 rt_const_keyword: FuncId,
49 rt_const_symbol: FuncId,
50 rt_truthiness: FuncId,
51 rt_add: FuncId,
52 rt_sub: FuncId,
53 rt_mul: FuncId,
54 rt_div: FuncId,
55 rt_rem: FuncId,
56 rt_eq: FuncId,
57 rt_lt: FuncId,
58 rt_gt: FuncId,
59 rt_lte: FuncId,
60 rt_gte: FuncId,
61 rt_alloc_vector: FuncId,
62 rt_alloc_map: FuncId,
63 rt_alloc_set: FuncId,
64 rt_alloc_list: FuncId,
65 rt_alloc_cons: FuncId,
66 rt_get: FuncId,
67 rt_count: FuncId,
68 rt_first: FuncId,
69 rt_rest: FuncId,
70 rt_assoc: FuncId,
71 rt_conj: FuncId,
72 rt_call: FuncId,
73 rt_deref: FuncId,
74 rt_println: FuncId,
75 rt_pr: FuncId,
76 rt_is_nil: FuncId,
77 rt_is_vector: FuncId,
78 rt_is_map: FuncId,
79 rt_is_seq: FuncId,
80 rt_identical: FuncId,
81 rt_str: FuncId,
82 rt_load_global: FuncId,
83 rt_def_var: FuncId,
84 rt_make_fn: FuncId,
85 rt_make_fn_variadic: FuncId,
86 rt_make_fn_multi: FuncId,
87 rt_throw: FuncId,
88 rt_try: FuncId,
89 rt_dissoc: FuncId,
90 rt_disj: FuncId,
91 rt_nth: FuncId,
92 rt_contains: FuncId,
93 rt_seq: FuncId,
94 rt_lazy_seq: FuncId,
95 rt_transient: FuncId,
96 rt_assoc_bang: FuncId,
97 rt_conj_bang: FuncId,
98 rt_persistent_bang: FuncId,
99 rt_atom_reset: FuncId,
100 rt_atom_swap: FuncId,
101 rt_apply: FuncId,
102 rt_set_bang: FuncId,
103 rt_with_bindings: FuncId,
104 rt_load_var: FuncId,
105 rt_reduce2: FuncId,
106 rt_reduce3: FuncId,
107 rt_map: FuncId,
108 rt_filter: FuncId,
109 rt_mapv: FuncId,
110 rt_filterv: FuncId,
111 rt_some: FuncId,
112 rt_every: FuncId,
113 rt_into: FuncId,
114 rt_into3: FuncId,
115 rt_group_by: FuncId,
116 rt_partition2: FuncId,
117 rt_partition3: FuncId,
118 rt_partition4: FuncId,
119 rt_frequencies: FuncId,
120 rt_keep: FuncId,
121 rt_remove: FuncId,
122 rt_map_indexed: FuncId,
123 rt_zipmap: FuncId,
124 rt_juxt: FuncId,
125 rt_comp: FuncId,
126 rt_partial: FuncId,
127 rt_complement: FuncId,
128 rt_concat: FuncId,
129 rt_range1: FuncId,
130 rt_range2: FuncId,
131 rt_range3: FuncId,
132 rt_take: FuncId,
133 rt_drop: FuncId,
134 rt_reverse: FuncId,
135 rt_sort: FuncId,
136 rt_sort_by: FuncId,
137 rt_keys: FuncId,
138 rt_vals: FuncId,
139 rt_merge: FuncId,
140 rt_update: FuncId,
141 rt_get_in: FuncId,
142 rt_assoc_in: FuncId,
143 rt_is_number: FuncId,
144 rt_is_string: FuncId,
145 rt_is_keyword: FuncId,
146 rt_is_symbol: FuncId,
147 rt_is_bool: FuncId,
148 rt_is_int: FuncId,
149 rt_prn: FuncId,
150 rt_print: FuncId,
151 rt_atom: FuncId,
152 rt_str_n: FuncId,
153 rt_println_n: FuncId,
154 rt_with_out_str: FuncId,
155 rt_peek: FuncId,
156 rt_pop: FuncId,
157 rt_vec: FuncId,
158 rt_mapcat: FuncId,
159 rt_is_empty: FuncId,
160 rt_repeatedly: FuncId,
161 rt_region_start: FuncId,
163 rt_region_end: FuncId,
164 rt_region_alloc_vector: FuncId,
165 rt_region_alloc_map: FuncId,
166 rt_region_alloc_set: FuncId,
167 rt_region_alloc_list: FuncId,
168 rt_region_alloc_cons: FuncId,
169}
170
171pub struct Compiler {
175 module: ObjectModule,
176 ctx: cranelift_codegen::Context,
177 fb_ctx: FunctionBuilderContext,
178 rt: RuntimeFuncs,
179 ptr_type: types::Type,
180 user_funcs: HashMap<Arc<str>, FuncId>,
182}
183
184impl Compiler {
185 pub fn new() -> CodegenResult<Self> {
187 let mut flag_builder = settings::builder();
188 flag_builder.set("opt_level", "speed").unwrap();
189 flag_builder.set("is_pic", "true").unwrap();
190
191 let isa_builder = cranelift_native::builder()
192 .map_err(|e| CodegenError::Codegen(format!("failed to create ISA builder: {e}")))?;
193 let isa = isa_builder
194 .finish(settings::Flags::new(flag_builder))
195 .map_err(|e| CodegenError::Codegen(format!("failed to build ISA: {e}")))?;
196
197 let ptr_type = isa.pointer_type();
198
199 let obj_builder = ObjectBuilder::new(
200 isa,
201 "clojurust_aot",
202 cranelift_module::default_libcall_names(),
203 )?;
204 let mut module = ObjectModule::new(obj_builder);
205
206 let rt = declare_runtime_funcs(&mut module, ptr_type)?;
207
208 Ok(Self {
209 ctx: module.make_context(),
210 fb_ctx: FunctionBuilderContext::new(),
211 module,
212 rt,
213 ptr_type,
214 user_funcs: HashMap::new(),
215 })
216 }
217
218 pub fn declare_function(&mut self, name: &str, param_count: usize) -> CodegenResult<FuncId> {
220 let mut sig = self.module.make_signature();
221 for _ in 0..param_count {
222 sig.params.push(AbiParam::new(self.ptr_type));
223 }
224 sig.returns.push(AbiParam::new(self.ptr_type));
225 let func_id = self.module.declare_function(name, Linkage::Export, &sig)?;
226 self.user_funcs.insert(Arc::from(name), func_id);
227 Ok(func_id)
228 }
229
230 pub fn compile_function(&mut self, ir_func: &IrFunction, func_id: FuncId) -> CodegenResult<()> {
232 self.ctx.func.signature = self
233 .module
234 .declarations()
235 .get_function_decl(func_id)
236 .signature
237 .clone();
238 self.ctx.func.name = cranelift_codegen::ir::UserFuncName::user(0, func_id.as_u32());
239
240 {
241 let mut builder = FunctionBuilder::new(&mut self.ctx.func, &mut self.fb_ctx);
242 {
243 let mut translator = FunctionTranslator {
244 builder: &mut builder,
245 module: &mut self.module,
246 rt: &self.rt,
247 ptr_type: self.ptr_type,
248 var_map: HashMap::new(),
249 block_map: HashMap::new(),
250 user_funcs: &self.user_funcs,
251 };
252 translator.translate(ir_func)?;
253 }
254 builder.finalize();
255 }
256
257 self.module.define_function(func_id, &mut self.ctx)?;
258 self.ctx.clear();
259 Ok(())
260 }
261
262 pub fn finish(self) -> Vec<u8> {
264 let product = self.module.finish();
265 product.emit().expect("failed to emit object code")
266 }
267}
268
269struct FunctionTranslator<'a, 'b> {
274 builder: &'b mut FunctionBuilder<'a>,
275 module: &'b mut ObjectModule,
276 rt: &'b RuntimeFuncs,
277 ptr_type: types::Type,
278 var_map: HashMap<VarId, Variable>,
280 user_funcs: &'b HashMap<Arc<str>, FuncId>,
282 block_map: HashMap<BlockId, cranelift_codegen::ir::Block>,
284}
285
286impl<'a, 'b> FunctionTranslator<'a, 'b> {
287 fn translate(&mut self, ir_func: &IrFunction) -> CodegenResult<()> {
288 for block in &ir_func.blocks {
290 let clif_block = self.builder.create_block();
291 self.block_map.insert(block.id, clif_block);
292 }
293
294 let entry_block = self.block_map[&ir_func.blocks[0].id];
296 self.builder.switch_to_block(entry_block);
297 self.builder
298 .append_block_params_for_function_params(entry_block);
299
300 for (i, (_name, var_id)) in ir_func.params.iter().enumerate() {
302 let var = self.ensure_var(*var_id);
303 let param_val = self.builder.block_params(entry_block)[i];
304 self.builder.def_var(var, param_val);
305 }
306
307 self.emit_safepoint();
309
310 for (block_idx, ir_block) in ir_func.blocks.iter().enumerate() {
312 let clif_block = self.block_map[&ir_block.id];
313
314 if block_idx > 0 {
315 self.builder.switch_to_block(clif_block);
316 }
317
318 for inst in &ir_block.phis {
323 if let Inst::Phi(dst, _) = inst {
324 let var = self.ensure_var(*dst);
325 let param = self.builder.append_block_param(clif_block, self.ptr_type);
326 self.builder.def_var(var, param);
327 }
328 }
329
330 for inst in &ir_block.insts {
332 self.translate_inst(inst)?;
333 }
334
335 self.translate_terminator(&ir_block.terminator, ir_block.id, ir_func)?;
337 }
338
339 self.builder.seal_all_blocks();
340 Ok(())
341 }
342
343 fn translate_inst(&mut self, inst: &Inst) -> CodegenResult<()> {
344 match inst {
345 Inst::Const(dst, c) => {
346 let val = self.emit_const(c)?;
347 let var = self.ensure_var(*dst);
348 self.builder.def_var(var, val);
349 }
350
351 Inst::LoadLocal(dst, _name) => {
352 let val = self.call_rt_0(self.rt.rt_const_nil)?;
356 let var = self.ensure_var(*dst);
357 self.builder.def_var(var, val);
358 }
359
360 Inst::LoadGlobal(dst, ns, name) => {
361 let val = self.emit_load_global(ns, name)?;
362 let var = self.ensure_var(*dst);
363 self.builder.def_var(var, val);
364 }
365
366 Inst::LoadVar(dst, ns, name) => {
367 let val = self.emit_load_var(ns, name)?;
368 let var = self.ensure_var(*dst);
369 self.builder.def_var(var, val);
370 }
371
372 Inst::AllocVector(dst, elems) => {
373 let val = self.emit_alloc_collection(self.rt.rt_alloc_vector, elems)?;
374 let var = self.ensure_var(*dst);
375 self.builder.def_var(var, val);
376 }
377
378 Inst::AllocMap(dst, pairs) => {
379 let flat: Vec<VarId> = pairs.iter().flat_map(|(k, v)| [*k, *v]).collect();
380 let val = self.emit_alloc_collection(self.rt.rt_alloc_map, &flat)?;
381 let var = self.ensure_var(*dst);
382 self.builder.def_var(var, val);
383 }
384
385 Inst::AllocSet(dst, elems) => {
386 let val = self.emit_alloc_collection(self.rt.rt_alloc_set, elems)?;
387 let var = self.ensure_var(*dst);
388 self.builder.def_var(var, val);
389 }
390
391 Inst::AllocList(dst, elems) => {
392 let val = self.emit_alloc_collection(self.rt.rt_alloc_list, elems)?;
393 let var = self.ensure_var(*dst);
394 self.builder.def_var(var, val);
395 }
396
397 Inst::AllocCons(dst, head, tail) => {
398 let h = self.use_var(*head);
399 let t = self.use_var(*tail);
400 let val = self.call_rt_2(self.rt.rt_alloc_cons, h, t)?;
401 let var = self.ensure_var(*dst);
402 self.builder.def_var(var, val);
403 }
404
405 Inst::CallKnown(dst, known_fn, args) => {
406 let val = self.emit_known_call(known_fn, args)?;
407 let var = self.ensure_var(*dst);
408 self.builder.def_var(var, val);
409 }
410
411 Inst::Call(dst, callee, args) => {
412 let val = self.emit_unknown_call(*callee, args)?;
413 let var = self.ensure_var(*dst);
414 self.builder.def_var(var, val);
415 }
416
417 Inst::CallDirect(dst, fn_name, args) => {
418 let val = self.emit_direct_call(fn_name, args)?;
419 let var = self.ensure_var(*dst);
420 self.builder.def_var(var, val);
421 }
422
423 Inst::Deref(dst, src) => {
424 let s = self.use_var(*src);
425 let val = self.call_rt_1(self.rt.rt_deref, s)?;
426 let var = self.ensure_var(*dst);
427 self.builder.def_var(var, val);
428 }
429
430 Inst::DefVar(dst, ns, name, val_var) => {
431 let val = self.emit_def_var(ns, name, *val_var)?;
432 let var = self.ensure_var(*dst);
433 self.builder.def_var(var, val);
434 }
435
436 Inst::SetBang(var, val) => {
437 let var_v = self.use_var(*var);
438 let val_v = self.use_var(*val);
439 let func_ref = self.import_func(self.rt.rt_set_bang);
440 self.builder.ins().call(func_ref, &[var_v, val_v]);
441 }
442
443 Inst::Throw(val) => {
444 let v = self.use_var(*val);
445 let func_ref = self.import_func(self.rt.rt_throw);
446 self.builder.ins().call(func_ref, &[v]);
447 }
451
452 Inst::Phi(_, _) => {
453 }
455
456 Inst::Recur(_) => {
457 }
459
460 Inst::SourceLoc(_) => {
461 }
463
464 Inst::AllocClosure(dst, template, captures) => {
465 if template.arity_fn_names.is_empty() {
466 let val = self.call_rt_0(self.rt.rt_const_nil)?;
468 let var = self.ensure_var(*dst);
469 self.builder.def_var(var, val);
470 } else {
471 let name_str = template
473 .name
474 .as_deref()
475 .unwrap_or(&template.arity_fn_names[0]);
476 let name_data = self.module.declare_anonymous_data(false, false)?;
477 let mut name_desc = cranelift_module::DataDescription::new();
478 name_desc.define(name_str.as_bytes().to_vec().into_boxed_slice());
479 self.module.define_data(name_data, &name_desc)?;
480 let name_gv = self
481 .module
482 .declare_data_in_func(name_data, self.builder.func);
483 let name_ptr = self.builder.ins().global_value(self.ptr_type, name_gv);
484 let name_len = self.builder.ins().iconst(types::I64, name_str.len() as i64);
485
486 let ncaptures = captures.len();
488 let (captures_ptr, ncaptures_val) = if ncaptures == 0 {
489 let null = self.builder.ins().iconst(self.ptr_type, 0);
490 let zero = self.builder.ins().iconst(types::I64, 0);
491 (null, zero)
492 } else {
493 let slot = self.builder.create_sized_stack_slot(
494 cranelift_codegen::ir::StackSlotData::new(
495 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
496 (ncaptures * 8) as u32,
497 3,
498 ),
499 );
500 for (i, cap_var) in captures.iter().enumerate() {
501 let cap_val = self.use_var(*cap_var);
502 self.builder
503 .ins()
504 .stack_store(cap_val, slot, (i * 8) as i32);
505 }
506 let slot_addr = self.builder.ins().stack_addr(self.ptr_type, slot, 0);
507 let n = self.builder.ins().iconst(types::I64, ncaptures as i64);
508 (slot_addr, n)
509 };
510
511 let n_arities = template.arity_fn_names.len();
512 if n_arities == 1 && !template.is_variadic[0] {
513 let arity_fn_name = &template.arity_fn_names[0];
515 let param_count = template.param_counts[0];
516 let arity_func_id = self.user_funcs[arity_fn_name];
517 let func_ref = self
518 .module
519 .declare_func_in_func(arity_func_id, self.builder.func);
520 let fn_ptr = self.builder.ins().func_addr(self.ptr_type, func_ref);
521 let param_count_val =
522 self.builder.ins().iconst(types::I64, param_count as i64);
523
524 let rt_ref = self.import_func(self.rt.rt_make_fn);
525 let call = self.builder.ins().call(
526 rt_ref,
527 &[
528 name_ptr,
529 name_len,
530 fn_ptr,
531 param_count_val,
532 captures_ptr,
533 ncaptures_val,
534 ],
535 );
536 let result = self.builder.inst_results(call)[0];
537 let var = self.ensure_var(*dst);
538 self.builder.def_var(var, result);
539 } else if n_arities == 1 && template.is_variadic[0] {
540 let arity_fn_name = &template.arity_fn_names[0];
542 let param_count = template.param_counts[0];
543 let arity_func_id = self.user_funcs[arity_fn_name];
544 let func_ref = self
545 .module
546 .declare_func_in_func(arity_func_id, self.builder.func);
547 let fn_ptr = self.builder.ins().func_addr(self.ptr_type, func_ref);
548 let param_count_val =
549 self.builder.ins().iconst(types::I64, param_count as i64);
550
551 let rt_ref = self.import_func(self.rt.rt_make_fn_variadic);
552 let call = self.builder.ins().call(
553 rt_ref,
554 &[
555 name_ptr,
556 name_len,
557 fn_ptr,
558 param_count_val,
559 captures_ptr,
560 ncaptures_val,
561 ],
562 );
563 let result = self.builder.inst_results(call)[0];
564 let var = self.ensure_var(*dst);
565 self.builder.def_var(var, result);
566 } else {
567 let fn_ptrs_slot = self.builder.create_sized_stack_slot(
572 cranelift_codegen::ir::StackSlotData::new(
573 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
574 (n_arities * 8) as u32,
575 3,
576 ),
577 );
578 for (i, arity_fn_name) in template.arity_fn_names.iter().enumerate() {
579 let arity_func_id = self.user_funcs[arity_fn_name];
580 let func_ref = self
581 .module
582 .declare_func_in_func(arity_func_id, self.builder.func);
583 let fn_ptr = self.builder.ins().func_addr(self.ptr_type, func_ref);
584 self.builder
585 .ins()
586 .stack_store(fn_ptr, fn_ptrs_slot, (i * 8) as i32);
587 }
588 let fn_ptrs_addr =
589 self.builder
590 .ins()
591 .stack_addr(self.ptr_type, fn_ptrs_slot, 0);
592
593 let pc_slot = self.builder.create_sized_stack_slot(
595 cranelift_codegen::ir::StackSlotData::new(
596 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
597 (n_arities * 8) as u32,
598 3,
599 ),
600 );
601 for (i, &pc) in template.param_counts.iter().enumerate() {
602 let pc_val = self.builder.ins().iconst(types::I64, pc as i64);
603 self.builder
604 .ins()
605 .stack_store(pc_val, pc_slot, (i * 8) as i32);
606 }
607 let pc_addr = self.builder.ins().stack_addr(self.ptr_type, pc_slot, 0);
608
609 let var_slot = self.builder.create_sized_stack_slot(
611 cranelift_codegen::ir::StackSlotData::new(
612 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
613 n_arities as u32,
614 0,
615 ),
616 );
617 for (i, &v) in template.is_variadic.iter().enumerate() {
618 let v_val = self.builder.ins().iconst(types::I8, if v { 1 } else { 0 });
619 self.builder.ins().stack_store(v_val, var_slot, i as i32);
620 }
621 let var_addr = self.builder.ins().stack_addr(self.ptr_type, var_slot, 0);
622
623 let n_arities_val = self.builder.ins().iconst(types::I64, n_arities as i64);
624
625 let rt_ref = self.import_func(self.rt.rt_make_fn_multi);
628 let call = self.builder.ins().call(
629 rt_ref,
630 &[
631 name_ptr,
632 name_len,
633 fn_ptrs_addr,
634 pc_addr,
635 var_addr,
636 n_arities_val,
637 captures_ptr,
638 ncaptures_val,
639 ],
640 );
641 let result = self.builder.inst_results(call)[0];
642 let var = self.ensure_var(*dst);
643 self.builder.def_var(var, result);
644 }
645 }
646 }
647
648 Inst::RegionStart(dst) => {
649 let val = self.call_rt_0(self.rt.rt_region_start)?;
651 let var = self.ensure_var(*dst);
652 self.builder.def_var(var, val);
653 }
654
655 Inst::RegionAlloc(dst, region, kind, operands) => {
656 let region_handle = self.use_var(*region);
657 let val = match kind {
658 RegionAllocKind::Vector => self.emit_region_alloc_collection(
659 self.rt.rt_region_alloc_vector,
660 region_handle,
661 operands,
662 )?,
663 RegionAllocKind::Map => self.emit_region_alloc_collection(
664 self.rt.rt_region_alloc_map,
665 region_handle,
666 operands,
667 )?,
668 RegionAllocKind::Set => self.emit_region_alloc_collection(
669 self.rt.rt_region_alloc_set,
670 region_handle,
671 operands,
672 )?,
673 RegionAllocKind::List => self.emit_region_alloc_collection(
674 self.rt.rt_region_alloc_list,
675 region_handle,
676 operands,
677 )?,
678 RegionAllocKind::Cons => {
679 if operands.len() == 2 {
680 let h = self.use_var(operands[0]);
681 let t = self.use_var(operands[1]);
682 let func_ref = self.import_func(self.rt.rt_region_alloc_cons);
683 let call = self.builder.ins().call(func_ref, &[region_handle, h, t]);
684 self.builder.inst_results(call)[0]
685 } else {
686 self.call_rt_0(self.rt.rt_const_nil)?
687 }
688 }
689 };
690 let var = self.ensure_var(*dst);
691 self.builder.def_var(var, val);
692 }
693
694 Inst::RegionEnd(region) => {
695 let handle = self.use_var(*region);
697 let func_ref = self.import_func(self.rt.rt_region_end);
698 self.builder.ins().call(func_ref, &[handle]);
699 }
700
701 Inst::RegionParam(dst) => {
702 let val = self.call_rt_0(self.rt.rt_const_nil)?;
706 let var = self.ensure_var(*dst);
707 self.builder.def_var(var, val);
708 }
709
710 Inst::CallWithRegion(dst, fn_name, args) => {
711 let val = self.emit_direct_call(fn_name, args)?;
715 let var = self.ensure_var(*dst);
716 self.builder.def_var(var, val);
717 }
718 }
719 Ok(())
720 }
721
722 fn translate_terminator(
723 &mut self,
724 term: &Terminator,
725 current_block_id: BlockId,
726 ir_func: &IrFunction,
727 ) -> CodegenResult<()> {
728 match term {
729 Terminator::Return(var_id) => {
730 let val = self.use_var(*var_id);
731 self.builder.ins().return_(&[val]);
732 }
733
734 Terminator::Jump(target) => {
735 let clif_block = self.block_map[target];
736 let phi_args = self.collect_phi_args(*target, current_block_id, ir_func);
737 self.builder.ins().jump(clif_block, &phi_args);
738 }
739
740 Terminator::Branch {
741 cond,
742 then_block,
743 else_block,
744 } => {
745 let cond_val = self.use_var(*cond);
746 let truthy = self.call_rt_1_i8(self.rt.rt_truthiness, cond_val)?;
747 let then_b = self.block_map[then_block];
748 let else_b = self.block_map[else_block];
749 let then_args = self.collect_phi_args(*then_block, current_block_id, ir_func);
750 let else_args = self.collect_phi_args(*else_block, current_block_id, ir_func);
751 self.builder
752 .ins()
753 .brif(truthy, then_b, &then_args, else_b, &else_args);
754 }
755
756 Terminator::RecurJump { target, args } => {
757 self.emit_safepoint();
760 let clif_block = self.block_map[target];
761 let arg_vals: Vec<BlockArg> = args
762 .iter()
763 .map(|a| BlockArg::Value(self.use_var(*a)))
764 .collect();
765 self.builder.ins().jump(clif_block, &arg_vals);
766 }
767
768 Terminator::Unreachable => {
769 let nil_ref = self.import_func(self.rt.rt_const_nil);
772 let nil_call = self.builder.ins().call(nil_ref, &[]);
773 let nil_val = self.builder.inst_results(nil_call)[0];
774 self.builder.ins().return_(&[nil_val]);
775 }
776 }
777 Ok(())
778 }
779
780 fn collect_phi_args(
782 &mut self,
783 to_block: BlockId,
784 from_block: BlockId,
785 ir_func: &IrFunction,
786 ) -> Vec<BlockArg> {
787 let target = ir_func.blocks.iter().find(|b| b.id == to_block);
788 let Some(target) = target else {
789 return vec![];
790 };
791 target
792 .phis
793 .iter()
794 .filter_map(|inst| {
795 if let Inst::Phi(_, entries) = inst {
796 entries
798 .iter()
799 .find(|(pred, _)| *pred == from_block)
800 .map(|(_, var_id)| BlockArg::Value(self.use_var(*var_id)))
801 } else {
802 None
803 }
804 })
805 .collect()
806 }
807
808 fn emit_safepoint(&mut self) {
812 let func_ref = self.import_func(self.rt.rt_safepoint);
813 self.builder.ins().call(func_ref, &[]);
814 }
815
816 fn ensure_var(&mut self, var_id: VarId) -> Variable {
817 if let Some(&var) = self.var_map.get(&var_id) {
818 var
819 } else {
820 let var = self.builder.declare_var(self.ptr_type);
821 self.var_map.insert(var_id, var);
822 var
823 }
824 }
825
826 fn use_var(&mut self, var_id: VarId) -> cranelift_codegen::ir::Value {
827 let var = self.ensure_var(var_id);
828 self.builder.use_var(var)
829 }
830
831 fn emit_const(&mut self, c: &Const) -> CodegenResult<cranelift_codegen::ir::Value> {
833 match c {
834 Const::Nil => self.call_rt_0(self.rt.rt_const_nil),
835 Const::Bool(true) => self.call_rt_0(self.rt.rt_const_true),
836 Const::Bool(false) => self.call_rt_0(self.rt.rt_const_false),
837 Const::Long(n) => {
838 let func_ref = self.import_func(self.rt.rt_const_long);
839 let arg = self.builder.ins().iconst(types::I64, *n);
840 let call = self.builder.ins().call(func_ref, &[arg]);
841 Ok(self.builder.inst_results(call)[0])
842 }
843 Const::Double(f) => {
844 let func_ref = self.import_func(self.rt.rt_const_double);
845 let arg = self.builder.ins().f64const(*f);
846 let call = self.builder.ins().call(func_ref, &[arg]);
847 Ok(self.builder.inst_results(call)[0])
848 }
849 Const::Char(ch) => {
850 let func_ref = self.import_func(self.rt.rt_const_char);
851 let arg = self.builder.ins().iconst(types::I32, *ch as i64);
852 let call = self.builder.ins().call(func_ref, &[arg]);
853 Ok(self.builder.inst_results(call)[0])
854 }
855 Const::Str(s) => self.emit_string_const(self.rt.rt_const_string, s),
856 Const::Keyword(s) => self.emit_string_const(self.rt.rt_const_keyword, s),
857 Const::Symbol(s) => self.emit_string_const(self.rt.rt_const_symbol, s),
858 }
859 }
860
861 fn emit_string_const(
863 &mut self,
864 func_id: FuncId,
865 s: &str,
866 ) -> CodegenResult<cranelift_codegen::ir::Value> {
867 let data_id = self
869 .module
870 .declare_anonymous_data(false, false)
871 .map_err(CodegenError::Module)?;
872
873 let mut data_desc = cranelift_module::DataDescription::new();
874 data_desc.define(s.as_bytes().to_vec().into_boxed_slice());
875 self.module
876 .define_data(data_id, &data_desc)
877 .map_err(CodegenError::Module)?;
878
879 let global_val = self.module.declare_data_in_func(data_id, self.builder.func);
880 let ptr = self.builder.ins().global_value(self.ptr_type, global_val);
881 let len = self.builder.ins().iconst(types::I64, s.len() as i64);
882
883 let func_ref = self.import_func(func_id);
884 let call = self.builder.ins().call(func_ref, &[ptr, len]);
885 Ok(self.builder.inst_results(call)[0])
886 }
887
888 fn emit_load_global(
890 &mut self,
891 ns: &str,
892 name: &str,
893 ) -> CodegenResult<cranelift_codegen::ir::Value> {
894 let ns_data = self.module.declare_anonymous_data(false, false)?;
896 let mut ns_desc = cranelift_module::DataDescription::new();
897 ns_desc.define(ns.as_bytes().to_vec().into_boxed_slice());
898 self.module.define_data(ns_data, &ns_desc)?;
899
900 let name_data = self.module.declare_anonymous_data(false, false)?;
901 let mut name_desc = cranelift_module::DataDescription::new();
902 name_desc.define(name.as_bytes().to_vec().into_boxed_slice());
903 self.module.define_data(name_data, &name_desc)?;
904
905 let ns_gv = self.module.declare_data_in_func(ns_data, self.builder.func);
906 let ns_ptr = self.builder.ins().global_value(self.ptr_type, ns_gv);
907 let ns_len = self.builder.ins().iconst(types::I64, ns.len() as i64);
908
909 let name_gv = self
910 .module
911 .declare_data_in_func(name_data, self.builder.func);
912 let name_ptr = self.builder.ins().global_value(self.ptr_type, name_gv);
913 let name_len = self.builder.ins().iconst(types::I64, name.len() as i64);
914
915 let func_ref = self.import_func(self.rt.rt_load_global);
916 let call = self
917 .builder
918 .ins()
919 .call(func_ref, &[ns_ptr, ns_len, name_ptr, name_len]);
920 Ok(self.builder.inst_results(call)[0])
921 }
922
923 fn emit_load_var(
925 &mut self,
926 ns: &str,
927 name: &str,
928 ) -> CodegenResult<cranelift_codegen::ir::Value> {
929 let ns_data = self.module.declare_anonymous_data(false, false)?;
930 let mut ns_desc = cranelift_module::DataDescription::new();
931 ns_desc.define(ns.as_bytes().to_vec().into_boxed_slice());
932 self.module.define_data(ns_data, &ns_desc)?;
933
934 let name_data = self.module.declare_anonymous_data(false, false)?;
935 let mut name_desc = cranelift_module::DataDescription::new();
936 name_desc.define(name.as_bytes().to_vec().into_boxed_slice());
937 self.module.define_data(name_data, &name_desc)?;
938
939 let ns_gv = self.module.declare_data_in_func(ns_data, self.builder.func);
940 let ns_ptr = self.builder.ins().global_value(self.ptr_type, ns_gv);
941 let ns_len = self.builder.ins().iconst(types::I64, ns.len() as i64);
942
943 let name_gv = self
944 .module
945 .declare_data_in_func(name_data, self.builder.func);
946 let name_ptr = self.builder.ins().global_value(self.ptr_type, name_gv);
947 let name_len = self.builder.ins().iconst(types::I64, name.len() as i64);
948
949 let func_ref = self.import_func(self.rt.rt_load_var);
950 let call = self
951 .builder
952 .ins()
953 .call(func_ref, &[ns_ptr, ns_len, name_ptr, name_len]);
954 Ok(self.builder.inst_results(call)[0])
955 }
956
957 fn emit_def_var(
959 &mut self,
960 ns: &str,
961 name: &str,
962 val_var: VarId,
963 ) -> CodegenResult<cranelift_codegen::ir::Value> {
964 let ns_data = self.module.declare_anonymous_data(false, false)?;
965 let mut ns_desc = cranelift_module::DataDescription::new();
966 ns_desc.define(ns.as_bytes().to_vec().into_boxed_slice());
967 self.module.define_data(ns_data, &ns_desc)?;
968
969 let name_data = self.module.declare_anonymous_data(false, false)?;
970 let mut name_desc = cranelift_module::DataDescription::new();
971 name_desc.define(name.as_bytes().to_vec().into_boxed_slice());
972 self.module.define_data(name_data, &name_desc)?;
973
974 let ns_gv = self.module.declare_data_in_func(ns_data, self.builder.func);
975 let ns_ptr = self.builder.ins().global_value(self.ptr_type, ns_gv);
976 let ns_len = self.builder.ins().iconst(types::I64, ns.len() as i64);
977
978 let name_gv = self
979 .module
980 .declare_data_in_func(name_data, self.builder.func);
981 let name_ptr = self.builder.ins().global_value(self.ptr_type, name_gv);
982 let name_len = self.builder.ins().iconst(types::I64, name.len() as i64);
983
984 let val = self.use_var(val_var);
985
986 let func_ref = self.import_func(self.rt.rt_def_var);
987 let call = self
988 .builder
989 .ins()
990 .call(func_ref, &[ns_ptr, ns_len, name_ptr, name_len, val]);
991 Ok(self.builder.inst_results(call)[0])
992 }
993
994 fn emit_alloc_collection(
997 &mut self,
998 func_id: FuncId,
999 elems: &[VarId],
1000 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1001 let n = elems.len();
1002 if n == 0 {
1003 let func_ref = self.import_func(func_id);
1004 let null = self.builder.ins().iconst(self.ptr_type, 0);
1006 let zero = self.builder.ins().iconst(types::I64, 0);
1007 let call = self.builder.ins().call(func_ref, &[null, zero]);
1008 return Ok(self.builder.inst_results(call)[0]);
1009 }
1010
1011 let slot = self
1013 .builder
1014 .create_sized_stack_slot(cranelift_codegen::ir::StackSlotData::new(
1015 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
1016 (n * 8) as u32,
1017 3, ));
1019
1020 for (i, elem_var) in elems.iter().enumerate() {
1022 let val = self.use_var(*elem_var);
1023 self.builder.ins().stack_store(val, slot, (i * 8) as i32);
1024 }
1025
1026 let slot_addr = self.builder.ins().stack_addr(self.ptr_type, slot, 0);
1028 let count = self.builder.ins().iconst(types::I64, n as i64);
1029
1030 let func_ref = self.import_func(func_id);
1031 let actual_count = if func_id == self.rt.rt_alloc_map {
1033 self.builder.ins().iconst(types::I64, (n / 2) as i64)
1034 } else {
1035 count
1036 };
1037 let call = self
1038 .builder
1039 .ins()
1040 .call(func_ref, &[slot_addr, actual_count]);
1041 Ok(self.builder.inst_results(call)[0])
1042 }
1043
1044 fn emit_region_alloc_collection(
1049 &mut self,
1050 func_id: FuncId,
1051 region_handle: cranelift_codegen::ir::Value,
1052 elems: &[VarId],
1053 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1054 let n = elems.len();
1055 if n == 0 {
1056 let func_ref = self.import_func(func_id);
1057 let null = self.builder.ins().iconst(self.ptr_type, 0);
1058 let zero = self.builder.ins().iconst(types::I64, 0);
1059 let call = self
1060 .builder
1061 .ins()
1062 .call(func_ref, &[region_handle, null, zero]);
1063 return Ok(self.builder.inst_results(call)[0]);
1064 }
1065
1066 let slot = self
1067 .builder
1068 .create_sized_stack_slot(cranelift_codegen::ir::StackSlotData::new(
1069 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
1070 (n * 8) as u32,
1071 3,
1072 ));
1073
1074 for (i, elem_var) in elems.iter().enumerate() {
1075 let val = self.use_var(*elem_var);
1076 self.builder.ins().stack_store(val, slot, (i * 8) as i32);
1077 }
1078
1079 let slot_addr = self.builder.ins().stack_addr(self.ptr_type, slot, 0);
1080 let func_ref = self.import_func(func_id);
1081 let actual_count = if func_id == self.rt.rt_region_alloc_map {
1082 self.builder.ins().iconst(types::I64, (n / 2) as i64)
1083 } else {
1084 self.builder.ins().iconst(types::I64, n as i64)
1085 };
1086 let call = self
1087 .builder
1088 .ins()
1089 .call(func_ref, &[region_handle, slot_addr, actual_count]);
1090 Ok(self.builder.inst_results(call)[0])
1091 }
1092
1093 fn emit_known_call(
1095 &mut self,
1096 known_fn: &KnownFn,
1097 args: &[VarId],
1098 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1099 match known_fn {
1101 KnownFn::Vector => return self.emit_alloc_collection(self.rt.rt_alloc_vector, args),
1102 KnownFn::HashMap => return self.emit_alloc_collection(self.rt.rt_alloc_map, args),
1103 KnownFn::HashSet => return self.emit_alloc_collection(self.rt.rt_alloc_set, args),
1104 KnownFn::List => return self.emit_alloc_collection(self.rt.rt_alloc_list, args),
1105 KnownFn::AtomSwap => return self.emit_atom_swap(args),
1106 KnownFn::WithBindings => return self.emit_with_bindings(args),
1107 KnownFn::Concat => return self.emit_alloc_collection(self.rt.rt_concat, args),
1108 KnownFn::Str if args.len() != 1 => {
1109 return self.emit_alloc_collection(self.rt.rt_str_n, args);
1110 }
1111 KnownFn::Println if args.len() != 1 => {
1112 return self.emit_alloc_collection(self.rt.rt_println_n, args);
1113 }
1114 KnownFn::Merge => return self.emit_alloc_collection(self.rt.rt_merge, args),
1115 KnownFn::Juxt => return self.emit_alloc_collection(self.rt.rt_juxt, args),
1116 KnownFn::Comp => return self.emit_alloc_collection(self.rt.rt_comp, args),
1117 KnownFn::Partial => return self.emit_alloc_collection(self.rt.rt_partial, args),
1118 _ => {}
1119 }
1120
1121 let rt_func = match known_fn {
1122 KnownFn::Add => self.rt.rt_add,
1123 KnownFn::Sub => self.rt.rt_sub,
1124 KnownFn::Mul => self.rt.rt_mul,
1125 KnownFn::Div => self.rt.rt_div,
1126 KnownFn::Rem => self.rt.rt_rem,
1127 KnownFn::Eq => self.rt.rt_eq,
1128 KnownFn::Lt => self.rt.rt_lt,
1129 KnownFn::Gt => self.rt.rt_gt,
1130 KnownFn::Lte => self.rt.rt_lte,
1131 KnownFn::Gte => self.rt.rt_gte,
1132 KnownFn::Get => self.rt.rt_get,
1133 KnownFn::Count => self.rt.rt_count,
1134 KnownFn::First => self.rt.rt_first,
1135 KnownFn::Rest | KnownFn::Next => self.rt.rt_rest,
1136 KnownFn::Assoc => self.rt.rt_assoc,
1137 KnownFn::Conj => self.rt.rt_conj,
1138 KnownFn::Deref | KnownFn::AtomDeref => self.rt.rt_deref,
1139 KnownFn::Println => self.rt.rt_println,
1140 KnownFn::Pr => self.rt.rt_pr,
1141 KnownFn::IsNil => self.rt.rt_is_nil,
1142 KnownFn::IsVector => self.rt.rt_is_vector,
1143 KnownFn::IsMap => self.rt.rt_is_map,
1144 KnownFn::IsSeq => self.rt.rt_is_seq,
1145 KnownFn::Identical => self.rt.rt_identical,
1146 KnownFn::Str => self.rt.rt_str,
1147 KnownFn::TryCatchFinally => self.rt.rt_try,
1148 KnownFn::Dissoc => self.rt.rt_dissoc,
1149 KnownFn::Disj => self.rt.rt_disj,
1150 KnownFn::Nth => self.rt.rt_nth,
1151 KnownFn::Contains => self.rt.rt_contains,
1152 KnownFn::Cons => self.rt.rt_alloc_cons,
1153 KnownFn::Seq => self.rt.rt_seq,
1154 KnownFn::LazySeq => self.rt.rt_lazy_seq,
1155 KnownFn::Transient => self.rt.rt_transient,
1156 KnownFn::AssocBang => self.rt.rt_assoc_bang,
1157 KnownFn::ConjBang => self.rt.rt_conj_bang,
1158 KnownFn::PersistentBang => self.rt.rt_persistent_bang,
1159 KnownFn::AtomReset => self.rt.rt_atom_reset,
1160 KnownFn::Apply => self.rt.rt_apply,
1161 KnownFn::SetBangVar => self.rt.rt_set_bang,
1162 KnownFn::Reduce2 => self.rt.rt_reduce2,
1163 KnownFn::Reduce3 => self.rt.rt_reduce3,
1164 KnownFn::Map => self.rt.rt_map,
1165 KnownFn::Filter => self.rt.rt_filter,
1166 KnownFn::Mapv => self.rt.rt_mapv,
1167 KnownFn::Filterv => self.rt.rt_filterv,
1168 KnownFn::Some => self.rt.rt_some,
1169 KnownFn::Every => self.rt.rt_every,
1170 KnownFn::Into => self.rt.rt_into,
1171 KnownFn::Into3 => self.rt.rt_into3,
1172 KnownFn::Range1 => self.rt.rt_range1,
1173 KnownFn::Range2 => self.rt.rt_range2,
1174 KnownFn::Range3 => self.rt.rt_range3,
1175 KnownFn::Take => self.rt.rt_take,
1176 KnownFn::Drop => self.rt.rt_drop,
1177 KnownFn::Reverse => self.rt.rt_reverse,
1178 KnownFn::Sort => self.rt.rt_sort,
1179 KnownFn::SortBy => self.rt.rt_sort_by,
1180 KnownFn::Keys => self.rt.rt_keys,
1181 KnownFn::Vals => self.rt.rt_vals,
1182 KnownFn::Update => self.rt.rt_update,
1183 KnownFn::GetIn => self.rt.rt_get_in,
1184 KnownFn::AssocIn => self.rt.rt_assoc_in,
1185 KnownFn::IsNumber => self.rt.rt_is_number,
1186 KnownFn::IsString => self.rt.rt_is_string,
1187 KnownFn::IsKeyword => self.rt.rt_is_keyword,
1188 KnownFn::IsSymbol => self.rt.rt_is_symbol,
1189 KnownFn::IsBool => self.rt.rt_is_bool,
1190 KnownFn::IsInt => self.rt.rt_is_int,
1191 KnownFn::Prn => self.rt.rt_prn,
1192 KnownFn::Print => self.rt.rt_print,
1193 KnownFn::Atom => self.rt.rt_atom,
1194 KnownFn::GroupBy => self.rt.rt_group_by,
1195 KnownFn::Partition2 => self.rt.rt_partition2,
1196 KnownFn::Partition3 => self.rt.rt_partition3,
1197 KnownFn::Partition4 => self.rt.rt_partition4,
1198 KnownFn::Frequencies => self.rt.rt_frequencies,
1199 KnownFn::Keep => self.rt.rt_keep,
1200 KnownFn::Remove => self.rt.rt_remove,
1201 KnownFn::MapIndexed => self.rt.rt_map_indexed,
1202 KnownFn::Zipmap => self.rt.rt_zipmap,
1203 KnownFn::Complement => self.rt.rt_complement,
1204 KnownFn::WithOutStr => self.rt.rt_with_out_str,
1205 KnownFn::Peek => self.rt.rt_peek,
1206 KnownFn::Pop => self.rt.rt_pop,
1207 KnownFn::Vec => self.rt.rt_vec,
1208 KnownFn::Mapcat => self.rt.rt_mapcat,
1209 KnownFn::IsEmpty => self.rt.rt_is_empty,
1210 KnownFn::Repeatedly => self.rt.rt_repeatedly,
1211 _ => {
1212 return self.emit_unknown_call_from_args(args);
1213 }
1214 };
1215
1216 let arg_vals: Vec<_> = args.iter().map(|a| self.use_var(*a)).collect();
1218 let func_ref = self.import_func(rt_func);
1219 let call = self.builder.ins().call(func_ref, &arg_vals);
1220 Ok(self.builder.inst_results(call)[0])
1221 }
1222
1223 fn emit_atom_swap(&mut self, args: &[VarId]) -> CodegenResult<cranelift_codegen::ir::Value> {
1225 let atom_val = self.use_var(args[0]);
1227 let f_val = self.use_var(args[1]);
1228 let extra = &args[2..];
1229 let n = extra.len();
1230
1231 let (extra_ptr, extra_count) = if n > 0 {
1232 let slot =
1233 self.builder
1234 .create_sized_stack_slot(cranelift_codegen::ir::StackSlotData::new(
1235 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
1236 (n * 8) as u32,
1237 3,
1238 ));
1239 for (i, arg) in extra.iter().enumerate() {
1240 let val = self.use_var(*arg);
1241 self.builder.ins().stack_store(val, slot, (i * 8) as i32);
1242 }
1243 let addr = self.builder.ins().stack_addr(self.ptr_type, slot, 0);
1244 let count = self.builder.ins().iconst(types::I64, n as i64);
1245 (addr, count)
1246 } else {
1247 let null = self.builder.ins().iconst(self.ptr_type, 0);
1248 let zero = self.builder.ins().iconst(types::I64, 0);
1249 (null, zero)
1250 };
1251
1252 let func_ref = self.import_func(self.rt.rt_atom_swap);
1253 let call = self
1254 .builder
1255 .ins()
1256 .call(func_ref, &[atom_val, f_val, extra_ptr, extra_count]);
1257 Ok(self.builder.inst_results(call)[0])
1258 }
1259
1260 fn emit_with_bindings(
1264 &mut self,
1265 args: &[VarId],
1266 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1267 let body_var = *args.last().unwrap();
1269 let binding_args = &args[..args.len() - 1];
1270 let npairs = binding_args.len() / 2;
1271
1272 let body_val = self.use_var(body_var);
1273
1274 let (bindings_ptr, npairs_val) = if npairs > 0 {
1275 let n = binding_args.len();
1276 let slot =
1277 self.builder
1278 .create_sized_stack_slot(cranelift_codegen::ir::StackSlotData::new(
1279 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
1280 (n * 8) as u32,
1281 3,
1282 ));
1283 for (i, arg) in binding_args.iter().enumerate() {
1284 let val = self.use_var(*arg);
1285 self.builder.ins().stack_store(val, slot, (i * 8) as i32);
1286 }
1287 let addr = self.builder.ins().stack_addr(self.ptr_type, slot, 0);
1288 let count = self.builder.ins().iconst(types::I64, npairs as i64);
1289 (addr, count)
1290 } else {
1291 let null = self.builder.ins().iconst(self.ptr_type, 0);
1292 let zero = self.builder.ins().iconst(types::I64, 0);
1293 (null, zero)
1294 };
1295
1296 let func_ref = self.import_func(self.rt.rt_with_bindings);
1297 let call = self
1298 .builder
1299 .ins()
1300 .call(func_ref, &[bindings_ptr, npairs_val, body_val]);
1301 Ok(self.builder.inst_results(call)[0])
1302 }
1303
1304 fn emit_direct_call(
1306 &mut self,
1307 fn_name: &str,
1308 args: &[VarId],
1309 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1310 let func_id = self.user_funcs.get(fn_name).ok_or_else(|| {
1311 CodegenError::Codegen(format!("CallDirect: unknown function {fn_name}"))
1312 })?;
1313 let func_ref = self.import_func(*func_id);
1314 let arg_vals: Vec<_> = args.iter().map(|a| self.use_var(*a)).collect();
1315 let call = self.builder.ins().call(func_ref, &arg_vals);
1316 Ok(self.builder.inst_results(call)[0])
1317 }
1318
1319 fn emit_unknown_call(
1321 &mut self,
1322 callee: VarId,
1323 args: &[VarId],
1324 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1325 let callee_val = self.use_var(callee);
1326 let n = args.len();
1327
1328 if n == 0 {
1329 let null = self.builder.ins().iconst(self.ptr_type, 0);
1330 let zero = self.builder.ins().iconst(types::I64, 0);
1331 let func_ref = self.import_func(self.rt.rt_call);
1332 let call = self.builder.ins().call(func_ref, &[callee_val, null, zero]);
1333 return Ok(self.builder.inst_results(call)[0]);
1334 }
1335
1336 let slot = self
1338 .builder
1339 .create_sized_stack_slot(cranelift_codegen::ir::StackSlotData::new(
1340 cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
1341 (n * 8) as u32,
1342 3,
1343 ));
1344 for (i, arg) in args.iter().enumerate() {
1345 let val = self.use_var(*arg);
1346 self.builder.ins().stack_store(val, slot, (i * 8) as i32);
1347 }
1348 let slot_addr = self.builder.ins().stack_addr(self.ptr_type, slot, 0);
1349 let count = self.builder.ins().iconst(types::I64, n as i64);
1350
1351 let func_ref = self.import_func(self.rt.rt_call);
1352 let call = self
1353 .builder
1354 .ins()
1355 .call(func_ref, &[callee_val, slot_addr, count]);
1356 Ok(self.builder.inst_results(call)[0])
1357 }
1358
1359 fn emit_unknown_call_from_args(
1361 &mut self,
1362 _args: &[VarId],
1363 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1364 self.call_rt_0(self.rt.rt_const_nil)
1367 }
1368
1369 fn import_func(&mut self, func_id: FuncId) -> cranelift_codegen::ir::FuncRef {
1372 self.module.declare_func_in_func(func_id, self.builder.func)
1373 }
1374
1375 fn call_rt_0(&mut self, func_id: FuncId) -> CodegenResult<cranelift_codegen::ir::Value> {
1376 let func_ref = self.import_func(func_id);
1377 let call = self.builder.ins().call(func_ref, &[]);
1378 Ok(self.builder.inst_results(call)[0])
1379 }
1380
1381 fn call_rt_1(
1382 &mut self,
1383 func_id: FuncId,
1384 arg: cranelift_codegen::ir::Value,
1385 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1386 let func_ref = self.import_func(func_id);
1387 let call = self.builder.ins().call(func_ref, &[arg]);
1388 Ok(self.builder.inst_results(call)[0])
1389 }
1390
1391 fn call_rt_1_i8(
1393 &mut self,
1394 func_id: FuncId,
1395 arg: cranelift_codegen::ir::Value,
1396 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1397 let func_ref = self.import_func(func_id);
1398 let call = self.builder.ins().call(func_ref, &[arg]);
1399 Ok(self.builder.inst_results(call)[0])
1400 }
1401
1402 fn call_rt_2(
1403 &mut self,
1404 func_id: FuncId,
1405 a: cranelift_codegen::ir::Value,
1406 b: cranelift_codegen::ir::Value,
1407 ) -> CodegenResult<cranelift_codegen::ir::Value> {
1408 let func_ref = self.import_func(func_id);
1409 let call = self.builder.ins().call(func_ref, &[a, b]);
1410 Ok(self.builder.inst_results(call)[0])
1411 }
1412}
1413
1414fn declare_rt(
1418 module: &mut ObjectModule,
1419 name: &str,
1420 params: &[types::Type],
1421 ret: types::Type,
1422) -> CodegenResult<FuncId> {
1423 let mut sig = module.make_signature();
1424 sig.call_conv = CallConv::SystemV;
1425 for &t in params {
1426 sig.params.push(AbiParam::new(t));
1427 }
1428 sig.returns.push(AbiParam::new(ret));
1429 Ok(module.declare_function(name, Linkage::Import, &sig)?)
1430}
1431
1432fn declare_runtime_funcs(
1434 module: &mut ObjectModule,
1435 ptr: types::Type,
1436) -> CodegenResult<RuntimeFuncs> {
1437 let rt_safepoint = {
1440 let mut sig = module.make_signature();
1441 sig.call_conv = CallConv::SystemV;
1442 module.declare_function("rt_safepoint", Linkage::Import, &sig)?
1443 };
1444
1445 Ok(RuntimeFuncs {
1446 rt_safepoint,
1447 rt_const_nil: declare_rt(module, "rt_const_nil", &[], ptr)?,
1448 rt_const_true: declare_rt(module, "rt_const_true", &[], ptr)?,
1449 rt_const_false: declare_rt(module, "rt_const_false", &[], ptr)?,
1450 rt_const_long: declare_rt(module, "rt_const_long", &[types::I64], ptr)?,
1451 rt_const_double: declare_rt(module, "rt_const_double", &[types::F64], ptr)?,
1452 rt_const_char: declare_rt(module, "rt_const_char", &[types::I32], ptr)?,
1453 rt_const_string: declare_rt(module, "rt_const_string", &[ptr, types::I64], ptr)?,
1454 rt_const_keyword: declare_rt(module, "rt_const_keyword", &[ptr, types::I64], ptr)?,
1455 rt_const_symbol: declare_rt(module, "rt_const_symbol", &[ptr, types::I64], ptr)?,
1456 rt_truthiness: declare_rt(module, "rt_truthiness", &[ptr], types::I8)?,
1457 rt_add: declare_rt(module, "rt_add", &[ptr, ptr], ptr)?,
1458 rt_sub: declare_rt(module, "rt_sub", &[ptr, ptr], ptr)?,
1459 rt_mul: declare_rt(module, "rt_mul", &[ptr, ptr], ptr)?,
1460 rt_div: declare_rt(module, "rt_div", &[ptr, ptr], ptr)?,
1461 rt_rem: declare_rt(module, "rt_rem", &[ptr, ptr], ptr)?,
1462 rt_eq: declare_rt(module, "rt_eq", &[ptr, ptr], ptr)?,
1463 rt_lt: declare_rt(module, "rt_lt", &[ptr, ptr], ptr)?,
1464 rt_gt: declare_rt(module, "rt_gt", &[ptr, ptr], ptr)?,
1465 rt_lte: declare_rt(module, "rt_lte", &[ptr, ptr], ptr)?,
1466 rt_gte: declare_rt(module, "rt_gte", &[ptr, ptr], ptr)?,
1467 rt_alloc_vector: declare_rt(module, "rt_alloc_vector", &[ptr, types::I64], ptr)?,
1468 rt_alloc_map: declare_rt(module, "rt_alloc_map", &[ptr, types::I64], ptr)?,
1469 rt_alloc_set: declare_rt(module, "rt_alloc_set", &[ptr, types::I64], ptr)?,
1470 rt_alloc_list: declare_rt(module, "rt_alloc_list", &[ptr, types::I64], ptr)?,
1471 rt_alloc_cons: declare_rt(module, "rt_alloc_cons", &[ptr, ptr], ptr)?,
1472 rt_get: declare_rt(module, "rt_get", &[ptr, ptr], ptr)?,
1473 rt_count: declare_rt(module, "rt_count", &[ptr], ptr)?,
1474 rt_first: declare_rt(module, "rt_first", &[ptr], ptr)?,
1475 rt_rest: declare_rt(module, "rt_rest", &[ptr], ptr)?,
1476 rt_assoc: declare_rt(module, "rt_assoc", &[ptr, ptr, ptr], ptr)?,
1477 rt_conj: declare_rt(module, "rt_conj", &[ptr, ptr], ptr)?,
1478 rt_call: declare_rt(module, "rt_call", &[ptr, ptr, types::I64], ptr)?,
1479 rt_deref: declare_rt(module, "rt_deref", &[ptr], ptr)?,
1480 rt_println: declare_rt(module, "rt_println", &[ptr], ptr)?,
1481 rt_pr: declare_rt(module, "rt_pr", &[ptr], ptr)?,
1482 rt_is_nil: declare_rt(module, "rt_is_nil", &[ptr], ptr)?,
1483 rt_is_vector: declare_rt(module, "rt_is_vector", &[ptr], ptr)?,
1484 rt_is_map: declare_rt(module, "rt_is_map", &[ptr], ptr)?,
1485 rt_is_seq: declare_rt(module, "rt_is_seq", &[ptr], ptr)?,
1486 rt_identical: declare_rt(module, "rt_identical", &[ptr, ptr], ptr)?,
1487 rt_str: declare_rt(module, "rt_str", &[ptr], ptr)?,
1488 rt_load_global: declare_rt(
1489 module,
1490 "rt_load_global",
1491 &[ptr, types::I64, ptr, types::I64],
1492 ptr,
1493 )?,
1494 rt_def_var: declare_rt(
1495 module,
1496 "rt_def_var",
1497 &[ptr, types::I64, ptr, types::I64, ptr],
1498 ptr,
1499 )?,
1500 rt_make_fn: declare_rt(
1501 module,
1502 "rt_make_fn",
1503 &[ptr, types::I64, ptr, types::I64, ptr, types::I64],
1504 ptr,
1505 )?,
1506 rt_make_fn_variadic: declare_rt(
1508 module,
1509 "rt_make_fn_variadic",
1510 &[ptr, types::I64, ptr, types::I64, ptr, types::I64],
1511 ptr,
1512 )?,
1513 rt_make_fn_multi: declare_rt(
1515 module,
1516 "rt_make_fn_multi",
1517 &[ptr, types::I64, ptr, ptr, ptr, types::I64, ptr, types::I64],
1518 ptr,
1519 )?,
1520 rt_throw: declare_rt(module, "rt_throw", &[ptr], ptr)?,
1521 rt_try: declare_rt(module, "rt_try", &[ptr, ptr, ptr], ptr)?,
1522 rt_dissoc: declare_rt(module, "rt_dissoc", &[ptr, ptr], ptr)?,
1523 rt_disj: declare_rt(module, "rt_disj", &[ptr, ptr], ptr)?,
1524 rt_nth: declare_rt(module, "rt_nth", &[ptr, ptr], ptr)?,
1525 rt_contains: declare_rt(module, "rt_contains", &[ptr, ptr], ptr)?,
1526 rt_seq: declare_rt(module, "rt_seq", &[ptr], ptr)?,
1527 rt_lazy_seq: declare_rt(module, "rt_lazy_seq", &[ptr], ptr)?,
1528 rt_transient: declare_rt(module, "rt_transient", &[ptr], ptr)?,
1529 rt_assoc_bang: declare_rt(module, "rt_assoc_bang", &[ptr, ptr, ptr], ptr)?,
1530 rt_conj_bang: declare_rt(module, "rt_conj_bang", &[ptr, ptr], ptr)?,
1531 rt_persistent_bang: declare_rt(module, "rt_persistent_bang", &[ptr], ptr)?,
1532 rt_atom_reset: declare_rt(module, "rt_atom_reset", &[ptr, ptr], ptr)?,
1533 rt_atom_swap: declare_rt(module, "rt_atom_swap", &[ptr, ptr, ptr, types::I64], ptr)?,
1534 rt_apply: declare_rt(module, "rt_apply", &[ptr, ptr], ptr)?,
1535 rt_set_bang: declare_rt(module, "rt_set_bang", &[ptr, ptr], ptr)?,
1536 rt_with_bindings: declare_rt(module, "rt_with_bindings", &[ptr, types::I64, ptr], ptr)?,
1537 rt_load_var: declare_rt(
1538 module,
1539 "rt_load_var",
1540 &[ptr, types::I64, ptr, types::I64],
1541 ptr,
1542 )?,
1543 rt_reduce2: declare_rt(module, "rt_reduce2", &[ptr, ptr], ptr)?,
1544 rt_reduce3: declare_rt(module, "rt_reduce3", &[ptr, ptr, ptr], ptr)?,
1545 rt_map: declare_rt(module, "rt_map", &[ptr, ptr], ptr)?,
1546 rt_filter: declare_rt(module, "rt_filter", &[ptr, ptr], ptr)?,
1547 rt_mapv: declare_rt(module, "rt_mapv", &[ptr, ptr], ptr)?,
1548 rt_filterv: declare_rt(module, "rt_filterv", &[ptr, ptr], ptr)?,
1549 rt_some: declare_rt(module, "rt_some", &[ptr, ptr], ptr)?,
1550 rt_every: declare_rt(module, "rt_every", &[ptr, ptr], ptr)?,
1551 rt_into: declare_rt(module, "rt_into", &[ptr, ptr], ptr)?,
1552 rt_into3: declare_rt(module, "rt_into3", &[ptr, ptr, ptr], ptr)?,
1553 rt_group_by: declare_rt(module, "rt_group_by", &[ptr, ptr], ptr)?,
1554 rt_partition2: declare_rt(module, "rt_partition2", &[ptr, ptr], ptr)?,
1555 rt_partition3: declare_rt(module, "rt_partition3", &[ptr, ptr, ptr], ptr)?,
1556 rt_partition4: declare_rt(module, "rt_partition4", &[ptr, ptr, ptr, ptr], ptr)?,
1557 rt_frequencies: declare_rt(module, "rt_frequencies", &[ptr], ptr)?,
1558 rt_keep: declare_rt(module, "rt_keep", &[ptr, ptr], ptr)?,
1559 rt_remove: declare_rt(module, "rt_remove", &[ptr, ptr], ptr)?,
1560 rt_map_indexed: declare_rt(module, "rt_map_indexed", &[ptr, ptr], ptr)?,
1561 rt_zipmap: declare_rt(module, "rt_zipmap", &[ptr, ptr], ptr)?,
1562 rt_juxt: declare_rt(module, "rt_juxt", &[ptr, types::I64], ptr)?,
1563 rt_comp: declare_rt(module, "rt_comp", &[ptr, types::I64], ptr)?,
1564 rt_partial: declare_rt(module, "rt_partial", &[ptr, types::I64], ptr)?,
1565 rt_complement: declare_rt(module, "rt_complement", &[ptr], ptr)?,
1566 rt_concat: declare_rt(module, "rt_concat", &[ptr, types::I64], ptr)?,
1567 rt_range1: declare_rt(module, "rt_range1", &[ptr], ptr)?,
1568 rt_range2: declare_rt(module, "rt_range2", &[ptr, ptr], ptr)?,
1569 rt_range3: declare_rt(module, "rt_range3", &[ptr, ptr, ptr], ptr)?,
1570 rt_take: declare_rt(module, "rt_take", &[ptr, ptr], ptr)?,
1571 rt_drop: declare_rt(module, "rt_drop", &[ptr, ptr], ptr)?,
1572 rt_reverse: declare_rt(module, "rt_reverse", &[ptr], ptr)?,
1573 rt_sort: declare_rt(module, "rt_sort", &[ptr], ptr)?,
1574 rt_sort_by: declare_rt(module, "rt_sort_by", &[ptr, ptr], ptr)?,
1575 rt_keys: declare_rt(module, "rt_keys", &[ptr], ptr)?,
1576 rt_vals: declare_rt(module, "rt_vals", &[ptr], ptr)?,
1577 rt_merge: declare_rt(module, "rt_merge", &[ptr, types::I64], ptr)?,
1578 rt_update: declare_rt(module, "rt_update", &[ptr, ptr, ptr], ptr)?,
1579 rt_get_in: declare_rt(module, "rt_get_in", &[ptr, ptr], ptr)?,
1580 rt_assoc_in: declare_rt(module, "rt_assoc_in", &[ptr, ptr, ptr], ptr)?,
1581 rt_is_number: declare_rt(module, "rt_is_number", &[ptr], ptr)?,
1582 rt_is_string: declare_rt(module, "rt_is_string", &[ptr], ptr)?,
1583 rt_is_keyword: declare_rt(module, "rt_is_keyword", &[ptr], ptr)?,
1584 rt_is_symbol: declare_rt(module, "rt_is_symbol", &[ptr], ptr)?,
1585 rt_is_bool: declare_rt(module, "rt_is_bool", &[ptr], ptr)?,
1586 rt_is_int: declare_rt(module, "rt_is_int", &[ptr], ptr)?,
1587 rt_prn: declare_rt(module, "rt_prn", &[ptr], ptr)?,
1588 rt_print: declare_rt(module, "rt_print", &[ptr], ptr)?,
1589 rt_atom: declare_rt(module, "rt_atom", &[ptr], ptr)?,
1590 rt_str_n: declare_rt(module, "rt_str_n", &[ptr, types::I64], ptr)?,
1591 rt_println_n: declare_rt(module, "rt_println_n", &[ptr, types::I64], ptr)?,
1592 rt_with_out_str: declare_rt(module, "rt_with_out_str", &[ptr], ptr)?,
1593 rt_peek: declare_rt(module, "rt_peek", &[ptr], ptr)?,
1594 rt_pop: declare_rt(module, "rt_pop", &[ptr], ptr)?,
1595 rt_vec: declare_rt(module, "rt_vec", &[ptr], ptr)?,
1596 rt_mapcat: declare_rt(module, "rt_mapcat", &[ptr, ptr], ptr)?,
1597 rt_is_empty: declare_rt(module, "rt_is_empty", &[ptr], ptr)?,
1598 rt_repeatedly: declare_rt(module, "rt_repeatedly", &[ptr, ptr], ptr)?,
1599 rt_region_start: declare_rt(module, "rt_region_start", &[], ptr)?,
1601 rt_region_end: declare_rt(module, "rt_region_end", &[ptr], ptr)?,
1602 rt_region_alloc_vector: declare_rt(
1603 module,
1604 "rt_region_alloc_vector",
1605 &[ptr, ptr, types::I64],
1606 ptr,
1607 )?,
1608 rt_region_alloc_map: declare_rt(
1609 module,
1610 "rt_region_alloc_map",
1611 &[ptr, ptr, types::I64],
1612 ptr,
1613 )?,
1614 rt_region_alloc_set: declare_rt(
1615 module,
1616 "rt_region_alloc_set",
1617 &[ptr, ptr, types::I64],
1618 ptr,
1619 )?,
1620 rt_region_alloc_list: declare_rt(
1621 module,
1622 "rt_region_alloc_list",
1623 &[ptr, ptr, types::I64],
1624 ptr,
1625 )?,
1626 rt_region_alloc_cons: declare_rt(module, "rt_region_alloc_cons", &[ptr, ptr, ptr], ptr)?,
1627 })
1628}
1629
1630#[cfg(test)]
1633mod tests {
1634 use super::*;
1635 use cljrs_reader::Parser;
1636
1637 fn parse_body(src: &str) -> Vec<cljrs_reader::Form> {
1638 let mut parser = Parser::new(src.to_string(), "<test>".to_string());
1639 let mut forms = Vec::new();
1640 while let Ok(Some(form)) = parser.parse_one() {
1641 forms.push(form);
1642 }
1643 forms
1644 }
1645
1646 fn lower(
1647 name: &str,
1648 params: &[Arc<str>],
1649 body: &[cljrs_reader::Form],
1650 ) -> crate::ir::IrFunction {
1651 let name = name.to_string();
1653 let params = params.to_vec();
1654 let body = body.to_vec();
1655 std::thread::Builder::new()
1656 .stack_size(8 * 1024 * 1024)
1657 .spawn(move || {
1658 let globals = cljrs_stdlib::standard_env();
1659 let mut env = cljrs_eval::Env::new(globals, "user");
1660 crate::aot::lower_via_rust(Some(&name), "user", ¶ms, &body, &mut env).unwrap()
1661 })
1662 .unwrap()
1663 .join()
1664 .unwrap()
1665 }
1666
1667 #[test]
1668 fn test_compile_constant_function() {
1669 let body = parse_body("42");
1671 let ir = lower("f", &[], &body);
1672
1673 let mut compiler = Compiler::new().unwrap();
1674 let func_id = compiler.declare_function("f", 0).unwrap();
1675 compiler.compile_function(&ir, func_id).unwrap();
1676 let obj = compiler.finish();
1677 assert!(!obj.is_empty(), "should produce non-empty object code");
1678 }
1679
1680 #[test]
1681 fn test_compile_add_function() {
1682 let body = parse_body("(+ a b)");
1684 let params: Vec<Arc<str>> = vec![Arc::from("a"), Arc::from("b")];
1685 let ir = lower("add", ¶ms, &body);
1686
1687 let mut compiler = Compiler::new().unwrap();
1688 let func_id = compiler.declare_function("add", 2).unwrap();
1689 compiler.compile_function(&ir, func_id).unwrap();
1690 let obj = compiler.finish();
1691 assert!(!obj.is_empty());
1692 }
1693
1694 #[test]
1695 fn test_compile_if_expression() {
1696 let body = parse_body("(if x 1 2)");
1698 let params: Vec<Arc<str>> = vec![Arc::from("x")];
1699 let ir = lower("f", ¶ms, &body);
1700
1701 let mut compiler = Compiler::new().unwrap();
1702 let func_id = compiler.declare_function("f", 1).unwrap();
1703 compiler.compile_function(&ir, func_id).unwrap();
1704 let obj = compiler.finish();
1705 assert!(!obj.is_empty());
1706 }
1707
1708 #[test]
1709 fn test_compile_let_expression() {
1710 let body = parse_body("(let [y (+ x 1)] y)");
1712 let params: Vec<Arc<str>> = vec![Arc::from("x")];
1713 let ir = lower("f", ¶ms, &body);
1714
1715 let mut compiler = Compiler::new().unwrap();
1716 let func_id = compiler.declare_function("f", 1).unwrap();
1717 compiler.compile_function(&ir, func_id).unwrap();
1718 let obj = compiler.finish();
1719 assert!(!obj.is_empty());
1720 }
1721
1722 #[test]
1723 fn test_compile_loop_recur() {
1724 let body = parse_body("(loop [i 0 acc 0] (if (= i n) acc (recur (+ i 1) (+ acc i))))");
1726 let params: Vec<Arc<str>> = vec![Arc::from("n")];
1727 let ir = lower("sum", ¶ms, &body);
1728
1729 let mut compiler = Compiler::new().unwrap();
1730 let func_id = compiler.declare_function("sum", 1).unwrap();
1731 compiler.compile_function(&ir, func_id).unwrap();
1732 let obj = compiler.finish();
1733 assert!(!obj.is_empty());
1734 }
1735}