wasmer_compiler_llvm/abi/
mod.rs1#![deny(missing_docs)]
7
8use crate::error::err;
9use crate::translator::intrinsics::{Intrinsics, type_to_llvm};
10use inkwell::values::BasicValue;
11use inkwell::{
12 attributes::{Attribute, AttributeLoc},
13 builder::Builder,
14 context::Context,
15 targets::TargetMachine,
16 types::FunctionType,
17 values::{BasicValueEnum, CallSiteValue, FunctionValue, PointerValue},
18};
19use wasmer_types::{CompileError, FunctionType as FuncSig, Type};
20use wasmer_vm::VMOffsets;
21
22mod aarch64_systemv;
23mod riscv_systemv;
24mod x86_64_systemv;
25
26use aarch64_systemv::Aarch64SystemV;
27use riscv_systemv::RiscvSystemV;
28use x86_64_systemv::X86_64SystemV;
29
30pub fn get_abi(target_machine: &TargetMachine) -> Box<dyn Abi> {
31 let target_name = target_machine.get_triple();
32 let target_name = target_name.as_str().to_string_lossy();
33
34 if target_name.starts_with("aarch64") {
35 Box::new(Aarch64SystemV {})
36 } else if target_name.starts_with("riscv") {
37 Box::new(RiscvSystemV {
38 is_riscv64: target_name.starts_with("riscv64"),
39 })
40 } else {
41 Box::new(X86_64SystemV {})
42 }
43}
44
45pub trait Abi {
50 fn get_vmctx_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
52 let param = func_value
53 .get_nth_param(u32::from(
54 func_value
55 .get_enum_attribute(
56 AttributeLoc::Param(0),
57 Attribute::get_named_enum_kind_id("sret"),
58 )
59 .is_some(),
60 ))
61 .unwrap();
62 param.set_name("vmctx");
63
64 param.into_pointer_value()
65 }
66
67 fn get_m0_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
70 let vmctx_idx = u32::from(
71 func_value
72 .get_enum_attribute(
73 AttributeLoc::Param(0),
74 Attribute::get_named_enum_kind_id("sret"),
75 )
76 .is_some(),
77 );
78
79 let param = func_value.get_nth_param(vmctx_idx + 1).unwrap();
80 param.set_name("m0_base_ptr");
81
82 param.into_pointer_value()
83 }
84
85 fn func_type_to_llvm<'ctx>(
90 &self,
91 context: &'ctx Context,
92 intrinsics: &Intrinsics<'ctx>,
93 offsets: Option<&VMOffsets>,
94 sig: &FuncSig,
95 include_m0_param: bool,
96 ) -> Result<(FunctionType<'ctx>, Vec<(Attribute, AttributeLoc)>), CompileError>;
97
98 #[allow(clippy::too_many_arguments)]
100 fn args_to_call<'ctx>(
101 &self,
102 alloca_builder: &Builder<'ctx>,
103 func_sig: &FuncSig,
104 llvm_fn_ty: &FunctionType<'ctx>,
105 ctx_ptr: PointerValue<'ctx>,
106 values: &[BasicValueEnum<'ctx>],
107 intrinsics: &Intrinsics<'ctx>,
108 m0: Option<PointerValue<'ctx>>,
109 sret_ptr: Option<PointerValue<'ctx>>,
110 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> {
111 let sret = if self.llvm_fn_uses_sret(llvm_fn_ty, func_sig) {
113 let llvm_params: Vec<_> = func_sig
114 .results()
115 .iter()
116 .map(|x| type_to_llvm(intrinsics, *x).unwrap())
117 .collect();
118 let llvm_params = llvm_fn_ty
119 .get_context()
120 .struct_type(llvm_params.as_slice(), false);
121 Some(match sret_ptr {
123 Some(sret_ptr) => sret_ptr,
124 None => err!(alloca_builder.build_alloca(llvm_params, "sret")),
125 })
126 } else {
127 None
128 };
129
130 let mut args = vec![ctx_ptr.as_basic_value_enum()];
131
132 if let Some(m0) = m0 {
133 args.push(m0.into());
134 }
135
136 let args = args.into_iter().chain(values.iter().copied());
137
138 let ret = if let Some(sret) = sret {
139 std::iter::once(sret.as_basic_value_enum())
140 .chain(args)
141 .collect()
142 } else {
143 args.collect()
144 };
145
146 Ok(ret)
147 }
148
149 fn llvm_fn_uses_sret<'ctx>(&self, llvm_fn_ty: &FunctionType<'ctx>, func_sig: &FuncSig) -> bool {
151 llvm_fn_ty.get_return_type().is_none() && func_sig.results().len() > 1
152 }
153
154 fn rets_from_call<'ctx>(
156 &self,
157 builder: &Builder<'ctx>,
158 intrinsics: &Intrinsics<'ctx>,
159 call_site: CallSiteValue<'ctx>,
160 func_sig: &FuncSig,
161 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError>;
162
163 fn is_sret(&self, func_sig: &FuncSig) -> Result<bool, CompileError> {
165 let func_sig_returns_bitwidths = func_sig
166 .results()
167 .iter()
168 .map(|ty| match ty {
169 Type::I32 | Type::F32 | Type::ExceptionRef => 32,
170 Type::I64 | Type::F64 => 64,
171 Type::V128 => 128,
172 Type::ExternRef | Type::FuncRef => 64, })
174 .collect::<Vec<i32>>();
175
176 Ok(!matches!(
177 func_sig_returns_bitwidths.as_slice(),
178 [] | [_]
179 | [32, 32]
180 | [32, 64]
181 | [64, 32]
182 | [64, 64]
183 | [32, 32, 32]
184 | [32, 32, 64]
185 | [64, 32, 32]
186 | [32, 32, 32, 32]
187 ))
188 }
189
190 fn pack_values_for_register_return<'ctx>(
192 &self,
193 intrinsics: &Intrinsics<'ctx>,
194 builder: &Builder<'ctx>,
195 values: &[BasicValueEnum<'ctx>],
196 func_type: &FunctionType<'ctx>,
197 ) -> Result<BasicValueEnum<'ctx>, CompileError>;
198}