Skip to content

Commit 3560399

Browse files
committed
Implement llvm.x86.addcarry.32 by refactoring llvm.x86.addcarry.64 to make it generic
1 parent d6b30b8 commit 3560399

File tree

2 files changed

+45
-16
lines changed

2 files changed

+45
-16
lines changed

src/tools/miri/src/shims/x86/mod.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use rustc_target::spec::abi::Abi;
55

66
use crate::*;
77
use helpers::bool_to_simd_element;
8-
use helpers::convert::Truncate as _;
98
use shims::foreign_items::EmulateByNameResult;
109

1110
mod sse;
@@ -26,23 +25,30 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
2625
// Prefix should have already been checked.
2726
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap();
2827
match unprefixed_name {
29-
"addcarry.64" if this.tcx.sess.target.arch == "x86_64" => {
30-
// Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum.
28+
// Used to implement the `_addcarry_u32` and `_addcarry_u64` functions.
29+
// Computes u8+uX+uX (uX is u32 or u64), returning tuple (u8,uX) comprising
30+
// the output carry and truncated sum.
31+
"addcarry.32" | "addcarry.64" => {
32+
if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" {
33+
return Ok(EmulateByNameResult::NotSupported);
34+
}
35+
3136
let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
3237
let c_in = this.read_scalar(c_in)?.to_u8()?;
33-
let a = this.read_scalar(a)?.to_u64()?;
34-
let b = this.read_scalar(b)?.to_u64()?;
35-
36-
#[allow(clippy::arithmetic_side_effects)]
37-
// adding two u64 and a u8 cannot wrap in a u128
38-
let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b);
39-
#[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64
40-
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
41-
42-
let c_out_field = this.project_field(dest, 0)?;
43-
this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?;
44-
let sum_field = this.project_field(dest, 1)?;
45-
this.write_scalar(Scalar::from_u64(sum), &sum_field)?;
38+
let a = this.read_immediate(a)?;
39+
let b = this.read_immediate(b)?;
40+
41+
let (sum, overflow1) = this.overflowing_binary_op(mir::BinOp::Add, &a, &b)?;
42+
let (sum, overflow2) = this.overflowing_binary_op(
43+
mir::BinOp::Add,
44+
&sum,
45+
&ImmTy::from_uint(c_in, a.layout),
46+
)?;
47+
#[allow(clippy::arithmetic_side_effects)] // adding two bools into a u8
48+
let c_out = u8::from(overflow1) + u8::from(overflow2);
49+
50+
this.write_scalar(Scalar::from_u8(c_out), &this.project_field(dest, 0)?)?;
51+
this.write_immediate(*sum, &this.project_field(dest, 1)?)?;
4652
}
4753

4854
name if name.starts_with("sse.") => {

src/tools/miri/tests/pass/intrinsics-x86.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2+
mod x86 {
3+
#[cfg(target_arch = "x86")]
4+
use core::arch::x86 as arch;
5+
#[cfg(target_arch = "x86_64")]
6+
use core::arch::x86_64 as arch;
7+
8+
fn adc(c_in: u8, a: u32, b: u32) -> (u8, u32) {
9+
let mut sum = 0;
10+
// SAFETY: There are no safety requirements for calling `_addcarry_u32`.
11+
// It's just unsafe for API consistency with other intrinsics.
12+
let c_out = unsafe { arch::_addcarry_u32(c_in, a, b, &mut sum) };
13+
(c_out, sum)
14+
}
15+
16+
pub fn main() {
17+
assert_eq!(adc(1, 1, 1), (0, 3));
18+
assert_eq!(adc(3, u32::MAX, u32::MAX), (2, 1));
19+
}
20+
}
21+
122
#[cfg(target_arch = "x86_64")]
223
mod x86_64 {
324
use core::arch::x86_64 as arch;
@@ -17,6 +38,8 @@ mod x86_64 {
1738
}
1839

1940
fn main() {
41+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
42+
x86::main();
2043
#[cfg(target_arch = "x86_64")]
2144
x86_64::main();
2245
}

0 commit comments

Comments
 (0)