From a893618854b3c22fbe54a9b771ade85edada4143 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 14:37:54 -0700 Subject: [PATCH] Implement llvm.x86.addcarry.64 --- src/shims/foreign_items.rs | 15 +++++++++++++++ tests/run-pass/intrinsics-x86.rs | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/run-pass/intrinsics-x86.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ef88c550ecb..807fca81701 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -671,6 +671,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims + "llvm.x86.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. + let &[ref c_in, ref a, ref 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()?; + + 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 c_out_field = this.place_field(dest, 0)?; + this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; + let sum_field = this.place_field(dest, 1)?; + this.write_scalar(Scalar::from_u64(sum), &sum_field)?; + } "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); diff --git a/tests/run-pass/intrinsics-x86.rs b/tests/run-pass/intrinsics-x86.rs new file mode 100644 index 00000000000..88cd782e70a --- /dev/null +++ b/tests/run-pass/intrinsics-x86.rs @@ -0,0 +1,22 @@ +#[cfg(target_arch = "x86_64")] +mod x86_64 { + use core::arch::x86_64 as arch; + + fn adc(c_in: u8, a: u64, b: u64) -> (u8, u64) { + let mut sum = 0; + // SAFETY: There are no safety requirements for calling `_addcarry_u64`. + // It's just unsafe for API consistency with other intrinsics. + let c_out = unsafe { arch::_addcarry_u64(c_in, a, b, &mut sum) }; + (c_out, sum) + } + + pub fn main() { + assert_eq!(adc(1, 1, 1), (0, 3)); + assert_eq!(adc(3, u64::MAX, u64::MAX), (2, 1)); + } +} + +fn main() { + #[cfg(target_arch = "x86_64")] + x86_64::main(); +}