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