xref: /wasmtime-44.0.1/pulley/src/op.rs (revision eed7c104)
1 //! Pulley bytecode operations with their operands.
2 
3 #[cfg(feature = "encode")]
4 use crate::encode::Encode;
5 use crate::imms::*;
6 use crate::regs::*;
7 
8 macro_rules! define_op {
9     (
10         $(
11             $( #[$attr:meta] )*
12             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
13         )*
14     ) => {
15         /// A complete, materialized operation/instruction.
16         ///
17         /// This type is useful for debugging, writing tests, etc... but is not
18         /// actually ever used by the interpreter, encoder, or decoder, all of
19         /// which avoid materializing ops.
20         #[derive(Clone, Copy, Debug, PartialEq, Eq)]
21         #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
22         pub enum Op {
23             $(
24                 $( #[$attr] )*
25                 $name($name),
26             )*
27             /// An extended operation/instruction.
28             ExtendedOp(ExtendedOp),
29         }
30 
31         $(
32             $( #[$attr] )*
33             #[derive(Clone, Copy, Debug, PartialEq, Eq)]
34             #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
35             pub struct $name { $(
36                 $(
37                     // TODO: add doc comments to all fields and update all
38                     // the macros to match them.
39                     #[expect(missing_docs, reason = "macro-generated code")]
40                     pub $field : $field_ty,
41                 )*
42             )? }
43 
44             impl From<$name> for Op {
45                 #[inline]
46                 fn from(op: $name) -> Self {
47                     Self::$name(op)
48                 }
49             }
50         )*
51     };
52 }
53 for_each_op!(define_op);
54 
55 impl From<ExtendedOp> for Op {
56     #[inline]
from(op: ExtendedOp) -> Self57     fn from(op: ExtendedOp) -> Self {
58         Op::ExtendedOp(op)
59     }
60 }
61 
62 macro_rules! define_extended_op {
63     (
64         $(
65             $( #[$attr:meta] )*
66             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
67         )*
68     ) => {
69         /// An extended operation/instruction.
70         ///
71         /// These tend to be colder than `Op`s.
72         #[derive(Clone, Copy, Debug, PartialEq, Eq)]
73         #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
74         pub enum ExtendedOp {
75             $(
76                 $( #[$attr] )*
77                 $name($name),
78             )*
79         }
80 
81         $(
82             $( #[$attr] )*
83             #[derive(Clone, Copy, Debug, PartialEq, Eq)]
84             #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
85             pub struct $name { $(
86                 $(
87                     // TODO: add doc comments to all fields and update all
88                     // the macros to match them.
89                     #[expect(missing_docs, reason = "macro-generated code")]
90                     pub $field : $field_ty,
91                 )*
92             )? }
93 
94             #[doc(hidden)]
95             #[expect(non_camel_case_types, reason = "used in macros as an alternative to camel case")]
96             pub type $snake_name = $name;
97 
98             impl From<$name> for Op {
99                 #[inline]
100                 fn from(op: $name) -> Self {
101                     Self::ExtendedOp(ExtendedOp::$name(op))
102                 }
103             }
104 
105             impl From<$name> for ExtendedOp {
106                 #[inline]
107                 fn from(op: $name) -> Self {
108                     Self::$name(op)
109                 }
110             }
111         )*
112     };
113 }
114 for_each_extended_op!(define_extended_op);
115 
116 macro_rules! define_op_encode {
117     (
118         $(
119             $( #[$attr:meta] )*
120             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
121         )*
122     ) => {
123         impl Op {
124             /// Encode this op into the given sink.
125             #[cfg(feature = "encode")]
126             pub fn encode<E>(&self, into: &mut E)
127             where
128                 E: Extend<u8>,
129             {
130                 match self {
131                     $(
132                         Self::$name(op) => op.encode(into),
133                     )*
134                     Self::ExtendedOp(op) => op.encode(into),
135                 }
136             }
137 
138             /// Returns the encoded size of this op.
139             #[cfg(feature = "encode")]
140             pub fn width(&self) -> u8 {
141                 match self {
142                     $(
143                         Self::$name(_) => <$name as Encode>::WIDTH,
144                     )*
145                     Self::ExtendedOp(op) => op.width(),
146                 }
147             }
148         }
149 
150         $(
151             impl $name {
152                 /// Encode this
153                 #[doc = concat!("`", stringify!($name), "`")]
154                 /// op into the given sink.
155                 #[cfg(feature = "encode")]
156                 pub fn encode<E>(&self, into: &mut E)
157                 where
158                     E: Extend<u8>,
159                 {
160                     crate::encode::$snake_name(into $( $( , self.$field )* )?);
161                 }
162             }
163         )*
164     };
165 }
166 for_each_op!(define_op_encode);
167 
168 macro_rules! define_extended_op_encode {
169     (
170         $(
171             $( #[$attr:meta] )*
172             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
173         )*
174     ) => {
175         impl ExtendedOp {
176             /// Encode this extended op into the given sink.
177             #[cfg(feature = "encode")]
178             pub fn encode<E>(&self, into: &mut E)
179             where
180                 E: Extend<u8>,
181             {
182                 match self {
183                     $(
184                         Self::$name(op) => op.encode(into),
185                     )*
186                 }
187             }
188 
189             /// Returns the encoded size of this op.
190             #[cfg(feature = "encode")]
191             pub fn width(&self) -> u8 {
192                 match self {
193                     $(
194                         Self::$name(_) => <$name as Encode>::WIDTH,
195                     )*
196                 }
197             }
198         }
199 
200         $(
201             impl $name {
202                 /// Encode this
203                 #[doc = concat!("`", stringify!($name), "`")]
204                 /// op into the given sink.
205                 #[cfg(feature = "encode")]
206                 pub fn encode<E>(&self, into: &mut E)
207                 where
208                     E: Extend<u8>,
209                 {
210                     crate::encode::$snake_name(into $( $( , self.$field )* )?);
211                 }
212             }
213         )*
214     };
215 }
216 for_each_extended_op!(define_extended_op_encode);
217 
218 /// A visitor that materializes whole `Op`s as it decodes the bytecode stream.
219 #[cfg(feature = "decode")]
220 #[derive(Default)]
221 pub struct MaterializeOpsVisitor<B> {
222     bytecode: B,
223 }
224 
225 #[cfg(feature = "decode")]
226 impl<B> MaterializeOpsVisitor<B> {
227     /// Create a new op-materializing visitor for the given bytecode.
new(bytecode: B) -> Self228     pub fn new(bytecode: B) -> Self {
229         Self { bytecode }
230     }
231 }
232 
233 macro_rules! define_materialize_op_visitor {
234     (
235         $(
236             $( #[$attr:meta] )*
237             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
238         )*
239     ) => {
240         #[cfg(feature = "decode")]
241         impl<B: crate::decode::BytecodeStream> crate::decode::OpVisitor for MaterializeOpsVisitor<B> {
242             type BytecodeStream = B;
243 
244             fn bytecode(&mut self) -> &mut Self::BytecodeStream {
245                 &mut self.bytecode
246             }
247 
248             type Return = crate::op::Op;
249 
250             $(
251                 $( #[$attr] )*
252                 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
253                     crate::op::Op::$name(crate::op::$name { $( $(
254                         $field,
255                     )* )? })
256                 }
257             )*
258         }
259     };
260 }
261 for_each_op!(define_materialize_op_visitor);
262 
263 macro_rules! define_materialize_extended_op_visitor {
264     (
265         $(
266             $( #[$attr:meta] )*
267             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
268         )*
269     ) => {
270         #[cfg(feature = "decode")]
271         impl<B: crate::decode::BytecodeStream> crate::decode::ExtendedOpVisitor for MaterializeOpsVisitor<B> {
272             $(
273                 $( #[$attr] )*
274                 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
275                     crate::op::ExtendedOp::$name(crate::op::$name { $( $(
276                         $field,
277                     )* )? }).into()
278                 }
279             )*
280         }
281     };
282 }
283 for_each_extended_op!(define_materialize_extended_op_visitor);
284