xref: /wasmtime-44.0.1/pulley/src/encode.rs (revision fee9be21)
1 //! Encoding support for pulley bytecode.
2 
3 use crate::imms::*;
4 use crate::opcode::{ExtendedOpcode, Opcode};
5 use crate::regs::*;
6 
7 /// Helper trait to encode instructions into a "sink".
8 pub trait Encode {
9     /// The encoded width of this instruction.
10     const WIDTH: u8;
11 
12     /// Encodes this operand or instruction into the provided `sink`.
13     fn encode<E>(&self, sink: &mut E)
14     where
15         E: Extend<u8>;
16 }
17 
18 impl Encode for u8 {
19     const WIDTH: u8 = 1;
20 
21     fn encode<E>(&self, sink: &mut E)
22     where
23         E: Extend<u8>,
24     {
25         sink.extend(core::iter::once(*self));
26     }
27 }
28 
29 impl Encode for u16 {
30     const WIDTH: u8 = 2;
31 
32     fn encode<E>(&self, sink: &mut E)
33     where
34         E: Extend<u8>,
35     {
36         sink.extend(self.to_le_bytes());
37     }
38 }
39 
40 impl Encode for u32 {
41     const WIDTH: u8 = 4;
42 
43     fn encode<E>(&self, sink: &mut E)
44     where
45         E: Extend<u8>,
46     {
47         sink.extend(self.to_le_bytes());
48     }
49 }
50 
51 impl Encode for u64 {
52     const WIDTH: u8 = 8;
53 
54     fn encode<E>(&self, sink: &mut E)
55     where
56         E: Extend<u8>,
57     {
58         sink.extend(self.to_le_bytes());
59     }
60 }
61 
62 impl Encode for u128 {
63     const WIDTH: u8 = 16;
64 
65     fn encode<E>(&self, sink: &mut E)
66     where
67         E: Extend<u8>,
68     {
69         sink.extend(self.to_le_bytes());
70     }
71 }
72 
73 impl Encode for i8 {
74     const WIDTH: u8 = 1;
75 
76     fn encode<E>(&self, sink: &mut E)
77     where
78         E: Extend<u8>,
79     {
80         sink.extend(core::iter::once(*self as u8));
81     }
82 }
83 
84 impl Encode for i16 {
85     const WIDTH: u8 = 2;
86 
87     fn encode<E>(&self, sink: &mut E)
88     where
89         E: Extend<u8>,
90     {
91         sink.extend(self.to_le_bytes());
92     }
93 }
94 
95 impl Encode for i32 {
96     const WIDTH: u8 = 4;
97 
98     fn encode<E>(&self, sink: &mut E)
99     where
100         E: Extend<u8>,
101     {
102         sink.extend(self.to_le_bytes());
103     }
104 }
105 
106 impl Encode for i64 {
107     const WIDTH: u8 = 8;
108 
109     fn encode<E>(&self, sink: &mut E)
110     where
111         E: Extend<u8>,
112     {
113         sink.extend(self.to_le_bytes());
114     }
115 }
116 
117 impl Encode for i128 {
118     const WIDTH: u8 = 16;
119 
120     fn encode<E>(&self, sink: &mut E)
121     where
122         E: Extend<u8>,
123     {
124         sink.extend(self.to_le_bytes());
125     }
126 }
127 
128 impl Encode for XReg {
129     const WIDTH: u8 = 1;
130 
131     fn encode<E>(&self, sink: &mut E)
132     where
133         E: Extend<u8>,
134     {
135         sink.extend(core::iter::once(self.to_u8()));
136     }
137 }
138 
139 impl Encode for FReg {
140     const WIDTH: u8 = 1;
141 
142     fn encode<E>(&self, sink: &mut E)
143     where
144         E: Extend<u8>,
145     {
146         sink.extend(core::iter::once(self.to_u8()));
147     }
148 }
149 
150 impl Encode for VReg {
151     const WIDTH: u8 = 1;
152 
153     fn encode<E>(&self, sink: &mut E)
154     where
155         E: Extend<u8>,
156     {
157         sink.extend(core::iter::once(self.to_u8()));
158     }
159 }
160 
161 impl Encode for PcRelOffset {
162     const WIDTH: u8 = 4;
163 
164     fn encode<E>(&self, sink: &mut E)
165     where
166         E: Extend<u8>,
167     {
168         i32::from(*self).encode(sink);
169     }
170 }
171 
172 impl<D: Reg, S1: Reg, S2: Reg> Encode for BinaryOperands<D, S1, S2> {
173     const WIDTH: u8 = 2;
174 
175     fn encode<E>(&self, sink: &mut E)
176     where
177         E: Extend<u8>,
178     {
179         self.to_bits().encode(sink);
180     }
181 }
182 
183 impl<D: Reg, S1: Reg> Encode for BinaryOperands<D, S1, U6> {
184     const WIDTH: u8 = 2;
185 
186     fn encode<E>(&self, sink: &mut E)
187     where
188         E: Extend<u8>,
189     {
190         self.to_bits().encode(sink);
191     }
192 }
193 
194 impl<R: Reg + Encode> Encode for UpperRegSet<R> {
195     const WIDTH: u8 = 2;
196 
197     fn encode<E>(&self, sink: &mut E)
198     where
199         E: Extend<u8>,
200     {
201         self.to_bitset().0.encode(sink);
202     }
203 }
204 
205 impl Encode for AddrO32 {
206     const WIDTH: u8 = 5;
207 
208     fn encode<E>(&self, sink: &mut E)
209     where
210         E: Extend<u8>,
211     {
212         self.addr.encode(sink);
213         self.offset.encode(sink);
214     }
215 }
216 
217 impl Encode for AddrZ {
218     const WIDTH: u8 = 5;
219 
220     fn encode<E>(&self, sink: &mut E)
221     where
222         E: Extend<u8>,
223     {
224         self.addr.encode(sink);
225         self.offset.encode(sink);
226     }
227 }
228 
229 impl Encode for AddrG32 {
230     const WIDTH: u8 = 4;
231 
232     fn encode<E>(&self, sink: &mut E)
233     where
234         E: Extend<u8>,
235     {
236         self.to_bits().encode(sink);
237     }
238 }
239 
240 impl Encode for AddrG32Bne {
241     const WIDTH: u8 = 4;
242 
243     fn encode<E>(&self, sink: &mut E)
244     where
245         E: Extend<u8>,
246     {
247         self.to_bits().encode(sink);
248     }
249 }
250 
251 macro_rules! impl_encoders {
252     (
253         $(
254             $( #[$attr:meta] )*
255                 $snake_name:ident = $name:ident $( {
256                 $(
257                     $( #[$field_attr:meta] )*
258                     $field:ident : $field_ty:ty
259                 ),*
260             } )? ;
261         )*
262     ) => {
263         $(
264             $( #[$attr] )*
265             pub fn $snake_name<E>(into: &mut E $( $( , $field : impl Into<$field_ty> )* )? )
266             where
267                 E: Extend<u8>,
268             {
269                 into.extend(core::iter::once(Opcode::$name as u8));
270                 $(
271                     $(
272                         $field.into().encode(into);
273                     )*
274                 )?
275             }
276 
277             impl Encode for crate::op::$name {
278                 const WIDTH: u8 = 1 $($( + <$field_ty as Encode>::WIDTH)*)?;
279 
280                 fn encode<E>(&self, sink: &mut E)
281                 where
282                     E: Extend<u8>,
283                 {
284                     let Self { $(  $( $field ),* )? } = *self;
285                     $snake_name(sink $( $(, $field)* )?)
286                 }
287             }
288         )*
289     };
290 }
291 for_each_op!(impl_encoders);
292 
293 macro_rules! impl_extended_encoders {
294     (
295         $(
296             $( #[$attr:meta] )*
297                 $snake_name:ident = $name:ident $( {
298                     $(
299                         $( #[$field_attr:meta] )*
300                         $field:ident : $field_ty:ty
301                     ),*
302                 } )? ;
303         )*
304     ) => {
305         $(
306             $( #[$attr] )*
307             pub fn $snake_name<E>(into: &mut E $( $( , $field : impl Into<$field_ty> )* )? )
308             where
309                 E: Extend<u8>,
310             {
311                 into.extend(core::iter::once(Opcode::ExtendedOp as u8));
312                 into.extend((ExtendedOpcode::$name as u16).to_le_bytes());
313                 $(
314                     $(
315                         $field.into().encode(into);
316                     )*
317                 )?
318             }
319 
320             impl Encode for crate::op::$name {
321                 const WIDTH: u8 = 3 $($( + <$field_ty as Encode>::WIDTH)*)?;
322 
323                 fn encode<E>(&self, sink: &mut E)
324                 where
325                     E: Extend<u8>,
326                 {
327                     let Self { $(  $( $field ),* )? } = *self;
328                     $snake_name(sink $( $(, $field)* )?)
329                 }
330             }
331         )*
332     };
333 }
334 for_each_extended_op!(impl_extended_encoders);
335 
336 #[test]
337 #[cfg(feature = "std")]
338 fn nop_is_single_byte() {
339     // NOP needs to be a single byte so that it can be used to NOP out
340     // an instruction sequence of any length.
341     let inst = crate::op::Nop {};
342     let mut bytes = vec![];
343     inst.encode(&mut bytes);
344     assert_eq!(bytes.len(), 1);
345 }
346