cranelift_codegen/ir/
types.rs

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