cranelift_codegen_meta/cdsl/
settings.rs1use std::iter;
2
3#[derive(Clone, Copy, Hash, PartialEq, Eq)]
4pub(crate) struct BoolSettingIndex(usize);
5
6#[derive(Hash, PartialEq, Eq)]
7pub(crate) struct BoolSetting {
8 pub default: bool,
9 pub bit_offset: u8,
10 pub predicate_number: u8,
11}
12
13#[derive(Hash, PartialEq, Eq)]
14pub(crate) enum SpecificSetting {
15 Bool(BoolSetting),
16 Enum(Vec<&'static str>),
17 Num(u8),
18}
19
20#[derive(Hash, PartialEq, Eq)]
21pub(crate) struct Setting {
22 pub name: &'static str,
23 pub description: &'static str,
24 pub comment: &'static str,
25 pub specific: SpecificSetting,
26 pub byte_offset: u8,
27}
28
29impl Setting {
30 pub fn default_byte(&self) -> u8 {
31 match self.specific {
32 SpecificSetting::Bool(BoolSetting {
33 default,
34 bit_offset,
35 ..
36 }) => {
37 if default {
38 1 << bit_offset
39 } else {
40 0
41 }
42 }
43 SpecificSetting::Enum(_) => 0,
44 SpecificSetting::Num(default) => default,
45 }
46 }
47
48 fn byte_for_value(&self, v: bool) -> u8 {
49 match self.specific {
50 SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
51 if v {
52 1 << bit_offset
53 } else {
54 0
55 }
56 }
57 _ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
58 }
59 }
60
61 fn byte_mask(&self) -> u8 {
62 match self.specific {
63 SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset,
64 _ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
65 }
66 }
67}
68
69#[derive(Hash, PartialEq, Eq, Copy, Clone)]
70pub(crate) struct PresetIndex(usize);
71
72#[derive(Hash, PartialEq, Eq)]
73pub(crate) enum PresetType {
74 BoolSetting(BoolSettingIndex),
75 OtherPreset(PresetIndex),
76}
77
78impl From<BoolSettingIndex> for PresetType {
79 fn from(bool_setting_index: BoolSettingIndex) -> Self {
80 PresetType::BoolSetting(bool_setting_index)
81 }
82}
83impl From<PresetIndex> for PresetType {
84 fn from(value: PresetIndex) -> Self {
85 PresetType::OtherPreset(value)
86 }
87}
88
89#[derive(Hash, PartialEq, Eq)]
90pub(crate) struct Preset {
91 pub name: &'static str,
92 pub description: &'static str,
93 values: Vec<BoolSettingIndex>,
94}
95
96impl Preset {
97 pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> {
98 let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0))
99 .take(group.settings_size as usize)
100 .collect();
101 for bool_index in &self.values {
102 let setting = &group.settings[bool_index.0];
103 let mask = setting.byte_mask();
104 let val = setting.byte_for_value(true);
105 assert!((val & !mask) == 0);
106 let (ref mut l_mask, ref mut l_val) =
107 *layout.get_mut(setting.byte_offset as usize).unwrap();
108 *l_mask |= mask;
109 *l_val = (*l_val & !mask) | val;
110 }
111 layout
112 }
113
114 pub fn setting_names<'a>(
115 &'a self,
116 group: &'a SettingGroup,
117 ) -> impl Iterator<Item = &'static str> + 'a {
118 self.values
119 .iter()
120 .map(|bool_index| group.settings[bool_index.0].name)
121 }
122}
123
124pub(crate) struct SettingGroup {
125 pub name: &'static str,
126 pub settings: Vec<Setting>,
127 pub bool_start_byte_offset: u8,
128 pub settings_size: u8,
129 pub presets: Vec<Preset>,
130}
131
132impl SettingGroup {
133 fn num_bool_settings(&self) -> u8 {
134 self.settings
135 .iter()
136 .filter(|s| matches!(s.specific, SpecificSetting::Bool(_)))
137 .count() as u8
138 }
139
140 pub fn byte_size(&self) -> u8 {
141 self.bool_start_byte_offset + (self.num_bool_settings() + 7) / 8
142 }
143}
144
145pub(crate) enum ProtoSpecificSetting {
148 Bool(bool),
149 Enum(Vec<&'static str>),
150 Num(u8),
151}
152
153struct ProtoSetting {
155 name: &'static str,
156 description: &'static str,
157 comment: &'static str,
158 specific: ProtoSpecificSetting,
159}
160
161pub(crate) struct SettingGroupBuilder {
162 name: &'static str,
163 settings: Vec<ProtoSetting>,
164 presets: Vec<Preset>,
165}
166
167impl SettingGroupBuilder {
168 pub fn new(name: &'static str) -> Self {
169 Self {
170 name,
171 settings: Vec::new(),
172 presets: Vec::new(),
173 }
174 }
175
176 fn add_setting(
177 &mut self,
178 name: &'static str,
179 description: &'static str,
180 comment: &'static str,
181 specific: ProtoSpecificSetting,
182 ) {
183 self.settings.push(ProtoSetting {
184 name,
185 description,
186 comment,
187 specific,
188 })
189 }
190
191 pub fn add_bool(
192 &mut self,
193 name: &'static str,
194 description: &'static str,
195 comment: &'static str,
196 default: bool,
197 ) -> BoolSettingIndex {
198 self.add_setting(
199 name,
200 description,
201 comment,
202 ProtoSpecificSetting::Bool(default),
203 );
204 BoolSettingIndex(self.settings.len() - 1)
205 }
206
207 pub fn add_enum(
208 &mut self,
209 name: &'static str,
210 description: &'static str,
211 comment: &'static str,
212 values: Vec<&'static str>,
213 ) {
214 self.add_setting(
215 name,
216 description,
217 comment,
218 ProtoSpecificSetting::Enum(values),
219 );
220 }
221
222 pub fn add_num(
223 &mut self,
224 name: &'static str,
225 description: &'static str,
226 comment: &'static str,
227 default: u8,
228 ) {
229 self.add_setting(
230 name,
231 description,
232 comment,
233 ProtoSpecificSetting::Num(default),
234 );
235 }
236
237 pub fn add_preset(
238 &mut self,
239 name: &'static str,
240 description: &'static str,
241 args: Vec<PresetType>,
242 ) -> PresetIndex {
243 let mut values = Vec::new();
244 for arg in args {
245 match arg {
246 PresetType::OtherPreset(index) => {
247 values.extend(self.presets[index.0].values.iter());
248 }
249 PresetType::BoolSetting(index) => values.push(index),
250 }
251 }
252 self.presets.push(Preset {
253 name,
254 description,
255 values,
256 });
257 PresetIndex(self.presets.len() - 1)
258 }
259
260 pub fn build(self) -> SettingGroup {
277 let mut group = SettingGroup {
278 name: self.name,
279 settings: Vec::new(),
280 bool_start_byte_offset: 0,
281 settings_size: 0,
282 presets: Vec::new(),
283 };
284
285 let mut byte_offset = 0;
286
287 for s in &self.settings {
289 let specific = match s.specific {
290 ProtoSpecificSetting::Bool(..) => continue,
291 ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()),
292 ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default),
293 };
294
295 group.settings.push(Setting {
296 name: s.name,
297 description: s.description,
298 comment: s.comment,
299 byte_offset,
300 specific,
301 });
302
303 byte_offset += 1;
304 }
305
306 group.bool_start_byte_offset = byte_offset;
307
308 let mut predicate_number = 0;
309
310 for s in &self.settings {
312 let default = match s.specific {
313 ProtoSpecificSetting::Bool(default) => default,
314 ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,
315 };
316 group.settings.push(Setting {
317 name: s.name,
318 description: s.description,
319 comment: s.comment,
320 byte_offset: byte_offset + predicate_number / 8,
321 specific: SpecificSetting::Bool(BoolSetting {
322 default,
323 bit_offset: predicate_number % 8,
324 predicate_number,
325 }),
326 });
327 predicate_number += 1;
328 }
329
330 group.settings_size = group.byte_size();
331
332 group.presets.extend(self.presets);
333
334 group
335 }
336}