1use 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#[derive(Copy, Clone, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
26pub struct Type(u16);
27
28pub const INVALID: Type = Type(0);
30
31include!(concat!(env!("OUT_DIR"), "/types.rs"));
35
36impl Type {
37 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 pub fn lane_of(self) -> Self {
52 self.lane_type()
53 }
54
55 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 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 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 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 pub fn int_with_byte_size(bytes: u16) -> Option<Self> {
121 Self::int(bytes.checked_mul(8)?)
122 }
123
124 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 pub fn as_truthy_pedantic(self) -> Self {
136 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 pub fn as_truthy(self) -> Self {
152 if !self.is_vector() {
153 I8
154 } else {
155 self.as_truthy_pedantic()
156 }
157 }
158
159 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 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 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 pub fn is_invalid(self) -> bool {
204 self == INVALID
205 }
206
207 pub fn is_special(self) -> bool {
209 self.0 < constants::LANE_BASE
210 }
211
212 pub fn is_lane(self) -> bool {
216 constants::LANE_BASE <= self.0 && self.0 < constants::VECTOR_BASE
217 }
218
219 pub fn is_vector(self) -> bool {
223 self.0 >= constants::VECTOR_BASE && !self.is_dynamic_vector()
224 }
225
226 pub fn is_dynamic_vector(self) -> bool {
228 self.0 >= constants::DYNAMIC_VECTOR_BASE
229 }
230
231 pub fn is_int(self) -> bool {
233 match self {
234 I8 | I16 | I32 | I64 | I128 => true,
235 _ => false,
236 }
237 }
238
239 pub fn is_float(self) -> bool {
241 match self {
242 F16 | F32 | F64 | F128 => true,
243 _ => false,
244 }
245 }
246
247 pub fn is_ref(self) -> bool {
249 match self {
250 R32 | R64 => true,
251 _ => false,
252 }
253 }
254
255 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 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 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 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 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 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 pub fn bytes(self) -> u32 {
322 (self.bits() + 7) / 8
323 }
324
325 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 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 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 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 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 pub fn index(self) -> usize {
396 usize::from(self.0)
397 }
398
399 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 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 pub(crate) fn repr(self) -> u16 {
420 self.0
421 }
422
423 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 assert_eq!(I32.by(4), Some(I32X4));
552 assert_eq!(F64.by(8), Some(F64X8));
553 }
554
555 #[test]
556 fn dynamic_vectors() {
557 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 assert_eq!(I16X8XN.lane_count(), 0);
565 assert_eq!(I16X8XN.min_lane_count(), 8);
566
567 assert_eq!(I8X8XN.by(2), None);
569
570 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 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}