1use 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#[derive(Copy, Clone, PartialEq, Eq, Hash)]
26#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
27pub struct Type(u16);
28
29pub const INVALID: Type = Type(0);
31
32include!(concat!(env!("OUT_DIR"), "/types.rs"));
36
37impl Type {
38 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 pub fn lane_of(self) -> Self {
53 self.lane_type()
54 }
55
56 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 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 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 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 pub fn int_with_byte_size(bytes: u16) -> Option<Self> {
122 Self::int(bytes.checked_mul(8)?)
123 }
124
125 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 pub fn as_truthy_pedantic(self) -> Self {
137 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 pub fn as_truthy(self) -> Self {
153 if !self.is_vector() {
154 I8
155 } else {
156 self.as_truthy_pedantic()
157 }
158 }
159
160 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 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 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 pub fn is_invalid(self) -> bool {
203 self == INVALID
204 }
205
206 pub fn is_special(self) -> bool {
208 self.0 < constants::LANE_BASE
209 }
210
211 pub fn is_lane(self) -> bool {
215 constants::LANE_BASE <= self.0 && self.0 < constants::VECTOR_BASE
216 }
217
218 pub fn is_vector(self) -> bool {
222 self.0 >= constants::VECTOR_BASE && !self.is_dynamic_vector()
223 }
224
225 pub fn is_dynamic_vector(self) -> bool {
227 self.0 >= constants::DYNAMIC_VECTOR_BASE
228 }
229
230 pub fn is_int(self) -> bool {
232 match self {
233 I8 | I16 | I32 | I64 | I128 => true,
234 _ => false,
235 }
236 }
237
238 pub fn is_float(self) -> bool {
240 match self {
241 F32 | F64 => true,
242 _ => false,
243 }
244 }
245
246 pub fn is_ref(self) -> bool {
248 match self {
249 R32 | R64 => true,
250 _ => false,
251 }
252 }
253
254 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 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 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 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 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 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 pub fn bytes(self) -> u32 {
321 (self.bits() + 7) / 8
322 }
323
324 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 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 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 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 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 pub fn index(self) -> usize {
395 usize::from(self.0)
396 }
397
398 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 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 pub(crate) fn repr(self) -> u16 {
419 self.0
420 }
421
422 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 assert_eq!(I32.by(4), Some(I32X4));
543 assert_eq!(F64.by(8), Some(F64X8));
544 }
545
546 #[test]
547 fn dynamic_vectors() {
548 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 assert_eq!(I16X8XN.lane_count(), 0);
556 assert_eq!(I16X8XN.min_lane_count(), 8);
557
558 assert_eq!(I8X8XN.by(2), None);
560
561 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 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}