cranelift_assembler_x64_meta/generate/
features.rs

1//! Generate feature-related Rust code.
2
3use super::{Formatter, fmtln};
4use crate::dsl;
5
6impl dsl::Feature {
7    /// `macro_rules! for_each_feature { ... }`
8    ///
9    /// This function generates a macro to allow generating code for each CPU
10    /// feature.
11    pub(crate) fn generate_macro(f: &mut Formatter) {
12        fmtln!(f, "#[doc(hidden)]");
13        fmtln!(f, "#[macro_export]");
14        f.add_block("macro_rules! for_each_feature", |f| {
15            f.add_block("($m:ident) =>", |f| {
16                f.add_block("$m!", |f| {
17                    for feature in dsl::ALL_FEATURES {
18                        fmtln!(f, "{feature}");
19                    }
20                });
21            });
22        });
23    }
24}
25
26impl dsl::Features {
27    /// E.g., `features.is_sse2() && features.is_64b()`
28    ///
29    /// Generate a boolean expression that checks if the features are available.
30    pub(crate) fn generate_boolean_expr(&self, name: &str) -> String {
31        use dsl::Features::*;
32        match self {
33            And(lhs, rhs) => {
34                let lhs = lhs.generate_inner_boolean_expr(name);
35                let rhs = rhs.generate_inner_boolean_expr(name);
36                format!("{lhs} && {rhs}")
37            }
38            Or(lhs, rhs) => {
39                let lhs = lhs.generate_inner_boolean_expr(name);
40                let rhs = rhs.generate_inner_boolean_expr(name);
41                format!("{lhs} || {rhs}")
42            }
43            Feature(feature) => {
44                format!("{name}.{feature}()")
45            }
46        }
47    }
48
49    // This adds parentheses for inner terms.
50    fn generate_inner_boolean_expr(&self, name: &str) -> String {
51        use dsl::Features::*;
52        match self {
53            And(lhs, rhs) => {
54                let lhs = lhs.generate_inner_boolean_expr(name);
55                let rhs = rhs.generate_inner_boolean_expr(name);
56                format!("({lhs} && {rhs})")
57            }
58            Or(lhs, rhs) => {
59                let lhs = lhs.generate_inner_boolean_expr(name);
60                let rhs = rhs.generate_inner_boolean_expr(name);
61                format!("({lhs} || {rhs})")
62            }
63            Feature(feature) => format!("{name}.{feature}()"),
64        }
65    }
66
67    /// E.g., `Features::Or(Features::Feature(compat), Features::Feature(64b))`
68    ///
69    /// Generate a Rust constructor expression that contains the feature
70    /// boolean term.
71    pub(crate) fn generate_constructor_expr(&self, f: &mut Formatter) {
72        let mut index = 0;
73        let name = self.generate_inner_constructor_expr(f, &mut index);
74        fmtln!(f, "{name}");
75    }
76
77    fn generate_inner_constructor_expr(&self, f: &mut Formatter, index: &mut u32) -> String {
78        use dsl::Features::*;
79
80        let name = format!("F{index}");
81        *index += 1;
82
83        let const_expr = format!("const {name}: &'static Features");
84        match self {
85            And(lhs, rhs) => {
86                let lhs = lhs.generate_inner_constructor_expr(f, index);
87                let rhs = rhs.generate_inner_constructor_expr(f, index);
88                fmtln!(f, "{const_expr} = &Features::And({lhs}, {rhs});");
89            }
90            Or(lhs, rhs) => {
91                let lhs = lhs.generate_inner_constructor_expr(f, index);
92                let rhs = rhs.generate_inner_constructor_expr(f, index);
93                fmtln!(f, "{const_expr} = &Features::Or({lhs}, {rhs});");
94            }
95            Feature(feature) => {
96                fmtln!(f, "{const_expr} = &Features::Feature(Feature::{feature});");
97            }
98        }
99        name
100    }
101}