1use std::fmt;
2use std::num::NonZero;
3
4use rustc_abi::Size;
5use rustc_apfloat::Float;
6use rustc_apfloat::ieee::{Double, Half, Quad, Single};
7use rustc_errors::{DiagArgValue, IntoDiagArg};
8use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
9
10use crate::ty::TyCtxt;
11
12#[derive(Copy, Clone)]
13pub struct ConstInt {
15 int: ScalarInt,
17 signed: bool,
19 is_ptr_sized_integral: bool,
21}
22
23impl ConstInt {
24 pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
25 Self { int, signed, is_ptr_sized_integral }
26 }
27}
28
29#[derive(Debug, Copy, Clone)]
33pub enum AtomicOrdering {
34 Relaxed = 0,
36 Release = 1,
37 Acquire = 2,
38 AcqRel = 3,
39 SeqCst = 4,
40}
41
42impl std::fmt::Debug for ConstInt {
43 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 let Self { int, signed, is_ptr_sized_integral } = *self;
45 let size = int.size().bytes();
46 let raw = int.data;
47 if signed {
48 let bit_size = size * 8;
49 let min = 1u128 << (bit_size - 1);
50 let max = min - 1;
51 if raw == min {
52 match (size, is_ptr_sized_integral) {
53 (_, true) => write!(fmt, "isize::MIN"),
54 (1, _) => write!(fmt, "i8::MIN"),
55 (2, _) => write!(fmt, "i16::MIN"),
56 (4, _) => write!(fmt, "i32::MIN"),
57 (8, _) => write!(fmt, "i64::MIN"),
58 (16, _) => write!(fmt, "i128::MIN"),
59 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
60 }
61 } else if raw == max {
62 match (size, is_ptr_sized_integral) {
63 (_, true) => write!(fmt, "isize::MAX"),
64 (1, _) => write!(fmt, "i8::MAX"),
65 (2, _) => write!(fmt, "i16::MAX"),
66 (4, _) => write!(fmt, "i32::MAX"),
67 (8, _) => write!(fmt, "i64::MAX"),
68 (16, _) => write!(fmt, "i128::MAX"),
69 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
70 }
71 } else {
72 match size {
73 1 => write!(fmt, "{}", raw as i8)?,
74 2 => write!(fmt, "{}", raw as i16)?,
75 4 => write!(fmt, "{}", raw as i32)?,
76 8 => write!(fmt, "{}", raw as i64)?,
77 16 => write!(fmt, "{}", raw as i128)?,
78 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
79 }
80 if fmt.alternate() {
81 match (size, is_ptr_sized_integral) {
82 (_, true) => write!(fmt, "_isize")?,
83 (1, _) => write!(fmt, "_i8")?,
84 (2, _) => write!(fmt, "_i16")?,
85 (4, _) => write!(fmt, "_i32")?,
86 (8, _) => write!(fmt, "_i64")?,
87 (16, _) => write!(fmt, "_i128")?,
88 (sz, _) => bug!("unexpected int size i{sz}"),
89 }
90 }
91 Ok(())
92 }
93 } else {
94 let max = Size::from_bytes(size).truncate(u128::MAX);
95 if raw == max {
96 match (size, is_ptr_sized_integral) {
97 (_, true) => write!(fmt, "usize::MAX"),
98 (1, _) => write!(fmt, "u8::MAX"),
99 (2, _) => write!(fmt, "u16::MAX"),
100 (4, _) => write!(fmt, "u32::MAX"),
101 (8, _) => write!(fmt, "u64::MAX"),
102 (16, _) => write!(fmt, "u128::MAX"),
103 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
104 }
105 } else {
106 match size {
107 1 => write!(fmt, "{}", raw as u8)?,
108 2 => write!(fmt, "{}", raw as u16)?,
109 4 => write!(fmt, "{}", raw as u32)?,
110 8 => write!(fmt, "{}", raw as u64)?,
111 16 => write!(fmt, "{}", raw as u128)?,
112 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
113 }
114 if fmt.alternate() {
115 match (size, is_ptr_sized_integral) {
116 (_, true) => write!(fmt, "_usize")?,
117 (1, _) => write!(fmt, "_u8")?,
118 (2, _) => write!(fmt, "_u16")?,
119 (4, _) => write!(fmt, "_u32")?,
120 (8, _) => write!(fmt, "_u64")?,
121 (16, _) => write!(fmt, "_u128")?,
122 (sz, _) => bug!("unexpected unsigned int size u{sz}"),
123 }
124 }
125 Ok(())
126 }
127 }
128 }
129}
130
131impl IntoDiagArg for ConstInt {
132 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
135 DiagArgValue::Str(format!("{self:?}").into())
136 }
137}
138
139#[derive(Clone, Copy, Eq, PartialEq, Hash)]
144#[repr(packed)]
145pub struct ScalarInt {
146 data: u128,
149 size: NonZero<u8>,
150}
151
152impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
155 fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
156 { self.data }.hash_stable(hcx, hasher);
161 self.size.get().hash_stable(hcx, hasher);
162 }
163}
164
165impl<S: Encoder> Encodable<S> for ScalarInt {
166 fn encode(&self, s: &mut S) {
167 let size = self.size.get();
168 s.emit_u8(size);
169 s.emit_raw_bytes(&self.data.to_le_bytes()[..size as usize]);
170 }
171}
172
173impl<D: Decoder> Decodable<D> for ScalarInt {
174 fn decode(d: &mut D) -> ScalarInt {
175 let mut data = [0u8; 16];
176 let size = d.read_u8();
177 data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
178 ScalarInt { data: u128::from_le_bytes(data), size: NonZero::new(size).unwrap() }
179 }
180}
181
182impl ScalarInt {
183 pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::new(1).unwrap() };
184 pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::new(1).unwrap() };
185
186 fn raw(data: u128, size: Size) -> Self {
187 Self { data, size: NonZero::new(size.bytes() as u8).unwrap() }
188 }
189
190 #[inline]
191 pub fn size(self) -> Size {
192 Size::from_bytes(self.size.get())
193 }
194
195 #[inline(always)]
199 fn check_data(self) {
200 debug_assert_eq!(
206 self.size().truncate(self.data),
207 { self.data },
208 "Scalar value {:#x} exceeds size of {} bytes",
209 { self.data },
210 self.size
211 );
212 }
213
214 #[inline]
215 pub fn null(size: Size) -> Self {
216 Self::raw(0, size)
217 }
218
219 #[inline]
220 pub fn is_null(self) -> bool {
221 self.data == 0
222 }
223
224 #[inline]
225 pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
226 let (r, overflow) = Self::truncate_from_uint(i, size);
227 if overflow { None } else { Some(r) }
228 }
229
230 #[inline]
232 pub fn truncate_from_uint(i: impl Into<u128>, size: Size) -> (Self, bool) {
233 let data = i.into();
234 let r = Self::raw(size.truncate(data), size);
235 (r, r.data != data)
236 }
237
238 #[inline]
239 pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
240 let (r, overflow) = Self::truncate_from_int(i, size);
241 if overflow { None } else { Some(r) }
242 }
243
244 #[inline]
246 pub fn truncate_from_int(i: impl Into<i128>, size: Size) -> (Self, bool) {
247 let data = i.into();
248 let r = Self::raw(size.truncate(data as u128), size);
250 (r, size.sign_extend(r.data) != data)
251 }
252
253 #[inline]
254 pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
255 Self::try_from_uint(i, tcx.data_layout.pointer_size)
256 }
257
258 #[inline]
263 pub fn try_to_bits(self, target_size: Size) -> Result<u128, Size> {
264 assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
265 if target_size.bytes() == u64::from(self.size.get()) {
266 self.check_data();
267 Ok(self.data)
268 } else {
269 Err(self.size())
270 }
271 }
272
273 #[inline]
274 pub fn to_bits(self, target_size: Size) -> u128 {
275 self.try_to_bits(target_size).unwrap_or_else(|size| {
276 bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
277 })
278 }
279
280 #[inline]
282 pub fn to_bits_unchecked(self) -> u128 {
283 self.check_data();
284 self.data
285 }
286
287 #[inline]
290 pub fn to_uint(self, size: Size) -> u128 {
291 self.to_bits(size)
292 }
293
294 #[inline]
297 pub fn to_u8(self) -> u8 {
298 self.to_uint(Size::from_bits(8)).try_into().unwrap()
299 }
300
301 #[inline]
304 pub fn to_u16(self) -> u16 {
305 self.to_uint(Size::from_bits(16)).try_into().unwrap()
306 }
307
308 #[inline]
311 pub fn to_u32(self) -> u32 {
312 self.to_uint(Size::from_bits(32)).try_into().unwrap()
313 }
314
315 #[inline]
318 pub fn to_u64(self) -> u64 {
319 self.to_uint(Size::from_bits(64)).try_into().unwrap()
320 }
321
322 #[inline]
325 pub fn to_u128(self) -> u128 {
326 self.to_uint(Size::from_bits(128))
327 }
328
329 #[inline]
330 pub fn to_target_usize(&self, tcx: TyCtxt<'_>) -> u64 {
331 self.to_uint(tcx.data_layout.pointer_size).try_into().unwrap()
332 }
333
334 #[inline]
335 pub fn to_atomic_ordering(self) -> AtomicOrdering {
336 use AtomicOrdering::*;
337 let val = self.to_u32();
338 if val == Relaxed as u32 {
339 Relaxed
340 } else if val == Release as u32 {
341 Release
342 } else if val == Acquire as u32 {
343 Acquire
344 } else if val == AcqRel as u32 {
345 AcqRel
346 } else if val == SeqCst as u32 {
347 SeqCst
348 } else {
349 panic!("not a valid atomic ordering")
350 }
351 }
352
353 #[inline]
357 pub fn try_to_bool(self) -> Result<bool, ()> {
358 match self.to_u8() {
359 0 => Ok(false),
360 1 => Ok(true),
361 _ => Err(()),
362 }
363 }
364
365 #[inline]
368 pub fn to_int(self, size: Size) -> i128 {
369 let b = self.to_bits(size);
370 size.sign_extend(b)
371 }
372
373 pub fn to_i8(self) -> i8 {
376 self.to_int(Size::from_bits(8)).try_into().unwrap()
377 }
378
379 pub fn to_i16(self) -> i16 {
382 self.to_int(Size::from_bits(16)).try_into().unwrap()
383 }
384
385 pub fn to_i32(self) -> i32 {
388 self.to_int(Size::from_bits(32)).try_into().unwrap()
389 }
390
391 pub fn to_i64(self) -> i64 {
394 self.to_int(Size::from_bits(64)).try_into().unwrap()
395 }
396
397 pub fn to_i128(self) -> i128 {
400 self.to_int(Size::from_bits(128))
401 }
402
403 #[inline]
404 pub fn to_target_isize(&self, tcx: TyCtxt<'_>) -> i64 {
405 self.to_int(tcx.data_layout.pointer_size).try_into().unwrap()
406 }
407
408 #[inline]
409 pub fn to_float<F: Float>(self) -> F {
410 F::from_bits(self.to_bits(Size::from_bits(F::BITS)))
412 }
413
414 #[inline]
415 pub fn to_f16(self) -> Half {
416 self.to_float()
417 }
418
419 #[inline]
420 pub fn to_f32(self) -> Single {
421 self.to_float()
422 }
423
424 #[inline]
425 pub fn to_f64(self) -> Double {
426 self.to_float()
427 }
428
429 #[inline]
430 pub fn to_f128(self) -> Quad {
431 self.to_float()
432 }
433}
434
435macro_rules! from_x_for_scalar_int {
436 ($($ty:ty),*) => {
437 $(
438 impl From<$ty> for ScalarInt {
439 #[inline]
440 fn from(u: $ty) -> Self {
441 Self {
442 data: u128::from(u),
443 size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
444 }
445 }
446 }
447 )*
448 }
449}
450
451macro_rules! from_scalar_int_for_x {
452 ($($ty:ty),*) => {
453 $(
454 impl From<ScalarInt> for $ty {
455 #[inline]
456 fn from(int: ScalarInt) -> Self {
457 int.to_uint(Size::from_bytes(size_of::<$ty>()))
460 .try_into().unwrap()
461 }
462 }
463 )*
464 }
465}
466
467from_x_for_scalar_int!(u8, u16, u32, u64, u128, bool);
468from_scalar_int_for_x!(u8, u16, u32, u64, u128);
469
470impl TryFrom<ScalarInt> for bool {
471 type Error = ();
472 #[inline]
473 fn try_from(int: ScalarInt) -> Result<Self, ()> {
474 int.try_to_bool()
475 }
476}
477
478impl From<char> for ScalarInt {
479 #[inline]
480 fn from(c: char) -> Self {
481 (c as u32).into()
482 }
483}
484
485macro_rules! from_x_for_scalar_int_signed {
486 ($($ty:ty),*) => {
487 $(
488 impl From<$ty> for ScalarInt {
489 #[inline]
490 fn from(u: $ty) -> Self {
491 Self {
492 data: u128::from(u.cast_unsigned()), size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
494 }
495 }
496 }
497 )*
498 }
499}
500
501macro_rules! from_scalar_int_for_x_signed {
502 ($($ty:ty),*) => {
503 $(
504 impl From<ScalarInt> for $ty {
505 #[inline]
506 fn from(int: ScalarInt) -> Self {
507 int.to_int(Size::from_bytes(size_of::<$ty>()))
510 .try_into().unwrap()
511 }
512 }
513 )*
514 }
515}
516
517from_x_for_scalar_int_signed!(i8, i16, i32, i64, i128);
518from_scalar_int_for_x_signed!(i8, i16, i32, i64, i128);
519
520impl From<std::cmp::Ordering> for ScalarInt {
521 #[inline]
522 fn from(c: std::cmp::Ordering) -> Self {
523 ScalarInt::from(c as i8)
525 }
526}
527
528#[derive(Debug)]
530pub struct CharTryFromScalarInt;
531
532impl TryFrom<ScalarInt> for char {
533 type Error = CharTryFromScalarInt;
534
535 #[inline]
536 fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
537 match char::from_u32(int.to_u32()) {
538 Some(c) => Ok(c),
539 None => Err(CharTryFromScalarInt),
540 }
541 }
542}
543
544impl From<Half> for ScalarInt {
545 #[inline]
546 fn from(f: Half) -> Self {
547 Self { data: f.to_bits(), size: NonZero::new((Half::BITS / 8) as u8).unwrap() }
549 }
550}
551
552impl From<ScalarInt> for Half {
553 #[inline]
554 fn from(int: ScalarInt) -> Self {
555 Self::from_bits(int.to_bits(Size::from_bytes(2)))
556 }
557}
558
559impl From<Single> for ScalarInt {
560 #[inline]
561 fn from(f: Single) -> Self {
562 Self { data: f.to_bits(), size: NonZero::new((Single::BITS / 8) as u8).unwrap() }
564 }
565}
566
567impl From<ScalarInt> for Single {
568 #[inline]
569 fn from(int: ScalarInt) -> Self {
570 Self::from_bits(int.to_bits(Size::from_bytes(4)))
571 }
572}
573
574impl From<Double> for ScalarInt {
575 #[inline]
576 fn from(f: Double) -> Self {
577 Self { data: f.to_bits(), size: NonZero::new((Double::BITS / 8) as u8).unwrap() }
579 }
580}
581
582impl From<ScalarInt> for Double {
583 #[inline]
584 fn from(int: ScalarInt) -> Self {
585 Self::from_bits(int.to_bits(Size::from_bytes(8)))
586 }
587}
588
589impl From<Quad> for ScalarInt {
590 #[inline]
591 fn from(f: Quad) -> Self {
592 Self { data: f.to_bits(), size: NonZero::new((Quad::BITS / 8) as u8).unwrap() }
594 }
595}
596
597impl From<ScalarInt> for Quad {
598 #[inline]
599 fn from(int: ScalarInt) -> Self {
600 Self::from_bits(int.to_bits(Size::from_bytes(16)))
601 }
602}
603
604impl fmt::Debug for ScalarInt {
605 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
606 write!(f, "0x{self:x}")
608 }
609}
610
611impl fmt::LowerHex for ScalarInt {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 self.check_data();
614 if f.alternate() {
615 write!(f, "0x")?;
617 }
618 write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
626 }
627}
628
629impl fmt::UpperHex for ScalarInt {
630 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
631 self.check_data();
632 write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
640 }
641}
642
643impl fmt::Display for ScalarInt {
644 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
645 self.check_data();
646 write!(f, "{}", { self.data })
647 }
648}