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