1 //! Generate feature-related Rust code.
2 
3 use super::{Formatter, fmtln};
4 use crate::dsl;
5 
6 impl dsl::Feature {
7     /// `macro_rules! for_each_feature { ... }`
8     ///
9     /// This function generates a macro to allow generating code for each CPU
10     /// feature.
generate_macro(f: &mut Formatter)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 
26 impl dsl::Features {
27     /// E.g., `features.is_sse2() && features.is_64b()`
28     ///
29     /// Generate a boolean expression that checks if the features are available.
generate_boolean_expr(&self, name: &str) -> String30     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.
generate_inner_boolean_expr(&self, name: &str) -> String50     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.
generate_constructor_expr(&self, f: &mut Formatter)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 
generate_inner_constructor_expr(&self, f: &mut Formatter, index: &mut u32) -> String77     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 }
102