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