xref: /wasmtime-44.0.1/pulley/src/opcode.rs (revision 56cae563)
14ac1bedfSNick Fitzgerald //! Pulley opcodes (without operands).
24ac1bedfSNick Fitzgerald 
34ac1bedfSNick Fitzgerald macro_rules! define_opcode {
44ac1bedfSNick Fitzgerald     (
54ac1bedfSNick Fitzgerald         $(
64ac1bedfSNick Fitzgerald             $( #[$attr:meta] )*
74ac1bedfSNick Fitzgerald             $snake_name:ident = $name:ident $( {
84ac1bedfSNick Fitzgerald                 $(
94ac1bedfSNick Fitzgerald                     $( #[$field_attr:meta] )*
104ac1bedfSNick Fitzgerald                     $field:ident : $field_ty:ty
114ac1bedfSNick Fitzgerald                 ),*
124ac1bedfSNick Fitzgerald             } )? ;
134ac1bedfSNick Fitzgerald         )*
144ac1bedfSNick Fitzgerald     ) => {
154ac1bedfSNick Fitzgerald         /// An opcode without its immediates and operands.
164ac1bedfSNick Fitzgerald         #[repr(u8)]
174ac1bedfSNick Fitzgerald         #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
184ac1bedfSNick Fitzgerald         pub enum Opcode {
194ac1bedfSNick Fitzgerald             $(
204ac1bedfSNick Fitzgerald                 $( #[$attr] )*
214ac1bedfSNick Fitzgerald                 $name,
224ac1bedfSNick Fitzgerald             )*
234ac1bedfSNick Fitzgerald             /// The extended-op opcode. An `ExtendedOpcode` follows this opcode.
244ac1bedfSNick Fitzgerald             ExtendedOp,
254ac1bedfSNick Fitzgerald         }
264ac1bedfSNick Fitzgerald 
274ac1bedfSNick Fitzgerald         impl Opcode {
284ac1bedfSNick Fitzgerald             /// The value of the maximum defined opcode.
290058cb78SAlex Crichton             pub const MAX: u8 = Opcode::ExtendedOp as u8;
304ac1bedfSNick Fitzgerald         }
31c1d405c1SAlex Crichton     }
324ac1bedfSNick Fitzgerald }
334ac1bedfSNick Fitzgerald for_each_op!(define_opcode);
344ac1bedfSNick Fitzgerald 
354ac1bedfSNick Fitzgerald impl Opcode {
364ac1bedfSNick Fitzgerald     /// Create a new `Opcode` from the given byte.
374ac1bedfSNick Fitzgerald     ///
384ac1bedfSNick Fitzgerald     /// Returns `None` if `byte` is not a valid opcode.
new(byte: u8) -> Option<Self>394ac1bedfSNick Fitzgerald     pub fn new(byte: u8) -> Option<Self> {
404ac1bedfSNick Fitzgerald         if byte <= Self::MAX {
414ac1bedfSNick Fitzgerald             Some(unsafe { Self::unchecked_new(byte) })
424ac1bedfSNick Fitzgerald         } else {
434ac1bedfSNick Fitzgerald             None
444ac1bedfSNick Fitzgerald         }
454ac1bedfSNick Fitzgerald     }
464ac1bedfSNick Fitzgerald 
474ac1bedfSNick Fitzgerald     /// Like `new` but does not check whether `byte` is a valid opcode.
484ac1bedfSNick Fitzgerald     ///
494ac1bedfSNick Fitzgerald     /// # Safety
504ac1bedfSNick Fitzgerald     ///
514ac1bedfSNick Fitzgerald     /// It is unsafe to pass a `byte` that is not a valid opcode.
unchecked_new(byte: u8) -> Self524ac1bedfSNick Fitzgerald     pub unsafe fn unchecked_new(byte: u8) -> Self {
534ac1bedfSNick Fitzgerald         debug_assert!(byte <= Self::MAX);
54073aedabSAlex Crichton         unsafe { core::mem::transmute(byte) }
554ac1bedfSNick Fitzgerald     }
564ac1bedfSNick Fitzgerald }
574ac1bedfSNick Fitzgerald 
584ac1bedfSNick Fitzgerald macro_rules! define_extended_opcode {
594ac1bedfSNick Fitzgerald     (
604ac1bedfSNick Fitzgerald         $(
614ac1bedfSNick Fitzgerald             $( #[$attr:meta] )*
624ac1bedfSNick Fitzgerald             $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
634ac1bedfSNick Fitzgerald         )*
644ac1bedfSNick Fitzgerald     ) => {
654ac1bedfSNick Fitzgerald         /// An extended opcode.
664ac1bedfSNick Fitzgerald         #[repr(u16)]
674ac1bedfSNick Fitzgerald         #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
684ac1bedfSNick Fitzgerald         pub enum ExtendedOpcode {
694ac1bedfSNick Fitzgerald             $(
704ac1bedfSNick Fitzgerald                 $( #[$attr] )*
714ac1bedfSNick Fitzgerald                     $name,
724ac1bedfSNick Fitzgerald             )*
734ac1bedfSNick Fitzgerald         }
744ac1bedfSNick Fitzgerald 
754ac1bedfSNick Fitzgerald         impl ExtendedOpcode {
764ac1bedfSNick Fitzgerald             /// The value of the maximum defined extended opcode.
77c1d405c1SAlex Crichton             pub const MAX: u16 = $(
78c1d405c1SAlex Crichton                 if true { 1 } else { ExtendedOpcode::$name as u16 } +
79*56cae563SAlex Crichton             )* 0 - 1;
804ac1bedfSNick Fitzgerald         }
814ac1bedfSNick Fitzgerald     };
824ac1bedfSNick Fitzgerald }
834ac1bedfSNick Fitzgerald for_each_extended_op!(define_extended_opcode);
844ac1bedfSNick Fitzgerald 
854ac1bedfSNick Fitzgerald impl ExtendedOpcode {
864ac1bedfSNick Fitzgerald     /// Create a new `ExtendedOpcode` from the given bytes.
874ac1bedfSNick Fitzgerald     ///
884ac1bedfSNick Fitzgerald     /// Returns `None` if `bytes` is not a valid extended opcode.
new(bytes: u16) -> Option<Self>894ac1bedfSNick Fitzgerald     pub fn new(bytes: u16) -> Option<Self> {
904ac1bedfSNick Fitzgerald         if bytes <= Self::MAX {
914ac1bedfSNick Fitzgerald             Some(unsafe { Self::unchecked_new(bytes) })
924ac1bedfSNick Fitzgerald         } else {
934ac1bedfSNick Fitzgerald             None
944ac1bedfSNick Fitzgerald         }
954ac1bedfSNick Fitzgerald     }
964ac1bedfSNick Fitzgerald 
974ac1bedfSNick Fitzgerald     /// Like `new` but does not check whether `bytes` is a valid opcode.
984ac1bedfSNick Fitzgerald     ///
994ac1bedfSNick Fitzgerald     /// # Safety
1004ac1bedfSNick Fitzgerald     ///
1014ac1bedfSNick Fitzgerald     /// It is unsafe to pass `bytes` that is not a valid opcode.
unchecked_new(byte: u16) -> Self1024ac1bedfSNick Fitzgerald     pub unsafe fn unchecked_new(byte: u16) -> Self {
1034ac1bedfSNick Fitzgerald         debug_assert!(byte <= Self::MAX);
104073aedabSAlex Crichton         unsafe { core::mem::transmute(byte) }
1054ac1bedfSNick Fitzgerald     }
1064ac1bedfSNick Fitzgerald }
107*56cae563SAlex Crichton 
108*56cae563SAlex Crichton #[cfg(test)]
109*56cae563SAlex Crichton mod tests {
110*56cae563SAlex Crichton     use super::*;
111*56cae563SAlex Crichton 
112*56cae563SAlex Crichton     #[test]
max_values()113*56cae563SAlex Crichton     fn max_values() {
114*56cae563SAlex Crichton         assert!(Opcode::new(Opcode::MAX).is_some());
115*56cae563SAlex Crichton         assert!(Opcode::new(Opcode::MAX + 1).is_none());
116*56cae563SAlex Crichton         assert!(ExtendedOpcode::new(ExtendedOpcode::MAX).is_some());
117*56cae563SAlex Crichton         assert!(ExtendedOpcode::new(ExtendedOpcode::MAX + 1).is_none());
118*56cae563SAlex Crichton     }
119*56cae563SAlex Crichton }
120