revmc_llvm/
lib.rs

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 inkwell::{
9    attributes::{Attribute, AttributeLoc},
10    basic_block::BasicBlock,
11    execution_engine::ExecutionEngine,
12    module::{FlagBehavior, Module},
13    passes::PassBuilderOptions,
14    support::error_handling::install_fatal_error_handler,
15    targets::{
16        CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, TargetTriple,
17    },
18    types::{
19        AnyType, AnyTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, PointerType,
20        StringRadix, VoidType,
21    },
22    values::{
23        BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, InstructionValue,
24        PointerValue,
25    },
26    AddressSpace, IntPredicate, OptimizationLevel,
27};
28use revmc_backend::{
29    eyre, Backend, BackendTypes, Builder, Error, IntCC, Result, TailCallKind, TypeMethods, U256,
30};
31use rustc_hash::FxHashMap;
32use std::{
33    borrow::Cow,
34    iter,
35    path::Path,
36    sync::{Once, OnceLock},
37};
38
39pub use inkwell::{self, context::Context};
40
41mod dh;
42pub mod orc;
43
44mod utils;
45pub(crate) use utils::*;
46
47const DEFAULT_WEIGHT: u32 = 20000;
48
49/// Executes the given closure with a thread-local LLVM context.
50#[inline]
51pub fn with_llvm_context<R>(f: impl FnOnce(&Context) -> R) -> R {
52    thread_local! {
53        static TLS_LLVM_CONTEXT: Context = Context::create();
54    }
55    TLS_LLVM_CONTEXT.with(f)
56}
57
58/// The LLVM-based EVM bytecode compiler backend.
59#[derive(Debug)]
60#[must_use]
61pub struct EvmLlvmBackend<'ctx> {
62    cx: &'ctx Context,
63    _dh: dh::DiagnosticHandlerGuard<'ctx>,
64    bcx: inkwell::builder::Builder<'ctx>,
65    module: Module<'ctx>,
66    exec_engine: Option<ExecutionEngine<'ctx>>,
67    machine: TargetMachine,
68
69    ty_void: VoidType<'ctx>,
70    ty_ptr: PointerType<'ctx>,
71    ty_i1: IntType<'ctx>,
72    ty_i8: IntType<'ctx>,
73    ty_i32: IntType<'ctx>,
74    ty_i64: IntType<'ctx>,
75    ty_i256: IntType<'ctx>,
76    ty_isize: IntType<'ctx>,
77
78    aot: bool,
79    debug_assertions: bool,
80    opt_level: OptimizationLevel,
81    /// Separate from `functions` to have always increasing IDs.
82    function_counter: u32,
83    functions: FxHashMap<u32, (String, FunctionValue<'ctx>)>,
84}
85
86impl<'ctx> EvmLlvmBackend<'ctx> {
87    /// Creates a new LLVM backend for the host machine.
88    ///
89    /// Use [`new_for_target`](Self::new_for_target) to create a backend for a specific target.
90    pub fn new(
91        cx: &'ctx Context,
92        aot: bool,
93        opt_level: revmc_backend::OptimizationLevel,
94    ) -> Result<Self> {
95        Self::new_for_target(cx, aot, opt_level, &revmc_backend::Target::Native)
96    }
97
98    /// Creates a new LLVM backend for the given target.
99    #[instrument(name = "new_llvm_backend", level = "debug", skip_all)]
100    pub fn new_for_target(
101        cx: &'ctx Context,
102        aot: bool,
103        opt_level: revmc_backend::OptimizationLevel,
104        target: &revmc_backend::Target,
105    ) -> Result<Self> {
106        init()?;
107
108        let opt_level = convert_opt_level(opt_level);
109
110        let target_info = TargetInfo::new(target)?;
111        let target = &target_info.target;
112        let machine = target
113            .create_target_machine(
114                &target_info.triple,
115                &target_info.cpu,
116                &target_info.features,
117                opt_level,
118                RelocMode::PIC,
119                if aot { CodeModel::Default } else { CodeModel::JITDefault },
120            )
121            .ok_or_else(|| eyre::eyre!("failed to create target machine"))?;
122
123        let module = create_module(cx, &machine)?;
124
125        let exec_engine = if aot {
126            None
127        } else {
128            if !target.has_jit() {
129                return Err(eyre::eyre!("target {:?} does not support JIT", target.get_name()));
130            }
131            if !target.has_target_machine() {
132                return Err(eyre::eyre!(
133                    "target {:?} does not have target machine",
134                    target.get_name()
135                ));
136            }
137            Some(module.create_jit_execution_engine(opt_level).map_err(error_msg)?)
138        };
139
140        let bcx = cx.create_builder();
141
142        let ty_void = cx.void_type();
143        let ty_i1 = cx.bool_type();
144        let ty_i8 = cx.i8_type();
145        let ty_i32 = cx.i32_type();
146        let ty_i64 = cx.i64_type();
147        let ty_i256 = cx.custom_width_int_type(256);
148        let ty_isize = cx.ptr_sized_int_type(&machine.get_target_data(), None);
149        let ty_ptr = cx.ptr_type(AddressSpace::default());
150        Ok(Self {
151            cx,
152            _dh: dh::DiagnosticHandlerGuard::new(cx),
153            bcx,
154            module,
155            exec_engine,
156            machine,
157            ty_void,
158            ty_i1,
159            ty_i8,
160            ty_i32,
161            ty_i64,
162            ty_i256,
163            ty_isize,
164            ty_ptr,
165            aot,
166            debug_assertions: cfg!(debug_assertions),
167            opt_level,
168            function_counter: 0,
169            functions: FxHashMap::default(),
170        })
171    }
172
173    /// Returns the LLVM context.
174    #[inline]
175    pub fn cx(&self) -> &'ctx Context {
176        self.cx
177    }
178
179    fn exec_engine(&self) -> &ExecutionEngine<'ctx> {
180        assert!(!self.aot, "requested JIT execution engine on AOT");
181        self.exec_engine.as_ref().expect("missing JIT execution engine")
182    }
183
184    fn fn_type(
185        &self,
186        ret: Option<BasicTypeEnum<'ctx>>,
187        params: &[BasicTypeEnum<'ctx>],
188    ) -> FunctionType<'ctx> {
189        let params = params.iter().copied().map(Into::into).collect::<Vec<_>>();
190        match ret {
191            Some(ret) => ret.fn_type(&params, false),
192            None => self.ty_void.fn_type(&params, false),
193        }
194    }
195
196    fn id_to_name(&self, id: u32) -> &str {
197        &self.functions[&id].0
198    }
199
200    // Delete IR to lower memory consumption.
201    // For some reason this does not happen when `Drop`ping either the `Module` or the engine.
202    fn clear_module(&mut self) {
203        for function in self.module.get_functions() {
204            unsafe { function.delete() };
205        }
206        for global in self.module.get_globals() {
207            unsafe { global.delete() };
208        }
209        self.functions.clear();
210    }
211}
212
213impl<'ctx> BackendTypes for EvmLlvmBackend<'ctx> {
214    type Type = BasicTypeEnum<'ctx>;
215    type Value = BasicValueEnum<'ctx>;
216    type StackSlot = PointerValue<'ctx>;
217    type BasicBlock = BasicBlock<'ctx>;
218    type Function = FunctionValue<'ctx>;
219}
220
221impl TypeMethods for EvmLlvmBackend<'_> {
222    fn type_ptr(&self) -> Self::Type {
223        self.ty_ptr.into()
224    }
225
226    fn type_ptr_sized_int(&self) -> Self::Type {
227        self.ty_isize.into()
228    }
229
230    fn type_int(&self, bits: u32) -> Self::Type {
231        match bits {
232            1 => self.ty_i1,
233            8 => self.ty_i8,
234            16 => self.cx.i16_type(),
235            32 => self.ty_i32,
236            64 => self.ty_i64,
237            128 => self.cx.i128_type(),
238            256 => self.ty_i256,
239            bits => self.cx.custom_width_int_type(bits),
240        }
241        .into()
242    }
243
244    fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type {
245        ty.array_type(size).into()
246    }
247
248    fn type_bit_width(&self, ty: Self::Type) -> u32 {
249        ty.into_int_type().get_bit_width()
250    }
251}
252
253impl<'ctx> Backend for EvmLlvmBackend<'ctx> {
254    type Builder<'a>
255        = EvmLlvmBuilder<'a, 'ctx>
256    where
257        Self: 'a;
258    type FuncId = u32;
259
260    fn ir_extension(&self) -> &'static str {
261        "ll"
262    }
263
264    fn set_module_name(&mut self, name: &str) {
265        self.module.set_name(name);
266    }
267
268    fn set_is_dumping(&mut self, yes: bool) {
269        self.machine.set_asm_verbosity(yes);
270    }
271
272    fn set_debug_assertions(&mut self, yes: bool) {
273        self.debug_assertions = yes;
274    }
275
276    fn opt_level(&self) -> revmc_backend::OptimizationLevel {
277        convert_opt_level_rev(self.opt_level)
278    }
279
280    fn set_opt_level(&mut self, level: revmc_backend::OptimizationLevel) {
281        self.opt_level = convert_opt_level(level);
282    }
283
284    fn is_aot(&self) -> bool {
285        self.aot
286    }
287
288    fn function_name_is_unique(&self, name: &str) -> bool {
289        self.module.get_function(name).is_none()
290    }
291
292    fn dump_ir(&mut self, path: &Path) -> Result<()> {
293        self.module.print_to_file(path).map_err(error_msg)
294    }
295
296    fn dump_disasm(&mut self, path: &Path) -> Result<()> {
297        self.machine.write_to_file(&self.module, FileType::Assembly, path).map_err(error_msg)
298    }
299
300    fn build_function(
301        &mut self,
302        name: &str,
303        ret: Option<Self::Type>,
304        params: &[Self::Type],
305        param_names: &[&str],
306        linkage: revmc_backend::Linkage,
307    ) -> Result<(Self::Builder<'_>, Self::FuncId)> {
308        let (id, function) = if let Some((&id, &(_, function))) =
309            self.functions.iter().find(|(_k, (fname, _f))| fname == name)
310        {
311            self.bcx.position_at_end(function.get_first_basic_block().unwrap());
312            (id, function)
313        } else {
314            let fn_type = self.fn_type(ret, params);
315            let function = self.module.add_function(name, fn_type, Some(convert_linkage(linkage)));
316            for (i, &name) in param_names.iter().enumerate() {
317                function.get_nth_param(i as u32).expect(name).set_name(name);
318            }
319
320            let entry = self.cx.append_basic_block(function, "entry");
321            self.bcx.position_at_end(entry);
322
323            let id = self.function_counter;
324            self.function_counter += 1;
325            self.functions.insert(id, (name.to_string(), function));
326            (id, function)
327        };
328        let builder = EvmLlvmBuilder { backend: self, function };
329        Ok((builder, id))
330    }
331
332    fn verify_module(&mut self) -> Result<()> {
333        self.module.verify().map_err(error_msg)
334    }
335
336    fn optimize_module(&mut self) -> Result<()> {
337        // From `opt --help`, `-passes`.
338        let passes = match self.opt_level {
339            OptimizationLevel::None => "default<O0>",
340            OptimizationLevel::Less => "default<O1>",
341            OptimizationLevel::Default => "default<O2>",
342            OptimizationLevel::Aggressive => "default<O3>",
343        };
344        let opts = PassBuilderOptions::create();
345        self.module.run_passes(passes, &self.machine, opts).map_err(error_msg)
346    }
347
348    fn write_object<W: std::io::Write>(&mut self, mut w: W) -> Result<()> {
349        let buffer = self
350            .machine
351            .write_to_memory_buffer(&self.module, FileType::Object)
352            .map_err(error_msg)?;
353        w.write_all(buffer.as_slice())?;
354        Ok(())
355    }
356
357    fn jit_function(&mut self, id: Self::FuncId) -> Result<usize> {
358        let name = self.id_to_name(id);
359        let addr = self.exec_engine().get_function_address(name)?;
360        Ok(addr)
361    }
362
363    unsafe fn free_function(&mut self, id: Self::FuncId) -> Result<()> {
364        let name = self.id_to_name(id);
365        let function = self.exec_engine().get_function_value(name)?;
366        self.exec_engine().free_fn_machine_code(function);
367        self.functions.clear();
368        Ok(())
369    }
370
371    unsafe fn free_all_functions(&mut self) -> Result<()> {
372        self.clear_module();
373        if let Some(exec_engine) = &self.exec_engine {
374            exec_engine.remove_module(&self.module).map_err(|e| Error::msg(e.to_string()))?;
375        }
376        self.module = create_module(self.cx, &self.machine)?;
377        if self.exec_engine.is_some() {
378            self.exec_engine =
379                Some(self.module.create_jit_execution_engine(self.opt_level).map_err(error_msg)?);
380        }
381        Ok(())
382    }
383}
384
385impl Drop for EvmLlvmBackend<'_> {
386    fn drop(&mut self) {
387        self.clear_module();
388    }
389}
390
391/// Cached target information for the host machine.
392#[derive(Debug)]
393struct TargetInfo {
394    triple: TargetTriple,
395    target: Target,
396    cpu: String,
397    features: String,
398}
399
400// SAFETY: No mutability is exposed and `TargetTriple` is an owned string.
401unsafe impl std::marker::Send for TargetInfo {}
402unsafe impl std::marker::Sync for TargetInfo {}
403
404impl Clone for TargetInfo {
405    fn clone(&self) -> Self {
406        let triple = TargetTriple::create(self.triple.as_str().to_str().unwrap());
407        Self {
408            target: Target::from_triple(&triple).unwrap(),
409            triple,
410            cpu: self.cpu.clone(),
411            features: self.features.clone(),
412        }
413    }
414}
415
416impl TargetInfo {
417    fn new(target: &revmc_backend::Target) -> Result<Cow<'static, Self>> {
418        match target {
419            revmc_backend::Target::Native => {
420                static HOST_TARGET_INFO: OnceLock<TargetInfo> = OnceLock::new();
421                Ok(Cow::Borrowed(HOST_TARGET_INFO.get_or_init(|| {
422                    let triple = TargetMachine::get_default_triple();
423                    let target = Target::from_triple(&triple).unwrap();
424                    let cpu = TargetMachine::get_host_cpu_name().to_string_lossy().into_owned();
425                    let features =
426                        TargetMachine::get_host_cpu_features().to_string_lossy().into_owned();
427                    Self { target, triple, cpu, features }
428                })))
429            }
430            revmc_backend::Target::Triple { triple, cpu, features } => {
431                let triple = TargetTriple::create(triple);
432                let target = Target::from_triple(&triple).map_err(error_msg)?;
433                let cpu = cpu.as_ref().cloned().unwrap_or_default();
434                let features = features.as_ref().cloned().unwrap_or_default();
435                Ok(Cow::Owned(Self { target, triple, cpu, features }))
436            }
437        }
438    }
439}
440
441/// The LLVM-based EVM bytecode compiler function builder.
442#[derive(Debug)]
443#[must_use]
444pub struct EvmLlvmBuilder<'a, 'ctx> {
445    backend: &'a mut EvmLlvmBackend<'ctx>,
446    function: FunctionValue<'ctx>,
447}
448
449impl<'ctx> std::ops::Deref for EvmLlvmBuilder<'_, 'ctx> {
450    type Target = EvmLlvmBackend<'ctx>;
451
452    #[inline]
453    fn deref(&self) -> &Self::Target {
454        self.backend
455    }
456}
457
458impl std::ops::DerefMut for EvmLlvmBuilder<'_, '_> {
459    #[inline]
460    fn deref_mut(&mut self) -> &mut Self::Target {
461        self.backend
462    }
463}
464
465impl<'ctx> EvmLlvmBuilder<'_, 'ctx> {
466    #[allow(dead_code)]
467    fn extract_value(
468        &mut self,
469        value: BasicValueEnum<'ctx>,
470        index: u32,
471        name: &str,
472    ) -> BasicValueEnum<'ctx> {
473        self.bcx.build_extract_value(value.into_struct_value(), index, name).unwrap()
474    }
475
476    fn memcpy_inner(
477        &mut self,
478        dst: BasicValueEnum<'ctx>,
479        src: BasicValueEnum<'ctx>,
480        len: BasicValueEnum<'ctx>,
481        inline: bool,
482    ) {
483        let dst = dst.into_pointer_value();
484        let src = src.into_pointer_value();
485        let len = len.into_int_value();
486        let volatile = self.bool_const(false);
487        let name = format!(
488            "llvm.memcpy{}.p0.p0.{}",
489            if inline { ".inline" } else { "" },
490            fmt_ty(len.get_type().into()),
491        );
492        let memcpy = self.get_or_add_function(&name, |this| {
493            this.ty_void.fn_type(
494                &[this.ty_ptr.into(), this.ty_ptr.into(), this.ty_i64.into(), this.ty_i1.into()],
495                false,
496            )
497        });
498        self.bcx
499            .build_call(memcpy, &[dst.into(), src.into(), len.into(), volatile.into()], "")
500            .unwrap();
501    }
502
503    #[allow(dead_code)]
504    fn call_overflow_function(
505        &mut self,
506        name: &str,
507        lhs: BasicValueEnum<'ctx>,
508        rhs: BasicValueEnum<'ctx>,
509    ) -> (BasicValueEnum<'ctx>, BasicValueEnum<'ctx>) {
510        let f = self.get_overflow_function(name, lhs.get_type());
511        let result = self.call(f, &[lhs, rhs]).unwrap();
512        (self.extract_value(result, 0, "result"), self.extract_value(result, 1, "overflow"))
513    }
514
515    #[allow(dead_code)]
516    fn get_overflow_function(
517        &mut self,
518        name: &str,
519        ty: BasicTypeEnum<'ctx>,
520    ) -> FunctionValue<'ctx> {
521        let name = format!("llvm.{name}.with.overflow.{}", fmt_ty(ty));
522        self.get_or_add_function(&name, |this| {
523            this.fn_type(
524                Some(this.cx.struct_type(&[ty, this.ty_i1.into()], false).into()),
525                &[ty, ty],
526            )
527        })
528    }
529
530    fn get_sat_function(&mut self, name: &str, ty: BasicTypeEnum<'ctx>) -> FunctionValue<'ctx> {
531        let name = format!("llvm.{name}.sat.{}", fmt_ty(ty));
532        self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, ty]))
533    }
534
535    fn get_or_add_function(
536        &mut self,
537        name: &str,
538        mk_ty: impl FnOnce(&mut Self) -> FunctionType<'ctx>,
539    ) -> FunctionValue<'ctx> {
540        match self.module.get_function(name) {
541            Some(function) => function,
542            None => {
543                let ty = mk_ty(self);
544                self.module.add_function(name, ty, None)
545            }
546        }
547    }
548
549    fn set_branch_weights(
550        &self,
551        inst: InstructionValue<'ctx>,
552        weights: impl IntoIterator<Item = u32>,
553    ) {
554        let weights = weights.into_iter();
555        let mut values =
556            Vec::<BasicMetadataValueEnum<'ctx>>::with_capacity(1 + weights.size_hint().1.unwrap());
557        values.push(self.cx.metadata_string("branch_weights").into());
558        for weight in weights {
559            values.push(self.ty_i32.const_int(weight as u64, false).into());
560        }
561        let metadata = self.cx.metadata_node(&values);
562        let kind_id = self.cx.get_kind_id("prof");
563        inst.set_metadata(metadata, kind_id).unwrap();
564    }
565}
566
567impl<'ctx> BackendTypes for EvmLlvmBuilder<'_, 'ctx> {
568    type Type = <EvmLlvmBackend<'ctx> as BackendTypes>::Type;
569    type Value = <EvmLlvmBackend<'ctx> as BackendTypes>::Value;
570    type StackSlot = <EvmLlvmBackend<'ctx> as BackendTypes>::StackSlot;
571    type BasicBlock = <EvmLlvmBackend<'ctx> as BackendTypes>::BasicBlock;
572    type Function = <EvmLlvmBackend<'ctx> as BackendTypes>::Function;
573}
574
575impl TypeMethods for EvmLlvmBuilder<'_, '_> {
576    fn type_ptr(&self) -> Self::Type {
577        self.backend.type_ptr()
578    }
579
580    fn type_ptr_sized_int(&self) -> Self::Type {
581        self.backend.type_ptr_sized_int()
582    }
583
584    fn type_int(&self, bits: u32) -> Self::Type {
585        self.backend.type_int(bits)
586    }
587
588    fn type_array(&self, ty: Self::Type, size: u32) -> Self::Type {
589        self.backend.type_array(ty, size)
590    }
591
592    fn type_bit_width(&self, ty: Self::Type) -> u32 {
593        self.backend.type_bit_width(ty)
594    }
595}
596
597impl Builder for EvmLlvmBuilder<'_, '_> {
598    fn create_block(&mut self, name: &str) -> Self::BasicBlock {
599        self.cx.append_basic_block(self.function, name)
600    }
601
602    fn create_block_after(&mut self, after: Self::BasicBlock, name: &str) -> Self::BasicBlock {
603        self.cx.insert_basic_block_after(after, name)
604    }
605
606    fn switch_to_block(&mut self, block: Self::BasicBlock) {
607        self.bcx.position_at_end(block);
608    }
609
610    fn seal_block(&mut self, block: Self::BasicBlock) {
611        let _ = block;
612        // Nothing to do.
613    }
614
615    fn seal_all_blocks(&mut self) {
616        // Nothing to do.
617    }
618
619    fn set_current_block_cold(&mut self) {
620        let function = self.get_or_add_function("llvm.assume", |this| {
621            this.ty_void.fn_type(&[this.ty_i1.into()], false)
622        });
623        let true_ = self.bool_const(true);
624        let callsite = self.bcx.build_call(function, &[true_.into()], "cold").unwrap();
625        let cold = self.cx.create_enum_attribute(Attribute::get_named_enum_kind_id("cold"), 1);
626        callsite.add_attribute(AttributeLoc::Function, cold);
627    }
628
629    fn current_block(&mut self) -> Option<Self::BasicBlock> {
630        self.bcx.get_insert_block()
631    }
632
633    fn block_addr(&mut self, block: Self::BasicBlock) -> Option<Self::Value> {
634        unsafe { block.get_address().map(Into::into) }
635    }
636
637    fn add_comment_to_current_inst(&mut self, comment: &str) {
638        let Some(block) = self.current_block() else { return };
639        let Some(ins) = block.get_last_instruction() else { return };
640        let metadata = self.cx.metadata_string(comment);
641        let metadata = self.cx.metadata_node(&[metadata.into()]);
642        ins.set_metadata(metadata, self.cx.get_kind_id("annotation")).unwrap();
643    }
644
645    fn fn_param(&mut self, index: usize) -> Self::Value {
646        self.function.get_nth_param(index as _).unwrap()
647    }
648
649    fn num_fn_params(&self) -> usize {
650        self.function.count_params() as usize
651    }
652
653    fn bool_const(&mut self, value: bool) -> Self::Value {
654        self.ty_i1.const_int(value as u64, false).into()
655    }
656
657    fn iconst(&mut self, ty: Self::Type, value: i64) -> Self::Value {
658        ty.into_int_type().const_int(value as u64, value.is_negative()).into()
659    }
660
661    fn uconst(&mut self, ty: Self::Type, value: u64) -> Self::Value {
662        ty.into_int_type().const_int(value, false).into()
663    }
664
665    fn iconst_256(&mut self, value: U256) -> Self::Value {
666        if value == U256::ZERO {
667            return self.ty_i256.const_zero().into();
668        }
669
670        self.ty_i256.const_int_from_string(&value.to_string(), StringRadix::Decimal).unwrap().into()
671    }
672
673    fn str_const(&mut self, value: &str) -> Self::Value {
674        self.bcx.build_global_string_ptr(value, "").unwrap().as_pointer_value().into()
675    }
676
677    fn nullptr(&mut self) -> Self::Value {
678        self.ty_ptr.const_null().into()
679    }
680
681    fn new_stack_slot_raw(&mut self, ty: Self::Type, name: &str) -> Self::StackSlot {
682        // let ty = self.ty_i8.array_type(size);
683        // let ptr = self.bcx.build_alloca(ty, name).unwrap();
684        // ptr.as_instruction().unwrap().set_alignment(align).unwrap();
685        // ptr
686        self.bcx.build_alloca(ty, name).unwrap()
687    }
688
689    fn stack_load(&mut self, ty: Self::Type, slot: Self::StackSlot, name: &str) -> Self::Value {
690        self.load(ty, slot.into(), name)
691    }
692
693    fn stack_store(&mut self, value: Self::Value, slot: Self::StackSlot) {
694        self.store(value, slot.into())
695    }
696
697    fn stack_addr(&mut self, ty: Self::Type, slot: Self::StackSlot) -> Self::Value {
698        let _ = ty;
699        slot.into()
700    }
701
702    fn load(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value {
703        self.bcx.build_load(ty, ptr.into_pointer_value(), name).unwrap()
704    }
705
706    fn load_unaligned(&mut self, ty: Self::Type, ptr: Self::Value, name: &str) -> Self::Value {
707        let value = self.load(ty, ptr, name);
708        self.current_block().unwrap().get_last_instruction().unwrap().set_alignment(1).unwrap();
709        value
710    }
711
712    fn store(&mut self, value: Self::Value, ptr: Self::Value) {
713        self.bcx.build_store(ptr.into_pointer_value(), value).unwrap();
714    }
715
716    fn store_unaligned(&mut self, value: Self::Value, ptr: Self::Value) {
717        let inst = self.bcx.build_store(ptr.into_pointer_value(), value).unwrap();
718        inst.set_alignment(1).unwrap();
719    }
720
721    fn nop(&mut self) {
722        // LLVM doesn't have a NOP instruction.
723    }
724
725    fn ret(&mut self, values: &[Self::Value]) {
726        match values {
727            [] => self.bcx.build_return(None),
728            [value] => self.bcx.build_return(Some(value)),
729            values => self.bcx.build_aggregate_return(values),
730        }
731        .unwrap();
732    }
733
734    fn icmp(&mut self, cond: IntCC, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
735        self.bcx
736            .build_int_compare(convert_intcc(cond), lhs.into_int_value(), rhs.into_int_value(), "")
737            .unwrap()
738            .into()
739    }
740
741    fn icmp_imm(&mut self, cond: IntCC, lhs: Self::Value, rhs: i64) -> Self::Value {
742        let rhs = self.iconst(lhs.get_type(), rhs);
743        self.icmp(cond, lhs, rhs)
744    }
745
746    fn is_null(&mut self, ptr: Self::Value) -> Self::Value {
747        self.bcx.build_is_null(ptr.into_pointer_value(), "").unwrap().into()
748    }
749
750    fn is_not_null(&mut self, ptr: Self::Value) -> Self::Value {
751        self.bcx.build_is_not_null(ptr.into_pointer_value(), "").unwrap().into()
752    }
753
754    fn br(&mut self, dest: Self::BasicBlock) {
755        self.bcx.build_unconditional_branch(dest).unwrap();
756    }
757
758    fn brif(
759        &mut self,
760        cond: Self::Value,
761        then_block: Self::BasicBlock,
762        else_block: Self::BasicBlock,
763    ) {
764        self.bcx.build_conditional_branch(cond.into_int_value(), then_block, else_block).unwrap();
765    }
766
767    fn brif_cold(
768        &mut self,
769        cond: Self::Value,
770        then_block: Self::BasicBlock,
771        else_block: Self::BasicBlock,
772        then_is_cold: bool,
773    ) {
774        let inst = self
775            .bcx
776            .build_conditional_branch(cond.into_int_value(), then_block, else_block)
777            .unwrap();
778        let weights = if then_is_cold { [1, DEFAULT_WEIGHT] } else { [DEFAULT_WEIGHT, 1] };
779        self.set_branch_weights(inst, weights);
780    }
781
782    fn switch(
783        &mut self,
784        index: Self::Value,
785        default: Self::BasicBlock,
786        targets: &[(u64, Self::BasicBlock)],
787        default_is_cold: bool,
788    ) {
789        let ty = index.get_type().into_int_type();
790        let targets =
791            targets.iter().map(|(v, b)| (ty.const_int(*v, false), *b)).collect::<Vec<_>>();
792        let inst = self.bcx.build_switch(index.into_int_value(), default, &targets).unwrap();
793        if default_is_cold {
794            let weights = iter::once(1).chain(iter::repeat(DEFAULT_WEIGHT).take(targets.len()));
795            self.set_branch_weights(inst, weights);
796        }
797    }
798
799    fn br_indirect(&mut self, address: Self::Value, destinations: &[Self::BasicBlock]) {
800        let _ = self.bcx.build_indirect_branch(address, destinations).unwrap();
801    }
802
803    fn phi(&mut self, ty: Self::Type, incoming: &[(Self::Value, Self::BasicBlock)]) -> Self::Value {
804        let incoming = incoming
805            .iter()
806            .map(|(value, block)| (value as &dyn BasicValue<'_>, *block))
807            .collect::<Vec<_>>();
808        let phi = self.bcx.build_phi(ty, "").unwrap();
809        phi.add_incoming(&incoming);
810        phi.as_basic_value()
811    }
812
813    fn select(
814        &mut self,
815        cond: Self::Value,
816        then_value: Self::Value,
817        else_value: Self::Value,
818    ) -> Self::Value {
819        self.bcx.build_select(cond.into_int_value(), then_value, else_value, "").unwrap()
820    }
821
822    fn lazy_select(
823        &mut self,
824        cond: Self::Value,
825        ty: Self::Type,
826        then_value: impl FnOnce(&mut Self) -> Self::Value,
827        else_value: impl FnOnce(&mut Self) -> Self::Value,
828    ) -> Self::Value {
829        let then_block = if let Some(current) = self.current_block() {
830            self.create_block_after(current, "then")
831        } else {
832            self.create_block("then")
833        };
834        let else_block = self.create_block_after(then_block, "else");
835        let done_block = self.create_block_after(else_block, "contd");
836
837        self.brif(cond, then_block, else_block);
838
839        self.switch_to_block(then_block);
840        let then_value = then_value(self);
841        self.br(done_block);
842
843        self.switch_to_block(else_block);
844        let else_value = else_value(self);
845        self.br(done_block);
846
847        self.switch_to_block(done_block);
848        let phi = self.bcx.build_phi(ty, "").unwrap();
849        phi.add_incoming(&[(&then_value, then_block), (&else_value, else_block)]);
850        phi.as_basic_value()
851    }
852
853    fn iadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
854        self.bcx.build_int_add(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
855    }
856
857    fn isub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
858        self.bcx.build_int_sub(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
859    }
860
861    fn imul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
862        self.bcx.build_int_mul(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
863    }
864
865    fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
866        self.bcx
867            .build_int_unsigned_div(lhs.into_int_value(), rhs.into_int_value(), "")
868            .unwrap()
869            .into()
870    }
871
872    fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
873        self.bcx
874            .build_int_signed_div(lhs.into_int_value(), rhs.into_int_value(), "")
875            .unwrap()
876            .into()
877    }
878
879    fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
880        self.bcx
881            .build_int_unsigned_rem(lhs.into_int_value(), rhs.into_int_value(), "")
882            .unwrap()
883            .into()
884    }
885
886    fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
887        self.bcx
888            .build_int_signed_rem(lhs.into_int_value(), rhs.into_int_value(), "")
889            .unwrap()
890            .into()
891    }
892
893    fn iadd_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
894        let rhs = self.iconst(lhs.get_type(), rhs);
895        self.iadd(lhs, rhs)
896    }
897
898    fn isub_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
899        let rhs = self.iconst(lhs.get_type(), rhs);
900        self.isub(lhs, rhs)
901    }
902
903    fn imul_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
904        let rhs = self.iconst(lhs.get_type(), rhs);
905        self.imul(lhs, rhs)
906    }
907
908    // - [Avoid using arithmetic intrinsics](https://llvm.org/docs/Frontend/PerformanceTips.html)
909    // - [Don't use usub.with.overflow intrinsic](https://github.com/rust-lang/rust/pull/103299)
910    // - [for unsigned add overflow the recommended pattern is x + y < x](https://github.com/rust-lang/rust/pull/124114#issuecomment-2066173305)
911    fn uadd_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
912        let result = self.iadd(lhs, rhs);
913        let overflow = self.icmp(IntCC::UnsignedLessThan, result, rhs);
914        (result, overflow)
915    }
916
917    fn usub_overflow(&mut self, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
918        let result = self.isub(lhs, rhs);
919        let overflow = self.icmp(IntCC::UnsignedLessThan, lhs, rhs);
920        (result, overflow)
921    }
922
923    fn uadd_sat(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
924        let f = self.get_sat_function("uadd", lhs.get_type());
925        self.call(f, &[lhs, rhs]).unwrap()
926    }
927
928    fn umax(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
929        let ty = lhs.get_type();
930        let name = format!("llvm.umin.{}", fmt_ty(ty));
931        let max = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, ty]));
932        self.call(max, &[lhs, rhs]).unwrap()
933    }
934
935    fn umin(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
936        let ty = lhs.get_type();
937        let name = format!("llvm.umin.{}", fmt_ty(ty));
938        let max = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, ty]));
939        self.call(max, &[lhs, rhs]).unwrap()
940    }
941
942    fn bswap(&mut self, value: Self::Value) -> Self::Value {
943        let ty = value.get_type();
944        let name = format!("llvm.bswap.{}", fmt_ty(ty));
945        let bswap = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty]));
946        self.call(bswap, &[value]).unwrap()
947    }
948
949    fn bitor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
950        self.bcx.build_or(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
951    }
952
953    fn bitand(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
954        self.bcx.build_and(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
955    }
956
957    fn bitxor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
958        self.bcx.build_xor(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
959    }
960
961    fn bitnot(&mut self, value: Self::Value) -> Self::Value {
962        self.bcx.build_not(value.into_int_value(), "").unwrap().into()
963    }
964
965    fn clz(&mut self, value: Self::Value) -> Self::Value {
966        let ty = value.get_type();
967        let i1_ty = self.type_int(1);
968        let name = format!("llvm.ctlz.{}", fmt_ty(ty));
969        let ctlz = self.get_or_add_function(&name, |this| this.fn_type(Some(ty), &[ty, i1_ty]));
970        let is_poison_on_zero = self.bool_const(false);
971        self.call(ctlz, &[value, is_poison_on_zero]).unwrap()
972    }
973
974    fn bitor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
975        let rhs = self.iconst(lhs.get_type(), rhs);
976        self.bitor(lhs, rhs)
977    }
978
979    fn bitand_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
980        let rhs = self.iconst(lhs.get_type(), rhs);
981        self.bitand(lhs, rhs)
982    }
983
984    fn bitxor_imm(&mut self, lhs: Self::Value, rhs: i64) -> Self::Value {
985        let rhs = self.iconst(lhs.get_type(), rhs);
986        self.bitxor(lhs, rhs)
987    }
988
989    fn ishl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
990        self.bcx.build_left_shift(lhs.into_int_value(), rhs.into_int_value(), "").unwrap().into()
991    }
992
993    fn ushr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
994        self.bcx
995            .build_right_shift(lhs.into_int_value(), rhs.into_int_value(), false, "")
996            .unwrap()
997            .into()
998    }
999
1000    fn sshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value {
1001        self.bcx
1002            .build_right_shift(lhs.into_int_value(), rhs.into_int_value(), true, "")
1003            .unwrap()
1004            .into()
1005    }
1006
1007    fn zext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value {
1008        self.bcx.build_int_z_extend(value.into_int_value(), ty.into_int_type(), "").unwrap().into()
1009    }
1010
1011    fn sext(&mut self, ty: Self::Type, value: Self::Value) -> Self::Value {
1012        self.bcx.build_int_s_extend(value.into_int_value(), ty.into_int_type(), "").unwrap().into()
1013    }
1014
1015    fn ireduce(&mut self, to: Self::Type, value: Self::Value) -> Self::Value {
1016        self.bcx.build_int_truncate(value.into_int_value(), to.into_int_type(), "").unwrap().into()
1017    }
1018
1019    fn inttoptr(&mut self, value: Self::Value, ty: Self::Type) -> Self::Value {
1020        self.bcx
1021            .build_int_to_ptr(value.into_int_value(), ty.into_pointer_type(), "")
1022            .unwrap()
1023            .into()
1024    }
1025
1026    fn gep(
1027        &mut self,
1028        elem_ty: Self::Type,
1029        ptr: Self::Value,
1030        indexes: &[Self::Value],
1031        name: &str,
1032    ) -> Self::Value {
1033        let indexes = indexes.iter().map(|idx| idx.into_int_value()).collect::<Vec<_>>();
1034        unsafe { self.bcx.build_in_bounds_gep(elem_ty, ptr.into_pointer_value(), &indexes, name) }
1035            .unwrap()
1036            .into()
1037    }
1038
1039    fn tail_call(
1040        &mut self,
1041        function: Self::Function,
1042        args: &[Self::Value],
1043        tail_call: TailCallKind,
1044    ) -> Option<Self::Value> {
1045        let args = args.iter().copied().map(Into::into).collect::<Vec<_>>();
1046        let callsite = self.bcx.build_call(function, &args, "").unwrap();
1047        if tail_call != TailCallKind::None {
1048            callsite.set_tail_call_kind(convert_tail_call_kind(tail_call));
1049        }
1050        callsite.try_as_basic_value().basic()
1051    }
1052
1053    fn is_compile_time_known(&mut self, value: Self::Value) -> Option<Self::Value> {
1054        let ty = value.get_type();
1055        let name = format!("llvm.is.constant.{}", fmt_ty(ty));
1056        let f =
1057            self.get_or_add_function(&name, |this| this.fn_type(Some(this.ty_i1.into()), &[ty]));
1058        Some(self.call(f, &[value]).unwrap())
1059    }
1060
1061    fn memcpy(&mut self, dst: Self::Value, src: Self::Value, len: Self::Value) {
1062        self.memcpy_inner(dst, src, len, false);
1063    }
1064
1065    fn memcpy_inline(&mut self, dst: Self::Value, src: Self::Value, len: i64) {
1066        let len = self.iconst(self.ty_i64.into(), len);
1067        self.memcpy_inner(dst, src, len, true);
1068    }
1069
1070    fn unreachable(&mut self) {
1071        self.bcx.build_unreachable().unwrap();
1072    }
1073
1074    fn get_or_build_function(
1075        &mut self,
1076        name: &str,
1077        params: &[Self::Type],
1078        ret: Option<Self::Type>,
1079        linkage: revmc_backend::Linkage,
1080        build: impl FnOnce(&mut Self),
1081    ) -> Self::Function {
1082        if let Some(function) = self.module.get_function(name) {
1083            return function;
1084        }
1085
1086        let before = self.current_block();
1087
1088        let func_ty = self.fn_type(ret, params);
1089        let function = self.module.add_function(name, func_ty, Some(convert_linkage(linkage)));
1090        let prev_function = std::mem::replace(&mut self.function, function);
1091
1092        let entry = self.cx.append_basic_block(function, "entry");
1093        self.bcx.position_at_end(entry);
1094        build(self);
1095        if let Some(before) = before {
1096            self.bcx.position_at_end(before);
1097        }
1098
1099        self.function = prev_function;
1100
1101        function
1102    }
1103
1104    fn get_function(&mut self, name: &str) -> Option<Self::Function> {
1105        self.module.get_function(name)
1106    }
1107
1108    fn get_printf_function(&mut self) -> Self::Function {
1109        let name = "printf";
1110        if let Some(function) = self.module.get_function(name) {
1111            return function;
1112        }
1113
1114        let ty = self.cx.void_type().fn_type(&[self.ty_ptr.into()], true);
1115        self.module.add_function(name, ty, Some(inkwell::module::Linkage::External))
1116    }
1117
1118    fn add_function(
1119        &mut self,
1120        name: &str,
1121        params: &[Self::Type],
1122        ret: Option<Self::Type>,
1123        address: Option<usize>,
1124        linkage: revmc_backend::Linkage,
1125    ) -> Self::Function {
1126        let func_ty = self.fn_type(ret, params);
1127        let function = self.module.add_function(name, func_ty, Some(convert_linkage(linkage)));
1128        if let (Some(address), Some(exec_engine)) = (address, &self.exec_engine) {
1129            exec_engine.add_global_mapping(&function, address);
1130        }
1131        function
1132    }
1133
1134    fn add_function_attribute(
1135        &mut self,
1136        function: Option<Self::Function>,
1137        attribute: revmc_backend::Attribute,
1138        loc: revmc_backend::FunctionAttributeLocation,
1139    ) {
1140        let loc = convert_attribute_loc(loc);
1141        let attr = convert_attribute(self, attribute);
1142        function.unwrap_or(self.function).add_attribute(loc, attr);
1143    }
1144}
1145
1146fn init() -> Result<()> {
1147    let mut init_result = Ok(());
1148    static INIT: Once = Once::new();
1149    INIT.call_once(|| init_result = init_());
1150    init_result
1151}
1152
1153fn init_() -> Result<()> {
1154    // TODO: This also reports "PLEASE submit a bug report to..." when the segfault is
1155    // outside of LLVM.
1156    // enable_llvm_pretty_stack_trace();
1157
1158    extern "C" fn report_fatal_error(msg: *const std::ffi::c_char) {
1159        let msg_cstr = unsafe { std::ffi::CStr::from_ptr(msg) };
1160        let msg = msg_cstr.to_string_lossy();
1161        error!(target: "llvm", "LLVM fatal error: {msg}");
1162    }
1163
1164    unsafe {
1165        install_fatal_error_handler(report_fatal_error);
1166    }
1167
1168    // The first arg is only used in `-help` output AFAICT.
1169    let args = [c"revmc-llvm".as_ptr(), c"-x86-asm-syntax=intel".as_ptr()];
1170    unsafe {
1171        inkwell::llvm_sys::support::LLVMParseCommandLineOptions(
1172            args.len() as i32,
1173            args.as_ptr(),
1174            std::ptr::null(),
1175        )
1176    }
1177
1178    let config = InitializationConfig {
1179        asm_parser: false,
1180        asm_printer: true,
1181        base: true,
1182        disassembler: true,
1183        info: true,
1184        machine_code: true,
1185    };
1186    Target::initialize_all(&config);
1187
1188    Ok(())
1189}
1190
1191fn create_module<'ctx>(cx: &'ctx Context, machine: &TargetMachine) -> Result<Module<'ctx>> {
1192    let module_name = "evm";
1193    let module = cx.create_module(module_name);
1194    module.set_source_file_name(module_name);
1195    module.set_data_layout(&machine.get_target_data().get_data_layout());
1196    module.set_triple(&machine.get_triple());
1197    module.add_basic_value_flag(
1198        "PIC Level",
1199        FlagBehavior::Error, // TODO: Min
1200        cx.i32_type().const_int(2, false),
1201    );
1202    module.add_basic_value_flag(
1203        "RtLibUseGOT",
1204        FlagBehavior::Warning,
1205        cx.i32_type().const_int(1, false),
1206    );
1207    Ok(module)
1208}
1209
1210fn convert_intcc(cond: IntCC) -> IntPredicate {
1211    match cond {
1212        IntCC::Equal => IntPredicate::EQ,
1213        IntCC::NotEqual => IntPredicate::NE,
1214        IntCC::SignedLessThan => IntPredicate::SLT,
1215        IntCC::SignedGreaterThanOrEqual => IntPredicate::SGE,
1216        IntCC::SignedGreaterThan => IntPredicate::SGT,
1217        IntCC::SignedLessThanOrEqual => IntPredicate::SLE,
1218        IntCC::UnsignedLessThan => IntPredicate::ULT,
1219        IntCC::UnsignedGreaterThanOrEqual => IntPredicate::UGE,
1220        IntCC::UnsignedGreaterThan => IntPredicate::UGT,
1221        IntCC::UnsignedLessThanOrEqual => IntPredicate::ULE,
1222    }
1223}
1224
1225fn convert_opt_level(level: revmc_backend::OptimizationLevel) -> OptimizationLevel {
1226    match level {
1227        revmc_backend::OptimizationLevel::None => OptimizationLevel::None,
1228        revmc_backend::OptimizationLevel::Less => OptimizationLevel::Less,
1229        revmc_backend::OptimizationLevel::Default => OptimizationLevel::Default,
1230        revmc_backend::OptimizationLevel::Aggressive => OptimizationLevel::Aggressive,
1231    }
1232}
1233
1234fn convert_opt_level_rev(level: OptimizationLevel) -> revmc_backend::OptimizationLevel {
1235    match level {
1236        OptimizationLevel::None => revmc_backend::OptimizationLevel::None,
1237        OptimizationLevel::Less => revmc_backend::OptimizationLevel::Less,
1238        OptimizationLevel::Default => revmc_backend::OptimizationLevel::Default,
1239        OptimizationLevel::Aggressive => revmc_backend::OptimizationLevel::Aggressive,
1240    }
1241}
1242
1243fn convert_attribute(bcx: &EvmLlvmBuilder<'_, '_>, attr: revmc_backend::Attribute) -> Attribute {
1244    use revmc_backend::Attribute as OurAttr;
1245
1246    enum AttrValue<'a> {
1247        String(&'a str),
1248        Enum(u64),
1249        Type(AnyTypeEnum<'a>),
1250    }
1251
1252    let cpu;
1253    let (key, value) = match attr {
1254        OurAttr::WillReturn => ("willreturn", AttrValue::Enum(1)),
1255        OurAttr::NoReturn => ("noreturn", AttrValue::Enum(1)),
1256        OurAttr::NoFree => ("nofree", AttrValue::Enum(1)),
1257        OurAttr::NoRecurse => ("norecurse", AttrValue::Enum(1)),
1258        OurAttr::NoSync => ("nosync", AttrValue::Enum(1)),
1259        OurAttr::NoUnwind => ("nounwind", AttrValue::Enum(1)),
1260        OurAttr::AllFramePointers => ("frame-pointer", AttrValue::String("all")),
1261        OurAttr::NativeTargetCpu => (
1262            "target-cpu",
1263            AttrValue::String({
1264                cpu = bcx.machine.get_cpu();
1265                cpu.to_str().unwrap()
1266            }),
1267        ),
1268        OurAttr::Cold => ("cold", AttrValue::Enum(1)),
1269        OurAttr::Hot => ("hot", AttrValue::Enum(1)),
1270        OurAttr::HintInline => ("inlinehint", AttrValue::Enum(1)),
1271        OurAttr::AlwaysInline => ("alwaysinline", AttrValue::Enum(1)),
1272        OurAttr::NoInline => ("noinline", AttrValue::Enum(1)),
1273        OurAttr::Speculatable => ("speculatable", AttrValue::Enum(1)),
1274
1275        OurAttr::NoAlias => ("noalias", AttrValue::Enum(1)),
1276        OurAttr::NoCapture => ("captures", AttrValue::Enum(0)), // captures(none) - no capture
1277        OurAttr::NoUndef => ("noundef", AttrValue::Enum(1)),
1278        OurAttr::Align(n) => ("align", AttrValue::Enum(n)),
1279        OurAttr::NonNull => ("nonnull", AttrValue::Enum(1)),
1280        OurAttr::Dereferenceable(n) => ("dereferenceable", AttrValue::Enum(n)),
1281        OurAttr::SRet(n) => {
1282            ("sret", AttrValue::Type(bcx.type_array(bcx.ty_i8.into(), n as _).as_any_type_enum()))
1283        }
1284        OurAttr::ReadNone => ("readnone", AttrValue::Enum(1)),
1285        OurAttr::ReadOnly => ("readonly", AttrValue::Enum(1)),
1286        OurAttr::WriteOnly => ("writeonly", AttrValue::Enum(1)),
1287        OurAttr::Writable => ("writable", AttrValue::Enum(1)),
1288
1289        attr => unimplemented!("llvm attribute conversion: {attr:?}"),
1290    };
1291    match value {
1292        AttrValue::String(value) => bcx.cx.create_string_attribute(key, value),
1293        AttrValue::Enum(value) => {
1294            let id = Attribute::get_named_enum_kind_id(key);
1295            bcx.cx.create_enum_attribute(id, value)
1296        }
1297        AttrValue::Type(ty) => {
1298            let id = Attribute::get_named_enum_kind_id(key);
1299            bcx.cx.create_type_attribute(id, ty)
1300        }
1301    }
1302}
1303
1304fn convert_attribute_loc(loc: revmc_backend::FunctionAttributeLocation) -> AttributeLoc {
1305    match loc {
1306        revmc_backend::FunctionAttributeLocation::Return => AttributeLoc::Return,
1307        revmc_backend::FunctionAttributeLocation::Param(i) => AttributeLoc::Param(i),
1308        revmc_backend::FunctionAttributeLocation::Function => AttributeLoc::Function,
1309    }
1310}
1311
1312fn convert_linkage(linkage: revmc_backend::Linkage) -> inkwell::module::Linkage {
1313    match linkage {
1314        revmc_backend::Linkage::Public => inkwell::module::Linkage::External,
1315        revmc_backend::Linkage::Import => inkwell::module::Linkage::External,
1316        revmc_backend::Linkage::Private => inkwell::module::Linkage::Private,
1317    }
1318}
1319
1320fn convert_tail_call_kind(kind: TailCallKind) -> inkwell::llvm_sys::LLVMTailCallKind {
1321    match kind {
1322        TailCallKind::None => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindNone,
1323        TailCallKind::Tail => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindTail,
1324        TailCallKind::MustTail => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindMustTail,
1325        TailCallKind::NoTail => inkwell::llvm_sys::LLVMTailCallKind::LLVMTailCallKindNoTail,
1326    }
1327}
1328
1329// No `#[track_caller]` because `map_err` doesn't propagate it.
1330fn error_msg(msg: inkwell::support::LLVMString) -> revmc_backend::Error {
1331    revmc_backend::Error::msg(msg.to_string_lossy().trim_end().to_string())
1332}
1333
1334fn fmt_ty(ty: BasicTypeEnum<'_>) -> impl std::fmt::Display {
1335    ty.print_to_string().to_str().unwrap().trim_matches('"').to_string()
1336}