1 use std::cell::RefCell;
2 use std::collections::BTreeSet;
3 use std::fmt;
4 use std::hash;
5 use std::ops;
6 use std::rc::Rc;
7
8 use crate::cdsl::types::{LaneType, ValueType};
9
10 const MAX_LANES: u16 = 256;
11 const MAX_BITS: u16 = 128;
12 const MAX_FLOAT_BITS: u16 = 128;
13
14 /// Type variables can be used in place of concrete types when defining
15 /// instructions. This makes the instructions *polymorphic*.
16 ///
17 /// A type variable is restricted to vary over a subset of the value types.
18 /// This subset is specified by a set of flags that control the permitted base
19 /// types and whether the type variable can assume scalar or vector types, or
20 /// both.
21 #[derive(Debug)]
22 pub(crate) struct TypeVarContent {
23 /// Short name of type variable used in instruction descriptions.
24 pub name: String,
25
26 /// Documentation string.
27 pub doc: String,
28
29 /// Type set associated to the type variable.
30 /// This field must remain private; use `get_typeset()` or `get_raw_typeset()` to get the
31 /// information you want.
32 type_set: TypeSet,
33
34 pub base: Option<TypeVarParent>,
35 }
36
37 #[derive(Clone, Debug)]
38 pub(crate) struct TypeVar {
39 content: Rc<RefCell<TypeVarContent>>,
40 }
41
42 impl TypeVar {
new(name: impl Into<String>, doc: impl Into<String>, type_set: TypeSet) -> Self43 pub fn new(name: impl Into<String>, doc: impl Into<String>, type_set: TypeSet) -> Self {
44 Self {
45 content: Rc::new(RefCell::new(TypeVarContent {
46 name: name.into(),
47 doc: doc.into(),
48 type_set,
49 base: None,
50 })),
51 }
52 }
53
new_singleton(value_type: ValueType) -> Self54 pub fn new_singleton(value_type: ValueType) -> Self {
55 let (name, doc) = (value_type.to_string(), value_type.doc());
56 let mut builder = TypeSetBuilder::new();
57
58 let (scalar_type, num_lanes) = match value_type {
59 ValueType::Lane(lane_type) => (lane_type, 1),
60 ValueType::Vector(vec_type) => {
61 (vec_type.lane_type(), vec_type.lane_count() as RangeBound)
62 }
63 ValueType::DynamicVector(vec_type) => (
64 vec_type.lane_type(),
65 vec_type.minimum_lane_count() as RangeBound,
66 ),
67 };
68
69 builder = builder.simd_lanes(num_lanes..num_lanes);
70
71 // Only generate dynamic types for multiple lanes.
72 if num_lanes > 1 {
73 builder = builder.dynamic_simd_lanes(num_lanes..num_lanes);
74 }
75
76 let builder = match scalar_type {
77 LaneType::Int(int_type) => {
78 let bits = int_type as RangeBound;
79 builder.ints(bits..bits)
80 }
81 LaneType::Float(float_type) => {
82 let bits = float_type as RangeBound;
83 builder.floats(bits..bits)
84 }
85 };
86 TypeVar::new(name, doc, builder.build())
87 }
88
89 /// Get a fresh copy of self, named after `name`. Can only be called on non-derived typevars.
copy_from(other: &TypeVar, name: String) -> TypeVar90 pub fn copy_from(other: &TypeVar, name: String) -> TypeVar {
91 assert!(
92 other.base.is_none(),
93 "copy_from() can only be called on non-derived type variables"
94 );
95 TypeVar {
96 content: Rc::new(RefCell::new(TypeVarContent {
97 name,
98 doc: "".into(),
99 type_set: other.type_set.clone(),
100 base: None,
101 })),
102 }
103 }
104
105 /// Returns the typeset for this TV. If the TV is derived, computes it recursively from the
106 /// derived function and the base's typeset.
107 /// Note this can't be done non-lazily in the constructor, because the TypeSet of the base may
108 /// change over time.
get_typeset(&self) -> TypeSet109 pub fn get_typeset(&self) -> TypeSet {
110 match &self.base {
111 Some(base) => base.type_var.get_typeset().image(base.derived_func),
112 None => self.type_set.clone(),
113 }
114 }
115
116 /// Returns this typevar's type set, assuming this type var has no parent.
get_raw_typeset(&self) -> &TypeSet117 pub fn get_raw_typeset(&self) -> &TypeSet {
118 assert_eq!(self.type_set, self.get_typeset());
119 &self.type_set
120 }
121
122 /// If the associated typeset has a single type return it. Otherwise return None.
singleton_type(&self) -> Option<ValueType>123 pub fn singleton_type(&self) -> Option<ValueType> {
124 let type_set = self.get_typeset();
125 if type_set.size() == 1 {
126 Some(type_set.get_singleton())
127 } else {
128 None
129 }
130 }
131
132 /// Get the free type variable controlling this one.
free_typevar(&self) -> Option<TypeVar>133 pub fn free_typevar(&self) -> Option<TypeVar> {
134 match &self.base {
135 Some(base) => base.type_var.free_typevar(),
136 None => {
137 match self.singleton_type() {
138 // A singleton type isn't a proper free variable.
139 Some(_) => None,
140 None => Some(self.clone()),
141 }
142 }
143 }
144 }
145
146 /// Create a type variable that is a function of another.
derived(&self, derived_func: DerivedFunc) -> TypeVar147 pub fn derived(&self, derived_func: DerivedFunc) -> TypeVar {
148 let ts = self.get_typeset();
149
150 // Safety checks to avoid over/underflows.
151 match derived_func {
152 DerivedFunc::HalfWidth => {
153 assert!(
154 ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8,
155 "can't halve all integer types"
156 );
157 assert!(
158 ts.floats.is_empty() || *ts.floats.iter().min().unwrap() > 16,
159 "can't halve all float types"
160 );
161 }
162 DerivedFunc::DoubleWidth => {
163 assert!(
164 ts.ints.is_empty() || *ts.ints.iter().max().unwrap() < MAX_BITS,
165 "can't double all integer types"
166 );
167 assert!(
168 ts.floats.is_empty() || *ts.floats.iter().max().unwrap() < MAX_FLOAT_BITS,
169 "can't double all float types"
170 );
171 }
172 DerivedFunc::SplitLanes => {
173 assert!(
174 ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8,
175 "can't halve all integer types"
176 );
177 assert!(
178 ts.floats.is_empty() || *ts.floats.iter().min().unwrap() > 16,
179 "can't halve all float types"
180 );
181 assert!(
182 *ts.lanes.iter().max().unwrap() < MAX_LANES,
183 "can't double 256 lanes"
184 );
185 }
186 DerivedFunc::MergeLanes => {
187 assert!(
188 ts.ints.is_empty() || *ts.ints.iter().max().unwrap() < MAX_BITS,
189 "can't double all integer types"
190 );
191 assert!(
192 ts.floats.is_empty() || *ts.floats.iter().max().unwrap() < MAX_FLOAT_BITS,
193 "can't double all float types"
194 );
195 assert!(
196 *ts.lanes.iter().min().unwrap() > 1,
197 "can't halve a scalar type"
198 );
199 }
200 DerivedFunc::Narrower => {
201 assert_eq!(
202 *ts.lanes.iter().max().unwrap(),
203 1,
204 "The `narrower` constraint does not apply to vectors"
205 );
206 assert!(
207 (!ts.ints.is_empty() || !ts.floats.is_empty()) && ts.dynamic_lanes.is_empty(),
208 "The `narrower` constraint only applies to scalar ints or floats"
209 );
210 }
211 DerivedFunc::Wider => {
212 assert_eq!(
213 *ts.lanes.iter().max().unwrap(),
214 1,
215 "The `wider` constraint does not apply to vectors"
216 );
217 assert!(
218 (!ts.ints.is_empty() || !ts.floats.is_empty()) && ts.dynamic_lanes.is_empty(),
219 "The `wider` constraint only applies to scalar ints or floats"
220 );
221 }
222 DerivedFunc::LaneOf | DerivedFunc::AsTruthy | DerivedFunc::DynamicToVector => {
223 /* no particular assertions */
224 }
225 }
226
227 TypeVar {
228 content: Rc::new(RefCell::new(TypeVarContent {
229 name: format!("{}({})", derived_func.name(), self.name),
230 doc: "".into(),
231 type_set: ts,
232 base: Some(TypeVarParent {
233 type_var: self.clone(),
234 derived_func,
235 }),
236 })),
237 }
238 }
239
lane_of(&self) -> TypeVar240 pub fn lane_of(&self) -> TypeVar {
241 self.derived(DerivedFunc::LaneOf)
242 }
as_truthy(&self) -> TypeVar243 pub fn as_truthy(&self) -> TypeVar {
244 self.derived(DerivedFunc::AsTruthy)
245 }
half_width(&self) -> TypeVar246 pub fn half_width(&self) -> TypeVar {
247 self.derived(DerivedFunc::HalfWidth)
248 }
double_width(&self) -> TypeVar249 pub fn double_width(&self) -> TypeVar {
250 self.derived(DerivedFunc::DoubleWidth)
251 }
split_lanes(&self) -> TypeVar252 pub fn split_lanes(&self) -> TypeVar {
253 self.derived(DerivedFunc::SplitLanes)
254 }
merge_lanes(&self) -> TypeVar255 pub fn merge_lanes(&self) -> TypeVar {
256 self.derived(DerivedFunc::MergeLanes)
257 }
dynamic_to_vector(&self) -> TypeVar258 pub fn dynamic_to_vector(&self) -> TypeVar {
259 self.derived(DerivedFunc::DynamicToVector)
260 }
261
262 /// Make a new [TypeVar] that includes all types narrower than self.
narrower(&self) -> TypeVar263 pub fn narrower(&self) -> TypeVar {
264 self.derived(DerivedFunc::Narrower)
265 }
266
267 /// Make a new [TypeVar] that includes all types wider than self.
wider(&self) -> TypeVar268 pub fn wider(&self) -> TypeVar {
269 self.derived(DerivedFunc::Wider)
270 }
271 }
272
273 impl From<&TypeVar> for TypeVar {
from(type_var: &TypeVar) -> Self274 fn from(type_var: &TypeVar) -> Self {
275 type_var.clone()
276 }
277 }
278 impl From<ValueType> for TypeVar {
from(value_type: ValueType) -> Self279 fn from(value_type: ValueType) -> Self {
280 TypeVar::new_singleton(value_type)
281 }
282 }
283
284 // Hash TypeVars by pointers.
285 // There might be a better way to do this, but since TypeVar's content (namely TypeSet) can be
286 // mutated, it makes sense to use pointer equality/hashing here.
287 impl hash::Hash for TypeVar {
hash<H: hash::Hasher>(&self, h: &mut H)288 fn hash<H: hash::Hasher>(&self, h: &mut H) {
289 match &self.base {
290 Some(base) => {
291 base.type_var.hash(h);
292 base.derived_func.hash(h);
293 }
294 None => {
295 (&**self as *const TypeVarContent).hash(h);
296 }
297 }
298 }
299 }
300
301 impl PartialEq for TypeVar {
eq(&self, other: &TypeVar) -> bool302 fn eq(&self, other: &TypeVar) -> bool {
303 match (&self.base, &other.base) {
304 (Some(base1), Some(base2)) => {
305 base1.type_var.eq(&base2.type_var) && base1.derived_func == base2.derived_func
306 }
307 (None, None) => Rc::ptr_eq(&self.content, &other.content),
308 _ => false,
309 }
310 }
311 }
312
313 // Allow TypeVar as map keys, based on pointer equality (see also above PartialEq impl).
314 impl Eq for TypeVar {}
315
316 impl ops::Deref for TypeVar {
317 type Target = TypeVarContent;
deref(&self) -> &Self::Target318 fn deref(&self) -> &Self::Target {
319 unsafe { self.content.as_ptr().as_ref().unwrap() }
320 }
321 }
322
323 #[derive(Clone, Copy, Debug, Hash, PartialEq)]
324 pub(crate) enum DerivedFunc {
325 LaneOf,
326 AsTruthy,
327 HalfWidth,
328 DoubleWidth,
329 SplitLanes,
330 MergeLanes,
331 DynamicToVector,
332 Narrower,
333 Wider,
334 }
335
336 impl DerivedFunc {
name(self) -> &'static str337 pub fn name(self) -> &'static str {
338 match self {
339 DerivedFunc::LaneOf => "lane_of",
340 DerivedFunc::AsTruthy => "as_truthy",
341 DerivedFunc::HalfWidth => "half_width",
342 DerivedFunc::DoubleWidth => "double_width",
343 DerivedFunc::SplitLanes => "split_lanes",
344 DerivedFunc::MergeLanes => "merge_lanes",
345 DerivedFunc::DynamicToVector => "dynamic_to_vector",
346 DerivedFunc::Narrower => "narrower",
347 DerivedFunc::Wider => "wider",
348 }
349 }
350 }
351
352 #[derive(Debug, Hash)]
353 pub(crate) struct TypeVarParent {
354 pub type_var: TypeVar,
355 pub derived_func: DerivedFunc,
356 }
357
358 /// A set of types.
359 ///
360 /// We don't allow arbitrary subsets of types, but use a parametrized approach
361 /// instead.
362 ///
363 /// Objects of this class can be used as dictionary keys.
364 ///
365 /// Parametrized type sets are specified in terms of ranges:
366 /// - The permitted range of vector lanes, where 1 indicates a scalar type.
367 /// - The permitted range of integer types.
368 /// - The permitted range of floating point types, and
369 /// - The permitted range of boolean types.
370 ///
371 /// The ranges are inclusive from smallest bit-width to largest bit-width.
372
373 type RangeBound = u16;
374 type Range = ops::Range<RangeBound>;
375 type NumSet = BTreeSet<RangeBound>;
376
377 macro_rules! num_set {
378 ($($expr:expr),*) => {
379 NumSet::from_iter(vec![$($expr),*])
380 };
381 }
382
383 #[derive(Clone, PartialEq, Eq, Hash)]
384 pub(crate) struct TypeSet {
385 pub lanes: NumSet,
386 pub dynamic_lanes: NumSet,
387 pub ints: NumSet,
388 pub floats: NumSet,
389 }
390
391 impl TypeSet {
new(lanes: NumSet, dynamic_lanes: NumSet, ints: NumSet, floats: NumSet) -> Self392 fn new(lanes: NumSet, dynamic_lanes: NumSet, ints: NumSet, floats: NumSet) -> Self {
393 Self {
394 lanes,
395 dynamic_lanes,
396 ints,
397 floats,
398 }
399 }
400
401 /// Return the number of concrete types represented by this typeset.
size(&self) -> usize402 pub fn size(&self) -> usize {
403 self.lanes.len() * (self.ints.len() + self.floats.len())
404 + self.dynamic_lanes.len() * (self.ints.len() + self.floats.len())
405 }
406
407 /// Return the image of self across the derived function func.
image(&self, derived_func: DerivedFunc) -> TypeSet408 fn image(&self, derived_func: DerivedFunc) -> TypeSet {
409 match derived_func {
410 DerivedFunc::LaneOf => self.lane_of(),
411 DerivedFunc::AsTruthy => self.as_truthy(),
412 DerivedFunc::HalfWidth => self.half_width(),
413 DerivedFunc::DoubleWidth => self.double_width(),
414 DerivedFunc::SplitLanes => self.half_width().double_vector(),
415 DerivedFunc::MergeLanes => self.double_width().half_vector(),
416 DerivedFunc::DynamicToVector => self.dynamic_to_vector(),
417 DerivedFunc::Narrower => self.clone(),
418 DerivedFunc::Wider => self.clone(),
419 }
420 }
421
422 /// Return a TypeSet describing the image of self across lane_of.
lane_of(&self) -> TypeSet423 fn lane_of(&self) -> TypeSet {
424 let mut copy = self.clone();
425 copy.lanes = num_set![1];
426 copy
427 }
428
429 /// Return a TypeSet describing the image of self across as_truthy.
as_truthy(&self) -> TypeSet430 fn as_truthy(&self) -> TypeSet {
431 let mut copy = self.clone();
432
433 // If this type set represents a scalar, `as_truthy` produces an I8, otherwise it returns a
434 // vector of the same number of lanes, whose elements are integers of the same width. For
435 // example, F32X4 gets turned into I32X4, while I32 gets turned into I8.
436 if self.lanes.len() == 1 && self.lanes.contains(&1) {
437 copy.ints = NumSet::from([8]);
438 } else {
439 copy.ints.extend(&self.floats)
440 }
441
442 copy.floats = NumSet::new();
443 copy
444 }
445
446 /// Return a TypeSet describing the image of self across halfwidth.
half_width(&self) -> TypeSet447 fn half_width(&self) -> TypeSet {
448 let mut copy = self.clone();
449 copy.ints = NumSet::from_iter(self.ints.iter().filter(|&&x| x > 8).map(|&x| x / 2));
450 copy.floats = NumSet::from_iter(self.floats.iter().filter(|&&x| x > 16).map(|&x| x / 2));
451 copy
452 }
453
454 /// Return a TypeSet describing the image of self across doublewidth.
double_width(&self) -> TypeSet455 fn double_width(&self) -> TypeSet {
456 let mut copy = self.clone();
457 copy.ints = NumSet::from_iter(self.ints.iter().filter(|&&x| x < MAX_BITS).map(|&x| x * 2));
458 copy.floats = NumSet::from_iter(
459 self.floats
460 .iter()
461 .filter(|&&x| x < MAX_FLOAT_BITS)
462 .map(|&x| x * 2),
463 );
464 copy
465 }
466
467 /// Return a TypeSet describing the image of self across halfvector.
half_vector(&self) -> TypeSet468 fn half_vector(&self) -> TypeSet {
469 let mut copy = self.clone();
470 copy.lanes = NumSet::from_iter(self.lanes.iter().filter(|&&x| x > 1).map(|&x| x / 2));
471 copy
472 }
473
474 /// Return a TypeSet describing the image of self across doublevector.
double_vector(&self) -> TypeSet475 fn double_vector(&self) -> TypeSet {
476 let mut copy = self.clone();
477 copy.lanes = NumSet::from_iter(
478 self.lanes
479 .iter()
480 .filter(|&&x| x < MAX_LANES)
481 .map(|&x| x * 2),
482 );
483 copy
484 }
485
dynamic_to_vector(&self) -> TypeSet486 fn dynamic_to_vector(&self) -> TypeSet {
487 let mut copy = self.clone();
488 copy.lanes = NumSet::from_iter(
489 self.dynamic_lanes
490 .iter()
491 .filter(|&&x| x < MAX_LANES)
492 .copied(),
493 );
494 copy.dynamic_lanes = NumSet::new();
495 copy
496 }
497
concrete_types(&self) -> Vec<ValueType>498 fn concrete_types(&self) -> Vec<ValueType> {
499 let mut ret = Vec::new();
500 for &num_lanes in &self.lanes {
501 for &bits in &self.ints {
502 ret.push(LaneType::int_from_bits(bits).by(num_lanes));
503 }
504 for &bits in &self.floats {
505 ret.push(LaneType::float_from_bits(bits).by(num_lanes));
506 }
507 }
508 for &num_lanes in &self.dynamic_lanes {
509 for &bits in &self.ints {
510 ret.push(LaneType::int_from_bits(bits).to_dynamic(num_lanes));
511 }
512 for &bits in &self.floats {
513 ret.push(LaneType::float_from_bits(bits).to_dynamic(num_lanes));
514 }
515 }
516 ret
517 }
518
519 /// Return the singleton type represented by self. Can only call on typesets containing 1 type.
get_singleton(&self) -> ValueType520 fn get_singleton(&self) -> ValueType {
521 let mut types = self.concrete_types();
522 assert_eq!(types.len(), 1);
523 types.remove(0)
524 }
525 }
526
527 impl fmt::Debug for TypeSet {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>528 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
529 write!(fmt, "TypeSet(")?;
530
531 let mut subsets = Vec::new();
532 if !self.lanes.is_empty() {
533 subsets.push(format!(
534 "lanes={{{}}}",
535 Vec::from_iter(self.lanes.iter().map(|x| x.to_string())).join(", ")
536 ));
537 }
538 if !self.dynamic_lanes.is_empty() {
539 subsets.push(format!(
540 "dynamic_lanes={{{}}}",
541 Vec::from_iter(self.dynamic_lanes.iter().map(|x| x.to_string())).join(", ")
542 ));
543 }
544 if !self.ints.is_empty() {
545 subsets.push(format!(
546 "ints={{{}}}",
547 Vec::from_iter(self.ints.iter().map(|x| x.to_string())).join(", ")
548 ));
549 }
550 if !self.floats.is_empty() {
551 subsets.push(format!(
552 "floats={{{}}}",
553 Vec::from_iter(self.floats.iter().map(|x| x.to_string())).join(", ")
554 ));
555 }
556
557 write!(fmt, "{})", subsets.join(", "))?;
558 Ok(())
559 }
560 }
561
562 pub(crate) struct TypeSetBuilder {
563 ints: Interval,
564 floats: Interval,
565 includes_scalars: bool,
566 simd_lanes: Interval,
567 dynamic_simd_lanes: Interval,
568 }
569
570 impl TypeSetBuilder {
new() -> Self571 pub fn new() -> Self {
572 Self {
573 ints: Interval::None,
574 floats: Interval::None,
575 includes_scalars: true,
576 simd_lanes: Interval::None,
577 dynamic_simd_lanes: Interval::None,
578 }
579 }
580
ints(mut self, interval: impl Into<Interval>) -> Self581 pub fn ints(mut self, interval: impl Into<Interval>) -> Self {
582 assert!(self.ints == Interval::None);
583 self.ints = interval.into();
584 self
585 }
floats(mut self, interval: impl Into<Interval>) -> Self586 pub fn floats(mut self, interval: impl Into<Interval>) -> Self {
587 assert!(self.floats == Interval::None);
588 self.floats = interval.into();
589 self
590 }
includes_scalars(mut self, includes_scalars: bool) -> Self591 pub fn includes_scalars(mut self, includes_scalars: bool) -> Self {
592 self.includes_scalars = includes_scalars;
593 self
594 }
simd_lanes(mut self, interval: impl Into<Interval>) -> Self595 pub fn simd_lanes(mut self, interval: impl Into<Interval>) -> Self {
596 assert!(self.simd_lanes == Interval::None);
597 self.simd_lanes = interval.into();
598 self
599 }
dynamic_simd_lanes(mut self, interval: impl Into<Interval>) -> Self600 pub fn dynamic_simd_lanes(mut self, interval: impl Into<Interval>) -> Self {
601 assert!(self.dynamic_simd_lanes == Interval::None);
602 self.dynamic_simd_lanes = interval.into();
603 self
604 }
605
build(self) -> TypeSet606 pub fn build(self) -> TypeSet {
607 let min_lanes = if self.includes_scalars { 1 } else { 2 };
608
609 TypeSet::new(
610 range_to_set(self.simd_lanes.to_range(min_lanes..MAX_LANES, Some(1))),
611 range_to_set(self.dynamic_simd_lanes.to_range(2..MAX_LANES, None)),
612 range_to_set(self.ints.to_range(8..MAX_BITS, None)),
613 range_to_set(self.floats.to_range(16..MAX_FLOAT_BITS, None)),
614 )
615 }
616 }
617
618 #[derive(PartialEq)]
619 pub(crate) enum Interval {
620 None,
621 All,
622 Range(Range),
623 }
624
625 impl Interval {
to_range(&self, full_range: Range, default: Option<RangeBound>) -> Option<Range>626 fn to_range(&self, full_range: Range, default: Option<RangeBound>) -> Option<Range> {
627 match self {
628 Interval::None => default.map(|default_val| default_val..default_val),
629
630 Interval::All => Some(full_range),
631
632 Interval::Range(range) => {
633 let (low, high) = (range.start, range.end);
634 assert!(low.is_power_of_two());
635 assert!(high.is_power_of_two());
636 assert!(low <= high);
637 assert!(low >= full_range.start);
638 assert!(high <= full_range.end);
639 Some(low..high)
640 }
641 }
642 }
643 }
644
645 impl From<Range> for Interval {
from(range: Range) -> Self646 fn from(range: Range) -> Self {
647 Interval::Range(range)
648 }
649 }
650
651 /// Generates a set with all the powers of two included in the range.
range_to_set(range: Option<Range>) -> NumSet652 fn range_to_set(range: Option<Range>) -> NumSet {
653 let mut set = NumSet::new();
654
655 let (low, high) = match range {
656 Some(range) => (range.start, range.end),
657 None => return set,
658 };
659
660 assert!(low.is_power_of_two());
661 assert!(high.is_power_of_two());
662 assert!(low <= high);
663
664 for i in low.trailing_zeros()..=high.trailing_zeros() {
665 assert!(1 << i <= RangeBound::max_value());
666 set.insert(1 << i);
667 }
668 set
669 }
670
671 #[test]
test_typevar_builder()672 fn test_typevar_builder() {
673 let type_set = TypeSetBuilder::new().ints(Interval::All).build();
674 assert_eq!(type_set.lanes, num_set![1]);
675 assert!(type_set.floats.is_empty());
676 assert_eq!(type_set.ints, num_set![8, 16, 32, 64, 128]);
677
678 let type_set = TypeSetBuilder::new().floats(Interval::All).build();
679 assert_eq!(type_set.lanes, num_set![1]);
680 assert_eq!(type_set.floats, num_set![16, 32, 64, 128]);
681 assert!(type_set.ints.is_empty());
682
683 let type_set = TypeSetBuilder::new()
684 .floats(Interval::All)
685 .simd_lanes(Interval::All)
686 .includes_scalars(false)
687 .build();
688 assert_eq!(type_set.lanes, num_set![2, 4, 8, 16, 32, 64, 128, 256]);
689 assert_eq!(type_set.floats, num_set![16, 32, 64, 128]);
690 assert!(type_set.ints.is_empty());
691
692 let type_set = TypeSetBuilder::new()
693 .floats(Interval::All)
694 .simd_lanes(Interval::All)
695 .includes_scalars(true)
696 .build();
697 assert_eq!(type_set.lanes, num_set![1, 2, 4, 8, 16, 32, 64, 128, 256]);
698 assert_eq!(type_set.floats, num_set![16, 32, 64, 128]);
699 assert!(type_set.ints.is_empty());
700
701 let type_set = TypeSetBuilder::new()
702 .floats(Interval::All)
703 .simd_lanes(Interval::All)
704 .includes_scalars(false)
705 .build();
706 assert_eq!(type_set.lanes, num_set![2, 4, 8, 16, 32, 64, 128, 256]);
707 assert_eq!(type_set.floats, num_set![16, 32, 64, 128]);
708 assert!(type_set.dynamic_lanes.is_empty());
709 assert!(type_set.ints.is_empty());
710
711 let type_set = TypeSetBuilder::new()
712 .ints(Interval::All)
713 .floats(Interval::All)
714 .dynamic_simd_lanes(Interval::All)
715 .includes_scalars(false)
716 .build();
717 assert_eq!(
718 type_set.dynamic_lanes,
719 num_set![2, 4, 8, 16, 32, 64, 128, 256]
720 );
721 assert_eq!(type_set.ints, num_set![8, 16, 32, 64, 128]);
722 assert_eq!(type_set.floats, num_set![16, 32, 64, 128]);
723 assert_eq!(type_set.lanes, num_set![1]);
724
725 let type_set = TypeSetBuilder::new()
726 .floats(Interval::All)
727 .dynamic_simd_lanes(Interval::All)
728 .includes_scalars(false)
729 .build();
730 assert_eq!(
731 type_set.dynamic_lanes,
732 num_set![2, 4, 8, 16, 32, 64, 128, 256]
733 );
734 assert_eq!(type_set.floats, num_set![16, 32, 64, 128]);
735 assert_eq!(type_set.lanes, num_set![1]);
736 assert!(type_set.ints.is_empty());
737
738 let type_set = TypeSetBuilder::new().ints(16..64).build();
739 assert_eq!(type_set.lanes, num_set![1]);
740 assert_eq!(type_set.ints, num_set![16, 32, 64]);
741 assert!(type_set.floats.is_empty());
742 }
743
744 #[test]
test_dynamic_to_vector()745 fn test_dynamic_to_vector() {
746 // We don't generate single lane dynamic types, so the maximum number of
747 // lanes we support is 128, as MAX_BITS is 256.
748 assert_eq!(
749 TypeSetBuilder::new()
750 .dynamic_simd_lanes(Interval::All)
751 .ints(Interval::All)
752 .build()
753 .dynamic_to_vector(),
754 TypeSetBuilder::new()
755 .simd_lanes(2..128)
756 .ints(Interval::All)
757 .build()
758 );
759 assert_eq!(
760 TypeSetBuilder::new()
761 .dynamic_simd_lanes(Interval::All)
762 .floats(Interval::All)
763 .build()
764 .dynamic_to_vector(),
765 TypeSetBuilder::new()
766 .simd_lanes(2..128)
767 .floats(Interval::All)
768 .build()
769 );
770 }
771
772 #[test]
773 #[should_panic]
test_typevar_builder_too_high_bound_panic()774 fn test_typevar_builder_too_high_bound_panic() {
775 TypeSetBuilder::new().ints(16..2 * MAX_BITS).build();
776 }
777
778 #[test]
779 #[should_panic]
test_typevar_builder_inverted_bounds_panic()780 fn test_typevar_builder_inverted_bounds_panic() {
781 TypeSetBuilder::new().ints(32..16).build();
782 }
783
784 #[test]
test_as_truthy()785 fn test_as_truthy() {
786 let a = TypeSetBuilder::new()
787 .simd_lanes(2..8)
788 .ints(8..8)
789 .floats(32..32)
790 .build();
791 assert_eq!(
792 a.lane_of(),
793 TypeSetBuilder::new().ints(8..8).floats(32..32).build()
794 );
795
796 let mut a_as_truthy = TypeSetBuilder::new().simd_lanes(2..8).build();
797 a_as_truthy.ints = num_set![8, 32];
798 assert_eq!(a.as_truthy(), a_as_truthy);
799
800 let a = TypeSetBuilder::new().ints(8..32).floats(32..64).build();
801 let a_as_truthy = TypeSetBuilder::new().ints(8..8).build();
802 assert_eq!(a.as_truthy(), a_as_truthy);
803 }
804
805 #[test]
test_forward_images()806 fn test_forward_images() {
807 let empty_set = TypeSetBuilder::new().build();
808
809 // Half vector.
810 assert_eq!(
811 TypeSetBuilder::new()
812 .simd_lanes(1..32)
813 .build()
814 .half_vector(),
815 TypeSetBuilder::new().simd_lanes(1..16).build()
816 );
817
818 // Double vector.
819 assert_eq!(
820 TypeSetBuilder::new()
821 .simd_lanes(1..32)
822 .build()
823 .double_vector(),
824 TypeSetBuilder::new().simd_lanes(2..64).build()
825 );
826 assert_eq!(
827 TypeSetBuilder::new()
828 .simd_lanes(128..256)
829 .build()
830 .double_vector(),
831 TypeSetBuilder::new().simd_lanes(256..256).build()
832 );
833
834 // Half width.
835 assert_eq!(
836 TypeSetBuilder::new().ints(8..32).build().half_width(),
837 TypeSetBuilder::new().ints(8..16).build()
838 );
839 assert_eq!(
840 TypeSetBuilder::new().floats(16..16).build().half_width(),
841 empty_set
842 );
843 assert_eq!(
844 TypeSetBuilder::new().floats(32..128).build().half_width(),
845 TypeSetBuilder::new().floats(16..64).build()
846 );
847
848 // Double width.
849 assert_eq!(
850 TypeSetBuilder::new().ints(8..32).build().double_width(),
851 TypeSetBuilder::new().ints(16..64).build()
852 );
853 assert_eq!(
854 TypeSetBuilder::new().ints(32..64).build().double_width(),
855 TypeSetBuilder::new().ints(64..128).build()
856 );
857 assert_eq!(
858 TypeSetBuilder::new().floats(32..32).build().double_width(),
859 TypeSetBuilder::new().floats(64..64).build()
860 );
861 assert_eq!(
862 TypeSetBuilder::new().floats(16..64).build().double_width(),
863 TypeSetBuilder::new().floats(32..128).build()
864 );
865 }
866
867 #[test]
868 #[should_panic]
test_typeset_singleton_panic_nonsingleton_types()869 fn test_typeset_singleton_panic_nonsingleton_types() {
870 TypeSetBuilder::new()
871 .ints(8..8)
872 .floats(32..32)
873 .build()
874 .get_singleton();
875 }
876
877 #[test]
878 #[should_panic]
test_typeset_singleton_panic_nonsingleton_lanes()879 fn test_typeset_singleton_panic_nonsingleton_lanes() {
880 TypeSetBuilder::new()
881 .simd_lanes(1..2)
882 .floats(32..32)
883 .build()
884 .get_singleton();
885 }
886
887 #[test]
test_typeset_singleton()888 fn test_typeset_singleton() {
889 use crate::shared::types as shared_types;
890 assert_eq!(
891 TypeSetBuilder::new().ints(16..16).build().get_singleton(),
892 ValueType::Lane(shared_types::Int::I16.into())
893 );
894 assert_eq!(
895 TypeSetBuilder::new().floats(64..64).build().get_singleton(),
896 ValueType::Lane(shared_types::Float::F64.into())
897 );
898 assert_eq!(
899 TypeSetBuilder::new()
900 .simd_lanes(4..4)
901 .ints(32..32)
902 .build()
903 .get_singleton(),
904 LaneType::from(shared_types::Int::I32).by(4)
905 );
906 }
907
908 #[test]
test_typevar_functions()909 fn test_typevar_functions() {
910 let x = TypeVar::new(
911 "x",
912 "i16 and up",
913 TypeSetBuilder::new().ints(16..64).build(),
914 );
915 assert_eq!(x.half_width().name, "half_width(x)");
916 assert_eq!(
917 x.half_width().double_width().name,
918 "double_width(half_width(x))"
919 );
920
921 let x = TypeVar::new("x", "up to i32", TypeSetBuilder::new().ints(8..32).build());
922 assert_eq!(x.double_width().name, "double_width(x)");
923 }
924
925 #[test]
test_typevar_singleton()926 fn test_typevar_singleton() {
927 use crate::cdsl::types::VectorType;
928 use crate::shared::types as shared_types;
929
930 // Test i32.
931 let typevar = TypeVar::new_singleton(ValueType::Lane(LaneType::Int(shared_types::Int::I32)));
932 assert_eq!(typevar.name, "i32");
933 assert_eq!(typevar.type_set.ints, num_set![32]);
934 assert!(typevar.type_set.floats.is_empty());
935 assert_eq!(typevar.type_set.lanes, num_set![1]);
936
937 // Test f32x4.
938 let typevar = TypeVar::new_singleton(ValueType::Vector(VectorType::new(
939 LaneType::Float(shared_types::Float::F32),
940 4,
941 )));
942 assert_eq!(typevar.name, "f32x4");
943 assert!(typevar.type_set.ints.is_empty());
944 assert_eq!(typevar.type_set.floats, num_set![32]);
945 assert_eq!(typevar.type_set.lanes, num_set![4]);
946 }
947