Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/meta/src/cdsl/settings.rs
1693 views
1
use std::iter;
2
3
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
4
pub(crate) struct BoolSettingIndex(usize);
5
6
#[derive(Hash, PartialEq, Eq)]
7
pub(crate) struct BoolSetting {
8
pub default: bool,
9
pub bit_offset: u8,
10
pub predicate_number: u8,
11
}
12
13
#[derive(Hash, PartialEq, Eq)]
14
pub(crate) enum SpecificSetting {
15
Bool(BoolSetting),
16
Enum(Vec<&'static str>),
17
Num(u8),
18
}
19
20
#[derive(Hash, PartialEq, Eq)]
21
pub(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
29
impl 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)]
70
pub(crate) struct PresetIndex(usize);
71
72
#[derive(Hash, PartialEq, Eq)]
73
pub(crate) enum PresetType {
74
BoolSetting(BoolSettingIndex),
75
OtherPreset(PresetIndex),
76
}
77
78
impl From<BoolSettingIndex> for PresetType {
79
fn from(bool_setting_index: BoolSettingIndex) -> Self {
80
PresetType::BoolSetting(bool_setting_index)
81
}
82
}
83
impl From<PresetIndex> for PresetType {
84
fn from(value: PresetIndex) -> Self {
85
PresetType::OtherPreset(value)
86
}
87
}
88
89
#[derive(Hash, PartialEq, Eq)]
90
pub(crate) struct Preset {
91
pub name: &'static str,
92
pub description: &'static str,
93
values: Vec<BoolSettingIndex>,
94
}
95
96
impl 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
124
pub(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
pub predicates: Vec<Predicate>,
131
}
132
133
impl SettingGroup {
134
fn num_bool_settings(&self) -> u8 {
135
self.settings
136
.iter()
137
.filter(|s| matches!(s.specific, SpecificSetting::Bool(_)))
138
.count() as u8
139
}
140
141
pub fn byte_size(&self) -> u8 {
142
let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8);
143
self.bool_start_byte_offset + (num_predicates + 7) / 8
144
}
145
}
146
147
/// This is the basic information needed to track the specific parts of a setting when building
148
/// them.
149
pub(crate) enum ProtoSpecificSetting {
150
Bool(bool),
151
Enum(Vec<&'static str>),
152
Num(u8),
153
}
154
155
/// This is the information provided during building for a setting.
156
struct ProtoSetting {
157
name: &'static str,
158
description: &'static str,
159
comment: &'static str,
160
specific: ProtoSpecificSetting,
161
}
162
163
#[derive(Hash, PartialEq, Eq)]
164
pub(crate) enum PredicateNode {
165
OwnedBool(BoolSettingIndex),
166
SharedBool(&'static str, &'static str),
167
And(Box<PredicateNode>, Box<PredicateNode>),
168
}
169
170
impl From<BoolSettingIndex> for PredicateNode {
171
fn from(bool_setting_index: BoolSettingIndex) -> Self {
172
PredicateNode::OwnedBool(bool_setting_index)
173
}
174
}
175
176
impl<'a> From<(BoolSettingIndex, &'a SettingGroup)> for PredicateNode {
177
fn from(val: (BoolSettingIndex, &'a SettingGroup)) -> Self {
178
let (index, group) = (val.0, val.1);
179
let setting = &group.settings[index.0];
180
PredicateNode::SharedBool(group.name, setting.name)
181
}
182
}
183
184
impl PredicateNode {
185
fn render(&self, group: &SettingGroup) -> String {
186
match *self {
187
PredicateNode::OwnedBool(bool_setting_index) => format!(
188
"{}.{}()",
189
group.name, group.settings[bool_setting_index.0].name
190
),
191
PredicateNode::SharedBool(ref group_name, ref bool_name) => {
192
format!("{group_name}.{bool_name}()")
193
}
194
PredicateNode::And(ref lhs, ref rhs) => {
195
format!("{} && {}", lhs.render(group), rhs.render(group))
196
}
197
}
198
}
199
}
200
201
struct ProtoPredicate {
202
pub name: &'static str,
203
node: PredicateNode,
204
}
205
206
pub(crate) type SettingPredicateNumber = u8;
207
208
pub(crate) struct Predicate {
209
pub name: &'static str,
210
node: PredicateNode,
211
pub number: SettingPredicateNumber,
212
}
213
214
impl Predicate {
215
pub fn render(&self, group: &SettingGroup) -> String {
216
self.node.render(group)
217
}
218
}
219
220
pub(crate) struct SettingGroupBuilder {
221
name: &'static str,
222
settings: Vec<ProtoSetting>,
223
presets: Vec<Preset>,
224
predicates: Vec<ProtoPredicate>,
225
}
226
227
impl SettingGroupBuilder {
228
pub fn new(name: &'static str) -> Self {
229
Self {
230
name,
231
settings: Vec::new(),
232
presets: Vec::new(),
233
predicates: Vec::new(),
234
}
235
}
236
237
fn add_setting(
238
&mut self,
239
name: &'static str,
240
description: &'static str,
241
comment: &'static str,
242
specific: ProtoSpecificSetting,
243
) {
244
self.settings.push(ProtoSetting {
245
name,
246
description,
247
comment,
248
specific,
249
})
250
}
251
252
pub fn add_bool(
253
&mut self,
254
name: &'static str,
255
description: &'static str,
256
comment: &'static str,
257
default: bool,
258
) -> BoolSettingIndex {
259
assert!(
260
self.predicates.is_empty(),
261
"predicates must be added after the boolean settings"
262
);
263
self.add_setting(
264
name,
265
description,
266
comment,
267
ProtoSpecificSetting::Bool(default),
268
);
269
BoolSettingIndex(self.settings.len() - 1)
270
}
271
272
pub fn add_enum(
273
&mut self,
274
name: &'static str,
275
description: &'static str,
276
comment: &'static str,
277
values: Vec<&'static str>,
278
) {
279
self.add_setting(
280
name,
281
description,
282
comment,
283
ProtoSpecificSetting::Enum(values),
284
);
285
}
286
287
pub fn add_num(
288
&mut self,
289
name: &'static str,
290
description: &'static str,
291
comment: &'static str,
292
default: u8,
293
) {
294
self.add_setting(
295
name,
296
description,
297
comment,
298
ProtoSpecificSetting::Num(default),
299
);
300
}
301
302
pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) {
303
self.predicates.push(ProtoPredicate { name, node });
304
}
305
306
pub fn add_preset(
307
&mut self,
308
name: &'static str,
309
description: &'static str,
310
args: Vec<PresetType>,
311
) -> PresetIndex {
312
let mut values = Vec::new();
313
for arg in args {
314
match arg {
315
PresetType::OtherPreset(index) => {
316
values.extend(self.presets[index.0].values.iter());
317
}
318
PresetType::BoolSetting(index) => values.push(index),
319
}
320
}
321
self.presets.push(Preset {
322
name,
323
description,
324
values,
325
});
326
PresetIndex(self.presets.len() - 1)
327
}
328
329
/// Compute the layout of the byte vector used to represent this settings
330
/// group.
331
///
332
/// The byte vector contains the following entries in order:
333
///
334
/// 1. Byte-sized settings like `NumSetting` and `EnumSetting`.
335
/// 2. `BoolSetting` settings.
336
/// 3. Precomputed named predicates.
337
/// 4. Other numbered predicates, including parent predicates that need to be accessible by
338
/// number.
339
///
340
/// Set `self.settings_size` to the length of the byte vector prefix that
341
/// contains the settings. All bytes after that are computed, not
342
/// configured.
343
///
344
/// Set `self.boolean_offset` to the beginning of the numbered predicates,
345
/// 2. in the list above.
346
///
347
/// Assign `byte_offset` and `bit_offset` fields in all settings.
348
pub fn build(self) -> SettingGroup {
349
let mut group = SettingGroup {
350
name: self.name,
351
settings: Vec::new(),
352
bool_start_byte_offset: 0,
353
settings_size: 0,
354
presets: Vec::new(),
355
predicates: Vec::new(),
356
};
357
358
let mut byte_offset = 0;
359
360
// Assign the non-boolean settings first.
361
for s in &self.settings {
362
let specific = match s.specific {
363
ProtoSpecificSetting::Bool(..) => continue,
364
ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()),
365
ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default),
366
};
367
368
group.settings.push(Setting {
369
name: s.name,
370
description: s.description,
371
comment: s.comment,
372
byte_offset,
373
specific,
374
});
375
376
byte_offset += 1;
377
}
378
379
group.bool_start_byte_offset = byte_offset;
380
381
let mut predicate_number = 0;
382
383
// Then the boolean settings.
384
for s in &self.settings {
385
let default = match s.specific {
386
ProtoSpecificSetting::Bool(default) => default,
387
ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,
388
};
389
group.settings.push(Setting {
390
name: s.name,
391
description: s.description,
392
comment: s.comment,
393
byte_offset: byte_offset + predicate_number / 8,
394
specific: SpecificSetting::Bool(BoolSetting {
395
default,
396
bit_offset: predicate_number % 8,
397
predicate_number,
398
}),
399
});
400
predicate_number += 1;
401
}
402
403
assert!(
404
group.predicates.is_empty(),
405
"settings_size is the byte size before adding predicates"
406
);
407
group.settings_size = group.byte_size();
408
409
// Sort predicates by name to ensure the same order as the Python code.
410
let mut predicates = self.predicates;
411
predicates.sort_by_key(|predicate| predicate.name);
412
413
group
414
.predicates
415
.extend(predicates.into_iter().map(|predicate| {
416
let number = predicate_number;
417
predicate_number += 1;
418
Predicate {
419
name: predicate.name,
420
node: predicate.node,
421
number,
422
}
423
}));
424
425
group.presets.extend(self.presets);
426
427
group
428
}
429
}
430
431