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