Skip to main content

winch_codegen/codegen/
builtin.rs

1//! Builtin function handling.
2
3use crate::{
4    CallingConvention, Result,
5    abi::{ABI, ABISig},
6    codegen::env::ptr_type_from_ptr_size,
7};
8use std::sync::Arc;
9use wasmtime_environ::{BuiltinFunctionIndex, PtrSize, VMOffsets, WasmValType};
10
11#[derive(Copy, Clone)]
12pub(crate) enum BuiltinType {
13    /// Dynamic built-in function, derived from the VMContext.
14    Builtin(BuiltinFunctionIndex),
15}
16
17impl BuiltinType {
18    /// Creates a new builtin from a Wasmtime-defined builtin function
19    /// enumerated with a [`BuiltinFunctionIndex`].
20    pub fn builtin(idx: BuiltinFunctionIndex) -> Self {
21        Self::Builtin(idx)
22    }
23}
24
25#[derive(Clone)]
26pub struct BuiltinFunction {
27    inner: Arc<BuiltinFunctionInner>,
28}
29
30impl BuiltinFunction {
31    pub(crate) fn sig(&self) -> &ABISig {
32        &self.inner.sig
33    }
34
35    pub(crate) fn ty(&self) -> BuiltinType {
36        self.inner.ty
37    }
38}
39
40/// Metadata about a builtin function.
41pub struct BuiltinFunctionInner {
42    /// The ABI specific signature of the function.
43    sig: ABISig,
44    /// The built-in function type.
45    ty: BuiltinType,
46}
47
48macro_rules! declare_function_sig {
49    (
50        $(
51            $( #[$attr:meta] )*
52            $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
53         )*
54    ) => {
55        /// Provides the ABI signatures for each builtin function
56        /// signature.
57        pub struct BuiltinFunctions {
58            /// The target calling convention for host intrinsics.
59            host_call_conv: CallingConvention,
60            /// The target calling convention for wasm builtins.
61            wasm_call_conv: CallingConvention,
62            /// The target pointer type, as a WebAssembly type.
63            ptr_type: WasmValType,
64            $(
65                $( #[ $attr ] )*
66                $name: Option<BuiltinFunction>,
67            )*
68        }
69
70        #[expect(dead_code, reason = "not all functions used yet")]
71        impl BuiltinFunctions {
72            pub fn new<P: PtrSize>(
73                vmoffsets: &VMOffsets<P>,
74                host_call_conv: CallingConvention,
75                wasm_call_conv: CallingConvention,
76            ) -> Self {
77                let size = vmoffsets.ptr.size();
78                Self {
79                    host_call_conv,
80                    wasm_call_conv,
81                    ptr_type: ptr_type_from_ptr_size(size),
82                    $(
83                        $( #[ $attr ] )*
84                        $name: None,
85                    )*
86                }
87            }
88
89            fn pointer(&self) -> WasmValType {
90                self.ptr_type
91            }
92
93            fn size(&self) -> WasmValType {
94                self.ptr_type
95            }
96
97            fn vmctx(&self) -> WasmValType {
98                self.pointer()
99            }
100
101            fn u32(&self) -> WasmValType {
102                WasmValType::I32
103            }
104
105            fn u8(&self) -> WasmValType {
106                WasmValType::I32
107            }
108
109            fn f32(&self) -> WasmValType {
110                WasmValType::F32
111            }
112
113            fn f64(&self) -> WasmValType {
114                WasmValType::F64
115            }
116
117            fn u64(&self) -> WasmValType {
118                WasmValType::I64
119            }
120
121            fn i8x16(&self) -> WasmValType {
122                WasmValType::V128
123            }
124
125            fn f32x4(&self) -> WasmValType {
126                WasmValType::V128
127            }
128
129            fn f64x2(&self) -> WasmValType {
130                WasmValType::V128
131            }
132
133            fn bool(&self) -> WasmValType {
134                WasmValType::I32
135            }
136
137            fn over_f64<A: ABI>(&self) -> Result<ABISig> {
138                A::sig_from(&[self.f64()], &[self.f64()], &self.host_call_conv)
139            }
140
141            fn over_f32<A: ABI>(&self) -> Result<ABISig> {
142                A::sig_from(&[self.f64()], &[self.f64()], &self.host_call_conv)
143            }
144
145            $(
146                $( #[ $attr ] )*
147                pub(crate) fn $name<A: ABI>(&mut self) -> Result<BuiltinFunction> {
148                    if self.$name.is_none() {
149                        let params = vec![ $(self.$param() ),* ];
150                        let result = vec![ $(self.$result() )?];
151                        let sig = A::sig_from(&params, &result, &self.wasm_call_conv)?;
152                        let index = BuiltinFunctionIndex::$name();
153                        let inner = Arc::new(BuiltinFunctionInner { sig, ty: BuiltinType::builtin(index) });
154                        self.$name = Some(BuiltinFunction {
155                            inner,
156                        });
157                    }
158
159                    Ok(self.$name.as_ref().unwrap().clone())
160                }
161             )*
162        }
163    }
164}
165
166wasmtime_environ::foreach_builtin_function!(declare_function_sig);