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