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