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, IntValue, 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 #[allow(unused)]
70 fn get_g0_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> IntValue<'ctx> {
71 let vmctx_idx = u32::from(
73 func_value
74 .get_enum_attribute(
75 AttributeLoc::Param(0),
76 Attribute::get_named_enum_kind_id("sret"),
77 )
78 .is_some(),
79 );
80
81 let param = func_value.get_nth_param(vmctx_idx + 1).unwrap();
82 param.set_name("g0");
83
84 param.into_int_value()
85 }
86
87 fn get_m0_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
93 let vmctx_idx = u32::from(
95 func_value
96 .get_enum_attribute(
97 AttributeLoc::Param(0),
98 Attribute::get_named_enum_kind_id("sret"),
99 )
100 .is_some(),
101 );
102
103 let param = func_value.get_nth_param(vmctx_idx + 1).unwrap();
104 param.set_name("m0_base_ptr");
105
106 param.into_pointer_value()
107 }
108
109 fn func_type_to_llvm<'ctx>(
114 &self,
115 context: &'ctx Context,
116 intrinsics: &Intrinsics<'ctx>,
117 offsets: Option<&VMOffsets>,
118 sig: &FuncSig,
119 include_m0_param: bool,
120 ) -> Result<(FunctionType<'ctx>, Vec<(Attribute, AttributeLoc)>), CompileError>;
121
122 #[allow(clippy::too_many_arguments)]
124 fn args_to_call<'ctx>(
125 &self,
126 alloca_builder: &Builder<'ctx>,
127 func_sig: &FuncSig,
128 llvm_fn_ty: &FunctionType<'ctx>,
129 ctx_ptr: PointerValue<'ctx>,
130 values: &[BasicValueEnum<'ctx>],
131 intrinsics: &Intrinsics<'ctx>,
132 m0: Option<PointerValue<'ctx>>,
133 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> {
134 let sret = if llvm_fn_ty.get_return_type().is_none() && func_sig.results().len() > 1 {
136 let llvm_params: Vec<_> = func_sig
137 .results()
138 .iter()
139 .map(|x| type_to_llvm(intrinsics, *x).unwrap())
140 .collect();
141 let llvm_params = llvm_fn_ty
142 .get_context()
143 .struct_type(llvm_params.as_slice(), false);
144 Some(err!(alloca_builder.build_alloca(llvm_params, "sret")))
145 } else {
146 None
147 };
148
149 let mut args = vec![ctx_ptr.as_basic_value_enum()];
150
151 if let Some(m0) = m0 {
152 args.push(m0.into());
153 }
154
155 let args = args.into_iter().chain(values.iter().copied());
156
157 let ret = if let Some(sret) = sret {
158 std::iter::once(sret.as_basic_value_enum())
159 .chain(args)
160 .collect()
161 } else {
162 args.collect()
163 };
164
165 Ok(ret)
166 }
167
168 fn rets_from_call<'ctx>(
170 &self,
171 builder: &Builder<'ctx>,
172 intrinsics: &Intrinsics<'ctx>,
173 call_site: CallSiteValue<'ctx>,
174 func_sig: &FuncSig,
175 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError>;
176
177 fn is_sret(&self, func_sig: &FuncSig) -> Result<bool, CompileError> {
179 let func_sig_returns_bitwidths = func_sig
180 .results()
181 .iter()
182 .map(|ty| match ty {
183 Type::I32 | Type::F32 | Type::ExceptionRef => 32,
184 Type::I64 | Type::F64 => 64,
185 Type::V128 => 128,
186 Type::ExternRef | Type::FuncRef => 64, })
188 .collect::<Vec<i32>>();
189
190 Ok(!matches!(
191 func_sig_returns_bitwidths.as_slice(),
192 [] | [_]
193 | [32, 32]
194 | [32, 64]
195 | [64, 32]
196 | [64, 64]
197 | [32, 32, 32]
198 | [32, 32, 64]
199 | [64, 32, 32]
200 | [32, 32, 32, 32]
201 ))
202 }
203
204 fn pack_values_for_register_return<'ctx>(
206 &self,
207 intrinsics: &Intrinsics<'ctx>,
208 builder: &Builder<'ctx>,
209 values: &[BasicValueEnum<'ctx>],
210 func_type: &FunctionType<'ctx>,
211 ) -> Result<BasicValueEnum<'ctx>, CompileError>;
212}