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#[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 function_counter: u32,
74 functions: FxHashMap<u32, (String, FunctionValue<'static>)>,
75 mapped_symbols: FxHashSet<String>,
78}
79
80unsafe impl Send for EvmLlvmBackend {}
81
82impl EvmLlvmBackend {
83 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 #[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 #[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(¶ms, false),
186 None => self.ty_void.fn_type(¶ms, false),
187 }
188 }
189
190 fn id_to_name(&self, id: u32) -> &str {
191 &self.functions[&id].0
192 }
193
194 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 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 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#[derive(Debug)]
402struct TargetInfo {
403 triple: TargetTriple,
404 target: Target,
405 cpu: String,
406 features: String,
407}
408
409unsafe 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#[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 }
628
629 fn seal_all_blocks(&mut self) {
630 }
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 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 }
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 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 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 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 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 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, 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)), 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
1368fn 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