miri/intrinsics/x86/ssse3.rs
1use rustc_middle::mir;
2use rustc_span::Symbol;
3
4use super::{horizontal_bin_op, pmaddbw, pmulhrsw, pshufb, psign};
5use crate::*;
6
7impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
8pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
9 fn emulate_x86_ssse3_intrinsic(
10 &mut self,
11 link_name: Symbol,
12 args: &[OpTy<'tcx>],
13 dest: &MPlaceTy<'tcx>,
14 ) -> InterpResult<'tcx, EmulateItemResult> {
15 let this = self.eval_context_mut();
16 this.expect_target_feature_for_intrinsic(link_name, "ssse3")?;
17 // Prefix should have already been checked.
18 let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.ssse3.").unwrap();
19
20 match unprefixed_name {
21 // Used to implement the _mm_shuffle_epi8 intrinsic.
22 // Shuffles bytes from `left` using `right` as pattern.
23 // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8
24 "pshuf.b.128" => {
25 let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?;
26
27 pshufb(this, left, right, dest)?;
28 }
29 // Used to implement the _mm_h{adds,subs}_epi16 functions.
30 // Horizontally add / subtract with saturation adjacent 16-bit
31 // integer values in `left` and `right`.
32 "phadd.sw.128" | "phsub.sw.128" => {
33 let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?;
34
35 let which = match unprefixed_name {
36 "phadd.sw.128" => mir::BinOp::Add,
37 "phsub.sw.128" => mir::BinOp::Sub,
38 _ => unreachable!(),
39 };
40
41 horizontal_bin_op(this, which, /*saturating*/ true, left, right, dest)?;
42 }
43 // Used to implement the _mm_maddubs_epi16 function.
44 "pmadd.ub.sw.128" => {
45 let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?;
46
47 pmaddbw(this, left, right, dest)?;
48 }
49 // Used to implement the _mm_mulhrs_epi16 function.
50 // Multiplies packed 16-bit signed integer values, truncates the 32-bit
51 // product to the 18 most significant bits by right-shifting, and then
52 // divides the 18-bit value by 2 (rounding to nearest) by first adding
53 // 1 and then taking the bits `1..=16`.
54 // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16
55 "pmul.hr.sw.128" => {
56 let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?;
57
58 pmulhrsw(this, left, right, dest)?;
59 }
60 // Used to implement the _mm_sign_epi{8,16,32} functions.
61 // Negates elements from `left` when the corresponding element in
62 // `right` is negative. If an element from `right` is zero, zero
63 // is written to the corresponding output element.
64 // Basically, we multiply `left` with `right.signum()`.
65 "psign.b.128" | "psign.w.128" | "psign.d.128" => {
66 let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?;
67
68 psign(this, left, right, dest)?;
69 }
70 _ => return interp_ok(EmulateItemResult::NotSupported),
71 }
72 interp_ok(EmulateItemResult::NeedsReturn)
73 }
74}