Replace `as` casts in llvm.x86.addcarry.64 implementation

This commit is contained in:
David Tolnay 2022-04-30 10:06:19 -07:00
parent e1068cf211
commit 8d42a7cfdf
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
3 changed files with 54 additions and 2 deletions

View File

@ -1,3 +1,5 @@
pub mod convert;
use std::mem;
use std::num::NonZeroUsize;
use std::time::Duration;

49
src/helpers/convert.rs Normal file
View File

@ -0,0 +1,49 @@
use implementations::NarrowerThan;
/// Replacement for `as` casts going from wide integer to narrower integer.
///
/// # Example
///
/// ```ignore
/// let x = 99_u64;
/// let lo = x.truncate::<u16>();
/// // lo is of type u16, equivalent to `x as u16`.
/// ```
pub(crate) trait Truncate: Sized {
fn truncate<To>(self) -> To
where
To: NarrowerThan<Self>,
{
NarrowerThan::truncate_from(self)
}
}
impl Truncate for u16 {}
impl Truncate for u32 {}
impl Truncate for u64 {}
impl Truncate for u128 {}
mod implementations {
pub(crate) trait NarrowerThan<T> {
fn truncate_from(wide: T) -> Self;
}
macro_rules! impl_narrower_than {
($(NarrowerThan<{$($ty:ty),*}> for $self:ty)*) => {
$($(
impl NarrowerThan<$ty> for $self {
fn truncate_from(wide: $ty) -> Self {
wide as Self
}
}
)*)*
};
}
impl_narrower_than! {
NarrowerThan<{u128, u64, u32, u16}> for u8
NarrowerThan<{u128, u64, u32}> for u16
NarrowerThan<{u128, u64}> for u32
NarrowerThan<{u128}> for u64
}
}

View File

@ -22,6 +22,7 @@ use rustc_target::{
};
use super::backtrace::EvalContextExt as _;
use crate::helpers::convert::Truncate;
use crate::*;
/// Returned by `emulate_foreign_item_by_name`.
@ -678,8 +679,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let a = this.read_scalar(a)?.to_u64()?;
let b = this.read_scalar(b)?.to_u64()?;
let wide_sum = c_in as u128 + a as u128 + b as u128;
let (c_out, sum) = ((wide_sum >> 64) as u8, wide_sum as u64);
let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b);
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
let c_out_field = this.place_field(dest, 0)?;
this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?;