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 | R32 => 5,
61            I64 | F64 | R64 => 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 | R32 => 32,
73            I64 | F64 | R64 => 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            R32 | R64 => panic!("Reference types are not truthy"),
143            I128 | F128 => I128,
144            _ => I8,
145        })
146    }
147
148    /// Get the type of a comparison result for the given type. For vectors this will be a vector
149    /// with the same number of lanes and integer elements, and for scalar types this will be `i8`,
150    /// which is the result type of comparisons.
151    pub fn as_truthy(self) -> Self {
152        if !self.is_vector() {
153            I8
154        } else {
155            self.as_truthy_pedantic()
156        }
157    }
158
159    /// Get a type with the same number of lanes as this type, but with the lanes replaced by
160    /// integers of the same size.
161    pub fn as_int(self) -> Self {
162        self.replace_lanes(match self.lane_type() {
163            I8 => I8,
164            I16 | F16 => I16,
165            I32 | F32 | R32 => I32,
166            I64 | F64 | R64 => I64,
167            I128 | F128 => I128,
168            _ => unimplemented!(),
169        })
170    }
171
172    /// Get a type with the same number of lanes as this type, but with lanes that are half the
173    /// number of bits.
174    pub fn half_width(self) -> Option<Self> {
175        Some(self.replace_lanes(match self.lane_type() {
176            I16 => I8,
177            I32 => I16,
178            I64 => I32,
179            I128 => I64,
180            F32 => F16,
181            F64 => F32,
182            F128 => F64,
183            _ => return None,
184        }))
185    }
186
187    /// Get a type with the same number of lanes as this type, but with lanes that are twice the
188    /// number of bits.
189    pub fn double_width(self) -> Option<Self> {
190        Some(self.replace_lanes(match self.lane_type() {
191            I8 => I16,
192            I16 => I32,
193            I32 => I64,
194            I64 => I128,
195            F16 => F32,
196            F32 => F64,
197            F64 => F128,
198            _ => return None,
199        }))
200    }
201
202    /// Is this the INVALID type?
203    pub fn is_invalid(self) -> bool {
204        self == INVALID
205    }
206
207    /// Is this a special type?
208    pub fn is_special(self) -> bool {
209        self.0 < constants::LANE_BASE
210    }
211
212    /// Is this a lane type?
213    ///
214    /// This is a scalar type that can also appear as the lane type of a SIMD vector.
215    pub fn is_lane(self) -> bool {
216        constants::LANE_BASE <= self.0 && self.0 < constants::VECTOR_BASE
217    }
218
219    /// Is this a SIMD vector type?
220    ///
221    /// A vector type has 2 or more lanes.
222    pub fn is_vector(self) -> bool {
223        self.0 >= constants::VECTOR_BASE && !self.is_dynamic_vector()
224    }
225
226    /// Is this a SIMD vector type with a runtime number of lanes?
227    pub fn is_dynamic_vector(self) -> bool {
228        self.0 >= constants::DYNAMIC_VECTOR_BASE
229    }
230
231    /// Is this a scalar integer type?
232    pub fn is_int(self) -> bool {
233        match self {
234            I8 | I16 | I32 | I64 | I128 => true,
235            _ => false,
236        }
237    }
238
239    /// Is this a scalar floating point type?
240    pub fn is_float(self) -> bool {
241        match self {
242            F16 | F32 | F64 | F128 => true,
243            _ => false,
244        }
245    }
246
247    /// Is this a ref type?
248    pub fn is_ref(self) -> bool {
249        match self {
250            R32 | R64 => true,
251            _ => false,
252        }
253    }
254
255    /// Get log_2 of the number of lanes in this SIMD vector type.
256    ///
257    /// All SIMD types have a lane count that is a power of two and no larger than 256, so this
258    /// will be a number in the range 0-8.
259    ///
260    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 0.
261    pub fn log2_lane_count(self) -> u32 {
262        if self.is_dynamic_vector() {
263            0
264        } else {
265            (self.0.saturating_sub(constants::LANE_BASE) >> 4) as u32
266        }
267    }
268
269    /// Get log_2 of the number of lanes in this vector/dynamic type.
270    pub fn log2_min_lane_count(self) -> u32 {
271        if self.is_dynamic_vector() {
272            (self
273                .0
274                .saturating_sub(constants::VECTOR_BASE + constants::LANE_BASE)
275                >> 4) as u32
276        } else {
277            self.log2_lane_count()
278        }
279    }
280
281    /// Get the number of lanes in this SIMD vector type.
282    ///
283    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1.
284    pub fn lane_count(self) -> u32 {
285        if self.is_dynamic_vector() {
286            0
287        } else {
288            1 << self.log2_lane_count()
289        }
290    }
291
292    /// Get the total number of bits used to represent this type.
293    pub fn bits(self) -> u32 {
294        if self.is_dynamic_vector() {
295            0
296        } else {
297            self.lane_bits() * self.lane_count()
298        }
299    }
300
301    /// Get the minimum of lanes in this SIMD vector type, this supports both fixed and
302    /// dynamic types.
303    pub fn min_lane_count(self) -> u32 {
304        if self.is_dynamic_vector() {
305            1 << self.log2_min_lane_count()
306        } else {
307            1 << self.log2_lane_count()
308        }
309    }
310
311    /// Get the minimum number of bits used to represent this type.
312    pub fn min_bits(self) -> u32 {
313        if self.is_dynamic_vector() {
314            self.lane_bits() * self.min_lane_count()
315        } else {
316            self.bits()
317        }
318    }
319
320    /// Get the number of bytes used to store this type in memory.
321    pub fn bytes(self) -> u32 {
322        (self.bits() + 7) / 8
323    }
324
325    /// Get a SIMD vector type with `n` times more lanes than this one.
326    ///
327    /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes.
328    ///
329    /// If this is already a SIMD vector type, this produces a SIMD vector type with `n *
330    /// self.lane_count()` lanes.
331    pub fn by(self, n: u32) -> Option<Self> {
332        if self.is_dynamic_vector() {
333            return None;
334        }
335        if self.lane_bits() == 0 || !n.is_power_of_two() {
336            return None;
337        }
338        let log2_lanes: u32 = n.trailing_zeros();
339        let new_type = u32::from(self.0) + (log2_lanes << 4);
340        if new_type < constants::DYNAMIC_VECTOR_BASE as u32
341            && (new_type as u16) < constants::DYNAMIC_VECTOR_BASE
342        {
343            Some(Self(new_type as u16))
344        } else {
345            None
346        }
347    }
348
349    /// Convert a fixed vector type to a dynamic one.
350    pub fn vector_to_dynamic(self) -> Option<Self> {
351        assert!(self.is_vector());
352        if self.bits() > 256 {
353            return None;
354        }
355        let new_ty = self.0 + constants::VECTOR_BASE;
356        let ty = Some(Self(new_ty));
357        assert!(ty.unwrap().is_dynamic_vector());
358        return ty;
359    }
360
361    /// Convert a dynamic vector type to a fixed one.
362    pub fn dynamic_to_vector(self) -> Option<Self> {
363        assert!(self.is_dynamic_vector());
364        Some(Self(self.0 - constants::VECTOR_BASE))
365    }
366
367    /// Split the lane width in half and double the number of lanes to maintain the same bit-width.
368    ///
369    /// If this is a scalar type of `n` bits, it produces a SIMD vector type of `(n/2)x2`.
370    pub fn split_lanes(self) -> Option<Self> {
371        match self.half_width() {
372            Some(half_width) => half_width.by(2),
373            None => None,
374        }
375    }
376
377    /// Merge lanes to half the number of lanes and double the lane width to maintain the same
378    /// bit-width.
379    ///
380    /// If this is a scalar type, it will return `None`.
381    pub fn merge_lanes(self) -> Option<Self> {
382        match self.double_width() {
383            Some(double_width) => {
384                if double_width.is_vector() && !double_width.is_dynamic_vector() {
385                    Some(Self(double_width.0 - 0x10))
386                } else {
387                    None
388                }
389            }
390            None => None,
391        }
392    }
393
394    /// Index of this type, for use with hash tables etc.
395    pub fn index(self) -> usize {
396        usize::from(self.0)
397    }
398
399    /// True iff:
400    ///
401    /// 1. `self.lane_count() == other.lane_count()` and
402    /// 2. `self.lane_bits() >= other.lane_bits()`
403    pub fn wider_or_equal(self, other: Self) -> bool {
404        self.lane_count() == other.lane_count() && self.lane_bits() >= other.lane_bits()
405    }
406
407    /// Return the pointer type for the given target triple.
408    pub fn triple_pointer_type(triple: &Triple) -> Self {
409        match triple.pointer_width() {
410            Ok(PointerWidth::U16) => I16,
411            Ok(PointerWidth::U32) => I32,
412            Ok(PointerWidth::U64) => I64,
413            Err(()) => panic!("unable to determine architecture pointer width"),
414        }
415    }
416
417    /// Gets a bit-level representation of the type. Used only
418    /// internally for efficiently storing types.
419    pub(crate) fn repr(self) -> u16 {
420        self.0
421    }
422
423    /// Converts from a bit-level representation of the type back to a
424    /// `Type`.
425    pub(crate) fn from_repr(bits: u16) -> Type {
426        Type(bits)
427    }
428}
429
430impl Display for Type {
431    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
432        if self.is_int() {
433            write!(f, "i{}", self.lane_bits())
434        } else if self.is_float() {
435            write!(f, "f{}", self.lane_bits())
436        } else if self.is_vector() {
437            write!(f, "{}x{}", self.lane_type(), self.lane_count())
438        } else if self.is_dynamic_vector() {
439            write!(f, "{:?}x{}xN", self.lane_type(), self.min_lane_count())
440        } else if self.is_ref() {
441            write!(f, "r{}", self.lane_bits())
442        } else {
443            match *self {
444                INVALID => panic!("INVALID encountered"),
445                _ => panic!("Unknown Type(0x{:x})", self.0),
446            }
447        }
448    }
449}
450
451impl Debug for Type {
452    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
453        if self.is_int() {
454            write!(f, "types::I{}", self.lane_bits())
455        } else if self.is_float() {
456            write!(f, "types::F{}", self.lane_bits())
457        } else if self.is_vector() {
458            write!(f, "{:?}X{}", self.lane_type(), self.lane_count())
459        } else if self.is_dynamic_vector() {
460            write!(f, "{:?}X{}XN", self.lane_type(), self.min_lane_count())
461        } else if self.is_ref() {
462            write!(f, "types::R{}", self.lane_bits())
463        } else {
464            match *self {
465                INVALID => write!(f, "types::INVALID"),
466                _ => write!(f, "Type(0x{:x})", self.0),
467            }
468        }
469    }
470}
471
472impl Default for Type {
473    fn default() -> Self {
474        INVALID
475    }
476}
477
478#[cfg(test)]
479mod tests {
480    use super::*;
481    use alloc::string::ToString;
482
483    #[test]
484    fn basic_scalars() {
485        assert_eq!(INVALID, INVALID.lane_type());
486        assert_eq!(0, INVALID.bits());
487        assert_eq!(I8, I8.lane_type());
488        assert_eq!(I16, I16.lane_type());
489        assert_eq!(I32, I32.lane_type());
490        assert_eq!(I64, I64.lane_type());
491        assert_eq!(I128, I128.lane_type());
492        assert_eq!(F32, F32.lane_type());
493        assert_eq!(F16, F16.lane_type());
494        assert_eq!(F64, F64.lane_type());
495        assert_eq!(F128, F128.lane_type());
496        assert_eq!(I32, I32X4.lane_type());
497        assert_eq!(F64, F64X2.lane_type());
498        assert_eq!(R32, R32.lane_type());
499        assert_eq!(R64, R64.lane_type());
500
501        assert_eq!(INVALID.lane_bits(), 0);
502        assert_eq!(I8.lane_bits(), 8);
503        assert_eq!(I16.lane_bits(), 16);
504        assert_eq!(I32.lane_bits(), 32);
505        assert_eq!(I64.lane_bits(), 64);
506        assert_eq!(I128.lane_bits(), 128);
507        assert_eq!(F16.lane_bits(), 16);
508        assert_eq!(F32.lane_bits(), 32);
509        assert_eq!(F64.lane_bits(), 64);
510        assert_eq!(F128.lane_bits(), 128);
511        assert_eq!(R32.lane_bits(), 32);
512        assert_eq!(R64.lane_bits(), 64);
513    }
514
515    #[test]
516    fn typevar_functions() {
517        assert_eq!(INVALID.half_width(), None);
518        assert_eq!(INVALID.half_width(), None);
519        assert_eq!(I8.half_width(), None);
520        assert_eq!(I16.half_width(), Some(I8));
521        assert_eq!(I32.half_width(), Some(I16));
522        assert_eq!(I32X4.half_width(), Some(I16X4));
523        assert_eq!(I64.half_width(), Some(I32));
524        assert_eq!(I128.half_width(), Some(I64));
525        assert_eq!(F16.half_width(), None);
526        assert_eq!(F32.half_width(), Some(F16));
527        assert_eq!(F64.half_width(), Some(F32));
528        assert_eq!(F128.half_width(), Some(F64));
529
530        assert_eq!(INVALID.double_width(), None);
531        assert_eq!(I8.double_width(), Some(I16));
532        assert_eq!(I16.double_width(), Some(I32));
533        assert_eq!(I32.double_width(), Some(I64));
534        assert_eq!(I32X4.double_width(), Some(I64X4));
535        assert_eq!(I64.double_width(), Some(I128));
536        assert_eq!(I128.double_width(), None);
537        assert_eq!(F16.double_width(), Some(F32));
538        assert_eq!(F32.double_width(), Some(F64));
539        assert_eq!(F64.double_width(), Some(F128));
540        assert_eq!(F128.double_width(), None);
541    }
542
543    #[test]
544    fn vectors() {
545        let big = F64.by(256).unwrap();
546        assert_eq!(big.lane_bits(), 64);
547        assert_eq!(big.lane_count(), 256);
548        assert_eq!(big.bits(), 64 * 256);
549
550        // Check that the generated constants match the computed vector types.
551        assert_eq!(I32.by(4), Some(I32X4));
552        assert_eq!(F64.by(8), Some(F64X8));
553    }
554
555    #[test]
556    fn dynamic_vectors() {
557        // Identification.
558        assert_eq!(I8X16XN.is_dynamic_vector(), true);
559        assert_eq!(F32X8XN.is_dynamic_vector(), true);
560        assert_eq!(F64X4XN.is_dynamic_vector(), true);
561        assert_eq!(I128X2XN.is_dynamic_vector(), true);
562
563        // Lane counts.
564        assert_eq!(I16X8XN.lane_count(), 0);
565        assert_eq!(I16X8XN.min_lane_count(), 8);
566
567        // Change lane counts
568        assert_eq!(I8X8XN.by(2), None);
569
570        // Conversions to and from vectors.
571        assert_eq!(I8.by(16).unwrap().vector_to_dynamic(), Some(I8X16XN));
572        assert_eq!(I16.by(8).unwrap().vector_to_dynamic(), Some(I16X8XN));
573        assert_eq!(F16.by(8).unwrap().vector_to_dynamic(), Some(F16X8XN));
574        assert_eq!(I32.by(4).unwrap().vector_to_dynamic(), Some(I32X4XN));
575        assert_eq!(F32.by(4).unwrap().vector_to_dynamic(), Some(F32X4XN));
576        assert_eq!(F64.by(2).unwrap().vector_to_dynamic(), Some(F64X2XN));
577        assert_eq!(I128.by(2).unwrap().vector_to_dynamic(), Some(I128X2XN));
578        assert_eq!(F128.by(2).unwrap().vector_to_dynamic(), Some(F128X2XN));
579
580        assert_eq!(I128X2XN.dynamic_to_vector(), Some(I128X2));
581        assert_eq!(F16X4XN.dynamic_to_vector(), Some(F16X4));
582        assert_eq!(F32X4XN.dynamic_to_vector(), Some(F32X4));
583        assert_eq!(F64X4XN.dynamic_to_vector(), Some(F64X4));
584        assert_eq!(F128X4XN.dynamic_to_vector(), Some(F128X4));
585        assert_eq!(I32X2XN.dynamic_to_vector(), Some(I32X2));
586        assert_eq!(I32X8XN.dynamic_to_vector(), Some(I32X8));
587        assert_eq!(I16X16XN.dynamic_to_vector(), Some(I16X16));
588        assert_eq!(I8X32XN.dynamic_to_vector(), Some(I8X32));
589
590        assert_eq!(I8X64.vector_to_dynamic(), None);
591        assert_eq!(F32X16.vector_to_dynamic(), None);
592        assert_eq!(I64X8.vector_to_dynamic(), None);
593        assert_eq!(I128X4.vector_to_dynamic(), None);
594    }
595
596    #[test]
597    fn format_scalars() {
598        assert_eq!(I8.to_string(), "i8");
599        assert_eq!(I16.to_string(), "i16");
600        assert_eq!(I32.to_string(), "i32");
601        assert_eq!(I64.to_string(), "i64");
602        assert_eq!(I128.to_string(), "i128");
603        assert_eq!(F32.to_string(), "f32");
604        assert_eq!(F64.to_string(), "f64");
605        assert_eq!(R32.to_string(), "r32");
606        assert_eq!(R64.to_string(), "r64");
607    }
608
609    #[test]
610    fn format_vectors() {
611        assert_eq!(I8.by(64).unwrap().to_string(), "i8x64");
612        assert_eq!(F64.by(2).unwrap().to_string(), "f64x2");
613        assert_eq!(I8.by(3), None);
614        assert_eq!(I8.by(512), None);
615        assert_eq!(INVALID.by(4), None);
616    }
617
618    #[test]
619    fn as_truthy() {
620        assert_eq!(I32X4.as_truthy(), I32X4);
621        assert_eq!(I32.as_truthy(), I8);
622        assert_eq!(I32X4.as_truthy_pedantic(), I32X4);
623        assert_eq!(I32.as_truthy_pedantic(), I32);
624    }
625
626    #[test]
627    fn int_from_size() {
628        assert_eq!(Type::int(0), None);
629        assert_eq!(Type::int(8), Some(I8));
630        assert_eq!(Type::int(33), None);
631        assert_eq!(Type::int(64), Some(I64));
632
633        assert_eq!(Type::int_with_byte_size(0), None);
634        assert_eq!(Type::int_with_byte_size(2), Some(I16));
635        assert_eq!(Type::int_with_byte_size(6), None);
636        assert_eq!(Type::int_with_byte_size(16), Some(I128));
637
638        // Ensure `int_with_byte_size` handles overflow properly
639        let evil = 0xE001_u16;
640        assert_eq!(evil.wrapping_mul(8), 8, "check the constant is correct");
641        assert_eq!(Type::int_with_byte_size(evil), None);
642    }
643}