1use rustc_span::Symbol;
2
3use super::{
4 packssdw, packsswb, packusdw, packuswb, pavg, permute, permute2, pmaddbw, pmaddwd, psadbw,
5 pshufb,
6};
7use crate::*;
8
9impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
10pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11 fn emulate_x86_avx512_intrinsic(
12 &mut self,
13 link_name: Symbol,
14 args: &[OpTy<'tcx>],
15 dest: &MPlaceTy<'tcx>,
16 ) -> InterpResult<'tcx, EmulateItemResult> {
17 let this = self.eval_context_mut();
18 let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.avx512.").unwrap();
20
21 match unprefixed_name {
22 "pternlog.d.128" | "pternlog.d.256" | "pternlog.d.512" => {
24 this.expect_target_feature_for_intrinsic(link_name, "avx512f")?;
25 if matches!(unprefixed_name, "pternlog.d.128" | "pternlog.d.256") {
26 this.expect_target_feature_for_intrinsic(link_name, "avx512vl")?;
27 }
28
29 let [a, b, c, imm8] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
30
31 assert_eq!(dest.layout, a.layout);
32 assert_eq!(dest.layout, b.layout);
33 assert_eq!(dest.layout, c.layout);
34
35 let (a, _a_len) = this.project_to_simd(a)?;
46 let (b, _b_len) = this.project_to_simd(b)?;
47 let (c, _c_len) = this.project_to_simd(c)?;
48 let (dest, dest_len) = this.project_to_simd(dest)?;
49
50 let tern = |xa: u32, xb: u32, xc: u32, imm: u32| -> u32 {
52 let mut out = 0u32;
53 for bit in 0..32 {
55 let ia = (xa >> bit) & 1;
56 let ib = (xb >> bit) & 1;
57 let ic = (xc >> bit) & 1;
58 let idx = (ia << 2) | (ib << 1) | ic;
59 let v = (imm >> idx) & 1;
60 out |= v << bit;
61 }
62 out
63 };
64
65 let imm8 = this.read_scalar(imm8)?.to_u32()? & 0xFF;
66 for i in 0..dest_len {
67 let a_lane = this.project_index(&a, i)?;
68 let b_lane = this.project_index(&b, i)?;
69 let c_lane = this.project_index(&c, i)?;
70 let d_lane = this.project_index(&dest, i)?;
71
72 let va = this.read_scalar(&a_lane)?.to_u32()?;
73 let vb = this.read_scalar(&b_lane)?.to_u32()?;
74 let vc = this.read_scalar(&c_lane)?.to_u32()?;
75
76 let r = tern(va, vb, vc, imm8);
77 this.write_scalar(Scalar::from_u32(r), &d_lane)?;
78 }
79 }
80 "psad.bw.512" => {
82 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
83
84 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
85
86 psadbw(this, left, right, dest)?
87 }
88 "pmaddw.d.512" => {
90 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
91
92 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
93
94 pmaddwd(this, left, right, dest)?;
95 }
96 "pmaddubs.w.512" => {
98 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
99
100 pmaddbw(this, left, right, dest)?;
101 }
102 "permvar.si.512" | "permvar.di.512" => {
104 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
105
106 permute(this, left, right, dest)?;
107 }
108 "permvar.qi.512" | "permvar.qi.256" | "permvar.qi.128" => {
109 this.expect_target_feature_for_intrinsic(link_name, "avx512vbmi")?;
110 if !unprefixed_name.ends_with("512") {
111 this.expect_target_feature_for_intrinsic(link_name, "avx512vl")?;
112 }
113
114 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
115
116 permute(this, left, right, dest)?;
117 }
118 "vpermi2var.q.512" => {
120 let [left, indices, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
121
122 permute2(this, left, indices, right, dest)?;
123 }
124 "vpermi2var.qi.512" => {
126 this.expect_target_feature_for_intrinsic(link_name, "avx512vbmi")?;
127
128 let [left, indices, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
129
130 permute2(this, left, indices, right, dest)?;
131 }
132 "pshuf.b.512" => {
134 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
135
136 pshufb(this, left, right, dest)?;
137 }
138
139 "vpdpbusd.512" | "vpdpbusd.256" | "vpdpbusd.128" => {
141 this.expect_target_feature_for_intrinsic(link_name, "avx512vnni")?;
142 if matches!(unprefixed_name, "vpdpbusd.128" | "vpdpbusd.256") {
143 this.expect_target_feature_for_intrinsic(link_name, "avx512vl")?;
144 }
145
146 let [src, a, b] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
147
148 vpdpbusd(this, src, a, b, dest)?;
149 }
150 "packsswb.512" => {
152 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
153
154 let [a, b] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
155
156 packsswb(this, a, b, dest)?;
157 }
158 "packuswb.512" => {
160 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
161
162 let [a, b] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
163
164 packuswb(this, a, b, dest)?;
165 }
166 "packssdw.512" => {
168 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
169
170 let [a, b] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
171
172 packssdw(this, a, b, dest)?;
173 }
174 "packusdw.512" => {
176 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
177
178 let [a, b] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
179
180 packusdw(this, a, b, dest)?;
181 }
182 "pavg.b.512" | "pavg.w.512" => {
185 this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
186
187 let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?;
188
189 pavg(this, left, right, dest)?;
190 }
191 _ => return interp_ok(EmulateItemResult::NotSupported),
192 }
193 interp_ok(EmulateItemResult::NeedsReturn)
194 }
195}
196
197fn vpdpbusd<'tcx>(
206 ecx: &mut crate::MiriInterpCx<'tcx>,
207 src: &OpTy<'tcx>,
208 a: &OpTy<'tcx>,
209 b: &OpTy<'tcx>,
210 dest: &MPlaceTy<'tcx>,
211) -> InterpResult<'tcx, ()> {
212 let (src, src_len) = ecx.project_to_simd(src)?;
213 let (a, a_len) = ecx.project_to_simd(a)?;
214 let (b, b_len) = ecx.project_to_simd(b)?;
215 let (dest, dest_len) = ecx.project_to_simd(dest)?;
216
217 assert_eq!(src_len, dest_len);
221 assert_eq!(a_len, dest_len.strict_mul(4));
222 assert_eq!(b_len, a_len);
223
224 for i in 0..dest_len {
225 let src = ecx.read_scalar(&ecx.project_index(&src, i)?)?.to_i32()?;
226 let dest = ecx.project_index(&dest, i)?;
227
228 let mut intermediate_sum: i32 = 0;
229 for j in 0..4 {
230 let idx = i.strict_mul(4).strict_add(j);
231 let a = ecx.read_scalar(&ecx.project_index(&a, idx)?)?.to_u8()?;
232 let b = ecx.read_scalar(&ecx.project_index(&b, idx)?)?.to_i8()?;
233
234 let product = i32::from(a).strict_mul(i32::from(b));
235 intermediate_sum = intermediate_sum.strict_add(product);
236 }
237
238 let res = Scalar::from_i32(intermediate_sum.wrapping_add(src));
240 ecx.write_scalar(res, &dest)?;
241 }
242
243 interp_ok(())
244}