1 //! Common types for the Cranelift code generator.
2 
3 use core::fmt::{self, Debug, Display, Formatter};
4 use cranelift_codegen_shared::constants;
5 #[cfg(feature = "enable-serde")]
6 use serde_derive::{Deserialize, Serialize};
7 use 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))]
26 pub struct Type(u16);
27 
28 /// Not a valid type. Can't be loaded or stored. Can't be part of a SIMD vector.
29 pub 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.
34 include!(concat!(env!("OUT_DIR"), "/types.rs"));
35 
36 impl 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.
lane_type(self) -> Self40     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.
lane_of(self) -> Self51     pub fn lane_of(self) -> Self {
52         self.lane_type()
53     }
54 
55     /// Get log_2 of the number of bits in a lane.
log2_lane_bits(self) -> u3256     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.
lane_bits(self) -> u3268     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'.
bounds(self, signed: bool) -> (u128, u128)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`].
int(bits: u16) -> Option<Self>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`].
int_with_byte_size(bytes: u16) -> Option<Self>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.
replace_lanes(self, lane: Self) -> Self125     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.
as_truthy_pedantic(self) -> Self135     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.
as_truthy(self) -> Self150     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.
as_int(self) -> Self160     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.
half_width(self) -> Option<Self>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.
double_width(self) -> Option<Self>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?
is_invalid(self) -> bool202     pub fn is_invalid(self) -> bool {
203         self == INVALID
204     }
205 
206     /// Is this a special type?
is_special(self) -> bool207     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.
is_lane(self) -> bool214     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.
is_vector(self) -> bool221     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?
is_dynamic_vector(self) -> bool226     pub fn is_dynamic_vector(self) -> bool {
227         self.0 >= constants::DYNAMIC_VECTOR_BASE
228     }
229 
230     /// Is this a scalar integer type?
is_int(self) -> bool231     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?
is_float(self) -> bool239     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.
log2_lane_count(self) -> u32252     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.
log2_min_lane_count(self) -> u32261     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.
lane_count(self) -> u32275     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.
bits(self) -> u32284     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.
min_lane_count(self) -> u32294     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.
min_bits(self) -> u32303     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.
bytes(self) -> u32312     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.
by(self, n: u32) -> Option<Self>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.
vector_to_dynamic(self) -> Option<Self>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.
dynamic_to_vector(self) -> Option<Self>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`.
split_lanes(self) -> Option<Self>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`.
merge_lanes(self) -> Option<Self>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.
index(self) -> usize386     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()`
wider_or_equal(self, other: Self) -> bool394     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.
triple_pointer_type(triple: &Triple) -> Self399     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.
repr(self) -> u16410     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`.
from_repr(bits: u16) -> Type416     pub(crate) fn from_repr(bits: u16) -> Type {
417         Type(bits)
418     }
419 }
420 
421 impl Display for Type {
fmt(&self, f: &mut Formatter) -> fmt::Result422     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 
440 impl Debug for Type {
fmt(&self, f: &mut Formatter) -> fmt::Result441     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 
459 impl Default for Type {
default() -> Self460     fn default() -> Self {
461         INVALID
462     }
463 }
464 
465 #[cfg(test)]
466 mod tests {
467     use super::*;
468     use alloc::string::ToString;
469 
470     #[test]
basic_scalars()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]
typevar_functions()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]
vectors()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]
dynamic_vectors()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]
format_scalars()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]
format_vectors()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]
as_truthy()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]
int_from_size()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 }
625