1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), warn(unused_extern_crates))]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5#[macro_use]
6extern crate tracing;
7
8use alloy_primitives::map::{FxBuildHasher, HashSet};
9use inkwell::{
10 AddressSpace, IntPredicate,
11 attributes::{Attribute, AttributeLoc},
12 basic_block::BasicBlock,
13 debug_info::{
14 AsDIScope, DICompileUnit, DIFlags, DIFlagsConstants, DISubprogram, DWARFEmissionKind,
15 DWARFSourceLanguage, DebugInfoBuilder,
16 },
17 module::{FlagBehavior, Module},
18 passes::PassBuilderOptions,
19 support::error_handling::install_fatal_error_handler,
20 targets::{
21 CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, TargetTriple,
22 },
23 types::{
24 AnyType, AnyTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, PointerType,
25 StringRadix, VoidType,
26 },
27 values::{
28 AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue,
29 FunctionValue, InstructionValue, PointerValue,
30 },
31};
32use object::{Object, ObjectSymbol};
33use revmc_backend::{
34 Backend, BackendConfig, BackendTypes, Builder, CallConv, IntCC, OptimizationLevel, Result,
35 TailCallKind, TypeMethods, U256, eyre, format_bytes,
36};
37use std::{
38 cell::Cell,
39 ffi::{CStr, CString},
40 fmt::{self, Write},
41 iter,
42 mem::ManuallyDrop,
43 path::Path,
44 sync::{
45 Arc, Once, OnceLock,
46 atomic::{AtomicU64, AtomicUsize, Ordering},
47 },
48};
49
50pub use inkwell::{self, context::Context};
51
52mod cpp;
53
54mod dh;
55pub mod orc;
56
57mod utils;
58pub(crate) use utils::*;
59
60const DEFAULT_WEIGHT: u32 = 20000;
62
63#[derive(Clone, Copy, Debug, Default)]
68pub struct JitMemoryUsage {
69 pub code_bytes: usize,
71 pub data_bytes: usize,
73}
74
75impl JitMemoryUsage {
76 pub fn total_bytes(&self) -> usize {
78 self.code_bytes + self.data_bytes
79 }
80}
81
82impl fmt::Display for JitMemoryUsage {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 write!(
85 f,
86 "total: {}, code: {}, data: {}",
87 format_bytes(self.total_bytes()),
88 format_bytes(self.code_bytes),
89 format_bytes(self.data_bytes),
90 )
91 }
92}
93
94struct JitMemoryCounters {
99 code_bytes: AtomicUsize,
100 data_bytes: AtomicUsize,
101}
102
103impl JitMemoryCounters {
104 fn get(&self) -> JitMemoryUsage {
105 JitMemoryUsage {
106 code_bytes: self.code_bytes.load(Ordering::Relaxed),
107 data_bytes: self.data_bytes.load(Ordering::Relaxed),
108 }
109 }
110}
111
112pub fn jit_memory_usage() -> Option<JitMemoryUsage> {
116 GlobalOrcJit::try_get().map(|g| g.memory_counters.get())
117}
118
119pub fn global_gc() {
121 if let Some(orc) = GlobalOrcJit::try_get() {
122 orc.gc();
123 }
124}
125
126type FxHashMap<K, V> = alloy_primitives::map::HashMap<K, V, FxBuildHasher>;
127
128#[derive(Debug)]
130#[must_use]
131pub struct EvmLlvmBackend {
132 cx: &'static Context,
133 _dh: dh::DiagnosticHandlerGuard,
134 bcx: inkwell::builder::Builder<'static>,
135 module: Module<'static>,
136 machine: TargetMachine,
137
138 orc: Option<OrcJitState>,
141 _tscx: Option<orc::ThreadSafeContext>,
143 _cx_handle: Option<Box<ManuallyDrop<Context>>>,
145 _aot_cx: Option<Box<Context>>,
147
148 di_state: Option<DiState>,
150
151 ty_void: VoidType<'static>,
152 ty_ptr: PointerType<'static>,
153 ty_i1: IntType<'static>,
154 ty_i8: IntType<'static>,
155 ty_i32: IntType<'static>,
156 ty_i64: IntType<'static>,
157 ty_i256: IntType<'static>,
158 ty_isize: IntType<'static>,
159
160 aot: bool,
161 backend_config: BackendConfig,
162 scratch: String,
163 function_counter: u32,
165 function_names: FxHashMap<u32, String>,
167}
168
169thread_local! {
172 static OBJ_CAPTURE: Cell<*mut Option<Vec<u8>>> = const { Cell::new(std::ptr::null_mut()) };
173}
174
175struct ScopedObjCapture {
177 prev: *mut Option<Vec<u8>>,
178}
179
180impl ScopedObjCapture {
181 fn install(slot: &mut Option<Vec<u8>>) -> Self {
182 Self { prev: OBJ_CAPTURE.replace(slot as *mut _) }
183 }
184}
185
186impl Drop for ScopedObjCapture {
187 fn drop(&mut self) {
188 OBJ_CAPTURE.set(self.prev);
189 }
190}
191
192fn obj_capture_transform(obj: &[u8]) -> Result<Option<Vec<u8>>, String> {
193 OBJ_CAPTURE.with(|tls| {
194 let ptr = tls.get();
195 if !ptr.is_null() {
196 unsafe { *ptr = Some(obj.to_vec()) };
197 }
198 });
199 Ok(None)
200}
201
202struct GlobalOrcJit {
211 builtins_jd: orc::JITDylibRef,
214
215 builtins_defined: std::sync::Mutex<HashSet<CString>>,
217
218 next_dylib_id: AtomicU64,
219
220 memory_counters: &'static JitMemoryCounters,
222
223 jit: orc::LLJIT,
224}
225
226impl GlobalOrcJit {
227 fn global() -> &'static OnceLock<Result<Self, String>> {
228 static GLOBAL: OnceLock<Result<GlobalOrcJit, String>> = OnceLock::new();
229 &GLOBAL
230 }
231
232 fn try_get() -> Option<&'static Self> {
233 Self::global().get().and_then(|r| r.as_ref().ok())
234 }
235
236 fn get(
237 debug_support: bool,
238 profiling_support: bool,
239 simple_perf: bool,
240 ) -> Result<&'static Self> {
241 let result = Self::global().get_or_init(|| {
242 init().map_err(|e| e.to_string())?;
243 let jit =
244 orc::LLJIT::builder().concurrent_compiler().build().map_err(|e| e.to_string())?;
245 jit.get_execution_session().set_default_error_reporter();
246 jit.get_obj_transform_layer().set_transform(obj_capture_transform);
247
248 if debug_support && let Err(e) = jit.enable_debug_support() {
250 warn!("failed to enable JIT debug support: {e}");
251 }
252 if profiling_support && let Err(e) = jit.enable_perf_support() {
253 warn!("failed to enable JIT perf support: {e}");
254 }
255 if simple_perf && let Err(e) = jit.enable_simple_perf() {
256 warn!("failed to enable simple perf map support: {e}");
257 }
258
259 let memory_counters: &'static JitMemoryCounters =
261 Box::leak(Box::new(JitMemoryCounters {
262 code_bytes: AtomicUsize::new(0),
263 data_bytes: AtomicUsize::new(0),
264 }));
265 orc::cvt(unsafe {
266 cpp::revmc_llvm_lljit_enable_memory_usage(
267 jit.as_inner(),
268 &memory_counters.code_bytes,
269 &memory_counters.data_bytes,
270 )
271 })
272 .map_err(|e| e.to_string())?;
273
274 let builtins_jd = jit.get_execution_session().create_bare_jit_dylib(c"revmc.builtins");
275
276 Ok(Self {
277 jit,
278 builtins_jd,
279 builtins_defined: Default::default(),
280 next_dylib_id: Default::default(),
281 memory_counters,
282 })
283 });
284 match result {
285 Ok(g) => Ok(g),
286 Err(e) => Err(eyre::eyre!("{e}")),
287 }
288 }
289
290 fn create_jit_dylib(&self) -> orc::JITDylibRef {
292 let id = self.next_dylib_id.fetch_add(1, Ordering::Relaxed);
293 let name = CString::new(format!("revmc.compiler.{id}")).unwrap();
294 let es = self.jit.get_execution_session();
295 let jd = es.create_bare_jit_dylib(&name);
296 jd.add_to_link_order(self.builtins_jd);
298 let prefix = self.jit.get_global_prefix();
301 if let Ok(generator) = orc::DefinitionGenerator::for_current_process(prefix) {
302 jd.add_generator(generator);
303 }
304 jd
305 }
306
307 fn remove_jit_dylib(&self, jd: orc::JITDylibRef) {
309 let es = self.jit.get_execution_session();
310 if let Err(e) = es.remove_jit_dylib(jd) {
311 error!("failed to remove JITDylib: {e}");
312 }
313 es.get_symbol_string_pool().clear_dead_entries();
315 }
316
317 fn define_builtins(&self, symbols: &[(CString, usize)]) {
320 if symbols.is_empty() {
321 return;
322 }
323 let mut defined = self.builtins_defined.lock().unwrap();
324 let new_syms: Vec<_> = symbols
325 .iter()
326 .filter(|(name, _)| defined.insert(name.clone()))
327 .map(|(name, addr)| {
328 orc::SymbolMapPair::new(
329 self.jit.mangle_and_intern(name),
330 orc::EvaluatedSymbol::new(
331 *addr as u64,
332 orc::SymbolFlags::none().exported().callable(),
333 ),
334 )
335 })
336 .collect();
337 drop(defined);
338 if !new_syms.is_empty()
339 && let Err((e, _)) =
340 self.builtins_jd.define(orc::MaterializationUnit::absolute_symbols(new_syms))
341 {
342 error!("failed to define builtins: {e}");
343 }
344 }
345
346 fn gc(&self) {
347 self.jit.get_execution_session().get_symbol_string_pool().clear_dead_entries();
348 }
349}
350
351#[allow(missing_debug_implementations)]
357pub struct JitDylibGuard {
358 global: &'static GlobalOrcJit,
359 jd: orc::JITDylibRef,
360}
361
362impl Drop for JitDylibGuard {
363 fn drop(&mut self) {
364 self.global.remove_jit_dylib(self.jd);
365 }
366}
367
368struct OrcJitState {
373 global: &'static GlobalOrcJit,
375 jd_guard: Arc<JitDylibGuard>,
382 staged_functions: FxHashMap<u32, FunctionValue<'static>>,
384 pending_symbols: Vec<(CString, usize)>,
387 loaded_trackers: Vec<orc::ResourceTracker>,
389 committed_functions: FxHashMap<u32, usize>,
391 last_compiled_object: Option<Vec<u8>>,
394 clear_pool_counter: u32,
396}
397
398impl fmt::Debug for OrcJitState {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 f.debug_struct("OrcJitState")
401 .field("staged_functions", &self.staged_functions.len())
402 .field("pending_symbols", &self.pending_symbols.len())
403 .field("loaded_trackers", &self.loaded_trackers.len())
404 .field("committed_functions", &self.committed_functions.len())
405 .finish_non_exhaustive()
406 }
407}
408
409impl OrcJitState {
410 fn new(debug_support: bool, profiling_support: bool, simple_perf: bool) -> Result<Self> {
411 let global = GlobalOrcJit::get(debug_support, profiling_support, simple_perf)?;
412 let jd = global.create_jit_dylib();
413 let jd_guard = Arc::new(JitDylibGuard { global, jd });
414 Ok(Self {
415 global,
416 staged_functions: FxHashMap::default(),
417 pending_symbols: Vec::new(),
418 loaded_trackers: Vec::new(),
419 committed_functions: FxHashMap::default(),
420 last_compiled_object: None,
421 jd_guard,
422 clear_pool_counter: 0,
423 })
424 }
425
426 fn clear(&mut self) -> Result<()> {
428 self.staged_functions.clear();
429 self.pending_symbols.clear();
430 self.committed_functions.clear();
431 self.last_compiled_object = None;
432 self.jd().clear().map_err(error_msg)?;
436 self.loaded_trackers.clear();
437 Ok(())
438 }
439
440 fn maybe_clear_dead_pool_entries(&mut self) {
445 self.clear_pool_counter += 1;
446 if self.clear_pool_counter.is_multiple_of(256) {
447 self.global.jit.get_execution_session().get_symbol_string_pool().clear_dead_entries();
448 }
449 }
450
451 fn jd(&self) -> orc::JITDylibRef {
452 self.jd_guard.jd
453 }
454}
455
456fn link_jit_object_in_dylib(
457 orc: &OrcJitState,
458 jd: orc::JITDylibRef,
459 symbol_name: &CStr,
460 object: &[u8],
461 symbols: &[(CString, usize)],
462) -> Result<(usize, orc::ResourceTracker)> {
463 orc.global.define_builtins(symbols);
464 let tracker = jd.create_resource_tracker();
465 orc.global.jit.add_object_with_rt(symbol_name, object, &tracker).map_err(error_msg)?;
466 let addr = orc.global.jit.lookup_in(jd, symbol_name).map_err(error_msg)?;
467 Ok((addr, tracker))
468}
469
470fn create_thread_safe_module(
475 tscx: &orc::ThreadSafeContext,
476 module: Module<'static>,
477) -> orc::ThreadSafeModule {
478 let module = std::mem::ManuallyDrop::new(module);
479 unsafe { orc::ThreadSafeModule::create_in_context(Module::new(module.as_mut_ptr()), tscx) }
481}
482
483fn create_orc_context() -> (&'static Context, orc::ThreadSafeContext, Box<ManuallyDrop<Context>>) {
489 let cx = Context::create();
490 let raw = cx.raw();
491 let tscx = orc::ThreadSafeContext::from_context(cx);
492 let cx_handle = Box::new(ManuallyDrop::new(unsafe { Context::new(raw) }));
495 let cx: &'static Context = unsafe { &*(&**cx_handle as *const Context) };
498 (cx, tscx, cx_handle)
499}
500
501struct DiState {
503 dibuilder: DebugInfoBuilder<'static>,
504 compile_unit: DICompileUnit<'static>,
505 finalized: bool,
506}
507
508impl fmt::Debug for DiState {
509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510 f.debug_struct("DiState").field("finalized", &self.finalized).finish()
511 }
512}
513
514unsafe impl Send for EvmLlvmBackend {}
518
519impl EvmLlvmBackend {
520 #[instrument(name = "new_llvm_backend", level = "debug", skip_all)]
522 pub fn new(aot: bool) -> Result<Self> {
523 let config = BackendConfig::default();
524 init()?;
525
526 let target_info = TargetInfo::new();
527 let target = &target_info.target;
528 let machine = target
529 .create_target_machine(
530 &target_info.triple,
531 &target_info.cpu,
532 &target_info.features,
533 convert_opt_level(config.opt_level),
534 if aot { RelocMode::PIC } else { RelocMode::Static },
535 CodeModel::Default,
536 )
537 .ok_or_else(|| eyre::eyre!("failed to create target machine"))?;
538
539 let (cx, tscx, cx_handle, aot_cx) = if aot {
543 let aot_cx = Box::new(Context::create());
544 let cx: &'static Context = unsafe { &*(&*aot_cx as *const Context) };
547 (cx, None, None, Some(aot_cx))
548 } else {
549 if !target.has_jit() {
550 return Err(eyre::eyre!("target {:?} does not support JIT", target.get_name()));
551 }
552 if !target.has_target_machine() {
553 return Err(eyre::eyre!(
554 "target {:?} does not have target machine",
555 target.get_name()
556 ));
557 }
558
559 let (cx, tscx, cx_handle) = create_orc_context();
560 (cx, Some(tscx), Some(cx_handle), None)
561 };
562
563 let module = create_module(cx, &machine, aot)?;
564 let bcx = cx.create_builder();
565
566 let ty_void = cx.void_type();
567 let ty_i1 = cx.bool_type();
568 let ty_i8 = cx.i8_type();
569 let ty_i32 = cx.i32_type();
570 let ty_i64 = cx.i64_type();
571 let ty_i256 =
572 cx.custom_width_int_type(std::num::NonZeroU32::new(256).unwrap()).expect("i256");
573 let ty_isize = cx.ptr_sized_int_type(&machine.get_target_data(), None);
574 let ty_ptr = cx.ptr_type(AddressSpace::default());
575 Ok(Self {
576 cx,
577 _dh: dh::DiagnosticHandlerGuard::new(cx),
578 bcx,
579 module,
580 machine,
581 orc: None,
582 _tscx: tscx,
583 _cx_handle: cx_handle,
584 _aot_cx: aot_cx,
585 ty_void,
586 ty_i1,
587 ty_i8,
588 ty_i32,
589 ty_i64,
590 ty_i256,
591 ty_isize,
592 ty_ptr,
593 aot,
594 backend_config: config,
595 scratch: String::new(),
596 function_counter: 0,
597 function_names: FxHashMap::default(),
598 di_state: None,
599 })
600 }
601
602 #[inline]
604 pub fn cx(&self) -> &Context {
605 self.cx
606 }
607
608 #[inline]
609 fn module(&self) -> &Module<'static> {
610 &self.module
611 }
612
613 fn ensure_orc(&mut self) -> Result<&mut OrcJitState> {
614 if self.orc.is_none() {
615 self.orc = Some(OrcJitState::new(
616 self.backend_config.debug_support,
617 self.backend_config.profiling_support,
618 self.backend_config.simple_perf,
619 )?);
620 }
621 Ok(self.orc.as_mut().unwrap())
622 }
623
624 fn fn_type(
625 &self,
626 ret: Option<BasicTypeEnum<'static>>,
627 params: &[BasicTypeEnum<'static>],
628 ) -> FunctionType<'static> {
629 let params = params.iter().copied().map(Into::into).collect::<Vec<_>>();
630 match ret {
631 Some(ret) => ret.fn_type(¶ms, false),
632 None => self.ty_void.fn_type(¶ms, false),
633 }
634 }
635
636 #[inline]
640 fn name<'a>(&self, name: &'a str) -> &'a str {
641 if self.backend_config.is_dumping { name } else { "" }
642 }
643
644 fn id_to_name(&self, id: u32) -> &str {
645 &self.function_names[&id]
646 }
647
648 fn ensure_di_state(&mut self) {
650 if self.di_state.is_some() {
651 return;
652 }
653 let Some(debug_file) = &self.backend_config.debug_file else { return };
654
655 let filename =
656 debug_file.file_name().map(|f| f.to_string_lossy()).unwrap_or_default().into_owned();
657 let directory =
658 debug_file.parent().map(|p| p.to_string_lossy()).unwrap_or_default().into_owned();
659
660 self.module().add_basic_value_flag(
662 "Debug Info Version",
663 FlagBehavior::Warning,
664 self.ty_i32.const_int(inkwell::debug_info::debug_metadata_version() as u64, false),
665 );
666 self.module().add_basic_value_flag(
667 "Dwarf Version",
668 FlagBehavior::Warning,
669 self.ty_i32.const_int(5, false),
670 );
671
672 let opt_level = self.backend_config.opt_level;
673 let is_optimized = opt_level != OptimizationLevel::None;
674 let mut flags = Vec::new();
675 flags.push(match opt_level {
676 OptimizationLevel::None => "-O0",
677 OptimizationLevel::Less => "-O1",
678 OptimizationLevel::Default => "-O2",
679 OptimizationLevel::Aggressive => "-O3",
680 });
681 flags.push(if self.aot { "--aot" } else { "--jit" });
682 let flags = flags.join(" ");
683
684 let (dibuilder, compile_unit) = self.module().create_debug_info_builder(
685 true,
686 DWARFSourceLanguage::C,
687 &filename,
688 &directory,
689 "revmc",
690 is_optimized,
691 &flags,
692 0,
693 "",
694 DWARFEmissionKind::Full,
695 0,
696 false,
697 false,
698 "",
699 "",
700 );
701
702 self.di_state = Some(DiState { dibuilder, compile_unit, finalized: false });
703 }
704
705 fn commit_staged_module(&mut self) -> Result<()> {
707 if self.aot || self.orc.as_ref().is_none_or(|o| o.staged_functions.is_empty()) {
708 return Ok(());
709 }
710
711 self.di_state = None;
712
713 let new_module = create_module(self.cx, &self.machine, self.aot)?;
714 let old_module = std::mem::replace(&mut self.module, new_module);
715
716 let tscx = self._tscx.as_ref().expect("missing ThreadSafeContext");
717 let orc = self.orc.as_mut().unwrap();
718
719 let pending = &mut orc.pending_symbols;
721 if !pending.is_empty() {
722 orc.global.define_builtins(pending);
723 pending.clear();
724 }
725
726 let tracker = orc.jd().create_resource_tracker();
727
728 let tsm = create_thread_safe_module(tscx, old_module);
729 orc.global.jit.add_module_with_rt(tsm, &tracker).map_err(error_msg)?;
730
731 let tracker_idx = orc.loaded_trackers.len();
732 for &id in orc.staged_functions.keys() {
733 orc.committed_functions.insert(id, tracker_idx);
734 }
735 orc.loaded_trackers.push(tracker);
736 orc.staged_functions.clear();
737 Ok(())
738 }
739
740 fn reset_jit(&mut self) -> Result<()> {
743 self.function_names.clear();
744 self.di_state = None;
745
746 if let Some(orc) = &mut self.orc {
747 orc.clear()?;
748 }
749
750 self.module = create_module(self.cx, &self.machine, self.aot)?;
751
752 Ok(())
753 }
754
755 pub fn pending_symbol_names(&self) -> Vec<CString> {
757 self.orc
758 .as_ref()
759 .map(|orc| orc.pending_symbols.iter().map(|(name, _)| name.clone()).collect())
760 .unwrap_or_default()
761 }
762
763 pub fn link_jit_object(
766 &mut self,
767 symbol_name: &CStr,
768 object: &[u8],
769 symbols: &[(CString, usize)],
770 ) -> Result<(usize, orc::ResourceTracker)> {
771 let orc = self.ensure_orc()?;
772 let (addr, tracker) =
773 link_jit_object_in_dylib(orc, orc.jd(), symbol_name, object, symbols)?;
774 orc.loaded_trackers.push(tracker);
775 Ok((addr, orc.loaded_trackers.pop().unwrap()))
776 }
777
778 pub fn link_jit_object_in_fresh_dylib(
781 &mut self,
782 symbol_name: &CStr,
783 object: &[u8],
784 symbols: &[(CString, usize)],
785 ) -> Result<(usize, orc::ResourceTracker, Arc<JitDylibGuard>)> {
786 let orc = self.ensure_orc()?;
787 let jd = orc.global.create_jit_dylib();
788 let jd_guard = Arc::new(JitDylibGuard { global: orc.global, jd });
789 let (addr, tracker) = link_jit_object_in_dylib(orc, jd, symbol_name, object, symbols)?;
790 Ok((addr, tracker, jd_guard))
791 }
792
793 pub fn take_last_resource_tracker(&mut self) -> Option<orc::ResourceTracker> {
805 let orc = self.orc.as_mut()?;
806 let tracker = orc.loaded_trackers.pop()?;
807 let tracker_idx = orc.loaded_trackers.len();
808 orc.committed_functions.retain(|_, idx| *idx != tracker_idx);
809 Some(tracker)
810 }
811
812 pub fn jit_dylib_guard(&self) -> Arc<JitDylibGuard> {
818 Arc::clone(&self.orc.as_ref().expect("jit_dylib_guard called in AOT mode").jd_guard)
819 }
820}
821
822impl BackendTypes for EvmLlvmBackend {
823 type Type = BasicTypeEnum<'static>;
824 type Value = BasicValueEnum<'static>;
825 type StackSlot = PointerValue<'static>;
826 type BasicBlock = BasicBlock<'static>;
827 type Function = FunctionValue<'static>;
828}
829
830impl TypeMethods for EvmLlvmBackend {
831 fn type_ptr(&self) -> Self::Type {
832 self.ty_ptr.into()
833 }
834
835 fn type_ptr_sized_int(&self) -> Self::Type {
836 self.ty_isize.into()
837 }
838
839 fn type_int(&self, bits: u32) -> Self::Type {
840 match bits {
841 1 => self.ty_i1,
842 8 => self.ty_i8,
843 16 => self.cx.i16_type(),
844 32 => self.ty_i32,
845 64 => self.ty_i64,
846 128 => self.cx.i128_type(),
847 256 => self.ty_i256,
848 bits => self
849 .cx
850 .custom_width_int_type(std::num::NonZeroU32::new(bits).unwrap())
851 .expect("custom int type"),
852 }
853 .into()
854 }
855
856 fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type {
857 ty.array_type(size).into()
858 }
859
860 fn type_bit_width(&self, ty: Self::Type) -> u32 {
861 ty.into_int_type().get_bit_width()
862 }
863}
864
865impl Backend for EvmLlvmBackend {
866 type Builder<'a>
867 = EvmLlvmBuilder<'a>
868 where
869 Self: 'a;
870 type FuncId = u32;
871
872 fn ir_extension(&self) -> &'static str {
873 "ll"
874 }
875
876 fn set_module_name(&mut self, name: &str) {
877 self.module().set_name(name);
878 }
879
880 fn config(&self) -> &BackendConfig {
881 &self.backend_config
882 }
883
884 fn apply_config(&mut self, config: BackendConfig) {
885 if self.backend_config.is_dumping != config.is_dumping {
886 self.machine.set_asm_verbosity(config.is_dumping);
887 }
888 if self.backend_config.opt_level != config.opt_level {
889 unsafe {
890 cpp::revmc_llvm_target_machine_set_opt_level(
891 self.machine.as_mut_ptr(),
892 convert_opt_level(config.opt_level).into(),
893 );
894 }
895 }
896 self.backend_config = config;
897 }
898
899 fn finalize_debug_info(&mut self) -> Result<()> {
900 if let Some(di) = &mut self.di_state
901 && !di.finalized
902 {
903 di.dibuilder.finalize();
904 di.finalized = true;
905 }
906 Ok(())
907 }
908
909 fn is_aot(&self) -> bool {
910 self.aot
911 }
912
913 fn function_name_is_unique(&self, name: &str) -> bool {
914 self.module().get_function(name).is_none()
915 }
916
917 fn dump_ir(&mut self, path: &Path) -> Result<()> {
918 self.module().print_to_file(path).map_err(error_msg)
919 }
920
921 fn dump_disasm(&mut self, path: &Path) -> Result<()> {
922 self.machine.write_to_file(self.module(), FileType::Assembly, path).map_err(error_msg)
923 }
924
925 fn build_function(
926 &mut self,
927 name: &str,
928 ret: Option<Self::Type>,
929 params: &[Self::Type],
930 param_names: &[&str],
931 linkage: revmc_backend::Linkage,
932 ) -> Result<(Self::Builder<'_>, Self::FuncId)> {
933 if !self.aot {
934 self.ensure_orc()?;
935 }
936 let (id, function) = if let Some((&id, _fname)) =
937 self.function_names.iter().find(|(_k, fname)| fname.as_str() == name)
938 && let Some(orc) = &self.orc
939 && let Some(function) = orc.staged_functions.get(&id).copied()
940 && let Some(function2) = self.module().get_function(name)
941 && function == function2
942 {
943 self.bcx.position_at_end(function.get_first_basic_block().unwrap());
944 (id, function)
945 } else {
946 let fn_type = self.fn_type(ret, params);
947 let function =
948 self.module().add_function(name, fn_type, Some(convert_linkage(linkage)));
949 cpp::set_dso_local(function);
950 if self.backend_config.is_dumping {
951 for (i, &name) in param_names.iter().enumerate() {
952 function.get_nth_param(i as u32).expect(name).set_name(self.name(name));
953 }
954 }
955
956 let entry = self.cx.append_basic_block(function, self.name("entry"));
957 self.bcx.position_at_end(entry);
958
959 let id = self.function_counter;
960 self.function_counter += 1;
961 self.function_names.insert(id, name.to_string());
962 if let Some(orc) = &mut self.orc {
963 orc.staged_functions.insert(id, function);
964 }
965 (id, function)
966 };
967
968 self.ensure_di_state();
970 let debug_scope = if let Some(di) = &self.di_state {
971 let file = di.compile_unit.get_file();
972 let subroutine_type =
973 di.dibuilder.create_subroutine_type(file, None, &[], DIFlags::PUBLIC);
974 let subprogram = di.dibuilder.create_function(
975 di.compile_unit.as_debug_info_scope(),
976 name,
977 None,
978 file,
979 0,
980 subroutine_type,
981 true,
982 true,
983 0,
984 DIFlags::PUBLIC,
985 self.backend_config.opt_level != OptimizationLevel::None,
986 );
987 function.set_subprogram(subprogram);
988 Some(subprogram)
989 } else {
990 None
991 };
992
993 let builder = EvmLlvmBuilder { backend: self, function, debug_scope };
994 Ok((builder, id))
995 }
996
997 fn verify_module(&mut self) -> Result<()> {
998 self.module().verify().map_err(error_msg)
999 }
1000
1001 fn optimize_module(&mut self) -> Result<()> {
1002 static PASSES_OVERRIDE: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
1021 static PASSES: std::sync::OnceLock<String> = std::sync::OnceLock::new();
1022 static PASSES_WITH_LICM: std::sync::OnceLock<String> = std::sync::OnceLock::new();
1023
1024 let passes = PASSES_OVERRIDE.get_or_init(|| std::env::var("REVMC_PASSES").ok());
1025 let passes = passes.as_deref().unwrap_or_else(|| match self.backend_config.opt_level {
1026 OptimizationLevel::None => "default<O0>",
1027 OptimizationLevel::Less | OptimizationLevel::Default => {
1028 let total_bbs: u32 =
1029 self.module.get_functions().map(|f| f.count_basic_blocks()).sum();
1030 let with_licm = total_bbs <= 4000;
1031 let passes = if with_licm { &PASSES_WITH_LICM } else { &PASSES };
1032 passes.get_or_init(|| build_pass_pipeline(with_licm))
1033 }
1034 OptimizationLevel::Aggressive => "default<O3>",
1035 });
1036 let opts = PassBuilderOptions::create();
1037 self.module().run_passes(passes, &self.machine, opts).map_err(error_msg)
1038 }
1039
1040 fn write_object<W: std::io::Write>(&mut self, mut w: W) -> Result<()> {
1041 let buffer = self
1042 .machine
1043 .write_to_memory_buffer(self.module(), FileType::Object)
1044 .map_err(error_msg)?;
1045 w.write_all(buffer.as_slice())?;
1046 Ok(())
1047 }
1048
1049 fn jit_function(&mut self, id: Self::FuncId) -> Result<usize> {
1050 self.ensure_orc()?;
1051 self.commit_staged_module()?;
1052 let name_str = self.id_to_name(id);
1053 let name = CString::new(name_str).unwrap();
1054 let orc = self.orc.as_mut().unwrap();
1055 let mut captured = None;
1059 let _guard = ScopedObjCapture::install(&mut captured);
1060 let addr = orc.global.jit.lookup_in(orc.jd(), &name).map_err(error_msg)?;
1061 drop(_guard);
1062 if captured.is_some() {
1063 orc.last_compiled_object = captured;
1064 }
1065 Ok(addr)
1066 }
1067
1068 fn function_name(&self, id: Self::FuncId) -> Option<&str> {
1069 self.function_names.get(&id).map(|s| s.as_str())
1070 }
1071
1072 fn function_sizes(&self) -> Vec<(String, usize)> {
1073 let Some(orc) = &self.orc else { return Vec::new() };
1074 let Some(data) = orc.last_compiled_object.as_deref() else { return Vec::new() };
1075 let Ok(obj) = object::File::parse(data) else { return Vec::new() };
1076
1077 let mut result: Vec<_> = obj
1078 .symbols()
1079 .filter(|sym| sym.is_definition())
1080 .filter_map(|sym| {
1081 let name = sym.name().ok()?;
1082 self.function_names.values().any(|n| n == name).then_some(())?;
1083 Some((name.to_string(), sym.size() as usize))
1084 })
1085 .collect();
1086 result.sort_by_key(|(_, size)| std::cmp::Reverse(*size));
1087 result
1088 }
1089
1090 fn clear_ir(&mut self) -> Result<()> {
1091 self.di_state = None;
1092 self.function_names.clear();
1093 self.module = create_module(self.cx, &self.machine, self.aot)?;
1094 if let Some(orc) = &mut self.orc {
1095 orc.staged_functions.clear();
1096 orc.pending_symbols.clear();
1097 orc.maybe_clear_dead_pool_entries();
1098 }
1099 Ok(())
1100 }
1101
1102 unsafe fn free_function(&mut self, id: Self::FuncId) -> Result<()> {
1103 if let Some(orc) = &mut self.orc {
1104 if let Some(function) = orc.staged_functions.remove(&id) {
1106 unsafe { function.delete() };
1107 }
1108
1109 if let Some(tracker_idx) = orc.committed_functions.remove(&id) {
1111 orc.loaded_trackers[tracker_idx].remove().map_err(error_msg)?;
1112 orc.committed_functions.retain(|co_id, idx| {
1115 if *idx == tracker_idx {
1116 self.function_names.remove(co_id);
1117 false
1118 } else {
1119 true
1120 }
1121 });
1122 }
1125 }
1126 self.function_names.remove(&id);
1127 Ok(())
1128 }
1129
1130 unsafe fn free_all_functions(&mut self) -> Result<()> {
1131 self.reset_jit()
1132 }
1133}
1134
1135#[derive(Debug)]
1137struct TargetInfo {
1138 triple: TargetTriple,
1139 target: Target,
1140 cpu: String,
1141 features: String,
1142}
1143
1144unsafe impl std::marker::Send for TargetInfo {}
1146unsafe impl std::marker::Sync for TargetInfo {}
1147
1148impl Clone for TargetInfo {
1149 fn clone(&self) -> Self {
1150 let triple = TargetTriple::create(self.triple.as_str().to_str().unwrap());
1151 Self {
1152 target: Target::from_triple(&triple).unwrap(),
1153 triple,
1154 cpu: self.cpu.clone(),
1155 features: self.features.clone(),
1156 }
1157 }
1158}
1159
1160impl TargetInfo {
1161 fn new() -> &'static Self {
1162 static HOST_TARGET_INFO: OnceLock<TargetInfo> = OnceLock::new();
1163 HOST_TARGET_INFO.get_or_init(|| {
1164 let triple = TargetMachine::get_default_triple();
1165 let target = Target::from_triple(&triple).unwrap();
1166 let cpu = TargetMachine::get_host_cpu_name().to_string_lossy().into_owned();
1167 let features = TargetMachine::get_host_cpu_features().to_string_lossy().into_owned();
1168 Self { target, triple, cpu, features }
1169 })
1170 }
1171}
1172
1173#[derive(Debug)]
1175#[must_use]
1176pub struct EvmLlvmBuilder<'a> {
1177 backend: &'a mut EvmLlvmBackend,
1178 function: FunctionValue<'static>,
1179 debug_scope: Option<DISubprogram<'static>>,
1180}
1181
1182impl std::ops::Deref for EvmLlvmBuilder<'_> {
1183 type Target = EvmLlvmBackend;
1184
1185 #[inline]
1186 fn deref(&self) -> &Self::Target {
1187 self.backend
1188 }
1189}
1190
1191impl std::ops::DerefMut for EvmLlvmBuilder<'_> {
1192 #[inline]
1193 fn deref_mut(&mut self) -> &mut Self::Target {
1194 self.backend
1195 }
1196}
1197
1198impl EvmLlvmBuilder<'_> {
1199 #[allow(dead_code)]
1200 fn extract_value(
1201 &mut self,
1202 value: BasicValueEnum<'static>,
1203 index: u32,
1204 name: &str,
1205 ) -> BasicValueEnum<'static> {
1206 self.bcx.build_extract_value(value.into_struct_value(), index, self.name(name)).unwrap()
1207 }
1208
1209 fn memcpy_inner(
1210 &mut self,
1211 dst: BasicValueEnum<'static>,
1212 src: BasicValueEnum<'static>,
1213 len: BasicValueEnum<'static>,
1214 inline: bool,
1215 ) {
1216 let dst = dst.into_pointer_value();
1217 let src = src.into_pointer_value();
1218 let len = len.into_int_value();
1219 let volatile = self.bool_const(false);
1220 let name = format!(
1221 "llvm.memcpy{}.p0.p0.{}",
1222 if inline { ".inline" } else { "" },
1223 fmt_ty(len.get_type().into()),
1224 );
1225 let memcpy = self.get_or_add_function(&name, |this| {
1226 this.ty_void.fn_type(
1227 &[this.ty_ptr.into(), this.ty_ptr.into(), this.ty_i64.into(), this.ty_i1.into()],
1228 false,
1229 )
1230 });
1231 self.bcx
1232 .build_call(memcpy, &[dst.into(), src.into(), len.into(), volatile.into()], "")
1233 .unwrap();
1234 }
1235
1236 #[allow(dead_code)]
1237 fn call_overflow_function(
1238 &mut self,
1239 name: &str,
1240 lhs: BasicValueEnum<'static>,
1241 rhs: BasicValueEnum<'static>,
1242 ) -> (BasicValueEnum<'static>, BasicValueEnum<'static>) {
1243 let f = self.get_overflow_function(name, lhs.get_type());
1244 let result = self.call(f, &[lhs, rhs]).unwrap();
1245 (self.extract_value(result, 0, "result"), self.extract_value(result, 1, "overflow"))
1246 }
1247
1248 #[allow(dead_code)]
1249 fn get_overflow_function(
1250 &mut self,
1251 name: &str,
1252 ty: BasicTypeEnum<'static>,
1253 ) -> FunctionValue<'static> {
1254 let name = format!("llvm.{name}.with.overflow.{}", fmt_ty(ty));
1255 self.get_or_add_function(&name, |this| {
1256 this.fn_type(
1257 Some(this.cx.struct_type(&[ty, this.ty_i1.into()], false).into()),
1258 &[ty, ty],
1259 )
1260 })
1261 }
1262
1263 fn get_sat_function(
1264 &mut self,
1265 name: &str,
1266 ty: BasicTypeEnum<'static>,
1267 ) -> FunctionValue<'static> {
1268 let name = format!("llvm.{name}.sat.{}", fmt_ty(ty));
1269 self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, ty]))
1270 }
1271
1272 fn get_or_add_function(
1273 &mut self,
1274 name: &str,
1275 mk_ty: impl FnOnce(&mut Self) -> FunctionType<'static>,
1276 ) -> FunctionValue<'static> {
1277 match self.module().get_function(name) {
1278 Some(function) => function,
1279 None => {
1280 let ty = mk_ty(self);
1281 self.module().add_function(name, ty, None)
1282 }
1283 }
1284 }
1285
1286 fn set_branch_weights(
1287 &self,
1288 inst: InstructionValue<'static>,
1289 weights: impl IntoIterator<Item = u32>,
1290 ) {
1291 let weights = weights.into_iter();
1292 let mut values = Vec::<BasicMetadataValueEnum<'static>>::with_capacity(
1293 1 + weights.size_hint().1.unwrap(),
1294 );
1295 values.push(self.cx.metadata_string("branch_weights").into());
1296 for weight in weights {
1297 values.push(self.ty_i32.const_int(weight as u64, false).into());
1298 }
1299 let metadata = self.cx.metadata_node(&values);
1300 let kind_id = self.cx.get_kind_id("prof");
1301 inst.set_metadata(metadata, kind_id).unwrap();
1302 }
1303
1304 fn assume_inner(&mut self, cond: BasicValueEnum<'static>) -> CallSiteValue<'static> {
1305 let function = self.get_or_add_function("llvm.assume", |this| {
1306 this.ty_void.fn_type(&[this.ty_i1.into()], false)
1307 });
1308 self.bcx.build_call(function, &[cond.into()], "").unwrap()
1309 }
1310}
1311
1312impl BackendTypes for EvmLlvmBuilder<'_> {
1313 type Type = <EvmLlvmBackend as BackendTypes>::Type;
1314 type Value = <EvmLlvmBackend as BackendTypes>::Value;
1315 type StackSlot = <EvmLlvmBackend as BackendTypes>::StackSlot;
1316 type BasicBlock = <EvmLlvmBackend as BackendTypes>::BasicBlock;
1317 type Function = <EvmLlvmBackend as BackendTypes>::Function;
1318}
1319
1320impl TypeMethods for EvmLlvmBuilder<'_> {
1321 fn type_ptr(&self) -> Self::Type {
1322 self.backend.type_ptr()
1323 }
1324
1325 fn type_ptr_sized_int(&self) -> Self::Type {
1326 self.backend.type_ptr_sized_int()
1327 }
1328
1329 fn type_int(&self, bits: u32) -> Self::Type {
1330 self.backend.type_int(bits)
1331 }
1332
1333 fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type {
1334 self.backend.type_array(ty, size)
1335 }
1336
1337 fn type_bit_width(&self, ty: Self::Type) -> u32 {
1338 self.backend.type_bit_width(ty)
1339 }
1340}
1341
1342impl Builder for EvmLlvmBuilder<'_> {
1343 fn create_block(&mut self, name: &str) -> Self::BasicBlock {
1344 self.cx.append_basic_block(self.function, self.name(name))
1345 }
1346
1347 fn create_block_after(&mut self, after: Self::BasicBlock, name: &str) -> Self::BasicBlock {
1348 self.cx.insert_basic_block_after(after, self.name(name))
1349 }
1350
1351 fn switch_to_block(&mut self, block: Self::BasicBlock) {
1352 self.bcx.position_at_end(block);
1353 }
1354
1355 fn seal_block(&mut self, block: Self::BasicBlock) {
1356 let _ = block;
1357 }
1359
1360 fn seal_all_blocks(&mut self) {
1361 }
1363
1364 fn set_current_block_cold(&mut self) {
1365 let true_ = self.bool_const(true);
1366 let callsite = self.assume_inner(true_);
1367 let cold = self.cx.create_enum_attribute(Attribute::get_named_enum_kind_id("cold"), 0);
1368 callsite.add_attribute(AttributeLoc::Function, cold);
1369 }
1370
1371 fn current_block(&mut self) -> Option<Self::BasicBlock> {
1372 self.bcx.get_insert_block()
1373 }
1374
1375 fn block_addr(&mut self, block: Self::BasicBlock) -> Option<Self::Value> {
1376 unsafe { block.get_address().map(Into::into) }
1377 }
1378
1379 fn add_comment_to_current_inst(&mut self, comment: &str) {
1380 if !self.backend_config.is_dumping {
1381 return;
1382 }
1383 let Some(block) = self.current_block() else { return };
1384 let Some(ins) = block.get_last_instruction() else { return };
1385 let metadata = self.cx.metadata_string(comment);
1386 let metadata = self.cx.metadata_node(&[metadata.into()]);
1387 ins.set_metadata(metadata, self.cx.get_kind_id("annotation")).unwrap();
1388 }
1389
1390 fn set_debug_location(&mut self, line: u32, col: u32) {
1391 let Some(scope) = self.debug_scope else { return };
1392 let Some(di) = &self.di_state else { return };
1393 let loc = di.dibuilder.create_debug_location(
1394 self.cx,
1395 line,
1396 col,
1397 scope.as_debug_info_scope(),
1398 None,
1399 );
1400 self.bcx.set_current_debug_location(loc);
1401 }
1402
1403 fn clear_debug_location(&mut self) {
1404 if self.debug_scope.is_some() {
1405 self.bcx.unset_current_debug_location();
1406 }
1407 }
1408
1409 fn fn_param(&mut self, index: usize) -> Self::Value {
1410 self.function.get_nth_param(index as _).unwrap()
1411 }
1412
1413 fn num_fn_params(&self) -> usize {
1414 self.function.count_params() as usize
1415 }
1416
1417 fn bool_const(&mut self, value: bool) -> Self::Value {
1418 self.ty_i1.const_int(value as u64, false).into()
1419 }
1420
1421 fn iconst(&mut self, ty: Self::Type, value: i64) -> Self::Value {
1422 ty.into_int_type().const_int(value as u64, value.is_negative()).into()
1423 }
1424
1425 fn uconst(&mut self, ty: Self::Type, value: u64) -> Self::Value {
1426 ty.into_int_type().const_int(value, false).into()
1427 }
1428
1429 fn iconst_256(&mut self, value: impl TryInto<U256>) -> Self::Value {
1430 let value = value.try_into().ok().expect("invalid U256 value");
1431 if let Ok(low) = value.try_into() {
1432 return self.ty_i256.const_int(low, false).into();
1433 }
1434
1435 self.scratch.clear();
1436 write!(self.scratch, "{value:x}").unwrap();
1437 self.ty_i256.const_int_from_string(&self.scratch, StringRadix::Hexadecimal).unwrap().into()
1438 }
1439
1440 fn str_const(&mut self, value: &str) -> Self::Value {
1441 self.bcx.build_global_string_ptr(value, "").unwrap().as_pointer_value().into()
1442 }
1443
1444 fn nullptr(&mut self) -> Self::Value {
1445 self.ty_ptr.const_null().into()
1446 }
1447
1448 fn new_stack_slot_raw(&mut self, ty: Self::Type, name: &str) -> Self::StackSlot {
1449 self.bcx.build_alloca(ty, self.name(name)).unwrap()
1454 }
1455
1456 fn stack_load(&mut self, ty: Self::Type, slot: Self::StackSlot, name: &str) -> Self::Value {
1457 self.load(ty, slot.into(), name)
1458 }
1459
1460 fn stack_store(&mut self, value: Self::Value, slot: Self::StackSlot) {
1461 self.store(value, slot.into())
1462 }
1463
1464 fn stack_addr(&mut self, ty: Self::Type, slot: Self::StackSlot) -> Self::Value {
1465 let _ = ty;
1466 slot.into()
1467 }
1468
1469 fn load(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value {
1470 let value = self.bcx.build_load(ty, ptr.into_pointer_value(), self.name(name)).unwrap();
1471 if ty == self.ty_i256.into() {
1472 self.current_block().unwrap().get_last_instruction().unwrap().set_alignment(8).unwrap();
1473 }
1474 value
1475 }
1476
1477 fn load_aligned(
1478 &mut self,
1479 ty: Self::Type,
1480 ptr: Self::Value,
1481 align: usize,
1482 name: &str,
1483 ) -> Self::Value {
1484 let value = self.bcx.build_load(ty, ptr.into_pointer_value(), self.name(name)).unwrap();
1485 self.current_block()
1486 .unwrap()
1487 .get_last_instruction()
1488 .unwrap()
1489 .set_alignment(align as u32)
1490 .unwrap();
1491 value
1492 }
1493
1494 fn store(&mut self, value: Self::Value, ptr: Self::Value) {
1495 let inst = self.bcx.build_store(ptr.into_pointer_value(), value).unwrap();
1496 if value.get_type() == self.ty_i256.into() {
1497 inst.set_alignment(8).unwrap();
1498 }
1499 }
1500
1501 fn store_aligned(&mut self, value: Self::Value, ptr: Self::Value, align: usize) {
1502 let inst = self.bcx.build_store(ptr.into_pointer_value(), value).unwrap();
1503 inst.set_alignment(align as u32).unwrap();
1504 }
1505
1506 fn nop(&mut self) {
1507 }
1509
1510 fn ret(&mut self, values: &[Self::Value]) {
1511 match values {
1512 [] => self.bcx.build_return(None),
1513 [value] => self.bcx.build_return(Some(value)),
1514 values => self.bcx.build_aggregate_return(values),
1515 }
1516 .unwrap();
1517 }
1518
1519 fn assume(&mut self, cond: Self::Value) {
1520 self.assume_inner(cond);
1521 }
1522
1523 fn icmp(&mut self, cond: IntCC, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1524 self.bcx
1525 .build_int_compare(convert_intcc(cond), lhs.into_int_value(), rhs.into_int_value(), "")
1526 .unwrap()
1527 .into()
1528 }
1529
1530 fn icmp_imm(&mut self, cond: IntCC, lhs: Self::Value, rhs: i64) -> Self::Value {
1531 let rhs = self.iconst(lhs.get_type(), rhs);
1532 self.icmp(cond, lhs, rhs)
1533 }
1534
1535 fn is_null(&mut self, ptr: Self::Value) -> Self::Value {
1536 self.bcx.build_is_null(ptr.into_pointer_value(), "").unwrap().into()
1537 }
1538
1539 fn is_not_null(&mut self, ptr: Self::Value) -> Self::Value {
1540 self.bcx.build_is_not_null(ptr.into_pointer_value(), "").unwrap().into()
1541 }
1542
1543 fn br(&mut self, dest: Self::BasicBlock) {
1544 self.bcx.build_unconditional_branch(dest).unwrap();
1545 }
1546
1547 fn brif(
1548 &mut self,
1549 cond: Self::Value,
1550 then_block: Self::BasicBlock,
1551 else_block: Self::BasicBlock,
1552 ) {
1553 self.bcx.build_conditional_branch(cond.into_int_value(), then_block, else_block).unwrap();
1554 }
1555
1556 fn brif_cold(
1557 &mut self,
1558 cond: Self::Value,
1559 then_block: Self::BasicBlock,
1560 else_block: Self::BasicBlock,
1561 then_is_cold: bool,
1562 ) {
1563 let inst = self
1564 .bcx
1565 .build_conditional_branch(cond.into_int_value(), then_block, else_block)
1566 .unwrap();
1567 let weights = if then_is_cold { [1, DEFAULT_WEIGHT] } else { [DEFAULT_WEIGHT, 1] };
1568 self.set_branch_weights(inst, weights);
1569 }
1570
1571 fn switch(
1572 &mut self,
1573 index: Self::Value,
1574 default: Self::BasicBlock,
1575 targets: &[(u64, Self::BasicBlock)],
1576 default_is_cold: bool,
1577 ) {
1578 let ty = index.get_type().into_int_type();
1579 let targets =
1580 targets.iter().map(|(v, b)| (ty.const_int(*v, false), *b)).collect::<Vec<_>>();
1581 let inst = self.bcx.build_switch(index.into_int_value(), default, &targets).unwrap();
1582 if default_is_cold {
1583 let weights = iter::once(1).chain(iter::repeat_n(DEFAULT_WEIGHT, targets.len()));
1584 self.set_branch_weights(inst, weights);
1585 }
1586 }
1587
1588 fn br_indirect(&mut self, address: Self::Value, destinations: &[Self::BasicBlock]) {
1589 let _ = self.bcx.build_indirect_branch(address, destinations).unwrap();
1590 }
1591
1592 fn phi(&mut self, ty: Self::Type, incoming: &[(Self::Value, Self::BasicBlock)]) -> Self::Value {
1593 let incoming = incoming
1594 .iter()
1595 .map(|(value, block)| (value as &dyn BasicValue<'_>, *block))
1596 .collect::<Vec<_>>();
1597 let phi = self.bcx.build_phi(ty, "").unwrap();
1598 phi.add_incoming(&incoming);
1599 phi.as_basic_value()
1600 }
1601
1602 fn select(
1603 &mut self,
1604 cond: Self::Value,
1605 then_value: Self::Value,
1606 else_value: Self::Value,
1607 ) -> Self::Value {
1608 self.bcx.build_select(cond.into_int_value(), then_value, else_value, "").unwrap()
1609 }
1610
1611 fn iadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1612 self.bcx.build_int_add(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1613 }
1614
1615 fn isub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1616 self.bcx.build_int_sub(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1617 }
1618
1619 fn imul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1620 self.bcx.build_int_mul(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1621 }
1622
1623 fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1624 self.bcx
1625 .build_int_unsigned_div(lhs.into_int_value(), rhs.into_int_value(), "")
1626 .unwrap()
1627 .into()
1628 }
1629
1630 fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1631 self.bcx
1632 .build_int_signed_div(lhs.into_int_value(), rhs.into_int_value(), "")
1633 .unwrap()
1634 .into()
1635 }
1636
1637 fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1638 self.bcx
1639 .build_int_unsigned_rem(lhs.into_int_value(), rhs.into_int_value(), "")
1640 .unwrap()
1641 .into()
1642 }
1643
1644 fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1645 self.bcx
1646 .build_int_signed_rem(lhs.into_int_value(), rhs.into_int_value(), "")
1647 .unwrap()
1648 .into()
1649 }
1650
1651 fn iadd_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
1652 let rhs = self.iconst(lhs.get_type(), rhs);
1653 self.iadd(lhs, rhs)
1654 }
1655
1656 fn isub_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
1657 let rhs = self.iconst(lhs.get_type(), rhs);
1658 self.isub(lhs, rhs)
1659 }
1660
1661 fn imul_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
1662 let rhs = self.iconst(lhs.get_type(), rhs);
1663 self.imul(lhs, rhs)
1664 }
1665
1666 fn uadd_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
1670 let result = self.iadd(lhs, rhs);
1671 let overflow = self.icmp(IntCC::UnsignedLessThan, result, rhs);
1672 (result, overflow)
1673 }
1674
1675 fn usub_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
1676 let result = self.isub(lhs, rhs);
1677 let overflow = self.icmp(IntCC::UnsignedLessThan, lhs, rhs);
1678 (result, overflow)
1679 }
1680
1681 fn uadd_sat(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1682 let f = self.get_sat_function("uadd", lhs.get_type());
1683 self.call(f, &[lhs, rhs]).unwrap()
1684 }
1685
1686 fn umax(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1687 let ty = lhs.get_type();
1688 let name = format!("llvm.umax.{}", fmt_ty(ty));
1689 let max = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, ty]));
1690 self.call(max, &[lhs, rhs]).unwrap()
1691 }
1692
1693 fn umin(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1694 let ty = lhs.get_type();
1695 let name = format!("llvm.umin.{}", fmt_ty(ty));
1696 let min = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, ty]));
1697 self.call(min, &[lhs, rhs]).unwrap()
1698 }
1699
1700 fn bswap(&mut self, value: Self::Value) -> Self::Value {
1701 let ty = value.get_type();
1702 let name = format!("llvm.bswap.{}", fmt_ty(ty));
1703 let bswap = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty]));
1704 self.call(bswap, &[value]).unwrap()
1705 }
1706
1707 fn bitor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1708 self.bcx.build_or(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1709 }
1710
1711 fn bitand(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1712 self.bcx.build_and(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1713 }
1714
1715 fn bitxor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1716 self.bcx.build_xor(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1717 }
1718
1719 fn bitnot(&mut self, value: Self::Value) -> Self::Value {
1720 self.bcx.build_not(value.into_int_value(), "").unwrap().into()
1721 }
1722
1723 fn clz(&mut self, value: Self::Value) -> Self::Value {
1724 let ty = value.get_type();
1725 let i1_ty = self.type_int(1);
1726 let name = format!("llvm.ctlz.{}", fmt_ty(ty));
1727 let ctlz = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, i1_ty]));
1728 let is_poison_on_zero = self.bool_const(false);
1729 self.call(ctlz, &[value, is_poison_on_zero]).unwrap()
1730 }
1731
1732 fn bitor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
1733 let rhs = self.iconst(lhs.get_type(), rhs);
1734 self.bitor(lhs, rhs)
1735 }
1736
1737 fn bitand_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
1738 let rhs = self.iconst(lhs.get_type(), rhs);
1739 self.bitand(lhs, rhs)
1740 }
1741
1742 fn bitxor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
1743 let rhs = self.iconst(lhs.get_type(), rhs);
1744 self.bitxor(lhs, rhs)
1745 }
1746
1747 fn ishl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1748 self.bcx.build_left_shift(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
1749 }
1750
1751 fn ushr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1752 self.bcx
1753 .build_right_shift(lhs.into_int_value(), rhs.into_int_value(), false, "")
1754 .unwrap()
1755 .into()
1756 }
1757
1758 fn sshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1759 self.bcx
1760 .build_right_shift(lhs.into_int_value(), rhs.into_int_value(), true, "")
1761 .unwrap()
1762 .into()
1763 }
1764
1765 fn zext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value {
1766 self.bcx.build_int_z_extend(value.into_int_value(), ty.into_int_type(), "").unwrap().into()
1767 }
1768
1769 fn sext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value {
1770 self.bcx.build_int_s_extend(value.into_int_value(), ty.into_int_type(), "").unwrap().into()
1771 }
1772
1773 fn ireduce(&mut self, to: Self::Type, value: Self::Value) -> Self::Value {
1774 self.bcx.build_int_truncate(value.into_int_value(), to.into_int_type(), "").unwrap().into()
1775 }
1776
1777 fn inttoptr(&mut self, value: Self::Value, ty: Self::Type) -> Self::Value {
1778 self.bcx
1779 .build_int_to_ptr(value.into_int_value(), ty.into_pointer_type(), "")
1780 .unwrap()
1781 .into()
1782 }
1783
1784 fn gep(
1785 &mut self,
1786 elem_ty: Self::Type,
1787 ptr: Self::Value,
1788 indexes: &[Self::Value],
1789 name: &str,
1790 ) -> Self::Value {
1791 let indexes = indexes.iter().map(|idx| idx.into_int_value()).collect::<Vec<_>>();
1792 unsafe {
1793 self.bcx.build_in_bounds_gep(
1794 elem_ty,
1795 ptr.into_pointer_value(),
1796 &indexes,
1797 self.name(name),
1798 )
1799 }
1800 .unwrap()
1801 .into()
1802 }
1803
1804 fn tail_call(
1805 &mut self,
1806 function: Self::Function,
1807 args: &[Self::Value],
1808 tail_call: TailCallKind,
1809 ) -> Option<Self::Value> {
1810 let args = args.iter().copied().map(Into::into).collect::<Vec<_>>();
1811 let callsite = self.bcx.build_call(function, &args, "").unwrap();
1812 if let Some(call_conv) = function_call_conv(function) {
1813 unsafe {
1814 inkwell::llvm_sys::core::LLVMSetInstructionCallConv(
1815 callsite.as_value_ref(),
1816 call_conv as _,
1817 );
1818 }
1819 }
1820 if tail_call != TailCallKind::None {
1821 callsite.set_tail_call_kind(convert_tail_call_kind(tail_call));
1822 }
1823 callsite.try_as_basic_value().basic()
1824 }
1825
1826 fn is_compile_time_known(&mut self, value: Self::Value) -> Option<Self::Value> {
1827 let ty = value.get_type();
1828 let name = format!("llvm.is.constant.{}", fmt_ty(ty));
1829 let f =
1830 self.get_or_add_function(&name, |this| this.fn_type(Some(this.ty_i1.into()), &[ty]));
1831 Some(self.call(f, &[value]).unwrap())
1832 }
1833
1834 fn memcpy(&mut self, dst: Self::Value, src: Self::Value, len: Self::Value) {
1835 self.memcpy_inner(dst, src, len, false);
1836 }
1837
1838 fn memcpy_inline(&mut self, dst: Self::Value, src: Self::Value, len: i64) {
1839 let len = self.iconst(self.ty_i64.into(), len);
1840 self.memcpy_inner(dst, src, len, true);
1841 }
1842
1843 fn unreachable(&mut self) {
1844 self.bcx.build_unreachable().unwrap();
1845 }
1846
1847 fn get_or_build_function(
1848 &mut self,
1849 name: &str,
1850 params: &[Self::Type],
1851 ret: Option<Self::Type>,
1852 linkage: revmc_backend::Linkage,
1853 build: impl FnOnce(&mut Self),
1854 ) -> Self::Function {
1855 if let Some(function) = self.module().get_function(name) {
1856 return function;
1857 }
1858
1859 let before = self.current_block();
1860
1861 let func_ty = self.fn_type(ret, params);
1862 let function = self.module().add_function(name, func_ty, Some(convert_linkage(linkage)));
1863 cpp::set_dso_local(function);
1864 let prev_function = std::mem::replace(&mut self.function, function);
1865
1866 let entry = self.cx.append_basic_block(function, self.name("entry"));
1867 self.bcx.position_at_end(entry);
1868 build(self);
1869 if let Some(before) = before {
1870 self.bcx.position_at_end(before);
1871 }
1872
1873 self.function = prev_function;
1874
1875 function
1876 }
1877
1878 fn get_function(&mut self, name: &str) -> Option<Self::Function> {
1879 self.module().get_function(name)
1880 }
1881
1882 fn get_printf_function(&mut self) -> Self::Function {
1883 let name = "printf";
1884 if let Some(function) = self.module().get_function(name) {
1885 return function;
1886 }
1887
1888 let ty = self.cx.void_type().fn_type(&[self.ty_ptr.into()], true);
1889 let function =
1890 self.module().add_function(name, ty, Some(inkwell::module::Linkage::External));
1891 cpp::set_dso_local(function);
1892 function
1893 }
1894
1895 fn add_function(
1896 &mut self,
1897 name: &str,
1898 params: &[Self::Type],
1899 ret: Option<Self::Type>,
1900 address: Option<usize>,
1901 linkage: revmc_backend::Linkage,
1902 call_conv: CallConv,
1903 ) -> Self::Function {
1904 let func_ty = self.fn_type(ret, params);
1905 let function = self.module().add_function(name, func_ty, Some(convert_linkage(linkage)));
1906 set_function_call_conv(function, call_conv);
1907 cpp::set_dso_local(function);
1908 if let Some(address) = address
1909 && let Some(orc) = &mut self.orc
1910 {
1911 orc.pending_symbols.push((CString::new(name).unwrap(), address));
1912 }
1913 function
1914 }
1915
1916 fn add_function_stub(
1917 &mut self,
1918 function: Self::Function,
1919 call_conv: CallConv,
1920 ) -> Self::Function {
1921 let name = function.get_name().to_string_lossy();
1922 let stub_name = format!("{name}.stub");
1923 if let Some(stub) = self.module().get_function(&stub_name) {
1924 return stub;
1925 }
1926
1927 let func_ty = function.get_type();
1928 let stub = self.module().add_function(
1929 &stub_name,
1930 func_ty,
1931 Some(inkwell::module::Linkage::Internal),
1932 );
1933 set_function_call_conv(stub, call_conv);
1934 cpp::set_dso_local(stub);
1935 self.add_function_attribute(
1936 Some(stub),
1937 revmc_backend::Attribute::NoInline,
1938 revmc_backend::FunctionAttributeLocation::Function,
1939 );
1940
1941 let before = self.bcx.get_insert_block();
1942 let debug_location = self.debug_scope.and_then(|_| self.bcx.get_current_debug_location());
1943 self.bcx.unset_current_debug_location();
1944
1945 let entry = self.cx.append_basic_block(stub, self.name("stub"));
1946 self.bcx.position_at_end(entry);
1947 let args =
1948 (0..stub.count_params()).map(|i| stub.get_nth_param(i).unwrap()).collect::<Vec<_>>();
1949 if let Some(value) = self.call(function, &args) {
1950 self.bcx.build_return(Some(&value)).unwrap();
1951 } else {
1952 self.bcx.build_return(None).unwrap();
1953 }
1954
1955 if let Some(before) = before {
1956 self.bcx.position_at_end(before);
1957 }
1958 if let Some(debug_location) = debug_location {
1959 self.bcx.set_current_debug_location(debug_location);
1960 }
1961
1962 stub
1963 }
1964
1965 fn add_function_attribute(
1966 &mut self,
1967 function: Option<Self::Function>,
1968 attribute: revmc_backend::Attribute,
1969 loc: revmc_backend::FunctionAttributeLocation,
1970 ) {
1971 let func = function.unwrap_or(self.function);
1972 let loc = convert_attribute_loc(loc);
1973 let attr = convert_attribute(self, attribute);
1974 func.add_attribute(loc, attr);
1975 }
1976}
1977
1978fn build_pass_pipeline(with_licm: bool) -> String {
1980 let mut passes = String::from("module(globalopt,cgscc(inline),globalopt,function(");
1981 let function_passes: &[&str] = &[
1982 "simplifycfg",
1983 "sroa",
1984 "early-cse",
1985 "jump-threading",
1986 "correlated-propagation",
1987 "simplifycfg",
1988 "instcombine<no-verify-fixpoint>",
1989 ];
1990 let licm_passes: &[&str] =
1991 &["loop-mssa(licm,loop-rotate,licm)", "simplifycfg", "instcombine<no-verify-fixpoint>"];
1992 let post_passes: &[&str] = &[
1993 "sroa",
1994 "early-cse",
1995 "sccp",
1996 "instcombine<no-verify-fixpoint>",
1997 "adce",
1998 "dse",
1999 "simplifycfg",
2000 ];
2001
2002 let iter =
2003 function_passes.iter().chain(if with_licm { licm_passes } else { &[] }).chain(post_passes);
2004 for (i, pass) in iter.enumerate() {
2005 if i > 0 {
2006 passes.push(',');
2007 }
2008 passes.push_str(pass);
2009 }
2010 passes.push_str("),globaldce)");
2011 passes
2012}
2013
2014fn init() -> Result<()> {
2015 let mut init_result = Ok(());
2016 static INIT: Once = Once::new();
2017 INIT.call_once(|| init_result = init_());
2018 init_result
2019}
2020
2021fn init_() -> Result<()> {
2022 extern "C" fn report_fatal_error(msg: *const std::ffi::c_char) {
2027 let msg_cstr = unsafe { std::ffi::CStr::from_ptr(msg) };
2028 let msg = msg_cstr.to_string_lossy();
2029 error!(target: "llvm", "LLVM fatal error: {msg}");
2030 }
2031
2032 unsafe {
2033 install_fatal_error_handler(report_fatal_error);
2034 }
2035
2036 let extra: Vec<CString> = std::env::var("REVMC_LLVM_ARGS")
2038 .ok()
2039 .iter()
2040 .flat_map(|s| s.split_whitespace().filter_map(|s| CString::new(s).ok()).collect::<Vec<_>>())
2041 .collect();
2042 if !extra.is_empty() {
2043 debug!(extra = ?&extra, "passing extra LLVM args");
2044 }
2045
2046 let mut args = vec![
2048 c"revmc-llvm".as_ptr(),
2049 c"-x86-asm-syntax=intel".as_ptr(),
2050 c"--cgpp-huge-func=1000".as_ptr(),
2057 c"--huge-size-for-split=64".as_ptr(),
2062 ];
2063 args.extend(extra.iter().map(|s| s.as_ptr()));
2064 unsafe {
2065 inkwell::llvm_sys::support::LLVMParseCommandLineOptions(
2066 args.len() as i32,
2067 args.as_ptr(),
2068 std::ptr::null(),
2069 )
2070 }
2071
2072 let config = InitializationConfig {
2073 asm_parser: false,
2074 asm_printer: true,
2075 base: true,
2076 disassembler: true,
2077 info: true,
2078 machine_code: true,
2079 };
2080 Target::initialize_all(&config);
2081
2082 Ok(())
2083}
2084
2085fn create_module<'ctx>(
2086 cx: &'ctx Context,
2087 machine: &TargetMachine,
2088 aot: bool,
2089) -> Result<Module<'ctx>> {
2090 let module_name = "evm";
2091 let module = cx.create_module(module_name);
2092 module.set_source_file_name(module_name);
2093 module.set_data_layout(&machine.get_target_data().get_data_layout());
2094 module.set_triple(&machine.get_triple());
2095 if aot {
2096 module.add_basic_value_flag(
2097 "PIC Level",
2098 FlagBehavior::Error, cx.i32_type().const_int(2, false),
2100 );
2101 module.add_basic_value_flag(
2102 "RtLibUseGOT",
2103 FlagBehavior::Warning,
2104 cx.i32_type().const_int(1, false),
2105 );
2106 }
2107 Ok(module)
2108}
2109
2110fn convert_intcc(cond: IntCC) -> IntPredicate {
2111 match cond {
2112 IntCC::Equal => IntPredicate::EQ,
2113 IntCC::NotEqual => IntPredicate::NE,
2114 IntCC::SignedLessThan => IntPredicate::SLT,
2115 IntCC::SignedGreaterThanOrEqual => IntPredicate::SGE,
2116 IntCC::SignedGreaterThan => IntPredicate::SGT,
2117 IntCC::SignedLessThanOrEqual => IntPredicate::SLE,
2118 IntCC::UnsignedLessThan => IntPredicate::ULT,
2119 IntCC::UnsignedGreaterThanOrEqual => IntPredicate::UGE,
2120 IntCC::UnsignedGreaterThan => IntPredicate::UGT,
2121 IntCC::UnsignedLessThanOrEqual => IntPredicate::ULE,
2122 }
2123}
2124
2125fn convert_opt_level(level: OptimizationLevel) -> inkwell::OptimizationLevel {
2126 match level {
2127 OptimizationLevel::None => inkwell::OptimizationLevel::None,
2128 OptimizationLevel::Less => inkwell::OptimizationLevel::Less,
2129 OptimizationLevel::Default => inkwell::OptimizationLevel::Default,
2130 OptimizationLevel::Aggressive => inkwell::OptimizationLevel::Aggressive,
2131 }
2132}
2133
2134fn convert_attribute(bcx: &EvmLlvmBuilder<'_>, attr: revmc_backend::Attribute) -> Attribute {
2135 use revmc_backend::Attribute as OurAttr;
2136
2137 enum AttrValue<'a> {
2138 String(&'a str),
2139 Enum(u64),
2140 Type(AnyTypeEnum<'a>),
2141 }
2142
2143 let cpu;
2144 let (key, value) = match attr {
2145 OurAttr::WillReturn => ("willreturn", AttrValue::Enum(0)),
2146 OurAttr::NoReturn => ("noreturn", AttrValue::Enum(0)),
2147 OurAttr::NoFree => ("nofree", AttrValue::Enum(0)),
2148 OurAttr::NoRecurse => ("norecurse", AttrValue::Enum(0)),
2149 OurAttr::NoSync => ("nosync", AttrValue::Enum(0)),
2150 OurAttr::NoUnwind => ("nounwind", AttrValue::Enum(0)),
2151 OurAttr::NonLazyBind => ("nonlazybind", AttrValue::Enum(0)),
2152 OurAttr::UWTable => ("uwtable", AttrValue::Enum(2)),
2153 OurAttr::AllFramePointers => ("frame-pointer", AttrValue::String("all")),
2154 OurAttr::NativeTargetCpu => (
2155 "target-cpu",
2156 AttrValue::String({
2157 cpu = bcx.machine.get_cpu();
2158 cpu.to_str().unwrap()
2159 }),
2160 ),
2161 OurAttr::Cold => ("cold", AttrValue::Enum(0)),
2162 OurAttr::Hot => ("hot", AttrValue::Enum(0)),
2163 OurAttr::HintInline => ("inlinehint", AttrValue::Enum(0)),
2164 OurAttr::AlwaysInline => ("alwaysinline", AttrValue::Enum(0)),
2165 OurAttr::NoInline => ("noinline", AttrValue::Enum(0)),
2166 OurAttr::Speculatable => ("speculatable", AttrValue::Enum(0)),
2167
2168 OurAttr::NoAlias => ("noalias", AttrValue::Enum(0)),
2169 OurAttr::NoCapture => ("captures", AttrValue::Enum(0)), OurAttr::NoUndef => ("noundef", AttrValue::Enum(0)),
2171 OurAttr::Align(n) => ("align", AttrValue::Enum(n)),
2172 OurAttr::NonNull => ("nonnull", AttrValue::Enum(0)),
2173 OurAttr::Dereferenceable(n) => ("dereferenceable", AttrValue::Enum(n)),
2174 OurAttr::SRet(n) => {
2175 ("sret", AttrValue::Type(bcx.type_array(bcx.ty_i8.into(), n as _).as_any_type_enum()))
2176 }
2177 OurAttr::ReadNone => ("readnone", AttrValue::Enum(0)),
2178 OurAttr::ReadOnly => ("readonly", AttrValue::Enum(0)),
2179 OurAttr::WriteOnly => ("writeonly", AttrValue::Enum(0)),
2180 OurAttr::Writable => ("writable", AttrValue::Enum(0)),
2181 OurAttr::ArgMemOnly => ("memory", AttrValue::Enum(3)),
2183 OurAttr::DeadOnReturn => ("dead_on_return", AttrValue::Enum(0)),
2184
2185 OurAttr::Initializes(size) => {
2186 return cpp::create_initializes_attr(bcx.cx, 0, size as i64);
2187 }
2188
2189 attr => unimplemented!("llvm attribute conversion: {attr:?}"),
2190 };
2191 match value {
2192 AttrValue::String(value) => bcx.cx.create_string_attribute(key, value),
2193 AttrValue::Enum(value) => {
2194 let id = Attribute::get_named_enum_kind_id(key);
2195 bcx.cx.create_enum_attribute(id, value)
2196 }
2197 AttrValue::Type(ty) => {
2198 let id = Attribute::get_named_enum_kind_id(key);
2199 bcx.cx.create_type_attribute(id, ty)
2200 }
2201 }
2202}
2203
2204fn convert_attribute_loc(loc: revmc_backend::FunctionAttributeLocation) -> AttributeLoc {
2205 match loc {
2206 revmc_backend::FunctionAttributeLocation::Return => AttributeLoc::Return,
2207 revmc_backend::FunctionAttributeLocation::Param(i) => AttributeLoc::Param(i),
2208 revmc_backend::FunctionAttributeLocation::Function => AttributeLoc::Function,
2209 }
2210}
2211
2212fn function_call_conv(function: FunctionValue<'_>) -> Option<u32> {
2213 let call_conv =
2214 unsafe { inkwell::llvm_sys::core::LLVMGetFunctionCallConv(function.as_value_ref()) };
2215 (call_conv != inkwell::llvm_sys::LLVMCallConv::LLVMCCallConv as u32).then_some(call_conv)
2216}
2217
2218fn set_function_call_conv(function: FunctionValue<'_>, call_conv: CallConv) {
2219 let Some(call_conv) = convert_call_conv(call_conv) else { return };
2220 unsafe {
2221 inkwell::llvm_sys::core::LLVMSetFunctionCallConv(function.as_value_ref(), call_conv as _);
2222 }
2223}
2224
2225fn convert_call_conv(call_conv: CallConv) -> Option<inkwell::llvm_sys::LLVMCallConv> {
2226 match call_conv {
2227 CallConv::Default => None,
2228 CallConv::Cold => Some(inkwell::llvm_sys::LLVMCallConv::LLVMPreserveMostCallConv),
2229 }
2230}
2231
2232fn convert_linkage(linkage: revmc_backend::Linkage) -> inkwell::module::Linkage {
2233 match linkage {
2234 revmc_backend::Linkage::Public => inkwell::module::Linkage::External,
2235 revmc_backend::Linkage::Import => inkwell::module::Linkage::External,
2236 revmc_backend::Linkage::Private => inkwell::module::Linkage::Private,
2237 }
2238}
2239
2240fn convert_tail_call_kind(kind: TailCallKind) -> inkwell::llvm_sys::LLVMTailCallKind {
2241 match kind {
2242 TailCallKind::None => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindNone,
2243 TailCallKind::Tail => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindTail,
2244 TailCallKind::MustTail => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindMustTail,
2245 TailCallKind::NoTail => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindNoTail,
2246 }
2247}
2248
2249fn error_msg(msg: inkwell::support::LLVMString) -> revmc_backend::Error {
2251 revmc_backend::Error::msg(msg.to_string_lossy().trim_end().to_string())
2252}
2253
2254fn fmt_ty(ty: BasicTypeEnum<'_>) -> impl std::fmt::Display {
2255 ty.print_to_string().to_str().unwrap().trim_matches('"').to_string()
2256}