Skip to main content

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;
6use target_lexicon::{PointerWidth, Triple};
7
8/// The type of an SSA value.
9///
10/// The `INVALID` type isn't a real type, and is used as a placeholder in the IR where a type
11/// field is present put no type is needed, such as the controlling type variable for a
12/// non-polymorphic instruction.
13///
14/// Basic integer types: `I8`, `I16`, `I32`, `I64`, and `I128`. These types are sign-agnostic.
15///
16/// Basic floating point types: `F32` and `F64`. IEEE single and double precision.
17///
18/// Boolean types: `B1`, `B8`, `B16`, `B32`, `B64`, and `B128`. These all encode 'true' or 'false'. The
19/// larger types use redundant bits.
20///
21/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float/bool type.
22///
23#[derive(Copy, Clone, PartialEq, Eq, Hash)]
24pub struct Type(u8);
25
26/// Not a valid type. Can't be loaded or stored. Can't be part of a SIMD vector.
27pub const INVALID: Type = Type(0);
28
29// Include code generated by `cranelift-codegen/meta/gen_types.rs`. This file contains constant
30// definitions for all the scalar types as well as common vector types for 64, 128, 256, and
31// 512-bit SIMD vectors.
32include!(concat!(env!("OUT_DIR"), "/types.rs"));
33
34impl Type {
35    /// Get the lane type of this SIMD vector type.
36    ///
37    /// A lane type is the same as a SIMD vector type with one lane, so it returns itself.
38    pub fn lane_type(self) -> Self {
39        if self.0 < constants::VECTOR_BASE {
40            self
41        } else {
42            Self(constants::LANE_BASE | (self.0 & 0x0f))
43        }
44    }
45
46    /// The type transformation that returns the lane type of a type variable; it is just a
47    /// renaming of lane_type() to be used in context where we think in terms of type variable
48    /// transformations.
49    pub fn lane_of(self) -> Self {
50        self.lane_type()
51    }
52
53    /// Get log_2 of the number of bits in a lane.
54    pub fn log2_lane_bits(self) -> u8 {
55        match self.lane_type() {
56            B1 => 0,
57            B8 | I8 => 3,
58            B16 | I16 => 4,
59            B32 | I32 | F32 | R32 => 5,
60            B64 | I64 | F64 | R64 => 6,
61            B128 | I128 => 7,
62            _ => 0,
63        }
64    }
65
66    /// Get the number of bits in a lane.
67    pub fn lane_bits(self) -> u8 {
68        match self.lane_type() {
69            B1 => 1,
70            B8 | I8 => 8,
71            B16 | I16 => 16,
72            B32 | I32 | F32 | R32 => 32,
73            B64 | I64 | F64 | R64 => 64,
74            B128 | I128 => 128,
75            _ => 0,
76        }
77    }
78
79    /// Get an integer type with the requested number of bits.
80    pub fn int(bits: u16) -> Option<Self> {
81        match bits {
82            8 => Some(I8),
83            16 => Some(I16),
84            32 => Some(I32),
85            64 => Some(I64),
86            128 => Some(I128),
87            _ => None,
88        }
89    }
90
91    /// Get a type with the same number of lanes as `self`, but using `lane` as the lane type.
92    fn replace_lanes(self, lane: Self) -> Self {
93        debug_assert!(lane.is_lane() && !self.is_special());
94        Self((lane.0 & 0x0f) | (self.0 & 0xf0))
95    }
96
97    /// Get a type with the same number of lanes as this type, but with the lanes replaced by
98    /// booleans of the same size.
99    ///
100    /// Lane types are treated as vectors with one lane, so they are converted to the multi-bit
101    /// boolean types.
102    pub fn as_bool_pedantic(self) -> Self {
103        // Replace the low 4 bits with the boolean version, preserve the high 4 bits.
104        self.replace_lanes(match self.lane_type() {
105            B8 | I8 => B8,
106            B16 | I16 => B16,
107            B32 | I32 | F32 => B32,
108            B64 | I64 | F64 => B64,
109            R32 | R64 => panic!("Reference types should not convert to bool"),
110            B128 | I128 => B128,
111            _ => B1,
112        })
113    }
114
115    /// Get a type with the same number of lanes as this type, but with the lanes replaced by
116    /// booleans of the same size.
117    ///
118    /// Scalar types are all converted to `b1` which is usually what you want.
119    pub fn as_bool(self) -> Self {
120        if !self.is_vector() {
121            B1
122        } else {
123            self.as_bool_pedantic()
124        }
125    }
126
127    /// Get a type with the same number of lanes as this type, but with lanes that are half the
128    /// number of bits.
129    pub fn half_width(self) -> Option<Self> {
130        Some(self.replace_lanes(match self.lane_type() {
131            I16 => I8,
132            I32 => I16,
133            I64 => I32,
134            I128 => I64,
135            F64 => F32,
136            B16 => B8,
137            B32 => B16,
138            B64 => B32,
139            B128 => B64,
140            _ => return None,
141        }))
142    }
143
144    /// Get a type with the same number of lanes as this type, but with lanes that are twice the
145    /// number of bits.
146    pub fn double_width(self) -> Option<Self> {
147        Some(self.replace_lanes(match self.lane_type() {
148            I8 => I16,
149            I16 => I32,
150            I32 => I64,
151            I64 => I128,
152            F32 => F64,
153            B8 => B16,
154            B16 => B32,
155            B32 => B64,
156            B64 => B128,
157            _ => return None,
158        }))
159    }
160
161    /// Is this the INVALID type?
162    pub fn is_invalid(self) -> bool {
163        self == INVALID
164    }
165
166    /// Is this a special type?
167    pub fn is_special(self) -> bool {
168        self.0 < constants::LANE_BASE
169    }
170
171    /// Is this a lane type?
172    ///
173    /// This is a scalar type that can also appear as the lane type of a SIMD vector.
174    pub fn is_lane(self) -> bool {
175        constants::LANE_BASE <= self.0 && self.0 < constants::VECTOR_BASE
176    }
177
178    /// Is this a SIMD vector type?
179    ///
180    /// A vector type has 2 or more lanes.
181    pub fn is_vector(self) -> bool {
182        self.0 >= constants::VECTOR_BASE
183    }
184
185    /// Is this a scalar boolean type?
186    pub fn is_bool(self) -> bool {
187        match self {
188            B1 | B8 | B16 | B32 | B64 | B128 => true,
189            _ => false,
190        }
191    }
192
193    /// Is this a scalar integer type?
194    pub fn is_int(self) -> bool {
195        match self {
196            I8 | I16 | I32 | I64 | I128 => true,
197            _ => false,
198        }
199    }
200
201    /// Is this a scalar floating point type?
202    pub fn is_float(self) -> bool {
203        match self {
204            F32 | F64 => true,
205            _ => false,
206        }
207    }
208
209    /// Is this a CPU flags type?
210    pub fn is_flags(self) -> bool {
211        match self {
212            IFLAGS | FFLAGS => true,
213            _ => false,
214        }
215    }
216
217    /// Is this a ref type?
218    pub fn is_ref(self) -> bool {
219        match self {
220            R32 | R64 => true,
221            _ => false,
222        }
223    }
224
225    /// Get log_2 of the number of lanes in this SIMD vector type.
226    ///
227    /// All SIMD types have a lane count that is a power of two and no larger than 256, so this
228    /// will be a number in the range 0-8.
229    ///
230    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 0.
231    pub fn log2_lane_count(self) -> u8 {
232        self.0.saturating_sub(constants::LANE_BASE) >> 4
233    }
234
235    /// Get the number of lanes in this SIMD vector type.
236    ///
237    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1.
238    pub fn lane_count(self) -> u16 {
239        1 << self.log2_lane_count()
240    }
241
242    /// Get the total number of bits used to represent this type.
243    pub fn bits(self) -> u16 {
244        u16::from(self.lane_bits()) * self.lane_count()
245    }
246
247    /// Get the number of bytes used to store this type in memory.
248    pub fn bytes(self) -> u32 {
249        (u32::from(self.bits()) + 7) / 8
250    }
251
252    /// Get a SIMD vector type with `n` times more lanes than this one.
253    ///
254    /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes.
255    ///
256    /// If this is already a SIMD vector type, this produces a SIMD vector type with `n *
257    /// self.lane_count()` lanes.
258    pub fn by(self, n: u16) -> Option<Self> {
259        if self.lane_bits() == 0 || !n.is_power_of_two() {
260            return None;
261        }
262        let log2_lanes: u32 = n.trailing_zeros();
263        let new_type = u32::from(self.0) + (log2_lanes << 4);
264        if new_type < 0x100 {
265            Some(Self(new_type as u8))
266        } else {
267            None
268        }
269    }
270
271    /// Get a SIMD vector with half the number of lanes.
272    ///
273    /// There is no `double_vector()` method. Use `t.by(2)` instead.
274    pub fn half_vector(self) -> Option<Self> {
275        if self.is_vector() {
276            Some(Self(self.0 - 0x10))
277        } else {
278            None
279        }
280    }
281
282    /// Index of this type, for use with hash tables etc.
283    pub fn index(self) -> usize {
284        usize::from(self.0)
285    }
286
287    /// True iff:
288    ///
289    /// 1. `self.lane_count() == other.lane_count()` and
290    /// 2. `self.lane_bits() >= other.lane_bits()`
291    pub fn wider_or_equal(self, other: Self) -> bool {
292        self.lane_count() == other.lane_count() && self.lane_bits() >= other.lane_bits()
293    }
294
295    /// Return the pointer type for the given target triple.
296    pub fn triple_pointer_type(triple: &Triple) -> Self {
297        match triple.pointer_width() {
298            Ok(PointerWidth::U16) => I16,
299            Ok(PointerWidth::U32) => I32,
300            Ok(PointerWidth::U64) => I64,
301            Err(()) => panic!("unable to determine architecture pointer width"),
302        }
303    }
304}
305
306impl Display for Type {
307    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
308        if self.is_bool() {
309            write!(f, "b{}", self.lane_bits())
310        } else if self.is_int() {
311            write!(f, "i{}", self.lane_bits())
312        } else if self.is_float() {
313            write!(f, "f{}", self.lane_bits())
314        } else if self.is_vector() {
315            write!(f, "{}x{}", self.lane_type(), self.lane_count())
316        } else if self.is_ref() {
317            write!(f, "r{}", self.lane_bits())
318        } else {
319            f.write_str(match *self {
320                IFLAGS => "iflags",
321                FFLAGS => "fflags",
322                INVALID => panic!("INVALID encountered"),
323                _ => panic!("Unknown Type(0x{:x})", self.0),
324            })
325        }
326    }
327}
328
329impl Debug for Type {
330    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
331        if self.is_bool() {
332            write!(f, "types::B{}", self.lane_bits())
333        } else if self.is_int() {
334            write!(f, "types::I{}", self.lane_bits())
335        } else if self.is_float() {
336            write!(f, "types::F{}", self.lane_bits())
337        } else if self.is_vector() {
338            write!(f, "{:?}X{}", self.lane_type(), self.lane_count())
339        } else if self.is_ref() {
340            write!(f, "types::R{}", self.lane_bits())
341        } else {
342            match *self {
343                INVALID => write!(f, "types::INVALID"),
344                IFLAGS => write!(f, "types::IFLAGS"),
345                FFLAGS => write!(f, "types::FFLAGS"),
346                _ => write!(f, "Type(0x{:x})", self.0),
347            }
348        }
349    }
350}
351
352impl Default for Type {
353    fn default() -> Self {
354        INVALID
355    }
356}
357
358#[cfg(test)]
359mod tests {
360    use super::*;
361    use alloc::string::ToString;
362
363    #[test]
364    fn basic_scalars() {
365        assert_eq!(INVALID, INVALID.lane_type());
366        assert_eq!(0, INVALID.bits());
367        assert_eq!(IFLAGS, IFLAGS.lane_type());
368        assert_eq!(0, IFLAGS.bits());
369        assert_eq!(FFLAGS, FFLAGS.lane_type());
370        assert_eq!(0, FFLAGS.bits());
371        assert_eq!(B1, B1.lane_type());
372        assert_eq!(B8, B8.lane_type());
373        assert_eq!(B16, B16.lane_type());
374        assert_eq!(B32, B32.lane_type());
375        assert_eq!(B64, B64.lane_type());
376        assert_eq!(B128, B128.lane_type());
377        assert_eq!(I8, I8.lane_type());
378        assert_eq!(I16, I16.lane_type());
379        assert_eq!(I32, I32.lane_type());
380        assert_eq!(I64, I64.lane_type());
381        assert_eq!(I128, I128.lane_type());
382        assert_eq!(F32, F32.lane_type());
383        assert_eq!(F64, F64.lane_type());
384        assert_eq!(B1, B1.by(8).unwrap().lane_type());
385        assert_eq!(I32, I32X4.lane_type());
386        assert_eq!(F64, F64X2.lane_type());
387        assert_eq!(R32, R32.lane_type());
388        assert_eq!(R64, R64.lane_type());
389
390        assert_eq!(INVALID.lane_bits(), 0);
391        assert_eq!(IFLAGS.lane_bits(), 0);
392        assert_eq!(FFLAGS.lane_bits(), 0);
393        assert_eq!(B1.lane_bits(), 1);
394        assert_eq!(B8.lane_bits(), 8);
395        assert_eq!(B16.lane_bits(), 16);
396        assert_eq!(B32.lane_bits(), 32);
397        assert_eq!(B64.lane_bits(), 64);
398        assert_eq!(B128.lane_bits(), 128);
399        assert_eq!(I8.lane_bits(), 8);
400        assert_eq!(I16.lane_bits(), 16);
401        assert_eq!(I32.lane_bits(), 32);
402        assert_eq!(I64.lane_bits(), 64);
403        assert_eq!(I128.lane_bits(), 128);
404        assert_eq!(F32.lane_bits(), 32);
405        assert_eq!(F64.lane_bits(), 64);
406        assert_eq!(R32.lane_bits(), 32);
407        assert_eq!(R64.lane_bits(), 64);
408    }
409
410    #[test]
411    fn typevar_functions() {
412        assert_eq!(INVALID.half_width(), None);
413        assert_eq!(INVALID.half_width(), None);
414        assert_eq!(FFLAGS.half_width(), None);
415        assert_eq!(B1.half_width(), None);
416        assert_eq!(B8.half_width(), None);
417        assert_eq!(B16.half_width(), Some(B8));
418        assert_eq!(B32.half_width(), Some(B16));
419        assert_eq!(B64.half_width(), Some(B32));
420        assert_eq!(B128.half_width(), Some(B64));
421        assert_eq!(I8.half_width(), None);
422        assert_eq!(I16.half_width(), Some(I8));
423        assert_eq!(I32.half_width(), Some(I16));
424        assert_eq!(I32X4.half_width(), Some(I16X4));
425        assert_eq!(I64.half_width(), Some(I32));
426        assert_eq!(I128.half_width(), Some(I64));
427        assert_eq!(F32.half_width(), None);
428        assert_eq!(F64.half_width(), Some(F32));
429
430        assert_eq!(INVALID.double_width(), None);
431        assert_eq!(IFLAGS.double_width(), None);
432        assert_eq!(FFLAGS.double_width(), None);
433        assert_eq!(B1.double_width(), None);
434        assert_eq!(B8.double_width(), Some(B16));
435        assert_eq!(B16.double_width(), Some(B32));
436        assert_eq!(B32.double_width(), Some(B64));
437        assert_eq!(B64.double_width(), Some(B128));
438        assert_eq!(B128.double_width(), None);
439        assert_eq!(I8.double_width(), Some(I16));
440        assert_eq!(I16.double_width(), Some(I32));
441        assert_eq!(I32.double_width(), Some(I64));
442        assert_eq!(I32X4.double_width(), Some(I64X4));
443        assert_eq!(I64.double_width(), Some(I128));
444        assert_eq!(I128.double_width(), None);
445        assert_eq!(F32.double_width(), Some(F64));
446        assert_eq!(F64.double_width(), None);
447    }
448
449    #[test]
450    fn vectors() {
451        let big = F64.by(256).unwrap();
452        assert_eq!(big.lane_bits(), 64);
453        assert_eq!(big.lane_count(), 256);
454        assert_eq!(big.bits(), 64 * 256);
455
456        assert_eq!(big.half_vector().unwrap().to_string(), "f64x128");
457        assert_eq!(B1.by(2).unwrap().half_vector().unwrap().to_string(), "b1");
458        assert_eq!(I32.half_vector(), None);
459        assert_eq!(INVALID.half_vector(), None);
460
461        // Check that the generated constants match the computed vector types.
462        assert_eq!(I32.by(4), Some(I32X4));
463        assert_eq!(F64.by(8), Some(F64X8));
464    }
465
466    #[test]
467    fn format_scalars() {
468        assert_eq!(IFLAGS.to_string(), "iflags");
469        assert_eq!(FFLAGS.to_string(), "fflags");
470        assert_eq!(B1.to_string(), "b1");
471        assert_eq!(B8.to_string(), "b8");
472        assert_eq!(B16.to_string(), "b16");
473        assert_eq!(B32.to_string(), "b32");
474        assert_eq!(B64.to_string(), "b64");
475        assert_eq!(B128.to_string(), "b128");
476        assert_eq!(I8.to_string(), "i8");
477        assert_eq!(I16.to_string(), "i16");
478        assert_eq!(I32.to_string(), "i32");
479        assert_eq!(I64.to_string(), "i64");
480        assert_eq!(I128.to_string(), "i128");
481        assert_eq!(F32.to_string(), "f32");
482        assert_eq!(F64.to_string(), "f64");
483        assert_eq!(R32.to_string(), "r32");
484        assert_eq!(R64.to_string(), "r64");
485    }
486
487    #[test]
488    fn format_vectors() {
489        assert_eq!(B1.by(8).unwrap().to_string(), "b1x8");
490        assert_eq!(B8.by(1).unwrap().to_string(), "b8");
491        assert_eq!(B16.by(256).unwrap().to_string(), "b16x256");
492        assert_eq!(B32.by(4).unwrap().by(2).unwrap().to_string(), "b32x8");
493        assert_eq!(B64.by(8).unwrap().to_string(), "b64x8");
494        assert_eq!(I8.by(64).unwrap().to_string(), "i8x64");
495        assert_eq!(F64.by(2).unwrap().to_string(), "f64x2");
496        assert_eq!(I8.by(3), None);
497        assert_eq!(I8.by(512), None);
498        assert_eq!(INVALID.by(4), None);
499    }
500
501    #[test]
502    fn as_bool() {
503        assert_eq!(I32X4.as_bool(), B32X4);
504        assert_eq!(I32.as_bool(), B1);
505        assert_eq!(I32X4.as_bool_pedantic(), B32X4);
506        assert_eq!(I32.as_bool_pedantic(), B32);
507    }
508}