cranelift_codegen_meta/cdsl/
types.rs

1//! Cranelift ValueType hierarchy
2
3use std::fmt;
4
5use crate::shared::types as shared_types;
6use cranelift_codegen_shared::constants;
7
8// Rust name prefix used for the `rust_name` method.
9static RUST_NAME_PREFIX: &str = "ir::types::";
10
11// ValueType variants (i8, i32, ...) are provided in `shared::types.rs`.
12
13/// A concrete SSA value type.
14///
15/// All SSA values have a type that is described by an instance of `ValueType`
16/// or one of its subclasses.
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub(crate) enum ValueType {
19    Lane(LaneType),
20    Vector(VectorType),
21    DynamicVector(DynamicVectorType),
22}
23
24impl ValueType {
25    /// Iterate through all of the lane types.
26    pub fn all_lane_types() -> LaneTypeIterator {
27        LaneTypeIterator::new()
28    }
29
30    /// Return a string containing the documentation comment for this type.
31    pub fn doc(&self) -> String {
32        match *self {
33            ValueType::Lane(l) => l.doc(),
34            ValueType::Vector(ref v) => v.doc(),
35            ValueType::DynamicVector(ref v) => v.doc(),
36        }
37    }
38
39    /// Return the number of bits in a lane.
40    pub fn lane_bits(&self) -> u64 {
41        match *self {
42            ValueType::Lane(l) => l.lane_bits(),
43            ValueType::Vector(ref v) => v.lane_bits(),
44            ValueType::DynamicVector(ref v) => v.lane_bits(),
45        }
46    }
47
48    /// Return the number of lanes.
49    pub fn lane_count(&self) -> u64 {
50        match *self {
51            ValueType::Vector(ref v) => v.lane_count(),
52            _ => 1,
53        }
54    }
55
56    /// Find the number of bytes that this type occupies in memory.
57    pub fn membytes(&self) -> u64 {
58        self.width() / 8
59    }
60
61    /// Find the unique number associated with this type.
62    pub fn number(&self) -> u16 {
63        match *self {
64            ValueType::Lane(l) => l.number(),
65            ValueType::Vector(ref v) => v.number(),
66            ValueType::DynamicVector(ref v) => v.number(),
67        }
68    }
69
70    /// Return the name of this type for generated Rust source files.
71    pub fn rust_name(&self) -> String {
72        format!("{}{}", RUST_NAME_PREFIX, self.to_string().to_uppercase())
73    }
74
75    /// Return the total number of bits of an instance of this type.
76    pub fn width(&self) -> u64 {
77        self.lane_count() * self.lane_bits()
78    }
79}
80
81impl fmt::Display for ValueType {
82    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83        match *self {
84            ValueType::Lane(l) => l.fmt(f),
85            ValueType::Vector(ref v) => v.fmt(f),
86            ValueType::DynamicVector(ref v) => v.fmt(f),
87        }
88    }
89}
90
91/// Create a ValueType from a given lane type.
92impl From<LaneType> for ValueType {
93    fn from(lane: LaneType) -> Self {
94        ValueType::Lane(lane)
95    }
96}
97
98/// Create a ValueType from a given vector type.
99impl From<VectorType> for ValueType {
100    fn from(vector: VectorType) -> Self {
101        ValueType::Vector(vector)
102    }
103}
104
105/// Create a ValueType from a given dynamic vector type.
106impl From<DynamicVectorType> for ValueType {
107    fn from(vector: DynamicVectorType) -> Self {
108        ValueType::DynamicVector(vector)
109    }
110}
111
112/// A concrete scalar type that can appear as a vector lane too.
113#[derive(Clone, Copy, PartialEq, Eq, Hash)]
114pub(crate) enum LaneType {
115    Float(shared_types::Float),
116    Int(shared_types::Int),
117}
118
119impl LaneType {
120    /// Return a string containing the documentation comment for this lane type.
121    pub fn doc(self) -> String {
122        match self {
123            LaneType::Float(shared_types::Float::F16) => String::from(
124                "A 16-bit floating point type represented in the IEEE 754-2008
125                *binary16* interchange format. This corresponds to the :c:type:`_Float16`
126                type in most C implementations.
127                WARNING: f16 support is a work-in-progress and is incomplete",
128            ),
129            LaneType::Float(shared_types::Float::F32) => String::from(
130                "A 32-bit floating point type represented in the IEEE 754-2008
131                *binary32* interchange format. This corresponds to the :c:type:`float`
132                type in most C implementations.",
133            ),
134            LaneType::Float(shared_types::Float::F64) => String::from(
135                "A 64-bit floating point type represented in the IEEE 754-2008
136                *binary64* interchange format. This corresponds to the :c:type:`double`
137                type in most C implementations.",
138            ),
139            LaneType::Float(shared_types::Float::F128) => String::from(
140                "A 128-bit floating point type represented in the IEEE 754-2008
141                *binary128* interchange format. This corresponds to the :c:type:`_Float128`
142                type in most C implementations.
143                WARNING: f128 support is a work-in-progress and is incomplete",
144            ),
145            LaneType::Int(_) if self.lane_bits() < 32 => format!(
146                "An integer type with {} bits.
147                WARNING: arithmetic on {}bit integers is incomplete",
148                self.lane_bits(),
149                self.lane_bits()
150            ),
151            LaneType::Int(_) => format!("An integer type with {} bits.", self.lane_bits()),
152        }
153    }
154
155    /// Return the number of bits in a lane.
156    pub fn lane_bits(self) -> u64 {
157        match self {
158            LaneType::Float(ref f) => *f as u64,
159            LaneType::Int(ref i) => *i as u64,
160        }
161    }
162
163    /// Find the unique number associated with this lane type.
164    pub fn number(self) -> u16 {
165        constants::LANE_BASE
166            + match self {
167                LaneType::Int(shared_types::Int::I8) => 4,
168                LaneType::Int(shared_types::Int::I16) => 5,
169                LaneType::Int(shared_types::Int::I32) => 6,
170                LaneType::Int(shared_types::Int::I64) => 7,
171                LaneType::Int(shared_types::Int::I128) => 8,
172                LaneType::Float(shared_types::Float::F16) => 9,
173                LaneType::Float(shared_types::Float::F32) => 10,
174                LaneType::Float(shared_types::Float::F64) => 11,
175                LaneType::Float(shared_types::Float::F128) => 12,
176            }
177    }
178
179    pub fn int_from_bits(num_bits: u16) -> LaneType {
180        LaneType::Int(match num_bits {
181            8 => shared_types::Int::I8,
182            16 => shared_types::Int::I16,
183            32 => shared_types::Int::I32,
184            64 => shared_types::Int::I64,
185            128 => shared_types::Int::I128,
186            _ => unreachable!("unexpected num bits for int"),
187        })
188    }
189
190    pub fn float_from_bits(num_bits: u16) -> LaneType {
191        LaneType::Float(match num_bits {
192            16 => shared_types::Float::F16,
193            32 => shared_types::Float::F32,
194            64 => shared_types::Float::F64,
195            128 => shared_types::Float::F128,
196            _ => unreachable!("unexpected num bits for float"),
197        })
198    }
199
200    pub fn by(self, lanes: u16) -> ValueType {
201        if lanes == 1 {
202            self.into()
203        } else {
204            ValueType::Vector(VectorType::new(self, lanes.into()))
205        }
206    }
207
208    pub fn to_dynamic(self, lanes: u16) -> ValueType {
209        ValueType::DynamicVector(DynamicVectorType::new(self, lanes.into()))
210    }
211}
212
213impl fmt::Display for LaneType {
214    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215        match *self {
216            LaneType::Float(_) => write!(f, "f{}", self.lane_bits()),
217            LaneType::Int(_) => write!(f, "i{}", self.lane_bits()),
218        }
219    }
220}
221
222impl fmt::Debug for LaneType {
223    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224        let inner_msg = format!("bits={}", self.lane_bits());
225        write!(
226            f,
227            "{}",
228            match *self {
229                LaneType::Float(_) => format!("FloatType({inner_msg})"),
230                LaneType::Int(_) => format!("IntType({inner_msg})"),
231            }
232        )
233    }
234}
235
236/// Create a LaneType from a given float variant.
237impl From<shared_types::Float> for LaneType {
238    fn from(f: shared_types::Float) -> Self {
239        LaneType::Float(f)
240    }
241}
242
243/// Create a LaneType from a given int variant.
244impl From<shared_types::Int> for LaneType {
245    fn from(i: shared_types::Int) -> Self {
246        LaneType::Int(i)
247    }
248}
249
250/// An iterator for different lane types.
251pub(crate) struct LaneTypeIterator {
252    int_iter: shared_types::IntIterator,
253    float_iter: shared_types::FloatIterator,
254}
255
256impl LaneTypeIterator {
257    /// Create a new lane type iterator.
258    fn new() -> Self {
259        Self {
260            int_iter: shared_types::IntIterator::new(),
261            float_iter: shared_types::FloatIterator::new(),
262        }
263    }
264}
265
266impl Iterator for LaneTypeIterator {
267    type Item = LaneType;
268    fn next(&mut self) -> Option<Self::Item> {
269        if let Some(i) = self.int_iter.next() {
270            Some(LaneType::from(i))
271        } else if let Some(f) = self.float_iter.next() {
272            Some(LaneType::from(f))
273        } else {
274            None
275        }
276    }
277}
278
279/// A concrete SIMD vector type.
280///
281/// A vector type has a lane type which is an instance of `LaneType`,
282/// and a positive number of lanes.
283#[derive(Clone, PartialEq, Eq, Hash)]
284pub(crate) struct VectorType {
285    base: LaneType,
286    lanes: u64,
287}
288
289impl VectorType {
290    /// Initialize a new integer type with `n` bits.
291    pub fn new(base: LaneType, lanes: u64) -> Self {
292        Self { base, lanes }
293    }
294
295    /// Return a string containing the documentation comment for this vector type.
296    pub fn doc(&self) -> String {
297        format!(
298            "A SIMD vector with {} lanes containing a `{}` each.",
299            self.lane_count(),
300            self.base
301        )
302    }
303
304    /// Return the number of bits in a lane.
305    pub fn lane_bits(&self) -> u64 {
306        self.base.lane_bits()
307    }
308
309    /// Return the number of lanes.
310    pub fn lane_count(&self) -> u64 {
311        self.lanes
312    }
313
314    /// Return the lane type.
315    pub fn lane_type(&self) -> LaneType {
316        self.base
317    }
318
319    /// Find the unique number associated with this vector type.
320    ///
321    /// Vector types are encoded with the lane type in the low 4 bits and
322    /// log2(lanes) in the high 4 bits, giving a range of 2-256 lanes.
323    pub fn number(&self) -> u16 {
324        let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros();
325        let base_num = u32::from(self.base.number());
326        let num = (lanes_log_2 << 4) + base_num;
327        num as u16
328    }
329}
330
331impl fmt::Display for VectorType {
332    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
333        write!(f, "{}x{}", self.base, self.lane_count())
334    }
335}
336
337impl fmt::Debug for VectorType {
338    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
339        write!(
340            f,
341            "VectorType(base={}, lanes={})",
342            self.base,
343            self.lane_count()
344        )
345    }
346}
347
348/// A concrete dynamic SIMD vector type.
349///
350/// A vector type has a lane type which is an instance of `LaneType`,
351/// and a positive number of lanes.
352#[derive(Clone, PartialEq, Eq, Hash)]
353pub(crate) struct DynamicVectorType {
354    base: LaneType,
355    unscaled_lanes: u64,
356}
357
358impl DynamicVectorType {
359    /// Initialize a new type with `base` lane type and a minimum number of lanes.
360    pub fn new(base: LaneType, unscaled_lanes: u64) -> Self {
361        Self {
362            base,
363            unscaled_lanes,
364        }
365    }
366
367    /// Return a string containing the documentation comment for this vector type.
368    pub fn doc(&self) -> String {
369        format!(
370            "A dynamically-scaled SIMD vector with a minimum of {} lanes containing `{}` bits each.",
371            self.unscaled_lanes,
372            self.base
373        )
374    }
375
376    /// Return the number of bits in a lane.
377    pub fn lane_bits(&self) -> u64 {
378        self.base.lane_bits()
379    }
380
381    /// Return the number of lanes.
382    pub fn minimum_lane_count(&self) -> u64 {
383        self.unscaled_lanes
384    }
385
386    /// Return the lane type.
387    pub fn lane_type(&self) -> LaneType {
388        self.base
389    }
390
391    /// Find the unique number associated with this vector type.
392    ///
393    /// Dynamic vector types are encoded in the same manner as `VectorType`,
394    /// with lane type in the low 4 bits and the log2(lane_count). We add the
395    /// `VECTOR_BASE` to move these numbers into the range beyond the fixed
396    /// SIMD types.
397    pub fn number(&self) -> u16 {
398        let base_num = u32::from(self.base.number());
399        let lanes_log_2: u32 = 63 - self.minimum_lane_count().leading_zeros();
400        let num = 0x80 + (lanes_log_2 << 4) + base_num;
401        num as u16
402    }
403}
404
405impl fmt::Display for DynamicVectorType {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        write!(f, "{}x{}xN", self.base, self.minimum_lane_count())
408    }
409}
410
411impl fmt::Debug for DynamicVectorType {
412    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413        write!(
414            f,
415            "DynamicVectorType(base={}, lanes={})",
416            self.base,
417            self.minimum_lane_count(),
418        )
419    }
420}