cranelift_codegen/ir/
types.rs

1//! Common types for the Cranelift code generator.
2
3use core::fmt::{self, Debug, Display, Formatter};
4use cranelift_codegen_shared::constants;
5#[cfg(feature = "enable-serde")]
6use serde_derive::{Deserialize, Serialize};
7use target_lexicon::{PointerWidth, Triple};
8
9/// The type of an SSA value.
10///
11/// The `INVALID` type isn't a real type, and is used as a placeholder in the IR where a type
12/// field is present put no type is needed, such as the controlling type variable for a
13/// non-polymorphic instruction.
14///
15/// Basic integer types: `I8`, `I16`, `I32`, `I64`, and `I128`. These types are sign-agnostic.
16///
17/// Basic floating point types: `F16`, `F32`, `F64`, and `F128`. IEEE half, single, double, and quadruple precision.
18///
19/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float type.
20///
21/// Note that this is encoded in a `u16` currently for extensibility,
22/// but allows only 14 bits to be used due to some bitpacking tricks
23/// in the CLIF data structures.
24#[derive(Copy, Clone, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
26pub struct Type(u16);
27
28/// Not a valid type. Can't be loaded or stored. Can't be part of a SIMD vector.
29pub const INVALID: Type = Type(0);
30
31// Include code generated by `cranelift-codegen/meta/gen_types.rs`. This file contains constant
32// definitions for all the scalar types as well as common vector types for 64, 128, 256, and
33// 512-bit SIMD vectors.
34include!(concat!(env!("OUT_DIR"), "/types.rs"));
35
36impl Type {
37    /// Get the lane type of this SIMD vector type.
38    ///
39    /// A lane type is the same as a SIMD vector type with one lane, so it returns itself.
40    pub fn lane_type(self) -> Self {
41        if self.0 < constants::VECTOR_BASE {
42            self
43        } else {
44            Self(constants::LANE_BASE | (self.0 & 0x0f))
45        }
46    }
47
48    /// The type transformation that returns the lane type of a type variable; it is just a
49    /// renaming of lane_type() to be used in context where we think in terms of type variable
50    /// transformations.
51    pub fn lane_of(self) -> Self {
52        self.lane_type()
53    }
54
55    /// Get log_2 of the number of bits in a lane.
56    pub fn log2_lane_bits(self) -> u32 {
57        match self.lane_type() {
58            I8 => 3,
59            I16 | F16 => 4,
60            I32 | F32 => 5,
61            I64 | F64 => 6,
62            I128 | F128 => 7,
63            _ => 0,
64        }
65    }
66
67    /// Get the number of bits in a lane.
68    pub fn lane_bits(self) -> u32 {
69        match self.lane_type() {
70            I8 => 8,
71            I16 | F16 => 16,
72            I32 | F32 => 32,
73            I64 | F64 => 64,
74            I128 | F128 => 128,
75            _ => 0,
76        }
77    }
78
79    /// Get the (minimum, maximum) values represented by each lane in the type.
80    /// Note that these are returned as unsigned 'bit patterns'.
81    pub fn bounds(self, signed: bool) -> (u128, u128) {
82        if signed {
83            match self.lane_type() {
84                I8 => (i8::MIN as u128, i8::MAX as u128),
85                I16 => (i16::MIN as u128, i16::MAX as u128),
86                I32 => (i32::MIN as u128, i32::MAX as u128),
87                I64 => (i64::MIN as u128, i64::MAX as u128),
88                I128 => (i128::MIN as u128, i128::MAX as u128),
89                _ => unimplemented!(),
90            }
91        } else {
92            match self.lane_type() {
93                I8 => (u8::MIN as u128, u8::MAX as u128),
94                I16 => (u16::MIN as u128, u16::MAX as u128),
95                I32 => (u32::MIN as u128, u32::MAX as u128),
96                I64 => (u64::MIN as u128, u64::MAX as u128),
97                I128 => (u128::MIN, u128::MAX),
98                _ => unimplemented!(),
99            }
100        }
101    }
102
103    /// Get an integer type with the requested number of bits.
104    ///
105    /// For the same thing but in *bytes*, use [`Self::int_with_byte_size`].
106    pub fn int(bits: u16) -> Option<Self> {
107        match bits {
108            8 => Some(I8),
109            16 => Some(I16),
110            32 => Some(I32),
111            64 => Some(I64),
112            128 => Some(I128),
113            _ => None,
114        }
115    }
116
117    /// Get an integer type with the requested number of bytes.
118    ///
119    /// For the same thing but in *bits*, use [`Self::int`].
120    pub fn int_with_byte_size(bytes: u16) -> Option<Self> {
121        Self::int(bytes.checked_mul(8)?)
122    }
123
124    /// Get a type with the same number of lanes as `self`, but using `lane` as the lane type.
125    fn replace_lanes(self, lane: Self) -> Self {
126        debug_assert!(lane.is_lane() && !self.is_special());
127        Self((lane.0 & 0x0f) | (self.0 & 0xf0))
128    }
129
130    /// Get a type with the same number of lanes as this type, but with the lanes replaced by
131    /// booleans of the same size.
132    ///
133    /// Lane types are treated as vectors with one lane, so they are converted to the multi-bit
134    /// boolean types.
135    pub fn as_truthy_pedantic(self) -> Self {
136        // Replace the low 4 bits with the boolean version, preserve the high 4 bits.
137        self.replace_lanes(match self.lane_type() {
138            I8 => I8,
139            I16 | F16 => I16,
140            I32 | F32 => I32,
141            I64 | F64 => I64,
142            I128 | F128 => I128,
143            _ => I8,
144        })
145    }
146
147    /// Get the type of a comparison result for the given type. For vectors this will be a vector
148    /// with the same number of lanes and integer elements, and for scalar types this will be `i8`,
149    /// which is the result type of comparisons.
150    pub fn as_truthy(self) -> Self {
151        if !self.is_vector() {
152            I8
153        } else {
154            self.as_truthy_pedantic()
155        }
156    }
157
158    /// Get a type with the same number of lanes as this type, but with the lanes replaced by
159    /// integers of the same size.
160    pub fn as_int(self) -> Self {
161        self.replace_lanes(match self.lane_type() {
162            I8 => I8,
163            I16 | F16 => I16,
164            I32 | F32 => I32,
165            I64 | F64 => I64,
166            I128 | F128 => I128,
167            _ => unimplemented!(),
168        })
169    }
170
171    /// Get a type with the same number of lanes as this type, but with lanes that are half the
172    /// number of bits.
173    pub fn half_width(self) -> Option<Self> {
174        Some(self.replace_lanes(match self.lane_type() {
175            I16 => I8,
176            I32 => I16,
177            I64 => I32,
178            I128 => I64,
179            F32 => F16,
180            F64 => F32,
181            F128 => F64,
182            _ => return None,
183        }))
184    }
185
186    /// Get a type with the same number of lanes as this type, but with lanes that are twice the
187    /// number of bits.
188    pub fn double_width(self) -> Option<Self> {
189        Some(self.replace_lanes(match self.lane_type() {
190            I8 => I16,
191            I16 => I32,
192            I32 => I64,
193            I64 => I128,
194            F16 => F32,
195            F32 => F64,
196            F64 => F128,
197            _ => return None,
198        }))
199    }
200
201    /// Is this the INVALID type?
202    pub fn is_invalid(self) -> bool {
203        self == INVALID
204    }
205
206    /// Is this a special type?
207    pub fn is_special(self) -> bool {
208        self.0 < constants::LANE_BASE
209    }
210
211    /// Is this a lane type?
212    ///
213    /// This is a scalar type that can also appear as the lane type of a SIMD vector.
214    pub fn is_lane(self) -> bool {
215        constants::LANE_BASE <= self.0 && self.0 < constants::VECTOR_BASE
216    }
217
218    /// Is this a SIMD vector type?
219    ///
220    /// A vector type has 2 or more lanes.
221    pub fn is_vector(self) -> bool {
222        self.0 >= constants::VECTOR_BASE && !self.is_dynamic_vector()
223    }
224
225    /// Is this a SIMD vector type with a runtime number of lanes?
226    pub fn is_dynamic_vector(self) -> bool {
227        self.0 >= constants::DYNAMIC_VECTOR_BASE
228    }
229
230    /// Is this a scalar integer type?
231    pub fn is_int(self) -> bool {
232        match self {
233            I8 | I16 | I32 | I64 | I128 => true,
234            _ => false,
235        }
236    }
237
238    /// Is this a scalar floating point type?
239    pub fn is_float(self) -> bool {
240        match self {
241            F16 | F32 | F64 | F128 => true,
242            _ => false,
243        }
244    }
245
246    /// Get log_2 of the number of lanes in this SIMD vector type.
247    ///
248    /// All SIMD types have a lane count that is a power of two and no larger than 256, so this
249    /// will be a number in the range 0-8.
250    ///
251    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 0.
252    pub fn log2_lane_count(self) -> u32 {
253        if self.is_dynamic_vector() {
254            0
255        } else {
256            (self.0.saturating_sub(constants::LANE_BASE) >> 4) as u32
257        }
258    }
259
260    /// Get log_2 of the number of lanes in this vector/dynamic type.
261    pub fn log2_min_lane_count(self) -> u32 {
262        if self.is_dynamic_vector() {
263            (self
264                .0
265                .saturating_sub(constants::VECTOR_BASE + constants::LANE_BASE)
266                >> 4) as u32
267        } else {
268            self.log2_lane_count()
269        }
270    }
271
272    /// Get the number of lanes in this SIMD vector type.
273    ///
274    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1.
275    pub fn lane_count(self) -> u32 {
276        if self.is_dynamic_vector() {
277            0
278        } else {
279            1 << self.log2_lane_count()
280        }
281    }
282
283    /// Get the total number of bits used to represent this type.
284    pub fn bits(self) -> u32 {
285        if self.is_dynamic_vector() {
286            0
287        } else {
288            self.lane_bits() * self.lane_count()
289        }
290    }
291
292    /// Get the minimum of lanes in this SIMD vector type, this supports both fixed and
293    /// dynamic types.
294    pub fn min_lane_count(self) -> u32 {
295        if self.is_dynamic_vector() {
296            1 << self.log2_min_lane_count()
297        } else {
298            1 << self.log2_lane_count()
299        }
300    }
301
302    /// Get the minimum number of bits used to represent this type.
303    pub fn min_bits(self) -> u32 {
304        if self.is_dynamic_vector() {
305            self.lane_bits() * self.min_lane_count()
306        } else {
307            self.bits()
308        }
309    }
310
311    /// Get the number of bytes used to store this type in memory.
312    pub fn bytes(self) -> u32 {
313        (self.bits() + 7) / 8
314    }
315
316    /// Get a SIMD vector type with `n` times more lanes than this one.
317    ///
318    /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes.
319    ///
320    /// If this is already a SIMD vector type, this produces a SIMD vector type with `n *
321    /// self.lane_count()` lanes.
322    pub fn by(self, n: u32) -> Option<Self> {
323        if self.is_dynamic_vector() {
324            return None;
325        }
326        if self.lane_bits() == 0 || !n.is_power_of_two() {
327            return None;
328        }
329        let log2_lanes: u32 = n.trailing_zeros();
330        let new_type = u32::from(self.0) + (log2_lanes << 4);
331        if new_type < constants::DYNAMIC_VECTOR_BASE as u32
332            && (new_type as u16) < constants::DYNAMIC_VECTOR_BASE
333        {
334            Some(Self(new_type as u16))
335        } else {
336            None
337        }
338    }
339
340    /// Convert a fixed vector type to a dynamic one.
341    pub fn vector_to_dynamic(self) -> Option<Self> {
342        assert!(self.is_vector());
343        if self.bits() > 256 {
344            return None;
345        }
346        let new_ty = self.0 + constants::VECTOR_BASE;
347        let ty = Some(Self(new_ty));
348        assert!(ty.unwrap().is_dynamic_vector());
349        return ty;
350    }
351
352    /// Convert a dynamic vector type to a fixed one.
353    pub fn dynamic_to_vector(self) -> Option<Self> {
354        assert!(self.is_dynamic_vector());
355        Some(Self(self.0 - constants::VECTOR_BASE))
356    }
357
358    /// Split the lane width in half and double the number of lanes to maintain the same bit-width.
359    ///
360    /// If this is a scalar type of `n` bits, it produces a SIMD vector type of `(n/2)x2`.
361    pub fn split_lanes(self) -> Option<Self> {
362        match self.half_width() {
363            Some(half_width) => half_width.by(2),
364            None => None,
365        }
366    }
367
368    /// Merge lanes to half the number of lanes and double the lane width to maintain the same
369    /// bit-width.
370    ///
371    /// If this is a scalar type, it will return `None`.
372    pub fn merge_lanes(self) -> Option<Self> {
373        match self.double_width() {
374            Some(double_width) => {
375                if double_width.is_vector() && !double_width.is_dynamic_vector() {
376                    Some(Self(double_width.0 - 0x10))
377                } else {
378                    None
379                }
380            }
381            None => None,
382        }
383    }
384
385    /// Index of this type, for use with hash tables etc.
386    pub fn index(self) -> usize {
387        usize::from(self.0)
388    }
389
390    /// True iff:
391    ///
392    /// 1. `self.lane_count() == other.lane_count()` and
393    /// 2. `self.lane_bits() >= other.lane_bits()`
394    pub fn wider_or_equal(self, other: Self) -> bool {
395        self.lane_count() == other.lane_count() && self.lane_bits() >= other.lane_bits()
396    }
397
398    /// Return the pointer type for the given target triple.
399    pub fn triple_pointer_type(triple: &Triple) -> Self {
400        match triple.pointer_width() {
401            Ok(PointerWidth::U16) => I16,
402            Ok(PointerWidth::U32) => I32,
403            Ok(PointerWidth::U64) => I64,
404            Err(()) => panic!("unable to determine architecture pointer width"),
405        }
406    }
407
408    /// Gets a bit-level representation of the type. Used only
409    /// internally for efficiently storing types.
410    pub(crate) fn repr(self) -> u16 {
411        self.0
412    }
413
414    /// Converts from a bit-level representation of the type back to a
415    /// `Type`.
416    pub(crate) fn from_repr(bits: u16) -> Type {
417        Type(bits)
418    }
419}
420
421impl Display for Type {
422    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
423        if self.is_int() {
424            write!(f, "i{}", self.lane_bits())
425        } else if self.is_float() {
426            write!(f, "f{}", self.lane_bits())
427        } else if self.is_vector() {
428            write!(f, "{}x{}", self.lane_type(), self.lane_count())
429        } else if self.is_dynamic_vector() {
430            write!(f, "{:?}x{}xN", self.lane_type(), self.min_lane_count())
431        } else {
432            match *self {
433                INVALID => panic!("INVALID encountered"),
434                _ => panic!("Unknown Type(0x{:x})", self.0),
435            }
436        }
437    }
438}
439
440impl Debug for Type {
441    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
442        if self.is_int() {
443            write!(f, "types::I{}", self.lane_bits())
444        } else if self.is_float() {
445            write!(f, "types::F{}", self.lane_bits())
446        } else if self.is_vector() {
447            write!(f, "{:?}X{}", self.lane_type(), self.lane_count())
448        } else if self.is_dynamic_vector() {
449            write!(f, "{:?}X{}XN", self.lane_type(), self.min_lane_count())
450        } else {
451            match *self {
452                INVALID => write!(f, "types::INVALID"),
453                _ => write!(f, "Type(0x{:x})", self.0),
454            }
455        }
456    }
457}
458
459impl Default for Type {
460    fn default() -> Self {
461        INVALID
462    }
463}
464
465#[cfg(test)]
466mod tests {
467    use super::*;
468    use alloc::string::ToString;
469
470    #[test]
471    fn basic_scalars() {
472        assert_eq!(INVALID, INVALID.lane_type());
473        assert_eq!(0, INVALID.bits());
474        assert_eq!(I8, I8.lane_type());
475        assert_eq!(I16, I16.lane_type());
476        assert_eq!(I32, I32.lane_type());
477        assert_eq!(I64, I64.lane_type());
478        assert_eq!(I128, I128.lane_type());
479        assert_eq!(F32, F32.lane_type());
480        assert_eq!(F16, F16.lane_type());
481        assert_eq!(F64, F64.lane_type());
482        assert_eq!(F128, F128.lane_type());
483        assert_eq!(I32, I32X4.lane_type());
484        assert_eq!(F64, F64X2.lane_type());
485
486        assert_eq!(INVALID.lane_bits(), 0);
487        assert_eq!(I8.lane_bits(), 8);
488        assert_eq!(I16.lane_bits(), 16);
489        assert_eq!(I32.lane_bits(), 32);
490        assert_eq!(I64.lane_bits(), 64);
491        assert_eq!(I128.lane_bits(), 128);
492        assert_eq!(F16.lane_bits(), 16);
493        assert_eq!(F32.lane_bits(), 32);
494        assert_eq!(F64.lane_bits(), 64);
495        assert_eq!(F128.lane_bits(), 128);
496    }
497
498    #[test]
499    fn typevar_functions() {
500        assert_eq!(INVALID.half_width(), None);
501        assert_eq!(INVALID.half_width(), None);
502        assert_eq!(I8.half_width(), None);
503        assert_eq!(I16.half_width(), Some(I8));
504        assert_eq!(I32.half_width(), Some(I16));
505        assert_eq!(I32X4.half_width(), Some(I16X4));
506        assert_eq!(I64.half_width(), Some(I32));
507        assert_eq!(I128.half_width(), Some(I64));
508        assert_eq!(F16.half_width(), None);
509        assert_eq!(F32.half_width(), Some(F16));
510        assert_eq!(F64.half_width(), Some(F32));
511        assert_eq!(F128.half_width(), Some(F64));
512
513        assert_eq!(INVALID.double_width(), None);
514        assert_eq!(I8.double_width(), Some(I16));
515        assert_eq!(I16.double_width(), Some(I32));
516        assert_eq!(I32.double_width(), Some(I64));
517        assert_eq!(I32X4.double_width(), Some(I64X4));
518        assert_eq!(I64.double_width(), Some(I128));
519        assert_eq!(I128.double_width(), None);
520        assert_eq!(F16.double_width(), Some(F32));
521        assert_eq!(F32.double_width(), Some(F64));
522        assert_eq!(F64.double_width(), Some(F128));
523        assert_eq!(F128.double_width(), None);
524    }
525
526    #[test]
527    fn vectors() {
528        let big = F64.by(256).unwrap();
529        assert_eq!(big.lane_bits(), 64);
530        assert_eq!(big.lane_count(), 256);
531        assert_eq!(big.bits(), 64 * 256);
532
533        // Check that the generated constants match the computed vector types.
534        assert_eq!(I32.by(4), Some(I32X4));
535        assert_eq!(F64.by(8), Some(F64X8));
536    }
537
538    #[test]
539    fn dynamic_vectors() {
540        // Identification.
541        assert_eq!(I8X16XN.is_dynamic_vector(), true);
542        assert_eq!(F32X8XN.is_dynamic_vector(), true);
543        assert_eq!(F64X4XN.is_dynamic_vector(), true);
544        assert_eq!(I128X2XN.is_dynamic_vector(), true);
545
546        // Lane counts.
547        assert_eq!(I16X8XN.lane_count(), 0);
548        assert_eq!(I16X8XN.min_lane_count(), 8);
549
550        // Change lane counts
551        assert_eq!(I8X8XN.by(2), None);
552
553        // Conversions to and from vectors.
554        assert_eq!(I8.by(16).unwrap().vector_to_dynamic(), Some(I8X16XN));
555        assert_eq!(I16.by(8).unwrap().vector_to_dynamic(), Some(I16X8XN));
556        assert_eq!(F16.by(8).unwrap().vector_to_dynamic(), Some(F16X8XN));
557        assert_eq!(I32.by(4).unwrap().vector_to_dynamic(), Some(I32X4XN));
558        assert_eq!(F32.by(4).unwrap().vector_to_dynamic(), Some(F32X4XN));
559        assert_eq!(F64.by(2).unwrap().vector_to_dynamic(), Some(F64X2XN));
560        assert_eq!(I128.by(2).unwrap().vector_to_dynamic(), Some(I128X2XN));
561        assert_eq!(F128.by(2).unwrap().vector_to_dynamic(), Some(F128X2XN));
562
563        assert_eq!(I128X2XN.dynamic_to_vector(), Some(I128X2));
564        assert_eq!(F16X4XN.dynamic_to_vector(), Some(F16X4));
565        assert_eq!(F32X4XN.dynamic_to_vector(), Some(F32X4));
566        assert_eq!(F64X4XN.dynamic_to_vector(), Some(F64X4));
567        assert_eq!(F128X4XN.dynamic_to_vector(), Some(F128X4));
568        assert_eq!(I32X2XN.dynamic_to_vector(), Some(I32X2));
569        assert_eq!(I32X8XN.dynamic_to_vector(), Some(I32X8));
570        assert_eq!(I16X16XN.dynamic_to_vector(), Some(I16X16));
571        assert_eq!(I8X32XN.dynamic_to_vector(), Some(I8X32));
572
573        assert_eq!(I8X64.vector_to_dynamic(), None);
574        assert_eq!(F32X16.vector_to_dynamic(), None);
575        assert_eq!(I64X8.vector_to_dynamic(), None);
576        assert_eq!(I128X4.vector_to_dynamic(), None);
577    }
578
579    #[test]
580    fn format_scalars() {
581        assert_eq!(I8.to_string(), "i8");
582        assert_eq!(I16.to_string(), "i16");
583        assert_eq!(I32.to_string(), "i32");
584        assert_eq!(I64.to_string(), "i64");
585        assert_eq!(I128.to_string(), "i128");
586        assert_eq!(F32.to_string(), "f32");
587        assert_eq!(F64.to_string(), "f64");
588    }
589
590    #[test]
591    fn format_vectors() {
592        assert_eq!(I8.by(64).unwrap().to_string(), "i8x64");
593        assert_eq!(F64.by(2).unwrap().to_string(), "f64x2");
594        assert_eq!(I8.by(3), None);
595        assert_eq!(I8.by(512), None);
596        assert_eq!(INVALID.by(4), None);
597    }
598
599    #[test]
600    fn as_truthy() {
601        assert_eq!(I32X4.as_truthy(), I32X4);
602        assert_eq!(I32.as_truthy(), I8);
603        assert_eq!(I32X4.as_truthy_pedantic(), I32X4);
604        assert_eq!(I32.as_truthy_pedantic(), I32);
605    }
606
607    #[test]
608    fn int_from_size() {
609        assert_eq!(Type::int(0), None);
610        assert_eq!(Type::int(8), Some(I8));
611        assert_eq!(Type::int(33), None);
612        assert_eq!(Type::int(64), Some(I64));
613
614        assert_eq!(Type::int_with_byte_size(0), None);
615        assert_eq!(Type::int_with_byte_size(2), Some(I16));
616        assert_eq!(Type::int_with_byte_size(6), None);
617        assert_eq!(Type::int_with_byte_size(16), Some(I128));
618
619        // Ensure `int_with_byte_size` handles overflow properly
620        let evil = 0xE001_u16;
621        assert_eq!(evil.wrapping_mul(8), 8, "check the constant is correct");
622        assert_eq!(Type::int_with_byte_size(evil), None);
623    }
624}