1 //! Cranelift ValueType hierarchy
2 
3 use std::fmt;
4 
5 use crate::shared::types as shared_types;
6 use cranelift_codegen_shared::constants;
7 
8 // Rust name prefix used for the `rust_name` method.
9 static RUST_NAME_PREFIX: &str = "ir::types::";
10 
11 // ValueType variants (i8, i32, ...) are provided in `shared::types.rs`.
12 
13 /// A concrete SSA value type.
14 ///
15 /// All SSA values have a type that is described by an instance of `ValueType`
16 /// or one of its subclasses.
17 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
18 pub(crate) enum ValueType {
19     Lane(LaneType),
20     Vector(VectorType),
21     DynamicVector(DynamicVectorType),
22 }
23 
24 impl ValueType {
25     /// Iterate through all of the lane types.
all_lane_types() -> LaneTypeIterator26     pub fn all_lane_types() -> LaneTypeIterator {
27         LaneTypeIterator::new()
28     }
29 
30     /// Return a string containing the documentation comment for this type.
doc(&self) -> String31     pub fn doc(&self) -> String {
32         match *self {
33             ValueType::Lane(l) => l.doc(),
34             ValueType::Vector(ref v) => v.doc(),
35             ValueType::DynamicVector(ref v) => v.doc(),
36         }
37     }
38 
39     /// Return the number of bits in a lane.
lane_bits(&self) -> u6440     pub fn lane_bits(&self) -> u64 {
41         match *self {
42             ValueType::Lane(l) => l.lane_bits(),
43             ValueType::Vector(ref v) => v.lane_bits(),
44             ValueType::DynamicVector(ref v) => v.lane_bits(),
45         }
46     }
47 
48     /// Return the number of lanes.
lane_count(&self) -> u6449     pub fn lane_count(&self) -> u64 {
50         match *self {
51             ValueType::Vector(ref v) => v.lane_count(),
52             _ => 1,
53         }
54     }
55 
56     /// Find the number of bytes that this type occupies in memory.
membytes(&self) -> u6457     pub fn membytes(&self) -> u64 {
58         self.width() / 8
59     }
60 
61     /// Find the unique number associated with this type.
number(&self) -> u1662     pub fn number(&self) -> u16 {
63         match *self {
64             ValueType::Lane(l) => l.number(),
65             ValueType::Vector(ref v) => v.number(),
66             ValueType::DynamicVector(ref v) => v.number(),
67         }
68     }
69 
70     /// Return the name of this type for generated Rust source files.
rust_name(&self) -> String71     pub fn rust_name(&self) -> String {
72         format!("{}{}", RUST_NAME_PREFIX, self.to_string().to_uppercase())
73     }
74 
75     /// Return the total number of bits of an instance of this type.
width(&self) -> u6476     pub fn width(&self) -> u64 {
77         self.lane_count() * self.lane_bits()
78     }
79 }
80 
81 impl fmt::Display for ValueType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result82     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83         match *self {
84             ValueType::Lane(l) => l.fmt(f),
85             ValueType::Vector(ref v) => v.fmt(f),
86             ValueType::DynamicVector(ref v) => v.fmt(f),
87         }
88     }
89 }
90 
91 /// Create a ValueType from a given lane type.
92 impl From<LaneType> for ValueType {
from(lane: LaneType) -> Self93     fn from(lane: LaneType) -> Self {
94         ValueType::Lane(lane)
95     }
96 }
97 
98 /// Create a ValueType from a given vector type.
99 impl From<VectorType> for ValueType {
from(vector: VectorType) -> Self100     fn from(vector: VectorType) -> Self {
101         ValueType::Vector(vector)
102     }
103 }
104 
105 /// Create a ValueType from a given dynamic vector type.
106 impl From<DynamicVectorType> for ValueType {
from(vector: DynamicVectorType) -> Self107     fn from(vector: DynamicVectorType) -> Self {
108         ValueType::DynamicVector(vector)
109     }
110 }
111 
112 /// A concrete scalar type that can appear as a vector lane too.
113 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
114 pub(crate) enum LaneType {
115     Float(shared_types::Float),
116     Int(shared_types::Int),
117 }
118 
119 impl LaneType {
120     /// Return a string containing the documentation comment for this lane type.
doc(self) -> String121     pub fn doc(self) -> String {
122         match self {
123             LaneType::Float(shared_types::Float::F16) => String::from(
124                 "A 16-bit floating point type represented in the IEEE 754-2008
125                 *binary16* interchange format. This corresponds to the :c:type:`_Float16`
126                 type in most C implementations.
127                 WARNING: f16 support is a work-in-progress and is incomplete",
128             ),
129             LaneType::Float(shared_types::Float::F32) => String::from(
130                 "A 32-bit floating point type represented in the IEEE 754-2008
131                 *binary32* interchange format. This corresponds to the :c:type:`float`
132                 type in most C implementations.",
133             ),
134             LaneType::Float(shared_types::Float::F64) => String::from(
135                 "A 64-bit floating point type represented in the IEEE 754-2008
136                 *binary64* interchange format. This corresponds to the :c:type:`double`
137                 type in most C implementations.",
138             ),
139             LaneType::Float(shared_types::Float::F128) => String::from(
140                 "A 128-bit floating point type represented in the IEEE 754-2008
141                 *binary128* interchange format. This corresponds to the :c:type:`_Float128`
142                 type in most C implementations.
143                 WARNING: f128 support is a work-in-progress and is incomplete",
144             ),
145             LaneType::Int(_) if self.lane_bits() < 32 => format!(
146                 "An integer type with {} bits.
147                 WARNING: arithmetic on {}bit integers is incomplete",
148                 self.lane_bits(),
149                 self.lane_bits()
150             ),
151             LaneType::Int(_) => format!("An integer type with {} bits.", self.lane_bits()),
152         }
153     }
154 
155     /// Return the number of bits in a lane.
lane_bits(self) -> u64156     pub fn lane_bits(self) -> u64 {
157         match self {
158             LaneType::Float(ref f) => *f as u64,
159             LaneType::Int(ref i) => *i as u64,
160         }
161     }
162 
163     /// Find the unique number associated with this lane type.
number(self) -> u16164     pub fn number(self) -> u16 {
165         constants::LANE_BASE
166             + match self {
167                 LaneType::Int(shared_types::Int::I8) => 4,
168                 LaneType::Int(shared_types::Int::I16) => 5,
169                 LaneType::Int(shared_types::Int::I32) => 6,
170                 LaneType::Int(shared_types::Int::I64) => 7,
171                 LaneType::Int(shared_types::Int::I128) => 8,
172                 LaneType::Float(shared_types::Float::F16) => 9,
173                 LaneType::Float(shared_types::Float::F32) => 10,
174                 LaneType::Float(shared_types::Float::F64) => 11,
175                 LaneType::Float(shared_types::Float::F128) => 12,
176             }
177     }
178 
int_from_bits(num_bits: u16) -> LaneType179     pub fn int_from_bits(num_bits: u16) -> LaneType {
180         LaneType::Int(match num_bits {
181             8 => shared_types::Int::I8,
182             16 => shared_types::Int::I16,
183             32 => shared_types::Int::I32,
184             64 => shared_types::Int::I64,
185             128 => shared_types::Int::I128,
186             _ => unreachable!("unexpected num bits for int"),
187         })
188     }
189 
float_from_bits(num_bits: u16) -> LaneType190     pub fn float_from_bits(num_bits: u16) -> LaneType {
191         LaneType::Float(match num_bits {
192             16 => shared_types::Float::F16,
193             32 => shared_types::Float::F32,
194             64 => shared_types::Float::F64,
195             128 => shared_types::Float::F128,
196             _ => unreachable!("unexpected num bits for float"),
197         })
198     }
199 
by(self, lanes: u16) -> ValueType200     pub fn by(self, lanes: u16) -> ValueType {
201         if lanes == 1 {
202             self.into()
203         } else {
204             ValueType::Vector(VectorType::new(self, lanes.into()))
205         }
206     }
207 
to_dynamic(self, lanes: u16) -> ValueType208     pub fn to_dynamic(self, lanes: u16) -> ValueType {
209         ValueType::DynamicVector(DynamicVectorType::new(self, lanes.into()))
210     }
211 }
212 
213 impl fmt::Display for LaneType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result214     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215         match *self {
216             LaneType::Float(_) => write!(f, "f{}", self.lane_bits()),
217             LaneType::Int(_) => write!(f, "i{}", self.lane_bits()),
218         }
219     }
220 }
221 
222 impl fmt::Debug for LaneType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result223     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224         let inner_msg = format!("bits={}", self.lane_bits());
225         write!(
226             f,
227             "{}",
228             match *self {
229                 LaneType::Float(_) => format!("FloatType({inner_msg})"),
230                 LaneType::Int(_) => format!("IntType({inner_msg})"),
231             }
232         )
233     }
234 }
235 
236 /// Create a LaneType from a given float variant.
237 impl From<shared_types::Float> for LaneType {
from(f: shared_types::Float) -> Self238     fn from(f: shared_types::Float) -> Self {
239         LaneType::Float(f)
240     }
241 }
242 
243 /// Create a LaneType from a given int variant.
244 impl From<shared_types::Int> for LaneType {
from(i: shared_types::Int) -> Self245     fn from(i: shared_types::Int) -> Self {
246         LaneType::Int(i)
247     }
248 }
249 
250 /// An iterator for different lane types.
251 pub(crate) struct LaneTypeIterator {
252     int_iter: shared_types::IntIterator,
253     float_iter: shared_types::FloatIterator,
254 }
255 
256 impl LaneTypeIterator {
257     /// Create a new lane type iterator.
new() -> Self258     fn new() -> Self {
259         Self {
260             int_iter: shared_types::IntIterator::new(),
261             float_iter: shared_types::FloatIterator::new(),
262         }
263     }
264 }
265 
266 impl Iterator for LaneTypeIterator {
267     type Item = LaneType;
next(&mut self) -> Option<Self::Item>268     fn next(&mut self) -> Option<Self::Item> {
269         if let Some(i) = self.int_iter.next() {
270             Some(LaneType::from(i))
271         } else if let Some(f) = self.float_iter.next() {
272             Some(LaneType::from(f))
273         } else {
274             None
275         }
276     }
277 }
278 
279 /// A concrete SIMD vector type.
280 ///
281 /// A vector type has a lane type which is an instance of `LaneType`,
282 /// and a positive number of lanes.
283 #[derive(Clone, PartialEq, Eq, Hash)]
284 pub(crate) struct VectorType {
285     base: LaneType,
286     lanes: u64,
287 }
288 
289 impl VectorType {
290     /// Initialize a new integer type with `n` bits.
new(base: LaneType, lanes: u64) -> Self291     pub fn new(base: LaneType, lanes: u64) -> Self {
292         Self { base, lanes }
293     }
294 
295     /// Return a string containing the documentation comment for this vector type.
doc(&self) -> String296     pub fn doc(&self) -> String {
297         format!(
298             "A SIMD vector with {} lanes containing a `{}` each.",
299             self.lane_count(),
300             self.base
301         )
302     }
303 
304     /// Return the number of bits in a lane.
lane_bits(&self) -> u64305     pub fn lane_bits(&self) -> u64 {
306         self.base.lane_bits()
307     }
308 
309     /// Return the number of lanes.
lane_count(&self) -> u64310     pub fn lane_count(&self) -> u64 {
311         self.lanes
312     }
313 
314     /// Return the lane type.
lane_type(&self) -> LaneType315     pub fn lane_type(&self) -> LaneType {
316         self.base
317     }
318 
319     /// Find the unique number associated with this vector type.
320     ///
321     /// Vector types are encoded with the lane type in the low 4 bits and
322     /// log2(lanes) in the high 4 bits, giving a range of 2-256 lanes.
number(&self) -> u16323     pub fn number(&self) -> u16 {
324         let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros();
325         let base_num = u32::from(self.base.number());
326         let num = (lanes_log_2 << 4) + base_num;
327         num as u16
328     }
329 }
330 
331 impl fmt::Display for VectorType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result332     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
333         write!(f, "{}x{}", self.base, self.lane_count())
334     }
335 }
336 
337 impl fmt::Debug for VectorType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result338     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
339         write!(
340             f,
341             "VectorType(base={}, lanes={})",
342             self.base,
343             self.lane_count()
344         )
345     }
346 }
347 
348 /// A concrete dynamic SIMD vector type.
349 ///
350 /// A vector type has a lane type which is an instance of `LaneType`,
351 /// and a positive number of lanes.
352 #[derive(Clone, PartialEq, Eq, Hash)]
353 pub(crate) struct DynamicVectorType {
354     base: LaneType,
355     unscaled_lanes: u64,
356 }
357 
358 impl DynamicVectorType {
359     /// Initialize a new type with `base` lane type and a minimum number of lanes.
new(base: LaneType, unscaled_lanes: u64) -> Self360     pub fn new(base: LaneType, unscaled_lanes: u64) -> Self {
361         Self {
362             base,
363             unscaled_lanes,
364         }
365     }
366 
367     /// Return a string containing the documentation comment for this vector type.
doc(&self) -> String368     pub fn doc(&self) -> String {
369         format!(
370             "A dynamically-scaled SIMD vector with a minimum of {} lanes containing `{}` bits each.",
371             self.unscaled_lanes, self.base
372         )
373     }
374 
375     /// Return the number of bits in a lane.
lane_bits(&self) -> u64376     pub fn lane_bits(&self) -> u64 {
377         self.base.lane_bits()
378     }
379 
380     /// Return the number of lanes.
minimum_lane_count(&self) -> u64381     pub fn minimum_lane_count(&self) -> u64 {
382         self.unscaled_lanes
383     }
384 
385     /// Return the lane type.
lane_type(&self) -> LaneType386     pub fn lane_type(&self) -> LaneType {
387         self.base
388     }
389 
390     /// Find the unique number associated with this vector type.
391     ///
392     /// Dynamic vector types are encoded in the same manner as `VectorType`,
393     /// with lane type in the low 4 bits and the log2(lane_count). We add the
394     /// `VECTOR_BASE` to move these numbers into the range beyond the fixed
395     /// SIMD types.
number(&self) -> u16396     pub fn number(&self) -> u16 {
397         let base_num = u32::from(self.base.number());
398         let lanes_log_2: u32 = 63 - self.minimum_lane_count().leading_zeros();
399         let num = 0x80 + (lanes_log_2 << 4) + base_num;
400         num as u16
401     }
402 }
403 
404 impl fmt::Display for DynamicVectorType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result405     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
406         write!(f, "{}x{}xN", self.base, self.minimum_lane_count())
407     }
408 }
409 
410 impl fmt::Debug for DynamicVectorType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result411     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412         write!(
413             f,
414             "DynamicVectorType(base={}, lanes={})",
415             self.base,
416             self.minimum_lane_count(),
417         )
418     }
419 }
420