cranelift_assembler_x64/features.rs
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
34use crate::inst::for_each_feature;
35use std::fmt;
36
37// Helpfully generate `enum Feature`.
38macro_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}
58for_each_feature!(create_feature_enum);
59
60// Helpfully generate trait functions in `AvailableFeatures`.
61macro_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
74pub 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
84pub enum Features {
85 And(&'static Features, &'static Features),
86 Or(&'static Features, &'static Features),
87 Feature(Feature),
88}
89
90impl fmt::Display for Features {
91 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}