diff --git a/cranelift/docs/metaref.rst b/cranelift/docs/metaref.rst index 5548311cac..209fa230d6 100644 --- a/cranelift/docs/metaref.rst +++ b/cranelift/docs/metaref.rst @@ -166,18 +166,15 @@ Concrete value types are represented as instances of :class:`ValueType`. There are subclasses to represent scalar and vector types. .. autoclass:: ValueType -.. inheritance-diagram:: ValueType LaneType VectorType IntType FloatType BoolType +.. inheritance-diagram:: ValueType LaneType VectorType SpecialType IntType FloatType BoolType :parts: 1 .. autoclass:: LaneType :members: .. autoclass:: VectorType - :members: +.. autoclass:: SpecialType .. autoclass:: IntType - :members: .. autoclass:: FloatType - :members: .. autoclass:: BoolType - :members: .. automodule:: base.types :members: diff --git a/lib/cretonne/meta/cdsl/types.py b/lib/cretonne/meta/cdsl/types.py index 85bf164c62..505c0a1b2b 100644 --- a/lib/cretonne/meta/cdsl/types.py +++ b/lib/cretonne/meta/cdsl/types.py @@ -9,6 +9,18 @@ except ImportError: pass +# 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. +LANE_BASE = 0x70 + + # ValueType instances (i8, i32, ...) are provided in the `base.types` module. class ValueType(object): """ @@ -24,6 +36,9 @@ class ValueType(object): # List of all the lane types. all_lane_types = list() # type: List[LaneType] + # List of all the special types (neither lanes nor vectors). + all_special_types = list() # type: List[SpecialType] + def __init__(self, name, membytes, doc): # type: (str, int, str) -> None self.name = name @@ -87,10 +102,11 @@ class LaneType(ValueType): # type: (str, int, str) -> None super(LaneType, self).__init__(name, membytes, doc) self._vectors = dict() # type: Dict[int, VectorType] - # Assign numbers starting from 1. (0 is VOID). + # Assign numbers starting from LANE_BASE. + n = len(ValueType.all_lane_types) ValueType.all_lane_types.append(self) - self.number = len(ValueType.all_lane_types) - assert self.number < 16, 'Too many lane types' + assert n < 16, 'Too many lane types' + self.number = LANE_BASE + n def __repr__(self): # type: () -> str @@ -132,6 +148,7 @@ class VectorType(ValueType): doc=""" A SIMD vector with {} lanes containing a `{}` each. """.format(lanes, base.name)) + assert lanes <= 256, "Too many lanes" self.base = base self.lanes = lanes self.number = 16*int(math.log(lanes, 2)) + base.number @@ -152,6 +169,31 @@ class VectorType(ValueType): return self.base.lane_bits() +class SpecialType(ValueType): + """ + A concrete scalar type that is neither a vector nor a lane type. + + Special types cannot be used to form vectors. + """ + + def __init__(self, name, membytes, doc): + # type: (str, int, str) -> None + super(SpecialType, self).__init__(name, membytes, doc) + # Assign numbers starting from 1. (0 is VOID) + ValueType.all_special_types.append(self) + self.number = len(ValueType.all_special_types) + assert self.number < LANE_BASE, 'Too many special types' + + def __repr__(self): + # type: () -> str + return 'SpecialType({})'.format(self.name) + + def lane_count(self): + # type: () -> int + """Return the number of lanes.""" + return 1 + + class IntType(LaneType): """A concrete scalar integer type.""" diff --git a/lib/cretonne/src/ir/types.rs b/lib/cretonne/src/ir/types.rs index 3c0221d4cd..7efeb55558 100644 --- a/lib/cretonne/src/ir/types.rs +++ b/lib/cretonne/src/ir/types.rs @@ -30,6 +30,12 @@ pub struct Type(u8); /// a SIMD vector. pub const VOID: Type = Type(0); +// Start of the lane types. See also `meta/cdsl.types.py`. +const LANE_BASE: u8 = 0x70; + +// Start of the 2-lane vector types. +const VECTOR_BASE: u8 = LANE_BASE + 16; + // Include code generated by `lib/cretonne/meta/gen_types.py`. This file contains constant // definitions for all the scalar types as well as common vector types for 64, 128, 256, and // 512-bit SIMD vectors. @@ -40,7 +46,11 @@ impl Type { /// /// A lane type is the same as a SIMD vector type with one lane, so it returns itself. pub fn lane_type(self) -> Type { - Type(self.0 & 0x0f) + if self.0 < VECTOR_BASE { + self + } else { + Type(LANE_BASE | (self.0 & 0x0f)) + } } /// Get log_2 of the number of bits in a lane. @@ -78,6 +88,12 @@ impl Type { } } + /// Get a type with the same number of lanes as `self`, but using `lane` as the lane type. + fn replace_lanes(self, lane: Type) -> Type { + debug_assert!(lane.is_lane() && !self.is_special()); + Type((lane.0 & 0x0f) | (self.0 & 0xf0)) + } + /// Get a type with the same number of lanes as this type, but with the lanes replaced by /// booleans of the same size. /// @@ -85,14 +101,13 @@ impl Type { /// boolean types. pub fn as_bool_pedantic(self) -> Type { // Replace the low 4 bits with the boolean version, preserve the high 4 bits. - let lane = match self.lane_type() { + self.replace_lanes(match self.lane_type() { B8 | I8 => B8, B16 | I16 => B16, B32 | I32 | F32 => B32, B64 | I64 | F64 => B64, _ => B1, - }; - Type(lane.0 | (self.0 & 0xf0)) + }) } /// Get a type with the same number of lanes as this type, but with the lanes replaced by @@ -110,7 +125,7 @@ impl Type { /// Get a type with the same number of lanes as this type, but with lanes that are half the /// number of bits. pub fn half_width(self) -> Option { - let lane = match self.lane_type() { + Some(self.replace_lanes(match self.lane_type() { I16 => I8, I32 => I16, I64 => I32, @@ -119,14 +134,13 @@ impl Type { B32 => B16, B64 => B32, _ => return None, - }; - Some(Type(lane.0 | (self.0 & 0xf0))) + })) } /// Get a type with the same number of lanes as this type, but with lanes that are twice the /// number of bits. pub fn double_width(self) -> Option { - let lane = match self.lane_type() { + Some(self.replace_lanes(match self.lane_type() { I8 => I16, I16 => I32, I32 => I64, @@ -135,8 +149,7 @@ impl Type { B16 => B32, B32 => B64, _ => return None, - }; - Some(Type(lane.0 | (self.0 & 0xf0))) + })) } /// Is this the VOID type? @@ -144,6 +157,25 @@ impl Type { self == VOID } + /// Is this a special type? + pub fn is_special(self) -> bool { + self.0 < LANE_BASE + } + + /// Is this a lane type? + /// + /// This is a scalar type that can also appear as the lane type of a SIMD vector. + pub fn is_lane(self) -> bool { + LANE_BASE <= self.0 && self.0 < VECTOR_BASE + } + + /// Is this a SIMD vector type? + /// + /// A vector type has 2 or more lanes. + pub fn is_vector(self) -> bool { + self.0 >= VECTOR_BASE + } + /// Is this a scalar boolean type? pub fn is_bool(self) -> bool { match self { @@ -175,14 +207,7 @@ impl Type { /// /// A scalar type is the same as a SIMD vector type with one lane, so it returns 0. pub fn log2_lane_count(self) -> u8 { - self.0 >> 4 - } - - /// Is this a SIMD vector type? - /// - /// A vector type has 2 or more lanes. - pub fn is_vector(self) -> bool { - self.log2_lane_count() > 0 + self.0.saturating_sub(LANE_BASE) >> 4 } /// Get the number of lanes in this SIMD vector type. @@ -214,7 +239,7 @@ impl Type { } let log2_lanes: u32 = n.trailing_zeros(); let new_type = u32::from(self.0) + (log2_lanes << 4); - if new_type < 0x90 { + if new_type < 0x100 { Some(Type(new_type as u8)) } else { None