Skip to content

Commit 0143f1f

Browse files
committed
Auto merge of #3055 - eduardosm:x86-sse2-intrinsics, r=RalfJung
Implement some `llvm.x86.sse2.*` intrinsics and add tests Continuation of #2989 with SSE2 intrinsics. Thankfully, a significant amount of SSE2 functions use `simd_*` intrinsics, which are already implemented in Miri.
2 parents 13ad9d9 + 0567761 commit 0143f1f

File tree

6 files changed

+1894
-57
lines changed

6 files changed

+1894
-57
lines changed

src/shims/foreign_items.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10371037
this, link_name, abi, args, dest,
10381038
);
10391039
}
1040+
name if name.starts_with("llvm.x86.sse2.") => {
1041+
return shims::x86::sse2::EvalContextExt::emulate_x86_sse2_intrinsic(
1042+
this, link_name, abi, args, dest,
1043+
);
1044+
}
10401045

10411046
// Platform-specific shims
10421047
_ =>

src/shims/x86/mod.rs

+44
Original file line numberDiff line numberDiff line change
@@ -1 +1,45 @@
1+
use crate::InterpResult;
2+
13
pub(super) mod sse;
4+
pub(super) mod sse2;
5+
6+
/// Floating point comparison operation
7+
///
8+
/// <https://www.felixcloutier.com/x86/cmpss>
9+
/// <https://www.felixcloutier.com/x86/cmpps>
10+
/// <https://www.felixcloutier.com/x86/cmpsd>
11+
/// <https://www.felixcloutier.com/x86/cmppd>
12+
#[derive(Copy, Clone)]
13+
enum FloatCmpOp {
14+
Eq,
15+
Lt,
16+
Le,
17+
Unord,
18+
Neq,
19+
/// Not less-than
20+
Nlt,
21+
/// Not less-or-equal
22+
Nle,
23+
/// Ordered, i.e. neither of them is NaN
24+
Ord,
25+
}
26+
27+
impl FloatCmpOp {
28+
/// Convert from the `imm` argument used to specify the comparison
29+
/// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
30+
fn from_intrinsic_imm(imm: i8, intrinsic: &str) -> InterpResult<'_, Self> {
31+
match imm {
32+
0 => Ok(Self::Eq),
33+
1 => Ok(Self::Lt),
34+
2 => Ok(Self::Le),
35+
3 => Ok(Self::Unord),
36+
4 => Ok(Self::Neq),
37+
5 => Ok(Self::Nlt),
38+
6 => Ok(Self::Nle),
39+
7 => Ok(Self::Ord),
40+
imm => {
41+
throw_unsup_format!("invalid `imm` parameter of {intrinsic}: {imm}");
42+
}
43+
}
44+
}
45+
}

src/shims/x86/sse.rs

+14-55
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_target::spec::abi::Abi;
55

66
use rand::Rng as _;
77

8+
use super::FloatCmpOp;
89
use crate::*;
910
use shims::foreign_items::EmulateByNameResult;
1011

@@ -78,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7879

7980
unary_op_ss(this, which, op, dest)?;
8081
}
81-
// Used to implement _mm_{sqrt,rcp,rsqrt}_ss functions.
82+
// Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions.
8283
// Performs the operations on all components of `op`.
8384
"sqrt.ps" | "rcp.ps" | "rsqrt.ps" => {
8485
let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -100,22 +101,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
100101
let [left, right, imm] =
101102
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
102103

103-
let which = match this.read_scalar(imm)?.to_i8()? {
104-
0 => FloatBinOp::Cmp(FloatCmpOp::Eq),
105-
1 => FloatBinOp::Cmp(FloatCmpOp::Lt),
106-
2 => FloatBinOp::Cmp(FloatCmpOp::Le),
107-
3 => FloatBinOp::Cmp(FloatCmpOp::Unord),
108-
4 => FloatBinOp::Cmp(FloatCmpOp::Neq),
109-
5 => FloatBinOp::Cmp(FloatCmpOp::Nlt),
110-
6 => FloatBinOp::Cmp(FloatCmpOp::Nle),
111-
7 => FloatBinOp::Cmp(FloatCmpOp::Ord),
112-
imm => {
113-
throw_unsup_format!(
114-
"invalid 3rd parameter of llvm.x86.sse.cmp.ps: {}",
115-
imm
116-
);
117-
}
118-
};
104+
let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
105+
this.read_scalar(imm)?.to_i8()?,
106+
"llvm.x86.sse.cmp.ss",
107+
)?);
119108

120109
bin_op_ss(this, which, left, right, dest)?;
121110
}
@@ -127,26 +116,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
127116
let [left, right, imm] =
128117
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
129118

130-
let which = match this.read_scalar(imm)?.to_i8()? {
131-
0 => FloatBinOp::Cmp(FloatCmpOp::Eq),
132-
1 => FloatBinOp::Cmp(FloatCmpOp::Lt),
133-
2 => FloatBinOp::Cmp(FloatCmpOp::Le),
134-
3 => FloatBinOp::Cmp(FloatCmpOp::Unord),
135-
4 => FloatBinOp::Cmp(FloatCmpOp::Neq),
136-
5 => FloatBinOp::Cmp(FloatCmpOp::Nlt),
137-
6 => FloatBinOp::Cmp(FloatCmpOp::Nle),
138-
7 => FloatBinOp::Cmp(FloatCmpOp::Ord),
139-
imm => {
140-
throw_unsup_format!(
141-
"invalid 3rd parameter of llvm.x86.sse.cmp.ps: {}",
142-
imm
143-
);
144-
}
145-
};
119+
let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
120+
this.read_scalar(imm)?.to_i8()?,
121+
"llvm.x86.sse.cmp.ps",
122+
)?);
146123

147124
bin_op_ps(this, which, left, right, dest)?;
148125
}
149-
// Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ps functions.
126+
// Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ss functions.
150127
// Compares the first component of `left` and `right` and returns
151128
// a scalar value (0 or 1).
152129
"comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
@@ -292,6 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
292269
let op = this.read_scalar(&this.project_index(&op, i)?)?;
293270
let op = op.to_u32()?;
294271

272+
// Extract the highest bit of `op` and place it in the `i`-th bit of `res`
295273
res |= (op >> 31) << i;
296274
}
297275

@@ -303,25 +281,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
303281
}
304282
}
305283

306-
/// Floating point comparison operation
307-
///
308-
/// <https://www.felixcloutier.com/x86/cmpss>
309-
/// <https://www.felixcloutier.com/x86/cmpps>
310-
#[derive(Copy, Clone)]
311-
enum FloatCmpOp {
312-
Eq,
313-
Lt,
314-
Le,
315-
Unord,
316-
Neq,
317-
/// Not less-than
318-
Nlt,
319-
/// Not less-or-equal
320-
Nle,
321-
/// Ordered, i.e. neither of them is NaN
322-
Ord,
323-
}
324-
325284
#[derive(Copy, Clone)]
326285
enum FloatBinOp {
327286
/// Arithmetic operation
@@ -436,8 +395,8 @@ fn bin_op_ss<'tcx>(
436395
Ok(())
437396
}
438397

439-
/// Performs `which` operation on each component of `left`, and
440-
/// `right` storing the result is stored in `dest`.
398+
/// Performs `which` operation on each component of `left` and
399+
/// `right`, storing the result is stored in `dest`.
441400
fn bin_op_ps<'tcx>(
442401
this: &mut crate::MiriInterpCx<'_, 'tcx>,
443402
which: FloatBinOp,

0 commit comments

Comments
 (0)