Skip to main content

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