|
1 | 1 | use crate::compiler_interface::with;
|
| 2 | +use crate::error; |
2 | 3 | use crate::mir::FieldIdx;
|
3 |
| -use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx}; |
| 4 | +use crate::target::{MachineInfo, MachineSize as Size}; |
| 5 | +use crate::ty::{Align, IndexedVal, Ty, VariantIdx}; |
| 6 | +use crate::Error; |
4 | 7 | use crate::Opaque;
|
| 8 | +use std::fmt::{self, Debug}; |
5 | 9 | use std::num::NonZeroUsize;
|
6 | 10 | use std::ops::RangeInclusive;
|
7 | 11 |
|
@@ -100,7 +104,7 @@ impl LayoutShape {
|
100 | 104 |
|
101 | 105 | /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
|
102 | 106 | pub fn is_1zst(&self) -> bool {
|
103 |
| - self.is_sized() && self.size == 0 && self.abi_align == 1 |
| 107 | + self.is_sized() && self.size.bits() == 0 && self.abi_align == 1 |
104 | 108 | }
|
105 | 109 | }
|
106 | 110 |
|
@@ -245,8 +249,175 @@ impl ValueAbi {
|
245 | 249 | }
|
246 | 250 | }
|
247 | 251 |
|
248 |
| -/// We currently do not support `Scalar`, and use opaque instead. |
249 |
| -type Scalar = Opaque; |
| 252 | +/// Information about one scalar component of a Rust type. |
| 253 | +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
| 254 | +pub enum Scalar { |
| 255 | + Initialized { |
| 256 | + /// The primitive type used to represent this value. |
| 257 | + value: Primitive, |
| 258 | + /// The range that represents valid values. |
| 259 | + /// The range must be valid for the `primitive` size. |
| 260 | + valid_range: WrappingRange, |
| 261 | + }, |
| 262 | + Union { |
| 263 | + /// Unions never have niches, so there is no `valid_range`. |
| 264 | + /// Even for unions, we need to use the correct registers for the kind of |
| 265 | + /// values inside the union, so we keep the `Primitive` type around. |
| 266 | + /// It is also used to compute the size of the scalar. |
| 267 | + value: Primitive, |
| 268 | + }, |
| 269 | +} |
| 270 | + |
| 271 | +impl Scalar { |
| 272 | + pub fn has_niche(&self, target: &MachineInfo) -> bool { |
| 273 | + match self { |
| 274 | + Scalar::Initialized { value, valid_range } => { |
| 275 | + !valid_range.is_full(value.size(target)).unwrap() |
| 276 | + } |
| 277 | + Scalar::Union { .. } => false, |
| 278 | + } |
| 279 | + } |
| 280 | +} |
| 281 | + |
| 282 | +/// Fundamental unit of memory access and layout. |
| 283 | +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
| 284 | +pub enum Primitive { |
| 285 | + /// The `bool` is the signedness of the `Integer` type. |
| 286 | + /// |
| 287 | + /// One would think we would not care about such details this low down, |
| 288 | + /// but some ABIs are described in terms of C types and ISAs where the |
| 289 | + /// integer arithmetic is done on {sign,zero}-extended registers, e.g. |
| 290 | + /// a negative integer passed by zero-extension will appear positive in |
| 291 | + /// the callee, and most operations on it will produce the wrong values. |
| 292 | + Int { |
| 293 | + length: IntegerLength, |
| 294 | + signed: bool, |
| 295 | + }, |
| 296 | + Float { |
| 297 | + length: FloatLength, |
| 298 | + }, |
| 299 | + Pointer(AddressSpace), |
| 300 | +} |
| 301 | + |
| 302 | +impl Primitive { |
| 303 | + pub fn size(self, target: &MachineInfo) -> Size { |
| 304 | + match self { |
| 305 | + Primitive::Int { length, .. } => Size::from_bits(length.bits()), |
| 306 | + Primitive::Float { length } => Size::from_bits(length.bits()), |
| 307 | + Primitive::Pointer(_) => target.pointer_width, |
| 308 | + } |
| 309 | + } |
| 310 | +} |
| 311 | + |
| 312 | +/// Enum representing the existing integer lengths. |
| 313 | +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
| 314 | +pub enum IntegerLength { |
| 315 | + I8, |
| 316 | + I16, |
| 317 | + I32, |
| 318 | + I64, |
| 319 | + I128, |
| 320 | +} |
| 321 | + |
| 322 | +/// Enum representing the existing float lengths. |
| 323 | +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
| 324 | +pub enum FloatLength { |
| 325 | + F16, |
| 326 | + F32, |
| 327 | + F64, |
| 328 | + F128, |
| 329 | +} |
| 330 | + |
| 331 | +impl IntegerLength { |
| 332 | + pub fn bits(self) -> usize { |
| 333 | + match self { |
| 334 | + IntegerLength::I8 => 8, |
| 335 | + IntegerLength::I16 => 16, |
| 336 | + IntegerLength::I32 => 32, |
| 337 | + IntegerLength::I64 => 64, |
| 338 | + IntegerLength::I128 => 128, |
| 339 | + } |
| 340 | + } |
| 341 | +} |
| 342 | + |
| 343 | +impl FloatLength { |
| 344 | + pub fn bits(self) -> usize { |
| 345 | + match self { |
| 346 | + FloatLength::F16 => 16, |
| 347 | + FloatLength::F32 => 32, |
| 348 | + FloatLength::F64 => 64, |
| 349 | + FloatLength::F128 => 128, |
| 350 | + } |
| 351 | + } |
| 352 | +} |
| 353 | + |
| 354 | +/// An identifier that specifies the address space that some operation |
| 355 | +/// should operate on. Special address spaces have an effect on code generation, |
| 356 | +/// depending on the target and the address spaces it implements. |
| 357 | +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 358 | +pub struct AddressSpace(pub u32); |
| 359 | + |
| 360 | +impl AddressSpace { |
| 361 | + /// The default address space, corresponding to data space. |
| 362 | + pub const DATA: Self = AddressSpace(0); |
| 363 | +} |
| 364 | + |
| 365 | +/// Inclusive wrap-around range of valid values (bitwise representation), that is, if |
| 366 | +/// start > end, it represents `start..=MAX`, followed by `0..=end`. |
| 367 | +/// |
| 368 | +/// That is, for an i8 primitive, a range of `254..=2` means following |
| 369 | +/// sequence: |
| 370 | +/// |
| 371 | +/// 254 (-2), 255 (-1), 0, 1, 2 |
| 372 | +#[derive(Clone, Copy, PartialEq, Eq, Hash)] |
| 373 | +pub struct WrappingRange { |
| 374 | + pub start: u128, |
| 375 | + pub end: u128, |
| 376 | +} |
| 377 | + |
| 378 | +impl WrappingRange { |
| 379 | + /// Returns `true` if `size` completely fills the range. |
| 380 | + #[inline] |
| 381 | + pub fn is_full(&self, size: Size) -> Result<bool, Error> { |
| 382 | + let Some(max_value) = size.unsigned_int_max() else { |
| 383 | + return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits())); |
| 384 | + }; |
| 385 | + if self.start <= max_value && self.end <= max_value { |
| 386 | + Ok(self.start == 0 && max_value == self.end) |
| 387 | + } else { |
| 388 | + Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits())) |
| 389 | + } |
| 390 | + } |
| 391 | + |
| 392 | + /// Returns `true` if `v` is contained in the range. |
| 393 | + #[inline(always)] |
| 394 | + pub fn contains(&self, v: u128) -> bool { |
| 395 | + if self.wraps_around() { |
| 396 | + self.start <= v || v <= self.end |
| 397 | + } else { |
| 398 | + self.start <= v && v <= self.end |
| 399 | + } |
| 400 | + } |
| 401 | + |
| 402 | + /// Returns `true` if the range wraps around. |
| 403 | + /// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`. |
| 404 | + /// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`. |
| 405 | + #[inline] |
| 406 | + pub fn wraps_around(&self) -> bool { |
| 407 | + self.start > self.end |
| 408 | + } |
| 409 | +} |
| 410 | + |
| 411 | +impl Debug for WrappingRange { |
| 412 | + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 413 | + if self.start > self.end { |
| 414 | + write!(fmt, "(..={}) | ({}..)", self.end, self.start)?; |
| 415 | + } else { |
| 416 | + write!(fmt, "{}..={}", self.start, self.end)?; |
| 417 | + } |
| 418 | + Ok(()) |
| 419 | + } |
| 420 | +} |
250 | 421 |
|
251 | 422 | /// General language calling conventions.
|
252 | 423 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
0 commit comments