1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), warn(unused_extern_crates))]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5use codegen::ir::Function;
6use cranelift::{
7 codegen::ir::{FuncRef, StackSlot, instructions::BlockArg},
8 prelude::*,
9};
10use cranelift_jit::{JITBuilder, JITModule};
11use cranelift_module::{DataDescription, FuncId, FuncOrDataId, Linkage, Module, ModuleError};
12use cranelift_object::{ObjectBuilder, ObjectModule};
13use pretty_clif::CommentWriter;
14use revmc_backend::{
15 Backend, BackendTypes, Builder, OptimizationLevel, Result, TailCallKind, TypeMethods, U256,
16 eyre::eyre,
17};
18use std::{
19 collections::HashMap,
20 io::Write,
21 path::Path,
22 sync::{Arc, RwLock},
23};
24
25mod pretty_clif;
26
27pub use cranelift;
28pub use cranelift_jit;
29pub use cranelift_module;
30pub use cranelift_native;
31
32#[allow(missing_debug_implementations)]
34#[must_use]
35pub struct EvmCraneliftBackend {
36 builder_context: FunctionBuilderContext,
38
39 ctx: codegen::Context,
43
44 module: ModuleWrapper,
46
47 symbols: Symbols,
48
49 opt_level: OptimizationLevel,
50 comments: CommentWriter,
51 functions: Vec<FuncId>,
52}
53
54#[allow(clippy::new_without_default)]
55impl EvmCraneliftBackend {
56 pub fn is_supported() -> Result<(), &'static str> {
59 cranelift_native::builder().map(drop)
60 }
61
62 #[track_caller]
69 pub fn new(aot: bool, opt_level: OptimizationLevel) -> Self {
70 let symbols = Symbols::new();
71 let module = ModuleWrapper::new(aot, opt_level, &symbols).unwrap();
72 Self {
73 builder_context: FunctionBuilderContext::new(),
74 ctx: module.get().make_context(),
75 module,
76 symbols,
77 opt_level,
78 comments: CommentWriter::new(),
79 functions: Vec::new(),
80 }
81 }
82
83 fn finish_module(&mut self) -> Result<Option<ObjectModule>> {
84 let aot = match self.module {
85 ModuleWrapper::Jit(_) => {
86 let new = ModuleWrapper::new_jit(self.opt_level, self.symbols.clone())?;
88 let ModuleWrapper::Jit(old) = std::mem::replace(&mut self.module, new) else {
89 unreachable!()
90 };
91 unsafe { old.free_memory() };
92 None
93 }
94 ModuleWrapper::Aot(_) => {
95 let new = ModuleWrapper::new_aot(self.opt_level)?;
96 let ModuleWrapper::Aot(old) = std::mem::replace(&mut self.module, new) else {
97 unreachable!()
98 };
99 Some(old)
100 }
101 };
102 self.module.get().clear_context(&mut self.ctx);
103 Ok(aot)
104 }
105}
106
107impl BackendTypes for EvmCraneliftBackend {
108 type Type = Type;
109 type Value = Value;
110 type StackSlot = StackSlot;
111 type BasicBlock = Block;
112 type Function = FuncRef;
113}
114
115impl TypeMethods for EvmCraneliftBackend {
116 fn type_ptr(&self) -> Self::Type {
117 self.module.get().target_config().pointer_type()
118 }
119
120 fn type_ptr_sized_int(&self) -> Self::Type {
121 self.type_ptr()
122 }
123
124 fn type_int(&self, bits: u32) -> Self::Type {
125 bits.try_into().ok().and_then(Type::int).unwrap_or_else(|| unimplemented!("type: i{bits}"))
126 }
127
128 fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type {
129 unimplemented!("type: [{size} x {ty}]")
130 }
131
132 fn type_bit_width(&self, ty: Self::Type) -> u32 {
133 ty.bits()
134 }
135}
136
137impl Backend for EvmCraneliftBackend {
138 type Builder<'a> = EvmCraneliftBuilder<'a>;
139 type FuncId = FuncId;
140
141 fn ir_extension(&self) -> &'static str {
142 "clif"
143 }
144
145 fn set_module_name(&mut self, name: &str) {
146 let _ = name;
147 }
148
149 fn set_is_dumping(&mut self, yes: bool) {
150 self.ctx.set_disasm(yes);
151 }
152
153 fn set_debug_assertions(&mut self, yes: bool) {
154 let _ = yes;
155 }
156
157 fn opt_level(&self) -> OptimizationLevel {
158 self.opt_level
159 }
160
161 fn set_opt_level(&mut self, level: OptimizationLevel) {
162 self.opt_level = level;
165 }
166
167 fn is_aot(&self) -> bool {
168 self.module.is_aot()
169 }
170
171 fn function_name_is_unique(&self, name: &str) -> bool {
172 self.module.get().get_name(name).is_none()
173 }
174
175 fn dump_ir(&mut self, path: &Path) -> Result<()> {
176 crate::pretty_clif::write_clif_file(
177 path,
178 self.module.get().isa(),
179 &self.ctx.func,
180 &self.comments,
181 );
182 Ok(())
183 }
184
185 fn dump_disasm(&mut self, path: &Path) -> Result<()> {
186 if let Some(disasm) = &self.ctx.compiled_code().unwrap().vcode {
187 crate::pretty_clif::write_ir_file(path, |file| file.write_all(disasm.as_bytes()))
188 }
189 Ok(())
190 }
191
192 fn build_function(
193 &mut self,
194 name: &str,
195 ret: Option<Self::Type>,
196 params: &[Self::Type],
197 param_names: &[&str],
198 linkage: revmc_backend::Linkage,
199 ) -> Result<(Self::Builder<'_>, FuncId)> {
200 self.ctx.func.clear();
201 if let Some(ret) = ret {
202 self.ctx.func.signature.returns.push(AbiParam::new(ret));
203 }
204 for param in params {
205 self.ctx.func.signature.params.push(AbiParam::new(*param));
206 }
207 let _ = param_names;
208 let ptr_type = self.type_ptr();
209 let id = self.module.get_mut().declare_function(
210 name,
211 convert_linkage(linkage),
212 &self.ctx.func.signature,
213 )?;
214 self.functions.push(id);
215 let bcx = FunctionBuilder::new(&mut self.ctx.func, &mut self.builder_context);
216 let mut builder = EvmCraneliftBuilder {
217 module: &mut self.module,
218 comments: &mut self.comments,
219 bcx,
220 ptr_type,
221 symbols: self.symbols.clone(),
222 };
223 let entry = builder.bcx.create_block();
224 builder.bcx.append_block_params_for_function_params(entry);
225 builder.bcx.switch_to_block(entry);
226 Ok((builder, id))
227 }
228
229 fn verify_module(&mut self) -> Result<()> {
230 Ok(())
231 }
232
233 fn optimize_module(&mut self) -> Result<()> {
234 for &id in &self.functions {
240 self.module.get_mut().define_function(id, &mut self.ctx)?;
241 }
242 self.functions.clear();
243
244 self.module.get().clear_context(&mut self.ctx);
246
247 self.module.finalize_definitions()?;
250
251 self.comments.clear();
252
253 Ok(())
254 }
255
256 fn write_object<W: std::io::Write>(&mut self, w: W) -> Result<()> {
257 let module =
258 self.finish_module()?.ok_or_else(|| eyre!("cannot write object in JIT mode"))?;
259 let product = module.finish();
260 product.object.write_stream(w).map_err(|e| eyre!("{e}"))?;
261 Ok(())
262 }
263
264 fn jit_function(&mut self, id: Self::FuncId) -> Result<usize> {
265 self.module.get_finalized_function(id).map(|ptr| ptr as usize)
266 }
267
268 fn clear_ir(&mut self) -> Result<()> {
269 self.module.get().clear_context(&mut self.ctx);
270 self.comments.clear();
271 self.functions.clear();
272 Ok(())
273 }
274
275 unsafe fn free_function(&mut self, id: Self::FuncId) -> Result<()> {
276 let _ = id;
278 Ok(())
279 }
280
281 unsafe fn free_all_functions(&mut self) -> Result<()> {
282 self.finish_module().map(drop)
283 }
284}
285
286#[allow(missing_debug_implementations)]
288pub struct EvmCraneliftBuilder<'a> {
289 module: &'a mut ModuleWrapper,
290 comments: &'a mut CommentWriter,
291 bcx: FunctionBuilder<'a>,
292 ptr_type: Type,
293 symbols: Symbols,
294}
295
296impl BackendTypes for EvmCraneliftBuilder<'_> {
297 type Type = <EvmCraneliftBackend as BackendTypes>::Type;
298 type Value = <EvmCraneliftBackend as BackendTypes>::Value;
299 type StackSlot = <EvmCraneliftBackend as BackendTypes>::StackSlot;
300 type BasicBlock = <EvmCraneliftBackend as BackendTypes>::BasicBlock;
301 type Function = <EvmCraneliftBackend as BackendTypes>::Function;
302}
303
304impl TypeMethods for EvmCraneliftBuilder<'_> {
305 fn type_ptr(&self) -> Self::Type {
306 self.ptr_type
307 }
308
309 fn type_ptr_sized_int(&self) -> Self::Type {
310 self.ptr_type
311 }
312
313 fn type_int(&self, bits: u32) -> Self::Type {
314 bits.try_into().ok().and_then(Type::int).unwrap_or_else(|| unimplemented!("type: i{bits}"))
315 }
316
317 fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type {
318 unimplemented!("type: [{size} x {ty}]")
319 }
320
321 fn type_bit_width(&self, ty: Self::Type) -> u32 {
322 ty.bits()
323 }
324}
325
326impl<'a> Builder for EvmCraneliftBuilder<'a> {
327 fn create_block(&mut self, name: &str) -> Self::BasicBlock {
328 let block = self.bcx.create_block();
329 if !name.is_empty() && self.comments.enabled() {
330 self.comments.add_comment(block, name);
331 }
332 block
333 }
334
335 fn create_block_after(&mut self, after: Self::BasicBlock, name: &str) -> Self::BasicBlock {
336 let block = self.create_block(name);
337 self.bcx.insert_block_after(block, after);
338 block
339 }
340
341 fn switch_to_block(&mut self, block: Self::BasicBlock) {
342 self.bcx.switch_to_block(block);
343 }
344
345 fn seal_block(&mut self, block: Self::BasicBlock) {
346 self.bcx.seal_block(block);
347 }
348
349 fn seal_all_blocks(&mut self) {
350 self.bcx.seal_all_blocks();
351 }
352
353 fn set_current_block_cold(&mut self) {
354 self.bcx.set_cold_block(self.bcx.current_block().unwrap());
355 }
356
357 fn current_block(&mut self) -> Option<Self::BasicBlock> {
358 self.bcx.current_block()
359 }
360
361 fn block_addr(&mut self, _block: Self::BasicBlock) -> Option<Self::Value> {
362 None
363 }
364
365 fn add_comment_to_current_inst(&mut self, comment: &str) {
366 let Some(block) = self.bcx.current_block() else { return };
367 let Some(inst) = self.bcx.func.layout.last_inst(block) else { return };
368 self.comments.add_comment(inst, comment);
369 }
370
371 fn fn_param(&mut self, index: usize) -> Self::Value {
372 let block = self.current_block().unwrap();
373 self.bcx.block_params(block)[index]
374 }
375
376 fn num_fn_params(&self) -> usize {
377 self.bcx.func.signature.params.len()
378 }
379
380 fn bool_const(&mut self, value: bool) -> Self::Value {
381 self.iconst(types::I8, value as i64)
382 }
383
384 fn iconst(&mut self, ty: Self::Type, value: i64) -> Self::Value {
385 self.bcx.ins().iconst(ty, value)
386 }
387
388 fn uconst(&mut self, ty: Self::Type, value: u64) -> Self::Value {
389 self.iconst(ty, value as i64)
390 }
391
392 fn iconst_256(&mut self, value: U256) -> Self::Value {
393 let _ = value;
394 todo!("no i256 :(")
395 }
396
397 fn str_const(&mut self, value: &str) -> Self::Value {
398 let mut data = DataDescription::new();
401 data.define(value.as_bytes().into());
402 let msg_id = self.module.get_mut().declare_anonymous_data(false, false).unwrap();
403
404 let _ = self.module.get_mut().define_data(msg_id, &data);
406
407 let local_msg_id = self.module.get().declare_data_in_func(msg_id, self.bcx.func);
408 if self.comments.enabled() {
409 self.comments.add_comment(local_msg_id, value);
410 }
411 self.bcx.ins().global_value(self.ptr_type, local_msg_id)
412 }
413
414 fn nullptr(&mut self) -> Self::Value {
415 self.iconst(self.ptr_type, 0)
416 }
417
418 fn new_stack_slot_raw(&mut self, ty: Self::Type, name: &str) -> Self::StackSlot {
419 let _ = name;
451 self.bcx.create_sized_stack_slot(StackSlotData {
452 kind: StackSlotKind::ExplicitSlot,
453 size: ty.bytes(),
454 align_shift: 1,
455 })
456 }
457
458 fn stack_load(&mut self, ty: Self::Type, slot: Self::StackSlot, name: &str) -> Self::Value {
459 let _ = name;
460 self.bcx.ins().stack_load(ty, slot, 0)
461 }
462
463 fn stack_store(&mut self, value: Self::Value, slot: Self::StackSlot) {
464 self.bcx.ins().stack_store(value, slot, 0);
465 }
466
467 fn stack_addr(&mut self, ty: Self::Type, slot: Self::StackSlot) -> Self::Value {
468 self.bcx.ins().stack_addr(ty, slot, 0)
469 }
470
471 fn load(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value {
472 let _ = name;
473 self.bcx.ins().load(ty, MemFlags::trusted(), ptr, 0)
474 }
475
476 fn load_unaligned(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value {
477 let _ = name;
478 self.bcx.ins().load(ty, MemFlags::new().with_notrap(), ptr, 0)
479 }
480
481 fn store(&mut self, value: Self::Value, ptr: Self::Value) {
482 self.bcx.ins().store(MemFlags::trusted(), value, ptr, 0);
483 }
484
485 fn store_unaligned(&mut self, value: Self::Value, ptr: Self::Value) {
486 self.bcx.ins().store(MemFlags::new().with_notrap(), value, ptr, 0);
487 }
488
489 fn nop(&mut self) {
490 self.bcx.ins().nop();
491 }
492
493 fn ret(&mut self, values: &[Self::Value]) {
494 self.bcx.ins().return_(values);
495 }
496
497 fn icmp(
498 &mut self,
499 cond: revmc_backend::IntCC,
500 lhs: Self::Value,
501 rhs: Self::Value,
502 ) -> Self::Value {
503 self.bcx.ins().icmp(convert_intcc(cond), lhs, rhs)
504 }
505
506 fn icmp_imm(&mut self, cond: revmc_backend::IntCC, lhs: Self::Value, rhs: i64) -> Self::Value {
507 self.bcx.ins().icmp_imm(convert_intcc(cond), lhs, rhs)
508 }
509
510 fn is_null(&mut self, ptr: Self::Value) -> Self::Value {
511 self.bcx.ins().icmp_imm(IntCC::Equal, ptr, 0)
512 }
513
514 fn is_not_null(&mut self, ptr: Self::Value) -> Self::Value {
515 self.bcx.ins().icmp_imm(IntCC::NotEqual, ptr, 0)
516 }
517
518 fn br(&mut self, dest: Self::BasicBlock) {
519 self.bcx.ins().jump(dest, &[]);
520 }
521
522 fn brif(
523 &mut self,
524 cond: Self::Value,
525 then_block: Self::BasicBlock,
526 else_block: Self::BasicBlock,
527 ) {
528 self.bcx.ins().brif(cond, then_block, &[], else_block, &[]);
529 }
530
531 fn switch(
532 &mut self,
533 index: Self::Value,
534 default: Self::BasicBlock,
535 targets: &[(u64, Self::BasicBlock)],
536 default_is_cold: bool,
537 ) {
538 let _ = default_is_cold;
539 let mut switch = cranelift::frontend::Switch::new();
540 for (value, block) in targets {
541 switch.set_entry(*value as u128, *block);
542 }
543 switch.emit(&mut self.bcx, index, default)
544 }
545
546 fn br_indirect(&mut self, _address: Self::Value, _destinations: &[Self::BasicBlock]) {
547 unimplemented!()
548 }
549
550 fn phi(&mut self, ty: Self::Type, incoming: &[(Self::Value, Self::BasicBlock)]) -> Self::Value {
551 let current = self.current_block().unwrap();
552 let param = self.bcx.append_block_param(current, ty);
553 for &(value, block) in incoming {
554 self.bcx.switch_to_block(block);
555 let last_inst = self.bcx.func.layout.last_inst(block).unwrap();
556 let src = self.bcx.ins().jump(current, &[BlockArg::Value(value)]);
557 self.bcx.func.transplant_inst(last_inst, src);
558 }
559 self.bcx.switch_to_block(current);
560 param
561 }
562
563 fn select(
564 &mut self,
565 cond: Self::Value,
566 then_value: Self::Value,
567 else_value: Self::Value,
568 ) -> Self::Value {
569 self.bcx.ins().select(cond, then_value, else_value)
570 }
571
572 fn lazy_select(
573 &mut self,
574 cond: Self::Value,
575 ty: Self::Type,
576 then_value: impl FnOnce(&mut Self) -> Self::Value,
577 else_value: impl FnOnce(&mut Self) -> Self::Value,
578 ) -> Self::Value {
579 let then_block = if let Some(current) = self.current_block() {
580 self.create_block_after(current, "then")
581 } else {
582 self.create_block("then")
583 };
584 let else_block = self.create_block_after(then_block, "else");
585 let done_block = self.create_block_after(else_block, "contd");
586 let done_value = self.bcx.append_block_param(done_block, ty);
587
588 self.brif(cond, then_block, else_block);
589
590 self.seal_block(then_block);
591 self.switch_to_block(then_block);
592 let then_value = then_value(self);
593 self.bcx.ins().jump(done_block, &[BlockArg::Value(then_value)]);
594
595 self.seal_block(else_block);
596 self.switch_to_block(else_block);
597 let else_value = else_value(self);
598 self.bcx.ins().jump(done_block, &[BlockArg::Value(else_value)]);
599
600 self.seal_block(done_block);
601 self.switch_to_block(done_block);
602 done_value
603 }
604
605 fn iadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
606 self.bcx.ins().iadd(lhs, rhs)
607 }
608
609 fn isub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
610 self.bcx.ins().isub(lhs, rhs)
611 }
612
613 fn imul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
614 self.bcx.ins().imul(lhs, rhs)
615 }
616
617 fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
618 self.bcx.ins().udiv(lhs, rhs)
619 }
620
621 fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
622 self.bcx.ins().sdiv(lhs, rhs)
623 }
624
625 fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
626 self.bcx.ins().urem(lhs, rhs)
627 }
628
629 fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
630 self.bcx.ins().srem(lhs, rhs)
631 }
632
633 fn iadd_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
634 self.bcx.ins().iadd_imm(lhs, rhs)
635 }
636
637 fn isub_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
638 self.iadd_imm(lhs, -rhs)
639 }
640
641 fn imul_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
642 self.bcx.ins().imul_imm(lhs, rhs)
643 }
644
645 fn uadd_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
646 self.bcx.ins().uadd_overflow(lhs, rhs)
647 }
648
649 fn usub_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
650 self.bcx.ins().usub_overflow(lhs, rhs)
651 }
652
653 fn uadd_sat(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
654 self.bcx.ins().uadd_sat(lhs, rhs)
655 }
656
657 fn umax(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
658 self.bcx.ins().umax(lhs, rhs)
659 }
660
661 fn umin(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
662 self.bcx.ins().umin(lhs, rhs)
663 }
664
665 fn bswap(&mut self, value: Self::Value) -> Self::Value {
666 self.bcx.ins().bswap(value)
667 }
668
669 fn bitor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
670 self.bcx.ins().bor(lhs, rhs)
671 }
672
673 fn bitand(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
674 self.bcx.ins().band(lhs, rhs)
675 }
676
677 fn bitxor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
678 self.bcx.ins().bxor(lhs, rhs)
679 }
680
681 fn bitnot(&mut self, value: Self::Value) -> Self::Value {
682 self.bcx.ins().bnot(value)
683 }
684
685 fn clz(&mut self, value: Self::Value) -> Self::Value {
686 self.bcx.ins().clz(value)
687 }
688
689 fn bitor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
690 self.bcx.ins().bor_imm(lhs, rhs)
691 }
692
693 fn bitand_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
694 self.bcx.ins().band_imm(lhs, rhs)
695 }
696
697 fn bitxor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
698 self.bcx.ins().bxor_imm(lhs, rhs)
699 }
700
701 fn ishl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
702 self.bcx.ins().ishl(lhs, rhs)
703 }
704
705 fn ushr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
706 self.bcx.ins().ushr(lhs, rhs)
707 }
708
709 fn sshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
710 self.bcx.ins().sshr(lhs, rhs)
711 }
712
713 fn zext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value {
714 self.bcx.ins().uextend(ty, value)
715 }
716
717 fn sext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value {
718 self.bcx.ins().sextend(ty, value)
719 }
720
721 fn ireduce(&mut self, to: Self::Type, value: Self::Value) -> Self::Value {
722 self.bcx.ins().ireduce(to, value)
723 }
724
725 fn inttoptr(&mut self, value: Self::Value, _ty: Self::Type) -> Self::Value {
726 value
728 }
729
730 fn gep(
731 &mut self,
732 ty: Self::Type,
733 ptr: Self::Value,
734 indexes: &[Self::Value],
735 name: &str,
736 ) -> Self::Value {
737 let _ = name;
738 let offset = self.bcx.ins().imul_imm(*indexes.first().unwrap(), ty.bytes() as i64);
739 self.bcx.ins().iadd(ptr, offset)
740 }
741
742 fn tail_call(
743 &mut self,
744 function: Self::Function,
745 args: &[Self::Value],
746 tail_call: TailCallKind,
747 ) -> Option<Self::Value> {
748 if tail_call != TailCallKind::None {
749 todo!();
750 }
751 let ins = self.bcx.ins().call(function, args);
752 self.bcx.inst_results(ins).first().copied()
753 }
754
755 fn is_compile_time_known(&mut self, _value: Self::Value) -> Option<Self::Value> {
756 None
757 }
758
759 fn memcpy(&mut self, dst: Self::Value, src: Self::Value, len: Self::Value) {
760 let config = self.module.get().target_config();
761 self.bcx.call_memcpy(config, dst, src, len)
762 }
763
764 fn unreachable(&mut self) {
765 self.bcx.ins().trap(TrapCode::user(0).unwrap());
766 }
767
768 fn get_or_build_function(
769 &mut self,
770 name: &str,
771 params: &[Self::Type],
772 ret: Option<Self::Type>,
773 linkage: revmc_backend::Linkage,
774 build: impl FnOnce(&mut Self),
775 ) -> Self::Function {
776 if let Some(f) = self.get_function(name) {
777 return f;
778 }
779
780 let mut sig = self.module.get().make_signature();
781 if let Some(ret) = ret {
782 sig.returns.push(AbiParam::new(ret));
783 }
784 for param in params {
785 sig.params.push(AbiParam::new(*param));
786 }
787
788 let id =
789 self.module.get_mut().declare_function(name, convert_linkage(linkage), &sig).unwrap();
790
791 let mut func = Function::new();
792 func.signature = sig;
793 let mut builder_ctx = FunctionBuilderContext::new();
794 let new_bcx = FunctionBuilder::new(&mut func, &mut builder_ctx);
795 let new_bcx =
797 unsafe { std::mem::transmute::<FunctionBuilder<'_>, FunctionBuilder<'a>>(new_bcx) };
798 let old_bcx = std::mem::replace(&mut self.bcx, new_bcx);
799
800 let f = self.module.get_mut().declare_func_in_func(id, self.bcx.func);
801
802 let entry = self.bcx.create_block();
803 self.bcx.append_block_params_for_function_params(entry);
804 build(self);
805
806 self.bcx = old_bcx;
807
808 f
809 }
810
811 fn get_function(&mut self, name: &str) -> Option<Self::Function> {
812 self.module
813 .get()
814 .get_name(name)
815 .and_then(|id| match id {
816 FuncOrDataId::Func(f) => Some(f),
817 FuncOrDataId::Data(_) => None,
818 })
819 .map(|id| self.module.get_mut().declare_func_in_func(id, self.bcx.func))
820 }
821
822 fn get_printf_function(&mut self) -> Self::Function {
823 if let Some(f) = self.get_function("printf") {
824 return f;
825 }
826
827 unimplemented!()
828 }
829
830 fn add_function(
831 &mut self,
832 name: &str,
833 params: &[Self::Type],
834 ret: Option<Self::Type>,
835 address: Option<usize>,
836 linkage: revmc_backend::Linkage,
837 ) -> Self::Function {
838 let mut sig = self.module.get().make_signature();
839 if let Some(ret) = ret {
840 sig.returns.push(AbiParam::new(ret));
841 }
842 for param in params {
843 sig.params.push(AbiParam::new(*param));
844 }
845 if let Some(address) = address {
846 self.symbols.insert(name.to_string(), address as *const u8);
847 }
848 let id =
849 self.module.get_mut().declare_function(name, convert_linkage(linkage), &sig).unwrap();
850 self.module.get_mut().declare_func_in_func(id, self.bcx.func)
851 }
852
853 fn add_function_attribute(
854 &mut self,
855 function: Option<Self::Function>,
856 attribute: revmc_backend::Attribute,
857 loc: revmc_backend::FunctionAttributeLocation,
858 ) {
859 let _ = function;
860 let _ = attribute;
861 let _ = loc;
862 }
864}
865
866#[derive(Clone, Debug, Default)]
867struct Symbols(Arc<RwLock<HashMap<String, usize>>>);
868
869impl Symbols {
870 fn new() -> Self {
871 Self::default()
872 }
873
874 fn get(&self, name: &str) -> Option<*const u8> {
875 self.0.read().unwrap().get(name).copied().map(|addr| addr as *const u8)
876 }
877
878 fn insert(&self, name: String, ptr: *const u8) -> Option<*const u8> {
879 self.0.write().unwrap().insert(name, ptr as usize).map(|addr| addr as *const u8)
880 }
881}
882
883#[allow(clippy::large_enum_variant)]
884enum ModuleWrapper {
885 Jit(JITModule),
886 Aot(ObjectModule),
887}
888
889impl ModuleWrapper {
890 fn new(aot: bool, opt_level: OptimizationLevel, symbols: &Symbols) -> Result<Self> {
891 if aot { Self::new_aot(opt_level) } else { Self::new_jit(opt_level, symbols.clone()) }
892 }
893
894 fn new_jit(opt_level: OptimizationLevel, symbols: Symbols) -> Result<Self> {
895 let mut flag_builder = settings::builder();
897 flag_builder.set("opt_level", opt_level_flag(opt_level))?;
898 flag_builder.set("is_pic", "false")?;
899 let isa_builder = cranelift_native::builder().map_err(|s| eyre!(s))?;
900 let isa = isa_builder.finish(settings::Flags::new(flag_builder))?;
901
902 let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
903 builder.symbol_lookup_fn(Box::new(move |s| symbols.get(s)));
904 Ok(Self::Jit(JITModule::new(builder)))
905 }
906
907 fn new_aot(opt_level: OptimizationLevel) -> Result<Self> {
908 let mut flag_builder = settings::builder();
909 flag_builder.set("opt_level", opt_level_flag(opt_level))?;
910 let isa_builder = cranelift_native::builder().map_err(|s| eyre!(s))?;
911 let isa = isa_builder.finish(settings::Flags::new(flag_builder))?;
912
913 let builder =
914 ObjectBuilder::new(isa, "jit".to_string(), cranelift_module::default_libcall_names())?;
915 Ok(Self::Aot(ObjectModule::new(builder)))
916 }
917
918 fn is_aot(&self) -> bool {
919 matches!(self, Self::Aot(_))
920 }
921
922 #[inline]
923 fn get(&self) -> &dyn Module {
924 match self {
925 Self::Jit(module) => module,
926 Self::Aot(module) => module,
927 }
928 }
929
930 #[inline]
931 fn get_mut(&mut self) -> &mut dyn Module {
932 match self {
933 Self::Jit(module) => module,
934 Self::Aot(module) => module,
935 }
936 }
937
938 #[allow(clippy::result_large_err)]
939 fn finalize_definitions(&mut self) -> Result<(), ModuleError> {
940 match self {
941 Self::Jit(module) => module.finalize_definitions(),
942 Self::Aot(_) => Ok(()),
943 }
944 }
945
946 fn get_finalized_function(&self, id: FuncId) -> Result<*const u8> {
947 match self {
948 Self::Jit(module) => Ok(module.get_finalized_function(id)),
949 Self::Aot(_) => Err(eyre!("cannot get finalized JIT function in AOT mode")),
950 }
951 }
952}
953
954fn convert_intcc(cond: revmc_backend::IntCC) -> IntCC {
955 match cond {
956 revmc_backend::IntCC::Equal => IntCC::Equal,
957 revmc_backend::IntCC::NotEqual => IntCC::NotEqual,
958 revmc_backend::IntCC::SignedLessThan => IntCC::SignedLessThan,
959 revmc_backend::IntCC::SignedGreaterThanOrEqual => IntCC::SignedGreaterThanOrEqual,
960 revmc_backend::IntCC::SignedGreaterThan => IntCC::SignedGreaterThan,
961 revmc_backend::IntCC::SignedLessThanOrEqual => IntCC::SignedLessThanOrEqual,
962 revmc_backend::IntCC::UnsignedLessThan => IntCC::UnsignedLessThan,
963 revmc_backend::IntCC::UnsignedGreaterThanOrEqual => IntCC::UnsignedGreaterThanOrEqual,
964 revmc_backend::IntCC::UnsignedGreaterThan => IntCC::UnsignedGreaterThan,
965 revmc_backend::IntCC::UnsignedLessThanOrEqual => IntCC::UnsignedLessThanOrEqual,
966 }
967}
968
969fn convert_linkage(linkage: revmc_backend::Linkage) -> Linkage {
970 match linkage {
971 revmc_backend::Linkage::Import => Linkage::Import,
972 revmc_backend::Linkage::Public => Linkage::Export,
973 revmc_backend::Linkage::Private => Linkage::Local,
974 }
975}
976
977fn opt_level_flag(opt_level: OptimizationLevel) -> &'static str {
978 match opt_level {
979 OptimizationLevel::None => "none",
980 OptimizationLevel::Less | OptimizationLevel::Default | OptimizationLevel::Aggressive => {
981 "speed"
982 }
983 }
984}