Add support for setting presets.
Fixes #11. Presets are groups of settings and values applied at once. This is used as a shorthand in test files, so for example "isa intel nehalem" enables all of the CPUID bits that the Nehalem micro-architecture provides.
This commit is contained in:
@@ -4,7 +4,8 @@ from collections import OrderedDict
|
|||||||
from .predicates import Predicate
|
from .predicates import Predicate
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Set, List, Dict, Any, TYPE_CHECKING # noqa
|
from typing import Tuple, Set, List, Dict, Any, Union, TYPE_CHECKING # noqa
|
||||||
|
BoolOrPresetOrDict = Union['BoolSetting', 'Preset', Dict['Setting', Any]]
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .predicates import PredLeaf, PredNode # noqa
|
from .predicates import PredLeaf, PredNode # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -47,6 +48,17 @@ class Setting(object):
|
|||||||
# type: () -> int
|
# type: () -> int
|
||||||
raise NotImplementedError("default_byte is an abstract method")
|
raise NotImplementedError("default_byte is an abstract method")
|
||||||
|
|
||||||
|
def byte_for_value(self, value):
|
||||||
|
# type: (Any) -> int
|
||||||
|
"""Get the setting byte value that corresponds to `value`"""
|
||||||
|
raise NotImplementedError("byte_for_value is an abstract method")
|
||||||
|
|
||||||
|
def byte_mask(self):
|
||||||
|
# type: () -> int
|
||||||
|
"""Get a mask of bits in our byte that are relevant to this setting."""
|
||||||
|
# Only BoolSetting has a different mask.
|
||||||
|
return 0xff
|
||||||
|
|
||||||
|
|
||||||
class BoolSetting(Setting):
|
class BoolSetting(Setting):
|
||||||
"""
|
"""
|
||||||
@@ -73,6 +85,17 @@ class BoolSetting(Setting):
|
|||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def byte_for_value(self, value):
|
||||||
|
# type: (Any) -> int
|
||||||
|
if value:
|
||||||
|
return 1 << self.bit_offset
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def byte_mask(self):
|
||||||
|
# type: () -> int
|
||||||
|
return 1 << self.bit_offset
|
||||||
|
|
||||||
def predicate_leafs(self, leafs):
|
def predicate_leafs(self, leafs):
|
||||||
# type: (Set[PredLeaf]) -> None
|
# type: (Set[PredLeaf]) -> None
|
||||||
leafs.add(self)
|
leafs.add(self)
|
||||||
@@ -107,6 +130,12 @@ class NumSetting(Setting):
|
|||||||
# type: () -> int
|
# type: () -> int
|
||||||
return self.default
|
return self.default
|
||||||
|
|
||||||
|
def byte_for_value(self, value):
|
||||||
|
# type: (Any) -> int
|
||||||
|
assert isinstance(value, int), "NumSetting must be set to an int"
|
||||||
|
assert value >= 0 and value <= 255
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class EnumSetting(Setting):
|
class EnumSetting(Setting):
|
||||||
"""
|
"""
|
||||||
@@ -129,6 +158,10 @@ class EnumSetting(Setting):
|
|||||||
# type: () -> int
|
# type: () -> int
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def byte_for_value(self, value):
|
||||||
|
# type: (Any) -> int
|
||||||
|
return self.values.index(value)
|
||||||
|
|
||||||
|
|
||||||
class SettingGroup(object):
|
class SettingGroup(object):
|
||||||
"""
|
"""
|
||||||
@@ -160,6 +193,7 @@ class SettingGroup(object):
|
|||||||
# - Added parent predicates that are replicated in this group.
|
# - Added parent predicates that are replicated in this group.
|
||||||
# Maps predicate -> number.
|
# Maps predicate -> number.
|
||||||
self.predicate_number = OrderedDict() # type: OrderedDict[PredNode, int] # noqa
|
self.predicate_number = OrderedDict() # type: OrderedDict[PredNode, int] # noqa
|
||||||
|
self.presets = [] # type: List[Preset]
|
||||||
|
|
||||||
# Fully qualified Rust module name. See gen_settings.py.
|
# Fully qualified Rust module name. See gen_settings.py.
|
||||||
self.qual_mod = None # type: str
|
self.qual_mod = None # type: str
|
||||||
@@ -199,6 +233,10 @@ class SettingGroup(object):
|
|||||||
assert obj.name is None
|
assert obj.name is None
|
||||||
obj.name = name
|
obj.name = name
|
||||||
self.named_predicates.append(obj)
|
self.named_predicates.append(obj)
|
||||||
|
if isinstance(obj, Preset):
|
||||||
|
assert obj.name is None, obj.name
|
||||||
|
obj.name = name
|
||||||
|
|
||||||
self.layout()
|
self.layout()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -209,6 +247,14 @@ class SettingGroup(object):
|
|||||||
g.settings.append(setting)
|
g.settings.append(setting)
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def append_preset(preset):
|
||||||
|
# type: (Preset) -> SettingGroup
|
||||||
|
g = SettingGroup._current
|
||||||
|
assert g, "Open a setting group before defining presets."
|
||||||
|
g.presets.append(preset)
|
||||||
|
return g
|
||||||
|
|
||||||
def number_predicate(self, pred):
|
def number_predicate(self, pred):
|
||||||
# type: (PredNode) -> int
|
# type: (PredNode) -> int
|
||||||
"""
|
"""
|
||||||
@@ -295,3 +341,65 @@ class SettingGroup(object):
|
|||||||
predcate bits rounded up to a whole number of bytes.
|
predcate bits rounded up to a whole number of bytes.
|
||||||
"""
|
"""
|
||||||
return self.boolean_offset + (len(self.predicate_number) + 7) // 8
|
return self.boolean_offset + (len(self.predicate_number) + 7) // 8
|
||||||
|
|
||||||
|
|
||||||
|
class Preset(object):
|
||||||
|
"""
|
||||||
|
A collection of setting values that are applied at once.
|
||||||
|
|
||||||
|
A `Preset` represents a shorthand notation for applying a number of
|
||||||
|
settings at once. Example:
|
||||||
|
|
||||||
|
nehalem = Preset(has_sse41, has_cmov, has_avx=0)
|
||||||
|
|
||||||
|
Enabling the `nehalem` setting is equivalent to enabling `has_sse41` and
|
||||||
|
`has_cmov` while disabling the `has_avx` setting.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
# type: (*BoolOrPresetOrDict) -> None
|
||||||
|
self.name = None # type: str # Assigned later by `SettingGroup`.
|
||||||
|
# Each tuple provides the value for a setting.
|
||||||
|
self.values = list() # type: List[Tuple[Setting, Any]]
|
||||||
|
|
||||||
|
for arg in args:
|
||||||
|
if isinstance(arg, Preset):
|
||||||
|
# Any presets in args are immediately expanded.
|
||||||
|
self.values.extend(arg.values)
|
||||||
|
elif isinstance(arg, dict):
|
||||||
|
# A dictionary of key: value pairs.
|
||||||
|
self.values.extend(arg.items())
|
||||||
|
else:
|
||||||
|
# A BoolSetting to enable.
|
||||||
|
assert isinstance(arg, BoolSetting)
|
||||||
|
self.values.append((arg, True))
|
||||||
|
|
||||||
|
self.group = SettingGroup.append_preset(self)
|
||||||
|
# Index into the generated DESCRIPTORS table.
|
||||||
|
self.descriptor_index = None # type: int
|
||||||
|
|
||||||
|
def layout(self):
|
||||||
|
# type: () -> List[Tuple[int, int]]
|
||||||
|
"""
|
||||||
|
Compute a list of (mask, byte) pairs that incorporate all values in
|
||||||
|
this preset.
|
||||||
|
|
||||||
|
The list will have an entry for each setting byte in the settings
|
||||||
|
group.
|
||||||
|
"""
|
||||||
|
l = [(0, 0)] * self.group.settings_size
|
||||||
|
|
||||||
|
# Apply setting values in order.
|
||||||
|
for s, v in self.values:
|
||||||
|
ofs = s.byte_offset
|
||||||
|
s_mask = s.byte_mask()
|
||||||
|
s_val = s.byte_for_value(v)
|
||||||
|
assert (s_val & ~s_mask) == 0
|
||||||
|
l_mask, l_val = l[ofs]
|
||||||
|
# Accumulated mask of modified bits.
|
||||||
|
l_mask |= s_mask
|
||||||
|
# Overwrite the relevant bits with the new value.
|
||||||
|
l_val = (l_val & ~s_mask) | s_val
|
||||||
|
l[ofs] = (l_mask, l_val)
|
||||||
|
|
||||||
|
return l
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ from cdsl.settings import BoolSetting, NumSetting, EnumSetting
|
|||||||
from base import settings
|
from base import settings
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Sequence, Set, Tuple, List, TYPE_CHECKING # noqa
|
from typing import Sequence, Set, Tuple, List, Union, TYPE_CHECKING # noqa
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from cdsl.isa import TargetISA # noqa
|
from cdsl.isa import TargetISA # noqa
|
||||||
from cdsl.settings import Setting, SettingGroup # noqa
|
from cdsl.settings import Setting, Preset, SettingGroup # noqa
|
||||||
from cdsl.predicates import Predicate, PredContext # noqa
|
from cdsl.predicates import Predicate, PredContext # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
@@ -106,14 +106,14 @@ def gen_getters(sgrp, fmt):
|
|||||||
def gen_descriptors(sgrp, fmt):
|
def gen_descriptors(sgrp, fmt):
|
||||||
# type: (SettingGroup, srcgen.Formatter) -> None
|
# type: (SettingGroup, srcgen.Formatter) -> None
|
||||||
"""
|
"""
|
||||||
Generate the DESCRIPTORS and ENUMERATORS tables.
|
Generate the DESCRIPTORS, ENUMERATORS, and PRESETS tables.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
enums = UniqueSeqTable()
|
enums = UniqueSeqTable()
|
||||||
|
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'static DESCRIPTORS: [detail::Descriptor; {}] = ['
|
'static DESCRIPTORS: [detail::Descriptor; {}] = ['
|
||||||
.format(len(sgrp.settings)),
|
.format(len(sgrp.settings) + len(sgrp.presets)),
|
||||||
'];'):
|
'];'):
|
||||||
for idx, setting in enumerate(sgrp.settings):
|
for idx, setting in enumerate(sgrp.settings):
|
||||||
setting.descriptor_index = idx
|
setting.descriptor_index = idx
|
||||||
@@ -135,6 +135,13 @@ def gen_descriptors(sgrp, fmt):
|
|||||||
else:
|
else:
|
||||||
raise AssertionError("Unknown setting kind")
|
raise AssertionError("Unknown setting kind")
|
||||||
|
|
||||||
|
for idx, preset in enumerate(sgrp.presets):
|
||||||
|
preset.descriptor_index = len(sgrp.settings) + idx
|
||||||
|
with fmt.indented('detail::Descriptor {', '},'):
|
||||||
|
fmt.line('name: "{}",'.format(preset.name))
|
||||||
|
fmt.line('offset: {},'.format(idx * sgrp.settings_size))
|
||||||
|
fmt.line('detail: detail::Detail::Preset,')
|
||||||
|
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'static ENUMERATORS: [&str; {}] = ['
|
'static ENUMERATORS: [&str; {}] = ['
|
||||||
.format(len(enums.table)),
|
.format(len(enums.table)),
|
||||||
@@ -143,10 +150,13 @@ def gen_descriptors(sgrp, fmt):
|
|||||||
fmt.line('"{}",'.format(txt))
|
fmt.line('"{}",'.format(txt))
|
||||||
|
|
||||||
def hash_setting(s):
|
def hash_setting(s):
|
||||||
# type: (Setting) -> int
|
# type: (Union[Setting, Preset]) -> int
|
||||||
return constant_hash.simple_hash(s.name)
|
return constant_hash.simple_hash(s.name)
|
||||||
|
|
||||||
hash_table = constant_hash.compute_quadratic(sgrp.settings, hash_setting)
|
hash_elems = [] # type: List[Union[Setting, Preset]]
|
||||||
|
hash_elems.extend(sgrp.settings)
|
||||||
|
hash_elems.extend(sgrp.presets)
|
||||||
|
hash_table = constant_hash.compute_quadratic(hash_elems, hash_setting)
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'static HASH_TABLE: [u16; {}] = ['
|
'static HASH_TABLE: [u16; {}] = ['
|
||||||
.format(len(hash_table)),
|
.format(len(hash_table)),
|
||||||
@@ -157,6 +167,15 @@ def gen_descriptors(sgrp, fmt):
|
|||||||
else:
|
else:
|
||||||
fmt.line('{},'.format(h.descriptor_index))
|
fmt.line('{},'.format(h.descriptor_index))
|
||||||
|
|
||||||
|
with fmt.indented(
|
||||||
|
'static PRESETS: [(u8, u8); {}] = ['
|
||||||
|
.format(len(sgrp.presets) * sgrp.settings_size),
|
||||||
|
'];'):
|
||||||
|
for preset in sgrp.presets:
|
||||||
|
fmt.comment(preset.name)
|
||||||
|
for mask, value in preset.layout():
|
||||||
|
fmt.format('(0b{:08b}, 0b{:08b}),', mask, value)
|
||||||
|
|
||||||
|
|
||||||
def gen_template(sgrp, fmt):
|
def gen_template(sgrp, fmt):
|
||||||
# type: (SettingGroup, srcgen.Formatter) -> None
|
# type: (SettingGroup, srcgen.Formatter) -> None
|
||||||
@@ -175,6 +194,7 @@ def gen_template(sgrp, fmt):
|
|||||||
fmt.line('hash_table: &HASH_TABLE,')
|
fmt.line('hash_table: &HASH_TABLE,')
|
||||||
vs = ', '.join('{:#04x}'.format(x) for x in v)
|
vs = ', '.join('{:#04x}'.format(x) for x in v)
|
||||||
fmt.line('defaults: &[ {} ],'.format(vs))
|
fmt.line('defaults: &[ {} ],'.format(vs))
|
||||||
|
fmt.line('presets: &PRESETS,')
|
||||||
|
|
||||||
fmt.doc_comment(
|
fmt.doc_comment(
|
||||||
'Create a `settings::Builder` for the {} settings group.'
|
'Create a `settings::Builder` for the {} settings group.'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Intel settings.
|
Intel settings.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cdsl.settings import SettingGroup, BoolSetting
|
from cdsl.settings import SettingGroup, BoolSetting, Preset
|
||||||
from cdsl.predicates import And
|
from cdsl.predicates import And
|
||||||
import base.settings as shared
|
import base.settings as shared
|
||||||
from .defs import ISA
|
from .defs import ISA
|
||||||
@@ -38,4 +38,10 @@ use_popcnt = And(has_popcnt, has_sse42)
|
|||||||
use_bmi1 = And(has_bmi1)
|
use_bmi1 = And(has_bmi1)
|
||||||
use_lzcnt = And(has_lzcnt)
|
use_lzcnt = And(has_lzcnt)
|
||||||
|
|
||||||
|
# Presets corresponding to Intel CPUs.
|
||||||
|
|
||||||
|
nehalem = Preset(
|
||||||
|
has_sse2, has_sse3, has_ssse3, has_sse41, has_sse42, has_popcnt)
|
||||||
|
haswell = Preset(nehalem, has_bmi1, has_lzcnt)
|
||||||
|
|
||||||
ISA.settings.close(globals())
|
ISA.settings.close(globals())
|
||||||
|
|||||||
@@ -7,3 +7,27 @@ use std::fmt;
|
|||||||
// `Flags` struct with an impl for all of the settings defined in
|
// `Flags` struct with an impl for all of the settings defined in
|
||||||
// `lib/cretonne/meta/cretonne/settings.py`.
|
// `lib/cretonne/meta/cretonne/settings.py`.
|
||||||
include!(concat!(env!("OUT_DIR"), "/settings-intel.rs"));
|
include!(concat!(env!("OUT_DIR"), "/settings-intel.rs"));
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{builder, Flags};
|
||||||
|
use settings::{self, Configurable};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn presets() {
|
||||||
|
let shared = settings::Flags::new(&settings::builder());
|
||||||
|
|
||||||
|
// Nehalem has SSE4.1 but not BMI1.
|
||||||
|
let mut b1 = builder();
|
||||||
|
b1.enable("nehalem").unwrap();
|
||||||
|
let f1 = Flags::new(&shared, &b1);
|
||||||
|
assert_eq!(f1.has_sse41(), true);
|
||||||
|
assert_eq!(f1.has_bmi1(), false);
|
||||||
|
|
||||||
|
let mut b2 = builder();
|
||||||
|
b2.enable("haswell").unwrap();
|
||||||
|
let f2 = Flags::new(&shared, &b2);
|
||||||
|
assert_eq!(f2.has_sse41(), true);
|
||||||
|
assert_eq!(f2.has_bmi1(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ impl settings::Configurable for Builder {
|
|||||||
self.setup.set(name, value)
|
self.setup.set(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_bool(&mut self, name: &str, value: bool) -> settings::Result<()> {
|
fn enable(&mut self, name: &str) -> settings::Result<()> {
|
||||||
self.setup.set_bool(name, value)
|
self.setup.enable(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_64bitenc() {
|
fn test_64bitenc() {
|
||||||
let mut shared_builder = settings::builder();
|
let mut shared_builder = settings::builder();
|
||||||
shared_builder.set_bool("is_64bit", true).unwrap();
|
shared_builder.enable("is_64bit").unwrap();
|
||||||
let shared_flags = settings::Flags::new(&shared_builder);
|
let shared_flags = settings::Flags::new(&shared_builder);
|
||||||
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
|
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_32bitenc() {
|
fn test_32bitenc() {
|
||||||
let mut shared_builder = settings::builder();
|
let mut shared_builder = settings::builder();
|
||||||
shared_builder.set_bool("is_64bit", false).unwrap();
|
shared_builder.set("is_64bit", "false").unwrap();
|
||||||
let shared_flags = settings::Flags::new(&shared_builder);
|
let shared_flags = settings::Flags::new(&shared_builder);
|
||||||
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
|
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
|
||||||
|
|
||||||
@@ -216,13 +216,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_rv32m() {
|
fn test_rv32m() {
|
||||||
let mut shared_builder = settings::builder();
|
let mut shared_builder = settings::builder();
|
||||||
shared_builder.set_bool("is_64bit", false).unwrap();
|
shared_builder.set("is_64bit", "false").unwrap();
|
||||||
let shared_flags = settings::Flags::new(&shared_builder);
|
let shared_flags = settings::Flags::new(&shared_builder);
|
||||||
|
|
||||||
// Set the supports_m stting which in turn enables the use_m predicate that unlocks
|
// Set the supports_m stting which in turn enables the use_m predicate that unlocks
|
||||||
// encodings for imul.
|
// encodings for imul.
|
||||||
let mut isa_builder = isa::lookup("riscv").unwrap();
|
let mut isa_builder = isa::lookup("riscv").unwrap();
|
||||||
isa_builder.set_bool("supports_m", true).unwrap();
|
isa_builder.enable("supports_m").unwrap();
|
||||||
|
|
||||||
let isa = isa_builder.finish(shared_flags);
|
let isa = isa_builder.finish(shared_flags);
|
||||||
|
|
||||||
|
|||||||
@@ -34,17 +34,17 @@ mod tests {
|
|||||||
fn predicates() {
|
fn predicates() {
|
||||||
let shared = settings::Flags::new(&settings::builder());
|
let shared = settings::Flags::new(&settings::builder());
|
||||||
let mut b = builder();
|
let mut b = builder();
|
||||||
b.set_bool("supports_f", true).unwrap();
|
b.enable("supports_f").unwrap();
|
||||||
b.set_bool("supports_d", true).unwrap();
|
b.enable("supports_d").unwrap();
|
||||||
let f = Flags::new(&shared, &b);
|
let f = Flags::new(&shared, &b);
|
||||||
assert_eq!(f.full_float(), true);
|
assert_eq!(f.full_float(), true);
|
||||||
|
|
||||||
let mut sb = settings::builder();
|
let mut sb = settings::builder();
|
||||||
sb.set_bool("enable_simd", false).unwrap();
|
sb.set("enable_simd", "false").unwrap();
|
||||||
let shared = settings::Flags::new(&sb);
|
let shared = settings::Flags::new(&sb);
|
||||||
let mut b = builder();
|
let mut b = builder();
|
||||||
b.set_bool("supports_f", true).unwrap();
|
b.enable("supports_f").unwrap();
|
||||||
b.set_bool("supports_d", true).unwrap();
|
b.enable("supports_d").unwrap();
|
||||||
let f = Flags::new(&shared, &b);
|
let f = Flags::new(&shared, &b);
|
||||||
assert_eq!(f.full_float(), false);
|
assert_eq!(f.full_float(), false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ pub trait Configurable {
|
|||||||
/// This can set any type of setting whether it is numeric, boolean, or enumerated.
|
/// This can set any type of setting whether it is numeric, boolean, or enumerated.
|
||||||
fn set(&mut self, name: &str, value: &str) -> Result<()>;
|
fn set(&mut self, name: &str, value: &str) -> Result<()>;
|
||||||
|
|
||||||
/// Set the value of a boolean setting by name.
|
/// Enable a boolean setting or apply a preset.
|
||||||
///
|
///
|
||||||
/// If the identified setting isn't a boolean, a `BadType` error is returned.
|
/// If the identified setting isn't a boolean or a preset, a `BadType` error is returned.
|
||||||
fn set_bool(&mut self, name: &str, value: bool) -> Result<()>;
|
fn enable(&mut self, name: &str) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect settings values based on a template.
|
/// Collect settings values based on a template.
|
||||||
@@ -73,6 +73,13 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply a preset. The argument is a slice of (mask, value) bytes.
|
||||||
|
fn apply_preset(&mut self, values: &[(u8, u8)]) {
|
||||||
|
for (byte, &(mask, value)) in self.bytes.iter_mut().zip(values) {
|
||||||
|
*byte = (*byte & !mask) | value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Look up a descriptor by name.
|
/// Look up a descriptor by name.
|
||||||
fn lookup(&self, name: &str) -> Result<(usize, detail::Detail)> {
|
fn lookup(&self, name: &str) -> Result<(usize, detail::Detail)> {
|
||||||
match probe(self.template, name, simple_hash(name)) {
|
match probe(self.template, name, simple_hash(name)) {
|
||||||
@@ -101,14 +108,19 @@ fn parse_enum_value(value: &str, choices: &[&str]) -> Result<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Configurable for Builder {
|
impl Configurable for Builder {
|
||||||
fn set_bool(&mut self, name: &str, value: bool) -> Result<()> {
|
fn enable(&mut self, name: &str) -> Result<()> {
|
||||||
use self::detail::Detail;
|
use self::detail::Detail;
|
||||||
let (offset, detail) = self.lookup(name)?;
|
let (offset, detail) = self.lookup(name)?;
|
||||||
if let Detail::Bool { bit } = detail {
|
match detail {
|
||||||
self.set_bit(offset, bit, value);
|
Detail::Bool { bit } => {
|
||||||
|
self.set_bit(offset, bit, true);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
}
|
||||||
Err(Error::BadType)
|
Detail::Preset => {
|
||||||
|
self.apply_preset(&self.template.presets[offset..]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::BadType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +140,7 @@ impl Configurable for Builder {
|
|||||||
self.bytes[offset] = parse_enum_value(value,
|
self.bytes[offset] = parse_enum_value(value,
|
||||||
self.template.enums(last, enumerators))?;
|
self.template.enums(last, enumerators))?;
|
||||||
}
|
}
|
||||||
|
Detail::Preset => return Err(Error::BadName),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -169,6 +182,8 @@ pub mod detail {
|
|||||||
pub hash_table: &'static [u16],
|
pub hash_table: &'static [u16],
|
||||||
/// Default values.
|
/// Default values.
|
||||||
pub defaults: &'static [u8],
|
pub defaults: &'static [u8],
|
||||||
|
/// Pairs of (mask, value) for presets.
|
||||||
|
pub presets: &'static [(u8, u8)],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Template {
|
impl Template {
|
||||||
@@ -197,6 +212,8 @@ pub mod detail {
|
|||||||
write!(f, "{}", byte)
|
write!(f, "{}", byte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Presets aren't printed. They are reflected in the other settings.
|
||||||
|
Detail::Preset { .. } => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,6 +268,11 @@ pub mod detail {
|
|||||||
/// First enumerator in the ENUMERATORS table.
|
/// First enumerator in the ENUMERATORS table.
|
||||||
enumerators: u16,
|
enumerators: u16,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// A preset is not an individual setting, it is a collection of settings applied at once.
|
||||||
|
///
|
||||||
|
/// The `Descriptor::offset` field refers to the `PRESETS` table.
|
||||||
|
Preset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,9 +306,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn modify_bool() {
|
fn modify_bool() {
|
||||||
let mut b = builder();
|
let mut b = builder();
|
||||||
assert_eq!(b.set_bool("not_there", true), Err(BadName));
|
assert_eq!(b.enable("not_there"), Err(BadName));
|
||||||
assert_eq!(b.set_bool("enable_simd", true), Ok(()));
|
assert_eq!(b.enable("enable_simd"), Ok(()));
|
||||||
assert_eq!(b.set_bool("enable_simd", false), Ok(()));
|
assert_eq!(b.set("enable_simd", "false"), Ok(()));
|
||||||
|
|
||||||
let f = Flags::new(&b);
|
let f = Flags::new(&b);
|
||||||
assert_eq!(f.enable_simd(), false);
|
assert_eq!(f.enable_simd(), false);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ pub fn parse_options<'a, I>(iter: I, config: &mut Configurable, loc: &Location)
|
|||||||
for opt in iter.map(TestOption::new) {
|
for opt in iter.map(TestOption::new) {
|
||||||
match opt {
|
match opt {
|
||||||
TestOption::Flag(name) => {
|
TestOption::Flag(name) => {
|
||||||
match config.set_bool(name, true) {
|
match config.enable(name) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(SetError::BadName) => return err!(loc, "unknown flag '{}'", opt),
|
Err(SetError::BadName) => return err!(loc, "unknown flag '{}'", opt),
|
||||||
Err(_) => return err!(loc, "not a boolean flag: '{}'", opt),
|
Err(_) => return err!(loc, "not a boolean flag: '{}'", opt),
|
||||||
|
|||||||
@@ -609,7 +609,7 @@ impl<'a> Parser<'a> {
|
|||||||
// would slow down normal compilation, but when we're reading IL from a text file we're
|
// would slow down normal compilation, but when we're reading IL from a text file we're
|
||||||
// either testing or debugging Cretonne, and verification makes sense.
|
// either testing or debugging Cretonne, and verification makes sense.
|
||||||
flag_builder
|
flag_builder
|
||||||
.set_bool("enable_verifier", true)
|
.enable("enable_verifier")
|
||||||
.expect("Missing enable_verifier setting");
|
.expect("Missing enable_verifier setting");
|
||||||
|
|
||||||
while let Some(Token::Identifier(command)) = self.token() {
|
while let Some(Token::Identifier(command)) = self.token() {
|
||||||
|
|||||||
Reference in New Issue
Block a user