moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
This commit is contained in:
192
cranelift/codegen/meta/src/cdsl/isa.rs
Normal file
192
cranelift/codegen/meta/src/cdsl/isa.rs
Normal file
@@ -0,0 +1,192 @@
|
||||
use cranelift_entity::PrimaryMap;
|
||||
|
||||
use super::regs::{
|
||||
RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex, RegClassProto,
|
||||
};
|
||||
use super::settings::SettingGroup;
|
||||
|
||||
pub struct TargetIsa {
|
||||
pub name: &'static str,
|
||||
pub reg_banks: PrimaryMap<RegBankIndex, RegBank>,
|
||||
pub reg_classes: PrimaryMap<RegClassIndex, RegClass>,
|
||||
pub settings: SettingGroup,
|
||||
}
|
||||
|
||||
impl TargetIsa {
|
||||
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
|
||||
Self {
|
||||
name,
|
||||
reg_banks: PrimaryMap::new(),
|
||||
reg_classes: PrimaryMap::new(),
|
||||
settings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TargetIsaBuilder {
|
||||
isa: TargetIsa,
|
||||
}
|
||||
|
||||
impl TargetIsaBuilder {
|
||||
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
|
||||
Self {
|
||||
isa: TargetIsa::new(name, settings),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_reg_bank(&mut self, builder: RegBankBuilder) -> RegBankIndex {
|
||||
let first_unit = if self.isa.reg_banks.len() == 0 {
|
||||
0
|
||||
} else {
|
||||
let last = &self.isa.reg_banks.last().unwrap();
|
||||
let first_available_unit = (last.first_unit + last.units) as i8;
|
||||
let units = builder.units;
|
||||
let align = if units.is_power_of_two() {
|
||||
units
|
||||
} else {
|
||||
units.next_power_of_two()
|
||||
} as i8;
|
||||
(first_available_unit + align - 1) & -align
|
||||
} as u8;
|
||||
|
||||
self.isa.reg_banks.push(RegBank::new(
|
||||
builder.name,
|
||||
first_unit,
|
||||
builder.units,
|
||||
builder.names,
|
||||
builder.prefix,
|
||||
builder
|
||||
.pressure_tracking
|
||||
.expect("Pressure tracking must be explicitly set"),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn add_reg_class(&mut self, builder: RegClassBuilder) -> RegClassIndex {
|
||||
let class_index = self.isa.reg_classes.next_key();
|
||||
|
||||
// Finish delayed construction of RegClass.
|
||||
let (bank, toprc, start, width) = match builder.proto {
|
||||
RegClassProto::TopLevel(bank_index) => {
|
||||
self.isa
|
||||
.reg_banks
|
||||
.get_mut(bank_index)
|
||||
.unwrap()
|
||||
.toprcs
|
||||
.push(class_index);
|
||||
(bank_index, class_index, builder.start, builder.width)
|
||||
}
|
||||
RegClassProto::SubClass(parent_class_index) => {
|
||||
assert!(builder.width == 0);
|
||||
let (bank, toprc, start, width) = {
|
||||
let parent = self.isa.reg_classes.get(parent_class_index).unwrap();
|
||||
(parent.bank, parent.toprc, parent.start, parent.width)
|
||||
};
|
||||
for reg_class in self.isa.reg_classes.values_mut() {
|
||||
if reg_class.toprc == toprc {
|
||||
reg_class.subclasses.push(class_index);
|
||||
}
|
||||
}
|
||||
let subclass_start = start + builder.start * width;
|
||||
(bank, toprc, subclass_start, width)
|
||||
}
|
||||
};
|
||||
|
||||
let reg_bank_units = self.isa.reg_banks.get(bank).unwrap().units;
|
||||
assert!(start < reg_bank_units);
|
||||
|
||||
let count = if builder.count != 0 {
|
||||
builder.count
|
||||
} else {
|
||||
reg_bank_units / width
|
||||
};
|
||||
|
||||
let reg_class = RegClass::new(builder.name, class_index, width, bank, toprc, count, start);
|
||||
self.isa.reg_classes.push(reg_class);
|
||||
|
||||
let reg_bank = self.isa.reg_banks.get_mut(bank).unwrap();
|
||||
reg_bank.classes.push(class_index);
|
||||
|
||||
class_index
|
||||
}
|
||||
|
||||
/// Checks that the set of register classes satisfies:
|
||||
///
|
||||
/// 1. Closed under intersection: The intersection of any two register
|
||||
/// classes in the set is either empty or identical to a member of the
|
||||
/// set.
|
||||
/// 2. There are no identical classes under different names.
|
||||
/// 3. Classes are sorted topologically such that all subclasses have a
|
||||
/// higher index that the superclass.
|
||||
pub fn finish(self) -> TargetIsa {
|
||||
for reg_bank in self.isa.reg_banks.values() {
|
||||
for i1 in reg_bank.classes.iter() {
|
||||
for i2 in reg_bank.classes.iter() {
|
||||
if i1 >= i2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let rc1 = self.isa.reg_classes.get(*i1).unwrap();
|
||||
let rc2 = self.isa.reg_classes.get(*i2).unwrap();
|
||||
|
||||
let rc1_mask = rc1.mask(0);
|
||||
let rc2_mask = rc2.mask(0);
|
||||
|
||||
assert!(
|
||||
rc1.width != rc2.width || rc1_mask != rc2_mask,
|
||||
"no duplicates"
|
||||
);
|
||||
if rc1.width != rc2.width {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut intersect = Vec::new();
|
||||
for (a, b) in rc1_mask.iter().zip(rc2_mask.iter()) {
|
||||
intersect.push(a & b);
|
||||
}
|
||||
if intersect == vec![0; intersect.len()] {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Classes must be topologically ordered, so the intersection can't be the
|
||||
// superclass.
|
||||
assert!(intersect != rc1_mask);
|
||||
|
||||
// If the intersection is the second one, then it must be a subclass.
|
||||
if intersect == rc2_mask {
|
||||
assert!(self
|
||||
.isa
|
||||
.reg_classes
|
||||
.get(*i1)
|
||||
.unwrap()
|
||||
.subclasses
|
||||
.iter()
|
||||
.find(|x| **x == *i2)
|
||||
.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This limit should be coordinated with the `RegClassMask` and `RegClassIndex` types in
|
||||
// isa/registers.rs of the non-meta code.
|
||||
assert!(
|
||||
self.isa.reg_classes.len() <= 32,
|
||||
"Too many register classes"
|
||||
);
|
||||
|
||||
// The maximum number of top-level register classes which have pressure tracking should be
|
||||
// kept in sync with the MAX_TRACKED_TOPRCS constant in isa/registers.rs of the non-meta
|
||||
// code.
|
||||
let num_toplevel = self
|
||||
.isa
|
||||
.reg_classes
|
||||
.values()
|
||||
.filter(|x| {
|
||||
x.toprc == x.index && self.isa.reg_banks.get(x.bank).unwrap().pressure_tracking
|
||||
})
|
||||
.count();
|
||||
assert!(num_toplevel <= 4, "Too many top-level register classes");
|
||||
|
||||
self.isa
|
||||
}
|
||||
}
|
||||
68
cranelift/codegen/meta/src/cdsl/mod.rs
Normal file
68
cranelift/codegen/meta/src/cdsl/mod.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
//! Cranelift DSL classes.
|
||||
//!
|
||||
//! This module defines the classes that are used to define Cranelift
|
||||
//! instructions and other entities.
|
||||
|
||||
pub mod isa;
|
||||
pub mod regs;
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
|
||||
/// A macro that converts boolean settings into predicates to look more natural.
|
||||
#[macro_export]
|
||||
macro_rules! predicate {
|
||||
($a:ident && $($b:tt)*) => {
|
||||
PredicateNode::And(Box::new($a.into()), Box::new(predicate!($($b)*)))
|
||||
};
|
||||
($a:ident) => {
|
||||
$a.into()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! preset {
|
||||
() => {
|
||||
vec![]
|
||||
};
|
||||
($($x:ident)&&*) => {
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
$(
|
||||
v.push($x.into());
|
||||
)*
|
||||
v
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Convert the string `s` to CamelCase.
|
||||
pub fn camel_case(s: &str) -> String {
|
||||
let mut output_chars = String::with_capacity(s.len());
|
||||
|
||||
let mut capitalize = true;
|
||||
for curr_char in s.chars() {
|
||||
if curr_char == '_' {
|
||||
capitalize = true;
|
||||
} else {
|
||||
if capitalize {
|
||||
output_chars.extend(curr_char.to_uppercase());
|
||||
} else {
|
||||
output_chars.push(curr_char);
|
||||
}
|
||||
capitalize = false;
|
||||
}
|
||||
}
|
||||
|
||||
output_chars
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::camel_case;
|
||||
|
||||
#[test]
|
||||
fn camel_case_works() {
|
||||
assert_eq!(camel_case("x"), "X");
|
||||
assert_eq!(camel_case("camel_case"), "CamelCase");
|
||||
}
|
||||
}
|
||||
180
cranelift/codegen/meta/src/cdsl/regs.rs
Normal file
180
cranelift/codegen/meta/src/cdsl/regs.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
use cranelift_entity::entity_impl;
|
||||
use cranelift_entity::EntityRef;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct RegBankIndex(u32);
|
||||
entity_impl!(RegBankIndex);
|
||||
|
||||
pub struct RegBank {
|
||||
pub name: &'static str,
|
||||
pub first_unit: u8,
|
||||
pub units: u8,
|
||||
pub names: Vec<&'static str>,
|
||||
pub prefix: &'static str,
|
||||
pub pressure_tracking: bool,
|
||||
pub toprcs: Vec<RegClassIndex>,
|
||||
pub classes: Vec<RegClassIndex>,
|
||||
}
|
||||
|
||||
impl RegBank {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
first_unit: u8,
|
||||
units: u8,
|
||||
names: Vec<&'static str>,
|
||||
prefix: &'static str,
|
||||
pressure_tracking: bool,
|
||||
) -> Self {
|
||||
RegBank {
|
||||
name,
|
||||
first_unit,
|
||||
units,
|
||||
names,
|
||||
prefix,
|
||||
pressure_tracking,
|
||||
toprcs: Vec::new(),
|
||||
classes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct RegClassIndex(u32);
|
||||
entity_impl!(RegClassIndex);
|
||||
|
||||
pub struct RegClass {
|
||||
pub name: &'static str,
|
||||
pub index: RegClassIndex,
|
||||
pub width: u8,
|
||||
pub bank: RegBankIndex,
|
||||
pub toprc: RegClassIndex,
|
||||
pub count: u8,
|
||||
pub start: u8,
|
||||
pub subclasses: Vec<RegClassIndex>,
|
||||
}
|
||||
|
||||
impl RegClass {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
index: RegClassIndex,
|
||||
width: u8,
|
||||
bank: RegBankIndex,
|
||||
toprc: RegClassIndex,
|
||||
count: u8,
|
||||
start: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
index,
|
||||
width,
|
||||
bank,
|
||||
toprc,
|
||||
count,
|
||||
start,
|
||||
subclasses: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute a bit-mask of subclasses, including self.
|
||||
pub fn subclass_mask(&self) -> u64 {
|
||||
let mut m = 1 << self.index.index();
|
||||
for rc in self.subclasses.iter() {
|
||||
m |= 1 << rc.index();
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
/// Compute a bit-mask of the register units allocated by this register class.
|
||||
pub fn mask(&self, bank_first_unit: u8) -> Vec<u32> {
|
||||
let mut u = (self.start + bank_first_unit) as usize;
|
||||
let mut out_mask = vec![0, 0, 0];
|
||||
for _ in 0..self.count {
|
||||
out_mask[u / 32] |= 1 << (u % 32);
|
||||
u += self.width as usize;
|
||||
}
|
||||
out_mask
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RegClassProto {
|
||||
TopLevel(RegBankIndex),
|
||||
SubClass(RegClassIndex),
|
||||
}
|
||||
|
||||
pub struct RegClassBuilder {
|
||||
pub name: &'static str,
|
||||
pub width: u8,
|
||||
pub count: u8,
|
||||
pub start: u8,
|
||||
pub proto: RegClassProto,
|
||||
}
|
||||
|
||||
impl RegClassBuilder {
|
||||
pub fn new_toplevel(name: &'static str, bank: RegBankIndex) -> Self {
|
||||
Self {
|
||||
name,
|
||||
width: 1,
|
||||
count: 0,
|
||||
start: 0,
|
||||
proto: RegClassProto::TopLevel(bank),
|
||||
}
|
||||
}
|
||||
pub fn subclass_of(
|
||||
name: &'static str,
|
||||
parent_index: RegClassIndex,
|
||||
start: u8,
|
||||
stop: u8,
|
||||
) -> Self {
|
||||
assert!(stop >= start);
|
||||
Self {
|
||||
name,
|
||||
width: 0,
|
||||
count: stop - start,
|
||||
start: start,
|
||||
proto: RegClassProto::SubClass(parent_index),
|
||||
}
|
||||
}
|
||||
pub fn count(mut self, count: u8) -> Self {
|
||||
self.count = count;
|
||||
self
|
||||
}
|
||||
pub fn width(mut self, width: u8) -> Self {
|
||||
match self.proto {
|
||||
RegClassProto::TopLevel(_) => self.width = width,
|
||||
RegClassProto::SubClass(_) => panic!("Subclasses inherit their parent's width."),
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RegBankBuilder {
|
||||
pub name: &'static str,
|
||||
pub units: u8,
|
||||
pub names: Vec<&'static str>,
|
||||
pub prefix: &'static str,
|
||||
pub pressure_tracking: Option<bool>,
|
||||
}
|
||||
|
||||
impl RegBankBuilder {
|
||||
pub fn new(name: &'static str, prefix: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
units: 0,
|
||||
names: vec![],
|
||||
prefix,
|
||||
pressure_tracking: None,
|
||||
}
|
||||
}
|
||||
pub fn units(mut self, units: u8) -> Self {
|
||||
self.units = units;
|
||||
self
|
||||
}
|
||||
pub fn names(mut self, names: Vec<&'static str>) -> Self {
|
||||
self.names = names;
|
||||
self
|
||||
}
|
||||
pub fn track_pressure(mut self, track: bool) -> Self {
|
||||
self.pressure_tracking = Some(track);
|
||||
self
|
||||
}
|
||||
}
|
||||
387
cranelift/codegen/meta/src/cdsl/settings.rs
Normal file
387
cranelift/codegen/meta/src/cdsl/settings.rs
Normal file
@@ -0,0 +1,387 @@
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct BoolSettingIndex(usize);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct BoolSetting {
|
||||
pub default: bool,
|
||||
pub bit_offset: u8,
|
||||
pub predicate_number: u8,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum SpecificSetting {
|
||||
Bool(BoolSetting),
|
||||
Enum(Vec<&'static str>),
|
||||
Num(u8),
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct Setting {
|
||||
pub name: &'static str,
|
||||
pub comment: &'static str,
|
||||
pub specific: SpecificSetting,
|
||||
pub byte_offset: u8,
|
||||
}
|
||||
|
||||
impl Setting {
|
||||
pub fn default_byte(&self) -> u8 {
|
||||
match self.specific {
|
||||
SpecificSetting::Bool(BoolSetting {
|
||||
default,
|
||||
bit_offset,
|
||||
..
|
||||
}) => {
|
||||
if default {
|
||||
1 << bit_offset
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
SpecificSetting::Enum(_) => 0,
|
||||
SpecificSetting::Num(default) => default,
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_for_value(&self, v: bool) -> u8 {
|
||||
match self.specific {
|
||||
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
|
||||
if v {
|
||||
1 << bit_offset
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_mask(&self) -> u8 {
|
||||
match self.specific {
|
||||
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset,
|
||||
_ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct PresetIndex(usize);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum PresetType {
|
||||
BoolSetting(BoolSettingIndex),
|
||||
OtherPreset(PresetIndex),
|
||||
}
|
||||
|
||||
impl Into<PresetType> for BoolSettingIndex {
|
||||
fn into(self) -> PresetType {
|
||||
PresetType::BoolSetting(self)
|
||||
}
|
||||
}
|
||||
impl Into<PresetType> for PresetIndex {
|
||||
fn into(self) -> PresetType {
|
||||
PresetType::OtherPreset(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct Preset {
|
||||
pub name: &'static str,
|
||||
values: Vec<BoolSettingIndex>,
|
||||
}
|
||||
|
||||
impl Preset {
|
||||
pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> {
|
||||
let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0))
|
||||
.take(group.settings_size as usize)
|
||||
.collect();
|
||||
for bool_index in &self.values {
|
||||
let setting = &group.settings[bool_index.0];
|
||||
let mask = setting.byte_mask();
|
||||
let val = setting.byte_for_value(true);
|
||||
assert!((val & !mask) == 0);
|
||||
let (ref mut l_mask, ref mut l_val) =
|
||||
*layout.get_mut(setting.byte_offset as usize).unwrap();
|
||||
*l_mask |= mask;
|
||||
*l_val = (*l_val & !mask) | val;
|
||||
}
|
||||
layout
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SettingGroup {
|
||||
pub name: &'static str,
|
||||
pub settings: Vec<Setting>,
|
||||
pub bool_start_byte_offset: u8,
|
||||
pub settings_size: u8,
|
||||
pub presets: Vec<Preset>,
|
||||
pub predicates: Vec<Predicate>,
|
||||
}
|
||||
|
||||
impl SettingGroup {
|
||||
fn num_bool_settings(&self) -> u8 {
|
||||
self.settings
|
||||
.iter()
|
||||
.filter(|s| {
|
||||
if let SpecificSetting::Bool(_) = s.specific {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.count() as u8
|
||||
}
|
||||
|
||||
pub fn byte_size(&self) -> u8 {
|
||||
let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8);
|
||||
self.bool_start_byte_offset + (num_predicates + 7) / 8
|
||||
}
|
||||
|
||||
pub fn get_bool(&self, name: &'static str) -> (BoolSettingIndex, &Self) {
|
||||
for (i, s) in self.settings.iter().enumerate() {
|
||||
if let SpecificSetting::Bool(_) = s.specific {
|
||||
if s.name == name {
|
||||
return (BoolSettingIndex(i), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("Should have found bool setting by name.");
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the basic information needed to track the specific parts of a setting when building
|
||||
/// them.
|
||||
pub enum ProtoSpecificSetting {
|
||||
Bool(bool, u8),
|
||||
Enum(Vec<&'static str>),
|
||||
Num(u8),
|
||||
}
|
||||
|
||||
/// This is the information provided during building for a setting.
|
||||
struct ProtoSetting {
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
specific: ProtoSpecificSetting,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum PredicateNode {
|
||||
OwnedBool(BoolSettingIndex),
|
||||
SharedBool(&'static str, &'static str),
|
||||
And(Box<PredicateNode>, Box<PredicateNode>),
|
||||
}
|
||||
|
||||
impl Into<PredicateNode> for BoolSettingIndex {
|
||||
fn into(self) -> PredicateNode {
|
||||
PredicateNode::OwnedBool(self)
|
||||
}
|
||||
}
|
||||
impl<'a> Into<PredicateNode> for (BoolSettingIndex, &'a SettingGroup) {
|
||||
fn into(self) -> PredicateNode {
|
||||
let (index, group) = (self.0, self.1);
|
||||
let setting = &group.settings[index.0];
|
||||
PredicateNode::SharedBool(group.name, setting.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl PredicateNode {
|
||||
fn render(&self, group: &SettingGroup) -> String {
|
||||
match *self {
|
||||
PredicateNode::OwnedBool(bool_setting_index) => format!(
|
||||
"{}.{}()",
|
||||
group.name, group.settings[bool_setting_index.0].name
|
||||
),
|
||||
PredicateNode::SharedBool(ref group_name, ref bool_name) => {
|
||||
format!("{}.{}()", group_name, bool_name)
|
||||
}
|
||||
PredicateNode::And(ref lhs, ref rhs) => {
|
||||
format!("{} && {}", lhs.render(group), rhs.render(group))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Predicate {
|
||||
pub name: &'static str,
|
||||
node: PredicateNode,
|
||||
pub number: u8,
|
||||
}
|
||||
|
||||
impl Predicate {
|
||||
pub fn render(&self, group: &SettingGroup) -> String {
|
||||
self.node.render(group)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SettingGroupBuilder {
|
||||
name: &'static str,
|
||||
settings: Vec<ProtoSetting>,
|
||||
presets: Vec<Preset>,
|
||||
predicates: Vec<Predicate>,
|
||||
predicate_number: u8,
|
||||
}
|
||||
|
||||
impl SettingGroupBuilder {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
settings: Vec::new(),
|
||||
presets: Vec::new(),
|
||||
predicates: Vec::new(),
|
||||
predicate_number: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_setting(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
specific: ProtoSpecificSetting,
|
||||
) {
|
||||
self.settings.push(ProtoSetting {
|
||||
name,
|
||||
comment,
|
||||
specific,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_bool(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
default: bool,
|
||||
) -> BoolSettingIndex {
|
||||
assert!(
|
||||
self.predicates.len() == 0,
|
||||
"predicates must be added after the boolean settings"
|
||||
);
|
||||
let predicate_number = self.predicate_number;
|
||||
self.predicate_number += 1;
|
||||
self.add_setting(
|
||||
name,
|
||||
comment,
|
||||
ProtoSpecificSetting::Bool(default, predicate_number),
|
||||
);
|
||||
BoolSettingIndex(self.settings.len() - 1)
|
||||
}
|
||||
|
||||
pub fn add_enum(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
values: Vec<&'static str>,
|
||||
) {
|
||||
self.add_setting(name, comment, ProtoSpecificSetting::Enum(values));
|
||||
}
|
||||
|
||||
pub fn add_num(&mut self, name: &'static str, comment: &'static str, default: u8) {
|
||||
self.add_setting(name, comment, ProtoSpecificSetting::Num(default));
|
||||
}
|
||||
|
||||
pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) {
|
||||
let number = self.predicate_number;
|
||||
self.predicate_number += 1;
|
||||
self.predicates.push(Predicate { name, node, number });
|
||||
}
|
||||
|
||||
pub fn add_preset(&mut self, name: &'static str, args: Vec<PresetType>) -> PresetIndex {
|
||||
let mut values = Vec::new();
|
||||
for arg in args {
|
||||
match arg {
|
||||
PresetType::OtherPreset(index) => {
|
||||
values.extend(self.presets[index.0].values.iter());
|
||||
}
|
||||
PresetType::BoolSetting(index) => values.push(index),
|
||||
}
|
||||
}
|
||||
self.presets.push(Preset { name, values });
|
||||
PresetIndex(self.presets.len() - 1)
|
||||
}
|
||||
|
||||
/// Compute the layout of the byte vector used to represent this settings
|
||||
/// group.
|
||||
///
|
||||
/// The byte vector contains the following entries in order:
|
||||
///
|
||||
/// 1. Byte-sized settings like `NumSetting` and `EnumSetting`.
|
||||
/// 2. `BoolSetting` settings.
|
||||
/// 3. Precomputed named predicates.
|
||||
/// 4. Other numbered predicates, including anonymous predicates and parent
|
||||
/// predicates that need to be accessible by number.
|
||||
///
|
||||
/// Set `self.settings_size` to the length of the byte vector prefix that
|
||||
/// contains the settings. All bytes after that are computed, not
|
||||
/// configured.
|
||||
///
|
||||
/// Set `self.boolean_offset` to the beginning of the numbered predicates,
|
||||
/// 2. in the list above.
|
||||
///
|
||||
/// Assign `byte_offset` and `bit_offset` fields in all settings.
|
||||
///
|
||||
/// After calling this method, no more settings can be added, but
|
||||
/// additional predicates can be made accessible with `number_predicate()`.
|
||||
pub fn finish(self) -> SettingGroup {
|
||||
let mut group = SettingGroup {
|
||||
name: self.name,
|
||||
settings: Vec::new(),
|
||||
bool_start_byte_offset: 0,
|
||||
settings_size: 0,
|
||||
presets: Vec::new(),
|
||||
predicates: Vec::new(),
|
||||
};
|
||||
|
||||
let mut byte_offset = 0;
|
||||
|
||||
// Assign the non-boolean settings first.
|
||||
for s in &self.settings {
|
||||
let specific = match s.specific {
|
||||
ProtoSpecificSetting::Bool(..) => continue,
|
||||
ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()),
|
||||
ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default),
|
||||
};
|
||||
|
||||
group.settings.push(Setting {
|
||||
name: s.name,
|
||||
comment: s.comment,
|
||||
byte_offset,
|
||||
specific,
|
||||
});
|
||||
|
||||
byte_offset += 1;
|
||||
}
|
||||
|
||||
group.bool_start_byte_offset = byte_offset;
|
||||
|
||||
// Then the boolean settings.
|
||||
for s in &self.settings {
|
||||
let (default, predicate_number) = match s.specific {
|
||||
ProtoSpecificSetting::Bool(default, predicate_number) => {
|
||||
(default, predicate_number)
|
||||
}
|
||||
ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,
|
||||
};
|
||||
group.settings.push(Setting {
|
||||
name: s.name,
|
||||
comment: s.comment,
|
||||
byte_offset: byte_offset + predicate_number / 8,
|
||||
specific: SpecificSetting::Bool(BoolSetting {
|
||||
default,
|
||||
bit_offset: predicate_number % 8,
|
||||
predicate_number,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
assert!(
|
||||
group.predicates.len() == 0,
|
||||
"settings_size is the byte size before adding predicates"
|
||||
);
|
||||
group.settings_size = group.byte_size();
|
||||
|
||||
group.predicates.extend(self.predicates);
|
||||
group.presets.extend(self.presets);
|
||||
|
||||
group
|
||||
}
|
||||
}
|
||||
473
cranelift/codegen/meta/src/cdsl/types.rs
Normal file
473
cranelift/codegen/meta/src/cdsl/types.rs
Normal file
@@ -0,0 +1,473 @@
|
||||
//! Cranelift ValueType hierarchy
|
||||
|
||||
// Temporary disabled: Unused at the moment.
|
||||
// use std::collections::HashMap;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::base::types as base_types;
|
||||
|
||||
// Numbering scheme for value types:
|
||||
//
|
||||
// 0: Void
|
||||
// 0x01-0x6f: Special types
|
||||
// 0x70-0x7f: Lane types
|
||||
// 0x80-0xff: Vector types
|
||||
//
|
||||
// Vector types are encoded with the lane type in the low 4 bits and log2(lanes)
|
||||
// in the high 4 bits, giving a range of 2-256 lanes.
|
||||
static LANE_BASE: u8 = 0x70;
|
||||
|
||||
// Rust name prefix used for the `rust_name` method.
|
||||
static _RUST_NAME_PREFIX: &'static str = "ir::types::";
|
||||
|
||||
// ValueType variants (i8, i32, ...) are provided in `base::types.rs`.
|
||||
|
||||
/// A concrete SSA value type.
|
||||
///
|
||||
/// All SSA values have a type that is described by an instance of `ValueType`
|
||||
/// or one of its subclasses.
|
||||
#[derive(Debug)]
|
||||
pub enum ValueType {
|
||||
BV(BVType),
|
||||
Lane(LaneType),
|
||||
Special(SpecialType),
|
||||
Vector(VectorType),
|
||||
}
|
||||
|
||||
impl ValueType {
|
||||
/// Iterate through all of the lane types.
|
||||
pub fn all_lane_types() -> LaneTypeIterator {
|
||||
LaneTypeIterator::new()
|
||||
}
|
||||
|
||||
/// Iterate through all of the special types (neither lanes nor vectors).
|
||||
pub fn all_special_types() -> SpecialTypeIterator {
|
||||
SpecialTypeIterator::new()
|
||||
}
|
||||
|
||||
/// Return a string containing the documentation comment for this type.
|
||||
pub fn doc(&self) -> String {
|
||||
match *self {
|
||||
ValueType::BV(ref b) => b.doc(),
|
||||
ValueType::Lane(l) => l.doc(),
|
||||
ValueType::Special(s) => s.doc(),
|
||||
ValueType::Vector(ref v) => v.doc(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of bits in a lane.
|
||||
pub fn lane_bits(&self) -> u64 {
|
||||
match *self {
|
||||
ValueType::BV(ref b) => b.lane_bits(),
|
||||
ValueType::Lane(l) => l.lane_bits(),
|
||||
ValueType::Special(s) => s.lane_bits(),
|
||||
ValueType::Vector(ref v) => v.lane_bits(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of lanes.
|
||||
pub fn lane_count(&self) -> u64 {
|
||||
match *self {
|
||||
ValueType::Vector(ref v) => v.lane_count(),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the number of bytes that this type occupies in memory.
|
||||
pub fn membytes(&self) -> u64 {
|
||||
self.width() / 8
|
||||
}
|
||||
|
||||
/// Find the unique number associated with this type.
|
||||
pub fn number(&self) -> Option<u8> {
|
||||
match *self {
|
||||
ValueType::BV(_) => None,
|
||||
ValueType::Lane(l) => Some(l.number()),
|
||||
ValueType::Special(s) => Some(s.number()),
|
||||
ValueType::Vector(ref v) => Some(v.number()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the name of this type for generated Rust source files.
|
||||
pub fn _rust_name(&self) -> String {
|
||||
format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase())
|
||||
}
|
||||
|
||||
/// Return true iff:
|
||||
/// 1. self and other have equal number of lanes
|
||||
/// 2. each lane in self has at least as many bits as a lane in other
|
||||
pub fn _wider_or_equal(&self, rhs: &ValueType) -> bool {
|
||||
(self.lane_count() == rhs.lane_count()) && (self.lane_bits() >= rhs.lane_bits())
|
||||
}
|
||||
|
||||
/// Return the total number of bits of an instance of this type.
|
||||
pub fn width(&self) -> u64 {
|
||||
self.lane_count() * self.lane_bits()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ValueType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ValueType::BV(ref b) => b.fmt(f),
|
||||
ValueType::Lane(l) => l.fmt(f),
|
||||
ValueType::Special(s) => s.fmt(f),
|
||||
ValueType::Vector(ref v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a ValueType from a given bitvector type.
|
||||
impl From<BVType> for ValueType {
|
||||
fn from(bv: BVType) -> Self {
|
||||
ValueType::BV(bv)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a ValueType from a given lane type.
|
||||
impl From<LaneType> for ValueType {
|
||||
fn from(lane: LaneType) -> Self {
|
||||
ValueType::Lane(lane)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a ValueType from a given special type.
|
||||
impl From<SpecialType> for ValueType {
|
||||
fn from(spec: SpecialType) -> Self {
|
||||
ValueType::Special(spec)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a ValueType from a given vector type.
|
||||
impl From<VectorType> for ValueType {
|
||||
fn from(vector: VectorType) -> Self {
|
||||
ValueType::Vector(vector)
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete scalar type that can appear as a vector lane too.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum LaneType {
|
||||
BoolType(base_types::Bool),
|
||||
FloatType(base_types::Float),
|
||||
IntType(base_types::Int),
|
||||
}
|
||||
|
||||
impl LaneType {
|
||||
/// Return a string containing the documentation comment for this lane type.
|
||||
pub fn doc(self) -> String {
|
||||
match self {
|
||||
LaneType::BoolType(_) => format!("A boolean type with {} bits.", self.lane_bits()),
|
||||
LaneType::FloatType(base_types::Float::F32) => String::from(
|
||||
"A 32-bit floating point type represented in the IEEE 754-2008
|
||||
*binary32* interchange format. This corresponds to the :c:type:`float`
|
||||
type in most C implementations.",
|
||||
),
|
||||
LaneType::FloatType(base_types::Float::F64) => String::from(
|
||||
"A 64-bit floating point type represented in the IEEE 754-2008
|
||||
*binary64* interchange format. This corresponds to the :c:type:`double`
|
||||
type in most C implementations.",
|
||||
),
|
||||
LaneType::IntType(_) if self.lane_bits() < 32 => format!(
|
||||
"An integer type with {} bits.
|
||||
WARNING: arithmetic on {}bit integers is incomplete",
|
||||
self.lane_bits(),
|
||||
self.lane_bits()
|
||||
),
|
||||
LaneType::IntType(_) => format!("An integer type with {} bits.", self.lane_bits()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of bits in a lane.
|
||||
pub fn lane_bits(self) -> u64 {
|
||||
match self {
|
||||
LaneType::BoolType(ref b) => *b as u64,
|
||||
LaneType::FloatType(ref f) => *f as u64,
|
||||
LaneType::IntType(ref i) => *i as u64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the unique number associated with this lane type.
|
||||
pub fn number(self) -> u8 {
|
||||
LANE_BASE
|
||||
+ match self {
|
||||
LaneType::BoolType(base_types::Bool::B1) => 0,
|
||||
LaneType::BoolType(base_types::Bool::B8) => 1,
|
||||
LaneType::BoolType(base_types::Bool::B16) => 2,
|
||||
LaneType::BoolType(base_types::Bool::B32) => 3,
|
||||
LaneType::BoolType(base_types::Bool::B64) => 4,
|
||||
LaneType::IntType(base_types::Int::I8) => 5,
|
||||
LaneType::IntType(base_types::Int::I16) => 6,
|
||||
LaneType::IntType(base_types::Int::I32) => 7,
|
||||
LaneType::IntType(base_types::Int::I64) => 8,
|
||||
LaneType::FloatType(base_types::Float::F32) => 9,
|
||||
LaneType::FloatType(base_types::Float::F64) => 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LaneType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
LaneType::BoolType(_) => write!(f, "b{}", self.lane_bits()),
|
||||
LaneType::FloatType(_) => write!(f, "f{}", self.lane_bits()),
|
||||
LaneType::IntType(_) => write!(f, "i{}", self.lane_bits()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LaneType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let inner_msg = format!("bits={}", self.lane_bits());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match *self {
|
||||
LaneType::BoolType(_) => format!("BoolType({})", inner_msg),
|
||||
LaneType::FloatType(_) => format!("FloatType({})", inner_msg),
|
||||
LaneType::IntType(_) => format!("IntType({})", inner_msg),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a LaneType from a given bool variant.
|
||||
impl From<base_types::Bool> for LaneType {
|
||||
fn from(b: base_types::Bool) -> Self {
|
||||
LaneType::BoolType(b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a LaneType from a given float variant.
|
||||
impl From<base_types::Float> for LaneType {
|
||||
fn from(f: base_types::Float) -> Self {
|
||||
LaneType::FloatType(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a LaneType from a given int variant.
|
||||
impl From<base_types::Int> for LaneType {
|
||||
fn from(i: base_types::Int) -> Self {
|
||||
LaneType::IntType(i)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator for different lane types.
|
||||
pub struct LaneTypeIterator {
|
||||
bool_iter: base_types::BoolIterator,
|
||||
int_iter: base_types::IntIterator,
|
||||
float_iter: base_types::FloatIterator,
|
||||
}
|
||||
|
||||
impl LaneTypeIterator {
|
||||
/// Create a new lane type iterator.
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
bool_iter: base_types::BoolIterator::new(),
|
||||
int_iter: base_types::IntIterator::new(),
|
||||
float_iter: base_types::FloatIterator::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for LaneTypeIterator {
|
||||
type Item = LaneType;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(b) = self.bool_iter.next() {
|
||||
Some(LaneType::from(b))
|
||||
} else if let Some(i) = self.int_iter.next() {
|
||||
Some(LaneType::from(i))
|
||||
} else if let Some(f) = self.float_iter.next() {
|
||||
Some(LaneType::from(f))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete SIMD vector type.
|
||||
///
|
||||
/// A vector type has a lane type which is an instance of `LaneType`,
|
||||
/// and a positive number of lanes.
|
||||
pub struct VectorType {
|
||||
base: LaneType,
|
||||
lanes: u64,
|
||||
}
|
||||
|
||||
impl VectorType {
|
||||
/// Initialize a new integer type with `n` bits.
|
||||
pub fn new(base: LaneType, lanes: u64) -> Self {
|
||||
Self { base, lanes }
|
||||
}
|
||||
|
||||
/// Return a string containing the documentation comment for this vector type.
|
||||
pub fn doc(&self) -> String {
|
||||
format!(
|
||||
"A SIMD vector with {} lanes containing a `{}` each.",
|
||||
self.lane_count(),
|
||||
self.base
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the number of bits in a lane.
|
||||
pub fn lane_bits(&self) -> u64 {
|
||||
self.base.lane_bits()
|
||||
}
|
||||
|
||||
/// Return the number of lanes.
|
||||
pub fn lane_count(&self) -> u64 {
|
||||
self.lanes
|
||||
}
|
||||
|
||||
/// Find the unique number associated with this vector type.
|
||||
///
|
||||
/// Vector types are encoded with the lane type in the low 4 bits and
|
||||
/// log2(lanes) in the high 4 bits, giving a range of 2-256 lanes.
|
||||
pub fn number(&self) -> u8 {
|
||||
let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros();
|
||||
let base_num = u32::from(self.base.number());
|
||||
let num = (lanes_log_2 << 4) + base_num;
|
||||
num as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VectorType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}x{}", self.base, self.lane_count())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for VectorType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"VectorType(base={}, lanes={})",
|
||||
self.base,
|
||||
self.lane_count()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A flat bitvector type. Used for semantics description only.
|
||||
pub struct BVType {
|
||||
bits: u64,
|
||||
}
|
||||
|
||||
impl BVType {
|
||||
/// Initialize a new bitvector type with `n` bits.
|
||||
pub fn _new(bits: u64) -> Self {
|
||||
Self { bits }
|
||||
}
|
||||
|
||||
/// Return a string containing the documentation comment for this bitvector type.
|
||||
pub fn doc(&self) -> String {
|
||||
format!("A bitvector type with {} bits.", self.bits)
|
||||
}
|
||||
|
||||
/// Return the number of bits in a lane.
|
||||
pub fn lane_bits(&self) -> u64 {
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BVType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "bv{}", self.bits)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BVType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "BVType(bits={})", self.lane_bits())
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete scalar type that is neither a vector nor a lane type.
|
||||
///
|
||||
/// Special types cannot be used to form vectors.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum SpecialType {
|
||||
Flag(base_types::Flag),
|
||||
}
|
||||
|
||||
impl SpecialType {
|
||||
/// Return a string containing the documentation comment for this special type.
|
||||
pub fn doc(self) -> String {
|
||||
match self {
|
||||
SpecialType::Flag(base_types::Flag::IFlags) => String::from(
|
||||
"CPU flags representing the result of an integer comparison. These flags
|
||||
can be tested with an :type:`intcc` condition code.",
|
||||
),
|
||||
SpecialType::Flag(base_types::Flag::FFlags) => String::from(
|
||||
"CPU flags representing the result of a floating point comparison. These
|
||||
flags can be tested with a :type:`floatcc` condition code.",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of bits in a lane.
|
||||
pub fn lane_bits(self) -> u64 {
|
||||
match self {
|
||||
SpecialType::Flag(_) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the unique number associated with this special type.
|
||||
pub fn number(self) -> u8 {
|
||||
match self {
|
||||
SpecialType::Flag(base_types::Flag::IFlags) => 1,
|
||||
SpecialType::Flag(base_types::Flag::FFlags) => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SpecialType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
SpecialType::Flag(base_types::Flag::IFlags) => write!(f, "iflags"),
|
||||
SpecialType::Flag(base_types::Flag::FFlags) => write!(f, "fflags"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SpecialType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match *self {
|
||||
SpecialType::Flag(_) => format!("FlagsType({})", self),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<base_types::Flag> for SpecialType {
|
||||
fn from(f: base_types::Flag) -> Self {
|
||||
SpecialType::Flag(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpecialTypeIterator {
|
||||
flag_iter: base_types::FlagIterator,
|
||||
}
|
||||
|
||||
impl SpecialTypeIterator {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
flag_iter: base_types::FlagIterator::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for SpecialTypeIterator {
|
||||
type Item = SpecialType;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(f) = self.flag_iter.next() {
|
||||
Some(SpecialType::from(f))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user