Skip to main content

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}