Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/settings.rs
1693 views
1
//! Shared settings module.
2
//!
3
//! This module defines data structures to access the settings defined in the meta language.
4
//!
5
//! Each settings group is translated to a `Flags` struct either in this module or in its
6
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
7
//! settings as well as computed predicate flags.
8
//!
9
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
10
//! create it.
11
//!
12
//! # Example
13
//! ```
14
//! use cranelift_codegen::settings::{self, Configurable};
15
//!
16
//! let mut b = settings::builder();
17
//! b.set("opt_level", "speed_and_size");
18
//!
19
//! let f = settings::Flags::new(b);
20
//! assert_eq!(f.opt_level(), settings::OptLevel::SpeedAndSize);
21
//! ```
22
23
use crate::constant_hash::{probe, simple_hash};
24
use crate::isa::TargetIsa;
25
use alloc::boxed::Box;
26
use alloc::string::{String, ToString};
27
use core::fmt;
28
use core::str;
29
30
/// A string-based configurator for settings groups.
31
///
32
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
33
/// struct is created.
34
pub trait Configurable {
35
/// Set the string value of any setting by name.
36
///
37
/// This can set any type of setting whether it is numeric, boolean, or enumerated.
38
fn set(&mut self, name: &str, value: &str) -> SetResult<()>;
39
40
/// Enable a boolean setting or apply a preset.
41
///
42
/// If the identified setting isn't a boolean or a preset, a `BadType` error is returned.
43
fn enable(&mut self, name: &str) -> SetResult<()>;
44
}
45
46
/// Represents the kind of setting.
47
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48
pub enum SettingKind {
49
/// The setting is an enumeration.
50
Enum,
51
/// The setting is a number.
52
Num,
53
/// The setting is a boolean.
54
Bool,
55
/// The setting is a preset.
56
Preset,
57
}
58
59
/// Represents an available builder setting.
60
///
61
/// This is used for iterating settings in a builder.
62
#[derive(Clone, Copy, Debug)]
63
pub struct Setting {
64
/// The name of the setting.
65
pub name: &'static str,
66
/// The description of the setting.
67
pub description: &'static str,
68
/// The kind of the setting.
69
pub kind: SettingKind,
70
/// The supported values of the setting (for enum values).
71
pub values: Option<&'static [&'static str]>,
72
}
73
74
/// Represents a setting value.
75
///
76
/// This is used for iterating values in `Flags`.
77
pub struct Value {
78
/// The name of the setting associated with this value.
79
pub name: &'static str,
80
pub(crate) detail: detail::Detail,
81
pub(crate) values: Option<&'static [&'static str]>,
82
pub(crate) value: u8,
83
}
84
85
impl Value {
86
/// Gets the kind of setting.
87
pub fn kind(&self) -> SettingKind {
88
match &self.detail {
89
detail::Detail::Enum { .. } => SettingKind::Enum,
90
detail::Detail::Num => SettingKind::Num,
91
detail::Detail::Bool { .. } => SettingKind::Bool,
92
detail::Detail::Preset => unreachable!(),
93
}
94
}
95
96
/// Gets the enum value if the value is from an enum setting.
97
pub fn as_enum(&self) -> Option<&'static str> {
98
self.values.map(|v| v[self.value as usize])
99
}
100
101
/// Gets the numerical value if the value is from a num setting.
102
pub fn as_num(&self) -> Option<u8> {
103
match &self.detail {
104
detail::Detail::Num => Some(self.value),
105
_ => None,
106
}
107
}
108
109
/// Gets the boolean value if the value is from a boolean setting.
110
pub fn as_bool(&self) -> Option<bool> {
111
match &self.detail {
112
detail::Detail::Bool { bit } => Some(self.value & (1 << bit) != 0),
113
_ => None,
114
}
115
}
116
117
/// Builds a string from the current value
118
pub fn value_string(&self) -> String {
119
match self.kind() {
120
SettingKind::Enum => self.as_enum().map(|b| b.to_string()),
121
SettingKind::Num => self.as_num().map(|b| b.to_string()),
122
SettingKind::Bool => self.as_bool().map(|b| b.to_string()),
123
SettingKind::Preset => unreachable!(),
124
}
125
.unwrap()
126
}
127
}
128
129
impl fmt::Display for Value {
130
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131
if let Some(enum_variant) = self.as_enum() {
132
write!(f, "{}={}", self.name, enum_variant)
133
} else if let Some(num) = self.as_num() {
134
write!(f, "{}={}", self.name, num)
135
} else if let Some(b) = self.as_bool() {
136
if b {
137
write!(f, "{}=1", self.name)
138
} else {
139
write!(f, "{}=0", self.name)
140
}
141
} else {
142
unreachable!()
143
}
144
}
145
}
146
147
/// Collect settings values based on a template.
148
#[derive(Clone, Hash)]
149
pub struct Builder {
150
template: &'static detail::Template,
151
bytes: Box<[u8]>,
152
}
153
154
impl Builder {
155
/// Create a new builder with defaults and names from the given template.
156
pub fn new(tmpl: &'static detail::Template) -> Self {
157
Self {
158
template: tmpl,
159
bytes: tmpl.defaults.into(),
160
}
161
}
162
163
/// Extract contents of builder once everything is configured.
164
pub fn state_for(&self, name: &str) -> &[u8] {
165
assert_eq!(name, self.template.name);
166
&self.bytes
167
}
168
169
/// Iterates the available settings in the builder.
170
pub fn iter(&self) -> impl Iterator<Item = Setting> + use<> {
171
let template = self.template;
172
173
template.descriptors.iter().map(move |d| {
174
let (kind, values) = match d.detail {
175
detail::Detail::Enum { last, enumerators } => {
176
let values = template.enums(last, enumerators);
177
(SettingKind::Enum, Some(values))
178
}
179
detail::Detail::Num => (SettingKind::Num, None),
180
detail::Detail::Bool { .. } => (SettingKind::Bool, None),
181
detail::Detail::Preset => (SettingKind::Preset, None),
182
};
183
184
Setting {
185
name: d.name,
186
description: d.description,
187
kind,
188
values,
189
}
190
})
191
}
192
193
/// Set the value of a single bit.
194
fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
195
let byte = &mut self.bytes[offset];
196
let mask = 1 << bit;
197
if value {
198
*byte |= mask;
199
} else {
200
*byte &= !mask;
201
}
202
}
203
204
/// Apply a preset. The argument is a slice of (mask, value) bytes.
205
fn apply_preset(&mut self, values: &[(u8, u8)]) {
206
for (byte, &(mask, value)) in self.bytes.iter_mut().zip(values) {
207
*byte = (*byte & !mask) | value;
208
}
209
}
210
211
/// Look up a descriptor by name.
212
fn lookup(&self, name: &str) -> SetResult<(usize, detail::Detail)> {
213
match probe(self.template, name, simple_hash(name)) {
214
Err(_) => Err(SetError::BadName(name.to_string())),
215
Ok(entry) => {
216
let d = &self.template.descriptors[self.template.hash_table[entry] as usize];
217
Ok((d.offset as usize, d.detail))
218
}
219
}
220
}
221
}
222
223
fn parse_bool_value(value: &str) -> SetResult<bool> {
224
match value {
225
"true" | "on" | "yes" | "1" => Ok(true),
226
"false" | "off" | "no" | "0" => Ok(false),
227
_ => Err(SetError::BadValue("bool".to_string())),
228
}
229
}
230
231
fn parse_enum_value(value: &str, choices: &[&str]) -> SetResult<u8> {
232
match choices.iter().position(|&tag| tag == value) {
233
Some(idx) => Ok(idx as u8),
234
None => Err(SetError::BadValue(format!(
235
"any among {}",
236
choices.join(", ")
237
))),
238
}
239
}
240
241
impl Configurable for Builder {
242
fn enable(&mut self, name: &str) -> SetResult<()> {
243
use self::detail::Detail;
244
let (offset, detail) = self.lookup(name)?;
245
match detail {
246
Detail::Bool { bit } => {
247
self.set_bit(offset, bit, true);
248
Ok(())
249
}
250
Detail::Preset => {
251
self.apply_preset(&self.template.presets[offset..]);
252
Ok(())
253
}
254
_ => Err(SetError::BadType),
255
}
256
}
257
258
fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
259
use self::detail::Detail;
260
let (offset, detail) = self.lookup(name)?;
261
match detail {
262
Detail::Bool { bit } => {
263
self.set_bit(offset, bit, parse_bool_value(value)?);
264
}
265
Detail::Num => {
266
self.bytes[offset] = value
267
.parse()
268
.map_err(|_| SetError::BadValue("number".to_string()))?;
269
}
270
Detail::Enum { last, enumerators } => {
271
self.bytes[offset] =
272
parse_enum_value(value, self.template.enums(last, enumerators))?;
273
}
274
Detail::Preset => return Err(SetError::BadName(name.to_string())),
275
}
276
Ok(())
277
}
278
}
279
280
/// An error produced when changing a setting.
281
#[derive(Debug, PartialEq, Eq)]
282
pub enum SetError {
283
/// No setting by this name exists.
284
BadName(String),
285
286
/// Type mismatch for setting (e.g., setting an enum setting as a bool).
287
BadType,
288
289
/// This is not a valid value for this setting.
290
BadValue(String),
291
}
292
293
impl std::error::Error for SetError {}
294
295
impl fmt::Display for SetError {
296
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297
match self {
298
SetError::BadName(name) => write!(f, "No existing setting named '{name}'"),
299
SetError::BadType => {
300
write!(f, "Trying to set a setting with the wrong type")
301
}
302
SetError::BadValue(value) => {
303
write!(f, "Unexpected value for a setting, expected {value}")
304
}
305
}
306
}
307
}
308
309
/// A result returned when changing a setting.
310
pub type SetResult<T> = Result<T, SetError>;
311
312
/// Implementation details for generated code.
313
///
314
/// This module holds definitions that need to be public so the can be instantiated by generated
315
/// code in other modules.
316
pub mod detail {
317
use crate::constant_hash;
318
use core::fmt;
319
use core::hash::Hash;
320
321
/// An instruction group template.
322
#[derive(Hash)]
323
pub struct Template {
324
/// Name of the instruction group.
325
pub name: &'static str,
326
/// List of setting descriptors.
327
pub descriptors: &'static [Descriptor],
328
/// Union of all enumerators.
329
pub enumerators: &'static [&'static str],
330
/// Hash table of settings.
331
pub hash_table: &'static [u16],
332
/// Default values.
333
pub defaults: &'static [u8],
334
/// Pairs of (mask, value) for presets.
335
pub presets: &'static [(u8, u8)],
336
}
337
338
impl Template {
339
/// Get enumerators corresponding to a `Details::Enum`.
340
pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
341
let from = enumerators as usize;
342
let len = usize::from(last) + 1;
343
&self.enumerators[from..from + len]
344
}
345
346
/// Format a setting value as a TOML string. This is mostly for use by the generated
347
/// `Display` implementation.
348
pub fn format_toml_value(
349
&self,
350
detail: Detail,
351
byte: u8,
352
f: &mut fmt::Formatter,
353
) -> fmt::Result {
354
match detail {
355
Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
356
Detail::Num => write!(f, "{byte}"),
357
Detail::Enum { last, enumerators } => {
358
if byte <= last {
359
let tags = self.enums(last, enumerators);
360
write!(f, "\"{}\"", tags[usize::from(byte)])
361
} else {
362
write!(f, "{byte}")
363
}
364
}
365
// Presets aren't printed. They are reflected in the other settings.
366
Detail::Preset { .. } => Ok(()),
367
}
368
}
369
}
370
371
/// The template contains a hash table for by-name lookup.
372
impl<'a> constant_hash::Table<&'a str> for Template {
373
fn len(&self) -> usize {
374
self.hash_table.len()
375
}
376
377
fn key(&self, idx: usize) -> Option<&'a str> {
378
let e = self.hash_table[idx] as usize;
379
if e < self.descriptors.len() {
380
Some(self.descriptors[e].name)
381
} else {
382
None
383
}
384
}
385
}
386
387
/// A setting descriptor holds the information needed to generically set and print a setting.
388
///
389
/// Each settings group will be represented as a constant DESCRIPTORS array.
390
#[derive(Hash)]
391
pub struct Descriptor {
392
/// Lower snake-case name of setting as defined in meta.
393
pub name: &'static str,
394
395
/// The description of the setting.
396
pub description: &'static str,
397
398
/// Offset of byte containing this setting.
399
pub offset: u32,
400
401
/// Additional details, depending on the kind of setting.
402
pub detail: Detail,
403
}
404
405
/// The different kind of settings along with descriptor bits that depend on the kind.
406
#[derive(Clone, Copy, Hash)]
407
pub enum Detail {
408
/// A boolean setting only uses one bit, numbered from LSB.
409
Bool {
410
/// 0-7.
411
bit: u8,
412
},
413
414
/// A numerical setting uses the whole byte.
415
Num,
416
417
/// An Enum setting uses a range of enumerators.
418
Enum {
419
/// Numerical value of last enumerator, allowing for 1-256 enumerators.
420
last: u8,
421
422
/// First enumerator in the ENUMERATORS table.
423
enumerators: u16,
424
},
425
426
/// A preset is not an individual setting, it is a collection of settings applied at once.
427
///
428
/// The `Descriptor::offset` field refers to the `PRESETS` table.
429
Preset,
430
}
431
432
impl Detail {
433
/// Check if a detail is a Detail::Preset. Useful because the Descriptor
434
/// offset field has a different meaning when the detail is a preset.
435
pub fn is_preset(self) -> bool {
436
match self {
437
Self::Preset => true,
438
_ => false,
439
}
440
}
441
}
442
}
443
444
// Include code generated by `meta/gen_settings.rs`. This file contains a public `Flags` struct
445
// with an implementation for all of the settings defined in
446
// `cranelift-codegen/meta/src/shared/settings.rs`.
447
include!(concat!(env!("OUT_DIR"), "/settings.rs"));
448
449
/// Wrapper containing flags and optionally a `TargetIsa` trait object.
450
///
451
/// A few passes need to access the flags but only optionally a target ISA. The `FlagsOrIsa`
452
/// wrapper can be used to pass either, and extract the flags so they are always accessible.
453
#[derive(Clone, Copy)]
454
pub struct FlagsOrIsa<'a> {
455
/// Flags are always present.
456
pub flags: &'a Flags,
457
458
/// The ISA may not be present.
459
pub isa: Option<&'a dyn TargetIsa>,
460
}
461
462
impl<'a> From<&'a Flags> for FlagsOrIsa<'a> {
463
fn from(flags: &'a Flags) -> FlagsOrIsa<'a> {
464
FlagsOrIsa { flags, isa: None }
465
}
466
}
467
468
impl<'a> From<&'a dyn TargetIsa> for FlagsOrIsa<'a> {
469
fn from(isa: &'a dyn TargetIsa) -> FlagsOrIsa<'a> {
470
FlagsOrIsa {
471
flags: isa.flags(),
472
isa: Some(isa),
473
}
474
}
475
}
476
477
#[cfg(test)]
478
mod tests {
479
use super::Configurable;
480
use super::SetError::*;
481
use super::{Flags, builder};
482
use alloc::string::ToString;
483
484
#[test]
485
fn display_default() {
486
let b = builder();
487
let f = Flags::new(b);
488
let actual = f.to_string();
489
let expected = r#"[shared]
490
regalloc_algorithm = "backtracking"
491
opt_level = "none"
492
tls_model = "none"
493
stack_switch_model = "none"
494
libcall_call_conv = "isa_default"
495
probestack_size_log2 = 12
496
probestack_strategy = "outline"
497
bb_padding_log2_minus_one = 0
498
log2_min_function_alignment = 0
499
regalloc_checker = false
500
regalloc_verbose_logs = false
501
enable_alias_analysis = true
502
enable_verifier = true
503
enable_pcc = false
504
is_pic = false
505
use_colocated_libcalls = false
506
enable_float = true
507
enable_nan_canonicalization = false
508
enable_pinned_reg = false
509
enable_atomics = true
510
enable_safepoints = false
511
enable_llvm_abi_extensions = false
512
enable_multi_ret_implicit_sret = false
513
unwind_info = true
514
preserve_frame_pointers = false
515
machine_code_cfg_info = false
516
enable_probestack = false
517
enable_jump_tables = true
518
enable_heap_access_spectre_mitigation = true
519
enable_table_access_spectre_mitigation = true
520
enable_incremental_compilation_cache_checks = false
521
"#;
522
if actual != expected {
523
panic!(
524
"Default settings do not match expectations:\n\n{}",
525
similar::TextDiff::from_lines(expected, &actual)
526
.unified_diff()
527
.header("expected", "actual")
528
);
529
}
530
assert_eq!(f.opt_level(), super::OptLevel::None);
531
}
532
533
#[test]
534
fn modify_bool() {
535
let mut b = builder();
536
assert_eq!(b.enable("not_there"), Err(BadName("not_there".to_string())));
537
assert_eq!(b.enable("enable_atomics"), Ok(()));
538
assert_eq!(b.set("enable_atomics", "false"), Ok(()));
539
540
let f = Flags::new(b);
541
assert_eq!(f.enable_atomics(), false);
542
}
543
544
#[test]
545
fn modify_string() {
546
let mut b = builder();
547
assert_eq!(
548
b.set("not_there", "true"),
549
Err(BadName("not_there".to_string()))
550
);
551
assert_eq!(
552
b.set("enable_atomics", ""),
553
Err(BadValue("bool".to_string()))
554
);
555
assert_eq!(
556
b.set("enable_atomics", "best"),
557
Err(BadValue("bool".to_string()))
558
);
559
assert_eq!(
560
b.set("opt_level", "true"),
561
Err(BadValue(
562
"any among none, speed, speed_and_size".to_string()
563
))
564
);
565
assert_eq!(b.set("opt_level", "speed"), Ok(()));
566
assert_eq!(b.set("enable_atomics", "0"), Ok(()));
567
568
let f = Flags::new(b);
569
assert_eq!(f.enable_atomics(), false);
570
assert_eq!(f.opt_level(), super::OptLevel::Speed);
571
}
572
}
573
574