winch_codegen/codegen/
builtin.rs1use crate::{
4 abi::{ABISig, ABI},
5 codegen::env::ptr_type_from_ptr_size,
6 CallingConvention,
7};
8use cranelift_codegen::ir::LibCall;
9use std::sync::Arc;
10use wasmtime_environ::{BuiltinFunctionIndex, PtrSize, VMOffsets, WasmValType};
11
12#[derive(Copy, Clone)]
13pub(crate) enum BuiltinType {
14 Builtin(BuiltinFunctionIndex),
16 LibCall(LibCall),
19}
20
21impl BuiltinType {
22 pub fn builtin(idx: BuiltinFunctionIndex) -> Self {
25 Self::Builtin(idx)
26 }
27
28 pub fn libcall(libcall: LibCall) -> Self {
31 Self::LibCall(libcall)
32 }
33}
34
35#[derive(Clone)]
36pub struct BuiltinFunction {
37 inner: Arc<BuiltinFunctionInner>,
38}
39
40impl BuiltinFunction {
41 pub(crate) fn sig(&self) -> &ABISig {
42 &self.inner.sig
43 }
44
45 pub(crate) fn ty(&self) -> BuiltinType {
46 self.inner.ty
47 }
48}
49
50pub struct BuiltinFunctionInner {
52 sig: ABISig,
54 ty: BuiltinType,
56}
57
58macro_rules! declare_function_sig {
59 (
60 $(
61 $( #[$attr:meta] )*
62 $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
63 )*
64 ) => {
65 pub struct BuiltinFunctions {
68 call_conv: CallingConvention,
70 ptr_type: WasmValType,
72 ceil_f32: Option<BuiltinFunction>,
74 ceil_f64: Option<BuiltinFunction>,
76 floor_f32: Option<BuiltinFunction>,
78 floor_f64: Option<BuiltinFunction>,
80 trunc_f32: Option<BuiltinFunction>,
82 trunc_f64: Option<BuiltinFunction>,
84 nearest_f32: Option<BuiltinFunction>,
86 nearest_f64: Option<BuiltinFunction>,
88 $(
89 $( #[ $attr ] )*
90 $name: Option<BuiltinFunction>,
91 )*
92 }
93
94 #[allow(dead_code)]
96 impl BuiltinFunctions {
97 pub fn new<P: PtrSize>(vmoffsets: &VMOffsets<P>, call_conv: CallingConvention) -> Self {
98 let size = vmoffsets.ptr.size();
99 #[allow(unused_doc_comments)]
100 Self {
101 call_conv,
102 ptr_type: ptr_type_from_ptr_size(size),
103 ceil_f32: None,
104 ceil_f64: None,
105 floor_f32: None,
106 floor_f64: None,
107 trunc_f32: None,
108 trunc_f64: None,
109 nearest_f32: None,
110 nearest_f64: None,
111 $(
112 $( #[ $attr ] )*
113 $name: None,
114 )*
115 }
116 }
117
118 fn pointer(&self) -> WasmValType {
119 self.ptr_type
120 }
121
122 fn vmctx(&self) -> WasmValType {
123 self.pointer()
124 }
125
126 fn i32(&self) -> WasmValType {
127 WasmValType::I32
128 }
129
130 fn f32(&self) -> WasmValType {
131 WasmValType::F32
132 }
133
134 fn f64(&self) -> WasmValType {
135 WasmValType::F64
136 }
137
138 fn i64(&self) -> WasmValType {
139 WasmValType::I64
140 }
141
142 fn reference(&self) -> WasmValType {
143 self.pointer()
144 }
145
146 fn over_f64<A: ABI>(&self) -> ABISig {
147 A::sig_from(&[self.f64()], &[self.f64()], &self.call_conv)
148 }
149
150 fn over_f32<A: ABI>(&self) -> ABISig {
151 A::sig_from(&[self.f64()], &[self.f64()], &self.call_conv)
152 }
153
154 pub(crate) fn ceil_f32<A: ABI>(&mut self) -> BuiltinFunction {
155 if self.ceil_f32.is_none() {
156 let sig = self.over_f32::<A>();
157 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::CeilF32) });
158 self.ceil_f32 = Some(BuiltinFunction {
159 inner,
160 });
161 }
162 self.ceil_f32.as_ref().unwrap().clone()
163 }
164
165 pub(crate) fn ceil_f64<A: ABI>(&mut self) -> BuiltinFunction {
166 if self.ceil_f64.is_none() {
167 let sig = self.over_f64::<A>();
168 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::CeilF64) });
169 self.ceil_f64 = Some(BuiltinFunction {
170 inner,
171 });
172 }
173 self.ceil_f64.as_ref().unwrap().clone()
174 }
175
176 pub(crate) fn floor_f32<A: ABI>(&mut self) -> BuiltinFunction {
177 if self.floor_f32.is_none() {
178 let sig = self.over_f32::<A>();
179 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::FloorF32) });
180 self.floor_f32 = Some(BuiltinFunction {
181 inner,
182 });
183 }
184 self.floor_f32.as_ref().unwrap().clone()
185 }
186
187 pub(crate) fn floor_f64<A: ABI>(&mut self) -> BuiltinFunction {
188 if self.floor_f64.is_none() {
189 let sig = self.over_f64::<A>();
190 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::FloorF64) });
191 self.floor_f64 = Some(BuiltinFunction {
192 inner,
193 });
194 }
195 self.floor_f64.as_ref().unwrap().clone()
196 }
197
198 pub(crate) fn trunc_f32<A: ABI>(&mut self) -> BuiltinFunction {
199 if self.trunc_f32.is_none() {
200 let sig = self.over_f32::<A>();
201 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::TruncF32) });
202 self.trunc_f32 = Some(BuiltinFunction {
203 inner,
204 });
205 }
206 self.trunc_f32.as_ref().unwrap().clone()
207 }
208
209 pub(crate) fn trunc_f64<A: ABI>(&mut self) -> BuiltinFunction {
210 if self.trunc_f64.is_none() {
211 let sig = self.over_f64::<A>();
212 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::TruncF64) });
213 self.trunc_f64 = Some(BuiltinFunction {
214 inner,
215 });
216 }
217 self.trunc_f64.as_ref().unwrap().clone()
218 }
219
220 pub(crate) fn nearest_f32<A: ABI>(&mut self) -> BuiltinFunction {
221 if self.nearest_f32.is_none() {
222 let sig = self.over_f32::<A>();
223 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::NearestF32) });
224 self.nearest_f32 = Some(BuiltinFunction {
225 inner,
226 });
227 }
228 self.nearest_f32.as_ref().unwrap().clone()
229 }
230
231 pub(crate) fn nearest_f64<A: ABI>(&mut self) -> BuiltinFunction {
232 if self.nearest_f64.is_none() {
233 let sig = self.over_f64::<A>();
234 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::libcall(LibCall::NearestF64) });
235 self.nearest_f64 = Some(BuiltinFunction {
236 inner,
237 });
238 }
239 self.nearest_f64.as_ref().unwrap().clone()
240 }
241
242 $(
243 $( #[ $attr ] )*
244 pub(crate) fn $name<A: ABI, P: PtrSize>(&mut self) -> BuiltinFunction {
245 if self.$name.is_none() {
246 let params = vec![ $(self.$param() ),* ];
247 let result = vec![ $(self.$result() )?];
248 let sig = A::sig_from(¶ms, &result, &self.call_conv);
249 let index = BuiltinFunctionIndex::$name();
250 let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::builtin(index) });
251 self.$name = Some(BuiltinFunction {
252 inner,
253 });
254 }
255
256 self.$name.as_ref().unwrap().clone()
257 }
258 )*
259 }
260 }
261}
262
263wasmtime_environ::foreach_builtin_function!(declare_function_sig);