1 //! CPU features. 2 //! 3 //! Across generations, CPUs add features that include new instructions, e.g., 4 //! [`Feature::sse`], [`Feature::avx`], etc. x64 instructions are governed by 5 //! boolean terms of these CPU features: e.g., `(_64b | compat) & ssse3`. These 6 //! terms are defined per instruction in the `meta` crate and are exposed to 7 //! users in two ways: 8 //! - via the [`Inst::is_available`] function, which uses the 9 //! [`AvailableFeatures`] trait below to query "is this instruction currently 10 //! allowed?"; use this for fast checks during compilation 11 //! - via the [`Inst::features`] function, which returns a fully-constructed 12 //! [`Features`] term; use this for time-insensitive analysis or 13 //! pretty-printing. 14 //! 15 //! ```rust 16 //! # use cranelift_assembler_x64::{Registers, inst}; 17 //! # pub struct Regs; 18 //! # impl Registers for Regs { 19 //! # type ReadGpr = u8; 20 //! # type ReadWriteGpr = u8; 21 //! # type WriteGpr = u8; 22 //! # type ReadXmm = u8; 23 //! # type ReadWriteXmm = u8; 24 //! # type WriteXmm = u8; 25 //! # } 26 //! let xmm0: u8 = 0; 27 //! let andps = inst::andps_a::<Regs>::new(xmm0, xmm0); 28 //! assert_eq!(andps.features().to_string(), "((_64b | compat) & sse)"); 29 //! ``` 30 //! 31 //! [`Inst::is_available`]: crate::inst::Inst::is_available 32 //! [`Inst::features`]: crate::inst::Inst::features 33 34 use crate::inst::for_each_feature; 35 use core::fmt; 36 37 // Helpfully generate `enum Feature`. 38 macro_rules! create_feature_enum { 39 ($($f:ident)+) => { 40 /// A CPU feature. 41 /// 42 /// IA-32e mode is the typical mode of operation for modern 64-bit x86 43 /// processors. It consists of two sub-modes: 44 /// - __64-bit mode__: uses the full 64-bit address space 45 /// - __compatibility mode__: allows use of legacy 32-bit code 46 /// 47 /// Other features listed here should match the __CPUID Feature Flags__ 48 /// column of the instruction tables of the x64 reference manual. 49 /// 50 /// This is generated from the `dsl::Feature` enumeration defined in the 51 /// `meta` crate; see [`for_each_feature`]. 52 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 53 pub enum Feature { 54 $($f,)+ 55 } 56 }; 57 } 58 for_each_feature!(create_feature_enum); 59 60 // Helpfully generate trait functions in `AvailableFeatures`. 61 macro_rules! add_func { 62 ($($f:ident)+) => { 63 $(fn $f(&self) -> bool;)+ 64 }; 65 } 66 67 /// A trait for querying CPU features. 68 /// 69 /// This is generated from the `dsl::Feature` enumeration defined in the `meta` 70 /// crate. It allows querying the CPUID features required by an instruction; see 71 /// [`Inst::is_available`] and [`for_each_feature`]. 72 /// 73 /// [`Inst::is_available`]: crate::inst::Inst::is_available 74 pub trait AvailableFeatures { 75 for_each_feature!(add_func); 76 } 77 78 /// A boolean term of CPU features. 79 /// 80 /// An instruction is valid when the boolean term (a recursive tree of `AND` and 81 /// `OR` terms) is satisfied; see [`Inst::features`]. 82 /// 83 /// [`Inst::features`]: crate::inst::Inst::features 84 pub enum Features { 85 And(&'static Features, &'static Features), 86 Or(&'static Features, &'static Features), 87 Feature(Feature), 88 } 89 90 impl fmt::Display for Features { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 92 match self { 93 Features::And(lhs, rhs) => write!(f, "({lhs} & {rhs})"), 94 Features::Or(lhs, rhs) => write!(f, "({lhs} | {rhs})"), 95 Features::Feature(feature) => write!(f, "{feature:#?}"), 96 } 97 } 98 } 99