diff options
| -rw-r--r-- | src/tools/miri/src/shims/x86/mod.rs | 38 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/intrinsics-x86.rs | 23 |
2 files changed, 45 insertions, 16 deletions
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 16eac81fa0a..2db2f2e19ff 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -5,7 +5,6 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::bool_to_simd_element; -use helpers::convert::Truncate as _; use shims::foreign_items::EmulateByNameResult; mod sse; @@ -26,23 +25,30 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); match unprefixed_name { - "addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { - // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. + // Used to implement the `_addcarry_u32` and `_addcarry_u64` functions. + // Computes u8+uX+uX (uX is u32 or u64), returning tuple (u8,uX) comprising + // the output carry and truncated sum. + "addcarry.32" | "addcarry.64" => { + if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" { + return Ok(EmulateByNameResult::NotSupported); + } + let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let c_in = this.read_scalar(c_in)?.to_u8()?; - let a = this.read_scalar(a)?.to_u64()?; - let b = this.read_scalar(b)?.to_u64()?; - - #[allow(clippy::arithmetic_side_effects)] - // adding two u64 and a u8 cannot wrap in a u128 - let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); - #[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64 - let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>()); - - let c_out_field = this.project_field(dest, 0)?; - this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; - let sum_field = this.project_field(dest, 1)?; - this.write_scalar(Scalar::from_u64(sum), &sum_field)?; + let a = this.read_immediate(a)?; + let b = this.read_immediate(b)?; + + let (sum, overflow1) = this.overflowing_binary_op(mir::BinOp::Add, &a, &b)?; + let (sum, overflow2) = this.overflowing_binary_op( + mir::BinOp::Add, + &sum, + &ImmTy::from_uint(c_in, a.layout), + )?; + #[allow(clippy::arithmetic_side_effects)] // adding two bools into a u8 + let c_out = u8::from(overflow1) + u8::from(overflow2); + + this.write_scalar(Scalar::from_u8(c_out), &this.project_field(dest, 0)?)?; + this.write_immediate(*sum, &this.project_field(dest, 1)?)?; } name if name.starts_with("sse.") => { diff --git a/src/tools/miri/tests/pass/intrinsics-x86.rs b/src/tools/miri/tests/pass/intrinsics-x86.rs index 88cd782e70a..2e947200989 100644 --- a/src/tools/miri/tests/pass/intrinsics-x86.rs +++ b/src/tools/miri/tests/pass/intrinsics-x86.rs @@ -1,3 +1,24 @@ +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod x86 { + #[cfg(target_arch = "x86")] + use core::arch::x86 as arch; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64 as arch; + + fn adc(c_in: u8, a: u32, b: u32) -> (u8, u32) { + let mut sum = 0; + // SAFETY: There are no safety requirements for calling `_addcarry_u32`. + // It's just unsafe for API consistency with other intrinsics. + let c_out = unsafe { arch::_addcarry_u32(c_in, a, b, &mut sum) }; + (c_out, sum) + } + + pub fn main() { + assert_eq!(adc(1, 1, 1), (0, 3)); + assert_eq!(adc(3, u32::MAX, u32::MAX), (2, 1)); + } +} + #[cfg(target_arch = "x86_64")] mod x86_64 { use core::arch::x86_64 as arch; @@ -17,6 +38,8 @@ mod x86_64 { } fn main() { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + x86::main(); #[cfg(target_arch = "x86_64")] x86_64::main(); } |
