1use crate::v::vector_registers::{VRegGroup, VectorRegistersExt};
4pub use crate::v::zvexx::arith::zvexx_arith_helpers::{OpSrc, sew_mask, sign_extend};
5use crate::v::zvexx::load::zvexx_load_helpers::{mask_bit, snapshot_mask};
6use crate::v::zvexx::zvexx_helpers::WideningSew;
7use ab_riscv_primitives::prelude::*;
8use core::hint::cold_path;
9
10#[inline(always)]
18#[doc(hidden)]
19#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
20pub fn execute_arith_op<Reg, Env, F>(
21 env: &mut Env,
22 vd: VRegGroup<Env::Hart>,
23 vs2: VRegGroup<Env::Hart>,
24 src: OpSrc<VRegGroup<Env::Hart>>,
25 vm: bool,
26 sew: Vsew,
27 op: F,
28) where
29 Reg: Register,
30 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
31 F: Fn(u64, u64, Vsew) -> u64,
32{
33 let vl = vd.vl();
34 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
35 cold_path();
36 return;
37 };
38 let mask_buf = snapshot_mask(env.read_vregs(), vm);
39 for i in vl.indices() {
40 if !mask_bit(&mask_buf, i) {
41 continue;
42 }
43 let a = env
44 .read_vregs()
45 .read(vs2, i)
46 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
47 let b = match src.vreg {
48 Some(vs1) => env
49 .read_vregs()
50 .read(vs1, i)
51 .expect("`vs1` has the same `vl` as `vd`, checked above; qed"),
52 None => src.scalar,
53 };
54 let result = op(a, b, sew);
55 env.write_vregs()
56 .write(vd, i, result)
57 .expect("`i < vl` of `vd`; qed");
58 }
59 env.mark_vs_dirty();
60}
61
62#[inline(always)]
70#[doc(hidden)]
71#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
72pub fn execute_widening_op<Reg, Env, F>(
73 env: &mut Env,
74 vd: VRegGroup<Env::Hart>,
75 vs2: VRegGroup<Env::Hart>,
76 src: OpSrc<VRegGroup<Env::Hart>>,
77 vm: bool,
78 sew: WideningSew<Env::Hart>,
79 op: F,
80) where
81 Reg: Register,
82 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
83 F: Fn(u64, u64, Vsew) -> u64,
84{
85 let sew = sew.narrow();
86 let vl = vd.vl();
87 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
88 cold_path();
89 return;
90 };
91 let mask_buf = snapshot_mask(env.read_vregs(), vm);
92 for i in vl.indices() {
93 if !mask_bit(&mask_buf, i) {
94 continue;
95 }
96 let a = env
97 .read_vregs()
98 .read(vs2, i)
99 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
100 let b = match src.vreg {
101 Some(vs1) => env
102 .read_vregs()
103 .read(vs1, i)
104 .expect("`vs1` has the same `vl` as `vd`, checked above; qed"),
105 None => src.scalar,
106 };
107 let result = op(a, b, sew);
108 env.write_vregs()
109 .write(vd, i, result)
110 .expect("`i < vl` of `vd`; qed");
111 }
112 env.mark_vs_dirty();
113}
114
115#[inline(always)]
123#[doc(hidden)]
124#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
125pub fn execute_muladd_op<Reg, Env, F>(
126 env: &mut Env,
127 vd: VRegGroup<Env::Hart>,
128 a_reg: VRegGroup<Env::Hart>,
129 src: OpSrc<VRegGroup<Env::Hart>>,
130 vm: bool,
131 sew: Vsew,
132 op: F,
133) where
134 Reg: Register,
135 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
136 F: Fn(u64, u64, u64, Vsew) -> u64,
137{
138 let vl = vd.vl();
139 let (Some(a_reg), Some(src)) = (a_reg.with_same_vl(vl), src.with_same_vl(vl)) else {
140 cold_path();
141 return;
142 };
143 let mask_buf = snapshot_mask(env.read_vregs(), vm);
144 for i in vl.indices() {
145 if !mask_bit(&mask_buf, i) {
146 continue;
147 }
148 let acc = env.read_vregs().read(vd, i).expect("`i < vl` of `vd`; qed");
149 let a = env
150 .read_vregs()
151 .read(a_reg, i)
152 .expect("`a_reg` has the same `vl` as `vd`, checked above; qed");
153 let b = match src.vreg {
154 Some(b_reg) => env
155 .read_vregs()
156 .read(b_reg, i)
157 .expect("`b_reg` has the same `vl` as `vd`, checked above; qed"),
158 None => src.scalar,
159 };
160 let result = op(acc, a, b, sew);
161 env.write_vregs()
162 .write(vd, i, result)
163 .expect("`i < vl` of `vd`; qed");
164 }
165 env.mark_vs_dirty();
166}
167
168#[inline(always)]
175#[doc(hidden)]
176#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
177pub fn execute_muladd_scalar_op<Reg, Env, F>(
178 env: &mut Env,
179 vd: VRegGroup<Env::Hart>,
180 scalar: u64,
181 src: OpSrc<VRegGroup<Env::Hart>>,
182 vm: bool,
183 sew: Vsew,
184 op: F,
185) where
186 Reg: Register,
187 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
188 F: Fn(u64, u64, u64, Vsew) -> u64,
189{
190 let vl = vd.vl();
191 let Some(src) = src.with_same_vl(vl) else {
192 cold_path();
193 return;
194 };
195 let mask_buf = snapshot_mask(env.read_vregs(), vm);
196 for i in vl.indices() {
197 if !mask_bit(&mask_buf, i) {
198 continue;
199 }
200 let acc = env.read_vregs().read(vd, i).expect("`i < vl` of `vd`; qed");
201 let b = match src.vreg {
202 Some(b_reg) => env
203 .read_vregs()
204 .read(b_reg, i)
205 .expect("`b_reg` has the same `vl` as `vd`, checked above; qed"),
206 None => src.scalar,
207 };
208 let result = op(acc, scalar, b, sew);
209 env.write_vregs()
210 .write(vd, i, result)
211 .expect("`i < vl` of `vd`; qed");
212 }
213 env.mark_vs_dirty();
214}
215
216#[inline(always)]
226#[doc(hidden)]
227#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
228pub fn execute_widening_muladd_op<Reg, Env, F>(
229 env: &mut Env,
230 vd: VRegGroup<Env::Hart>,
231 a_reg: VRegGroup<Env::Hart>,
232 src: OpSrc<VRegGroup<Env::Hart>>,
233 vm: bool,
234 sew: WideningSew<Env::Hart>,
235 op: F,
236) where
237 Reg: Register,
238 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
239 F: Fn(u64, u64, u64, Vsew) -> u64,
240{
241 let sew = sew.narrow();
242 let vl = vd.vl();
243 let (Some(a_reg), Some(src)) = (a_reg.with_same_vl(vl), src.with_same_vl(vl)) else {
244 cold_path();
245 return;
246 };
247 let mask_buf = snapshot_mask(env.read_vregs(), vm);
248 for i in vl.indices() {
249 if !mask_bit(&mask_buf, i) {
250 continue;
251 }
252 let acc = env.read_vregs().read(vd, i).expect("`i < vl` of `vd`; qed");
254 let a = env
255 .read_vregs()
256 .read(a_reg, i)
257 .expect("`a_reg` has the same `vl` as `vd`, checked above; qed");
258 let b = match src.vreg {
259 Some(b_reg) => env
260 .read_vregs()
261 .read(b_reg, i)
262 .expect("`b_reg` has the same `vl` as `vd`, checked above; qed"),
263 None => src.scalar,
264 };
265 let result = op(acc, a, b, sew);
266 env.write_vregs()
267 .write(vd, i, result)
268 .expect("`i < vl` of `vd`; qed");
269 }
270 env.mark_vs_dirty();
271}
272
273#[inline(always)]
280#[doc(hidden)]
281#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
282pub fn execute_widening_muladd_scalar_op<Reg, Env, F>(
283 env: &mut Env,
284 vd: VRegGroup<Env::Hart>,
285 scalar: u64,
286 src: OpSrc<VRegGroup<Env::Hart>>,
287 vm: bool,
288 sew: WideningSew<Env::Hart>,
289 op: F,
290) where
291 Reg: Register,
292 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
293 F: Fn(u64, u64, u64, Vsew) -> u64,
294{
295 let sew = sew.narrow();
296 let vl = vd.vl();
297 let Some(src) = src.with_same_vl(vl) else {
298 cold_path();
299 return;
300 };
301 let mask_buf = snapshot_mask(env.read_vregs(), vm);
302 for i in vl.indices() {
303 if !mask_bit(&mask_buf, i) {
304 continue;
305 }
306 let acc = env.read_vregs().read(vd, i).expect("`i < vl` of `vd`; qed");
307 let b = match src.vreg {
308 Some(b_reg) => env
309 .read_vregs()
310 .read(b_reg, i)
311 .expect("`b_reg` has the same `vl` as `vd`, checked above; qed"),
312 None => src.scalar,
313 };
314 let result = op(acc, scalar, b, sew);
315 env.write_vregs()
316 .write(vd, i, result)
317 .expect("`i < vl` of `vd`; qed");
318 }
319 env.mark_vs_dirty();
320}
321
322#[inline(always)]
331#[doc(hidden)]
332#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
333pub fn mulh_ss(a: u64, b: u64, sew: Vsew) -> u64 {
334 let sa = sign_extend(a, sew);
335 let sb = sign_extend(b, sew);
336 let product = sa.widening_mul(sb);
337 let high = (product >> sew.bits_width()).cast_unsigned() as u64;
339 high & sew_mask(sew)
340}
341
342#[inline(always)]
346#[doc(hidden)]
347#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
348pub fn mulhu_uu(a: u64, b: u64, sew: Vsew) -> u64 {
349 let ua = a & sew_mask(sew);
350 let ub = b & sew_mask(sew);
351 let product = ua.widening_mul(ub);
352 let high = (product >> sew.bits_width()) as u64;
353 high & sew_mask(sew)
354}
355
356#[inline(always)]
364#[doc(hidden)]
365#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
366pub fn mulhsu_su(a: u64, b: u64, sew: Vsew) -> u64 {
367 let sa = i128::from(sign_extend(a, sew));
368 let ub = i128::from(b & sew_mask(sew));
369 let product = sa.wrapping_mul(ub);
370 let high = (product >> sew.bits_width()).cast_unsigned() as u64;
371 high & sew_mask(sew)
372}
373
374#[inline(always)]
379#[doc(hidden)]
380#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
381pub fn sdiv(a: u64, b: u64, sew: Vsew) -> u64 {
382 let sa = sign_extend(a, sew);
383 let sb = sign_extend(b, sew);
384 if sb == 0 {
386 return sew_mask(sew);
387 }
388 sa.wrapping_div(sb).cast_unsigned() & sew_mask(sew)
389}
390
391#[inline(always)]
397#[doc(hidden)]
398#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
399pub fn srem(a: u64, b: u64, sew: Vsew) -> u64 {
400 let sa = sign_extend(a, sew);
401 let sb = sign_extend(b, sew);
402 if sb == 0 {
404 return a & sew_mask(sew);
405 }
406 sa.wrapping_rem(sb).cast_unsigned() & sew_mask(sew)
407}