winch_codegen/codegen/
builtin.rs

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