1use crate::constant_hash::{probe, simple_hash};
24use crate::isa::TargetIsa;
25use alloc::boxed::Box;
26use alloc::string::{String, ToString};
27use core::fmt;
28use core::str;
29
30pub trait Configurable {
35 fn set(&mut self, name: &str, value: &str) -> SetResult<()>;
39
40 fn enable(&mut self, name: &str) -> SetResult<()>;
44}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub enum SettingKind {
49 Enum,
51 Num,
53 Bool,
55 Preset,
57}
58
59#[derive(Clone, Copy, Debug)]
63pub struct Setting {
64 pub name: &'static str,
66 pub description: &'static str,
68 pub kind: SettingKind,
70 pub values: Option<&'static [&'static str]>,
72}
73
74pub struct Value {
78 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
85impl Value {
86 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 pub fn as_enum(&self) -> Option<&'static str> {
98 self.values.map(|v| v[self.value as usize])
99 }
100
101 pub fn as_num(&self) -> Option<u8> {
103 match &self.detail {
104 detail::Detail::Num => Some(self.value),
105 _ => None,
106 }
107 }
108
109 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 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
129impl 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#[derive(Clone, Hash)]
149pub struct Builder {
150 template: &'static detail::Template,
151 bytes: Box<[u8]>,
152}
153
154impl Builder {
155 pub fn new(tmpl: &'static detail::Template) -> Self {
157 Self {
158 template: tmpl,
159 bytes: tmpl.defaults.into(),
160 }
161 }
162
163 pub fn state_for(&self, name: &str) -> &[u8] {
165 assert_eq!(name, self.template.name);
166 &self.bytes
167 }
168
169 pub fn iter(&self) -> impl Iterator<Item = Setting> {
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 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 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 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
223fn 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
231fn 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 => {
235 let mut all_choices = String::new();
238 let mut first = true;
239 for choice in choices {
240 if first {
241 first = false
242 } else {
243 all_choices += ", ";
244 }
245 all_choices += choice;
246 }
247 Err(SetError::BadValue(format!("any among {}", all_choices)))
248 }
249 }
250}
251
252impl Configurable for Builder {
253 fn enable(&mut self, name: &str) -> SetResult<()> {
254 use self::detail::Detail;
255 let (offset, detail) = self.lookup(name)?;
256 match detail {
257 Detail::Bool { bit } => {
258 self.set_bit(offset, bit, true);
259 Ok(())
260 }
261 Detail::Preset => {
262 self.apply_preset(&self.template.presets[offset..]);
263 Ok(())
264 }
265 _ => Err(SetError::BadType),
266 }
267 }
268
269 fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
270 use self::detail::Detail;
271 let (offset, detail) = self.lookup(name)?;
272 match detail {
273 Detail::Bool { bit } => {
274 self.set_bit(offset, bit, parse_bool_value(value)?);
275 }
276 Detail::Num => {
277 self.bytes[offset] = value
278 .parse()
279 .map_err(|_| SetError::BadValue("number".to_string()))?;
280 }
281 Detail::Enum { last, enumerators } => {
282 self.bytes[offset] =
283 parse_enum_value(value, self.template.enums(last, enumerators))?;
284 }
285 Detail::Preset => return Err(SetError::BadName(name.to_string())),
286 }
287 Ok(())
288 }
289}
290
291#[derive(Debug, PartialEq, Eq)]
293pub enum SetError {
294 BadName(String),
296
297 BadType,
299
300 BadValue(String),
302}
303
304impl std::error::Error for SetError {}
305
306impl fmt::Display for SetError {
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 match self {
309 SetError::BadName(name) => write!(f, "No existing setting named '{}'", name),
310 SetError::BadType => {
311 write!(f, "Trying to set a setting with the wrong type")
312 }
313 SetError::BadValue(value) => {
314 write!(f, "Unexpected value for a setting, expected {}", value)
315 }
316 }
317 }
318}
319
320pub type SetResult<T> = Result<T, SetError>;
322
323#[derive(Clone, Copy, Hash)]
329pub struct PredicateView<'a>(&'a [u8]);
330
331impl<'a> PredicateView<'a> {
332 pub fn new(bits: &'a [u8]) -> Self {
336 PredicateView(bits)
337 }
338
339 pub fn test(self, p: usize) -> bool {
341 self.0[p / 8] & (1 << (p % 8)) != 0
342 }
343}
344
345pub mod detail {
350 use crate::constant_hash;
351 use core::fmt;
352 use core::hash::Hash;
353
354 #[derive(Hash)]
356 pub struct Template {
357 pub name: &'static str,
359 pub descriptors: &'static [Descriptor],
361 pub enumerators: &'static [&'static str],
363 pub hash_table: &'static [u16],
365 pub defaults: &'static [u8],
367 pub presets: &'static [(u8, u8)],
369 }
370
371 impl Template {
372 pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
374 let from = enumerators as usize;
375 let len = usize::from(last) + 1;
376 &self.enumerators[from..from + len]
377 }
378
379 pub fn format_toml_value(
382 &self,
383 detail: Detail,
384 byte: u8,
385 f: &mut fmt::Formatter,
386 ) -> fmt::Result {
387 match detail {
388 Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
389 Detail::Num => write!(f, "{}", byte),
390 Detail::Enum { last, enumerators } => {
391 if byte <= last {
392 let tags = self.enums(last, enumerators);
393 write!(f, "\"{}\"", tags[usize::from(byte)])
394 } else {
395 write!(f, "{}", byte)
396 }
397 }
398 Detail::Preset { .. } => Ok(()),
400 }
401 }
402 }
403
404 impl<'a> constant_hash::Table<&'a str> for Template {
406 fn len(&self) -> usize {
407 self.hash_table.len()
408 }
409
410 fn key(&self, idx: usize) -> Option<&'a str> {
411 let e = self.hash_table[idx] as usize;
412 if e < self.descriptors.len() {
413 Some(self.descriptors[e].name)
414 } else {
415 None
416 }
417 }
418 }
419
420 #[derive(Hash)]
424 pub struct Descriptor {
425 pub name: &'static str,
427
428 pub description: &'static str,
430
431 pub offset: u32,
433
434 pub detail: Detail,
436 }
437
438 #[derive(Clone, Copy, Hash)]
440 pub enum Detail {
441 Bool {
443 bit: u8,
445 },
446
447 Num,
449
450 Enum {
452 last: u8,
454
455 enumerators: u16,
457 },
458
459 Preset,
463 }
464
465 impl Detail {
466 pub fn is_preset(self) -> bool {
469 match self {
470 Self::Preset => true,
471 _ => false,
472 }
473 }
474 }
475}
476
477include!(concat!(env!("OUT_DIR"), "/settings.rs"));
481
482#[derive(Clone, Copy)]
487pub struct FlagsOrIsa<'a> {
488 pub flags: &'a Flags,
490
491 pub isa: Option<&'a dyn TargetIsa>,
493}
494
495impl<'a> From<&'a Flags> for FlagsOrIsa<'a> {
496 fn from(flags: &'a Flags) -> FlagsOrIsa {
497 FlagsOrIsa { flags, isa: None }
498 }
499}
500
501impl<'a> From<&'a dyn TargetIsa> for FlagsOrIsa<'a> {
502 fn from(isa: &'a dyn TargetIsa) -> FlagsOrIsa {
503 FlagsOrIsa {
504 flags: isa.flags(),
505 isa: Some(isa),
506 }
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use super::Configurable;
513 use super::SetError::*;
514 use super::{builder, Flags};
515 use alloc::string::ToString;
516
517 #[test]
518 fn display_default() {
519 let b = builder();
520 let f = Flags::new(b);
521 let actual = f.to_string();
522 let expected = r#"[shared]
523opt_level = "none"
524tls_model = "none"
525libcall_call_conv = "isa_default"
526probestack_size_log2 = 12
527probestack_strategy = "outline"
528regalloc_checker = false
529regalloc_verbose_logs = false
530enable_alias_analysis = true
531use_egraphs = true
532enable_verifier = true
533is_pic = false
534use_colocated_libcalls = false
535enable_float = true
536enable_nan_canonicalization = false
537enable_pinned_reg = false
538enable_simd = false
539enable_atomics = true
540enable_safepoints = false
541enable_llvm_abi_extensions = false
542unwind_info = true
543preserve_frame_pointers = false
544machine_code_cfg_info = false
545enable_probestack = false
546probestack_func_adjusts_sp = false
547enable_jump_tables = true
548enable_heap_access_spectre_mitigation = true
549enable_table_access_spectre_mitigation = true
550enable_incremental_compilation_cache_checks = false
551"#;
552 if actual != expected {
553 panic!(
554 "Default settings do not match expectations:\n\n{}",
555 similar::TextDiff::from_lines(expected, &actual)
556 .unified_diff()
557 .header("expected", "actual")
558 );
559 }
560 assert_eq!(f.opt_level(), super::OptLevel::None);
561 assert_eq!(f.enable_simd(), false);
562 }
563
564 #[test]
565 fn modify_bool() {
566 let mut b = builder();
567 assert_eq!(b.enable("not_there"), Err(BadName("not_there".to_string())));
568 assert_eq!(b.enable("enable_simd"), Ok(()));
569 assert_eq!(b.set("enable_simd", "false"), Ok(()));
570
571 let f = Flags::new(b);
572 assert_eq!(f.enable_simd(), false);
573 }
574
575 #[test]
576 fn modify_string() {
577 let mut b = builder();
578 assert_eq!(
579 b.set("not_there", "true"),
580 Err(BadName("not_there".to_string()))
581 );
582 assert_eq!(b.set("enable_simd", ""), Err(BadValue("bool".to_string())));
583 assert_eq!(
584 b.set("enable_simd", "best"),
585 Err(BadValue("bool".to_string()))
586 );
587 assert_eq!(
588 b.set("opt_level", "true"),
589 Err(BadValue(
590 "any among none, speed, speed_and_size".to_string()
591 ))
592 );
593 assert_eq!(b.set("opt_level", "speed"), Ok(()));
594 assert_eq!(b.set("enable_simd", "0"), Ok(()));
595
596 let f = Flags::new(b);
597 assert_eq!(f.enable_simd(), false);
598 assert_eq!(f.opt_level(), super::OptLevel::Speed);
599 }
600}