1use crate::v::vector_registers::{VRegGroup, VectorRegisterFile, VectorRegistersExt};
4use crate::v::zvexx::load::zvexx_load_helpers::{mask_bit, snapshot_mask};
5use ab_riscv_primitives::prelude::*;
6use core::hint::cold_path;
7
8#[inline(always)]
23#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
24pub fn sign_extend_to_reg<Reg>(val: u64, sew: Vsew) -> Reg::Type
25where
26 Reg: Register,
27{
28 let sew_bits = u32::from(sew.bits_width());
29 let shift = u64::BITS - sew_bits;
31 let sign_extended = (val.cast_signed() << shift) >> shift;
33 let raw = sign_extended.cast_unsigned();
34 if Reg::XLEN == u64::BITS as u8 {
35 let lo = Reg::Type::from(raw as u32);
37 let hi = Reg::Type::from((raw >> u32::BITS) as u32);
38 lo | (hi << 32u8)
39 } else {
40 Reg::Type::from(raw as u32)
42 }
43}
44
45#[inline(always)]
53#[doc(hidden)]
54#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
55pub fn execute_slideup<Reg, Env>(
56 env: &mut Env,
57 vd: VRegGroup<Env::Hart>,
58 vs2: VRegGroup<Env::Hart>,
59 vm: bool,
60 offset: u64,
61) where
62 Reg: Register,
63 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
64{
65 let vl = vd.vl();
66 let Some(vs2) = vs2.with_same_vl(vl) else {
67 cold_path();
68 return;
69 };
70 if vm {
73 if let Some(count) = u64::from(u32::from(vl.get())).checked_sub(offset)
74 && let Ok(dst_first) = u16::try_from(offset)
75 && let Ok(count) = u32::try_from(count)
76 && !env
77 .write_vregs()
78 .copy_elements(vd, dst_first, vs2, 0, count)
79 {
80 cold_path();
83 }
84 env.mark_vs_dirty();
85 return;
86 }
87 let Ok(offset) = u16::try_from(offset) else {
89 env.mark_vs_dirty();
90 return;
91 };
92
93 let mask_buf = snapshot_mask(env.read_vregs(), vm);
94 for i in vl.indices() {
95 let Some(src_i) = i.checked_sub(offset) else {
96 continue;
97 };
98 if !mask_bit(&mask_buf, i) {
99 continue;
100 }
101 let val = env
102 .read_vregs()
103 .read(vs2, src_i)
104 .expect("`src_i <= i < vl`, which is the same for `vs2`, checked above; qed");
105 env.write_vregs()
106 .write(vd, i, val)
107 .expect("`i < vl` of `vd`; qed");
108 }
109 env.mark_vs_dirty();
110}
111
112#[inline(always)]
119#[doc(hidden)]
120#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
121pub fn execute_slidedown<Reg, Env>(
122 env: &mut Env,
123 vd: VRegGroup<Env::Hart>,
124 vs2: VRegGroup<Env::Hart>,
125 vm: bool,
126 offset: u64,
127) where
128 Reg: Register,
129 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
130{
131 let vl = vd.vl();
132 let Some(vs2) = vs2.with_same_vl(vl) else {
133 cold_path();
134 return;
135 };
136
137 if vm {
140 let vl_len = u32::from(vl.get());
141 let copied = u64::from(u32::from(vs2.vlmax()))
143 .saturating_sub(offset)
144 .min(u64::from(vl_len));
145 let copied = u32::try_from(copied).unwrap_or(vl_len);
146 let vregs = env.write_vregs();
147 if copied > 0
148 && let Ok(src_first) = u16::try_from(offset)
149 && !vregs.copy_elements(vd, 0, vs2, src_first, copied)
150 {
151 cold_path();
154 }
155 if let Ok(first_zeroed) = u16::try_from(copied)
156 && let Some(bytes) = vregs.elements_bytes_mut(vd, first_zeroed, vl_len - copied)
157 {
158 bytes.fill(0);
159 }
160 env.mark_vs_dirty();
161 return;
162 }
163
164 let mask_buf = snapshot_mask(env.read_vregs(), vm);
165 for i in vl.indices() {
166 if !mask_bit(&mask_buf, i) {
167 continue;
168 }
169 let val = u64::from(i)
171 .checked_add(offset)
172 .and_then(|src_idx| u16::try_from(src_idx).ok())
173 .and_then(|src_idx| env.read_vregs().read_up_to_vlmax(vs2, src_idx))
174 .unwrap_or_default();
175 env.write_vregs()
176 .write(vd, i, val)
177 .expect("`i < vl` of `vd`; qed");
178 }
179 env.mark_vs_dirty();
180}
181
182#[inline(always)]
191#[doc(hidden)]
192#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
193pub fn execute_slide1up<Reg, Env>(
194 env: &mut Env,
195 vd: VRegGroup<Env::Hart>,
196 vs2: VRegGroup<Env::Hart>,
197 vm: bool,
198 scalar: u64,
199) where
200 Reg: Register,
201 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
202{
203 let vl = vd.vl();
204 let Some(vs2) = vs2.with_same_vl(vl) else {
205 cold_path();
206 return;
207 };
208 let mask_buf = snapshot_mask(env.read_vregs(), vm);
209 for i in vl.indices() {
210 if !mask_bit(&mask_buf, i) {
211 continue;
212 }
213 let val = match i.checked_sub(1) {
214 Some(src_idx) => env
215 .read_vregs()
216 .read(vs2, src_idx)
217 .expect("`i - 1 < vl`, which is the same for `vs2`, checked above; qed"),
218 None => scalar,
219 };
220 env.write_vregs()
221 .write(vd, i, val)
222 .expect("`i < vl` of `vd`; qed");
223 }
224 env.mark_vs_dirty();
225}
226
227#[inline(always)]
240#[doc(hidden)]
241#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
242pub fn execute_slide1down<Reg, Env>(
243 env: &mut Env,
244 vd: VRegGroup<Env::Hart>,
245 vs2: VRegGroup<Env::Hart>,
246 vm: bool,
247 scalar: u64,
248) where
249 Reg: Register,
250 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
251{
252 let vl = vd.vl();
253 let Some(vs2) = vs2.with_same_vl(vl) else {
254 cold_path();
255 return;
256 };
257 let mask_buf = snapshot_mask(env.read_vregs(), vm);
258 for i in vl.indices() {
259 if !mask_bit(&mask_buf, i) {
260 continue;
261 }
262 let val = i
264 .checked_add(1)
265 .and_then(|src_idx| env.read_vregs().read(vs2, src_idx))
266 .unwrap_or(scalar);
267 env.write_vregs()
268 .write(vd, i, val)
269 .expect("`i < vl` of `vd`; qed");
270 }
271 env.mark_vs_dirty();
272}
273
274#[inline(always)]
279#[doc(hidden)]
280#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
281pub fn execute_rgather_vv<Reg, Env>(
282 env: &mut Env,
283 vd: VRegGroup<Env::Hart>,
284 vs2: VRegGroup<Env::Hart>,
285 vs1: VRegGroup<Env::Hart>,
286 vm: bool,
287) where
288 Reg: Register,
289 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
290{
291 let vl = vd.vl();
292 let Some(vs1) = vs1.with_same_vl(vl) else {
293 cold_path();
294 return;
295 };
296 let mask_buf = snapshot_mask(env.read_vregs(), vm);
297 for i in vl.indices() {
298 if !mask_bit(&mask_buf, i) {
299 continue;
300 }
301 let index = env
302 .read_vregs()
303 .read(vs1, i)
304 .expect("`vs1` has the same `vl` as `vd`, checked above; qed");
305 let val = gather_element(env.read_vregs(), vs2, index);
306 env.write_vregs()
307 .write(vd, i, val)
308 .expect("`i < vl` of `vd`; qed");
309 }
310 env.mark_vs_dirty();
311}
312
313#[inline(always)]
315#[doc(hidden)]
316#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
317pub fn execute_rgather_scalar<Reg, Env>(
318 env: &mut Env,
319 vd: VRegGroup<Env::Hart>,
320 vs2: VRegGroup<Env::Hart>,
321 vm: bool,
322 index: u64,
323) where
324 Reg: Register,
325 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
326{
327 let mask_buf = snapshot_mask(env.read_vregs(), vm);
328 let val = gather_element(env.read_vregs(), vs2, index);
330 for i in vd.vl().indices() {
331 if !mask_bit(&mask_buf, i) {
332 continue;
333 }
334 env.write_vregs()
335 .write(vd, i, val)
336 .expect("`i < vl` of `vd`; qed");
337 }
338 env.mark_vs_dirty();
339}
340
341#[inline(always)]
348#[doc(hidden)]
349#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
350pub fn execute_rgatherei16<Reg, Env>(
351 env: &mut Env,
352 vd: VRegGroup<Env::Hart>,
353 vs2: VRegGroup<Env::Hart>,
354 vs1: VRegGroup<Env::Hart>,
355 vm: bool,
356) where
357 Reg: Register,
358 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
359{
360 execute_rgather_vv::<Reg, Env>(env, vd, vs2, vs1, vm);
361}
362
363#[inline(always)]
366#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
367fn gather_element<Hart>(vregs: &VectorRegisterFile<Hart>, vs2: VRegGroup<Hart>, index: u64) -> u64
368where
369 Hart: VectorHartConfig,
370{
371 u16::try_from(index)
372 .ok()
373 .and_then(|index| vregs.read_up_to_vlmax(vs2, index))
374 .unwrap_or_default()
375}
376
377#[inline(always)]
386#[doc(hidden)]
387#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
388pub fn execute_merge_vv<Reg, Env>(
389 env: &mut Env,
390 vd: VRegGroup<Env::Hart>,
391 vs2: VRegGroup<Env::Hart>,
392 vs1: VRegGroup<Env::Hart>,
393 vm: bool,
394) where
395 Reg: Register,
396 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
397{
398 let vl = vd.vl();
399 let (Some(vs2), Some(vs1)) = (vs2.with_same_vl(vl), vs1.with_same_vl(vl)) else {
400 cold_path();
401 return;
402 };
403 let mask_buf = snapshot_mask(env.read_vregs(), vm);
405 for i in vl.indices() {
406 let source = if mask_bit(&mask_buf, i) { vs1 } else { vs2 };
408 let val = env
409 .read_vregs()
410 .read(source, i)
411 .expect("`vs1` and `vs2` have the same `vl` as `vd`, checked above; qed");
412 env.write_vregs()
413 .write(vd, i, val)
414 .expect("`i < vl` of `vd`; qed");
415 }
416 env.mark_vs_dirty();
417}
418
419#[inline(always)]
428#[doc(hidden)]
429#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
430pub fn execute_merge_scalar<Reg, Env>(
431 env: &mut Env,
432 vd: VRegGroup<Env::Hart>,
433 vs2: VRegGroup<Env::Hart>,
434 vm: bool,
435 scalar: u64,
436) where
437 Reg: Register,
438 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
439{
440 let vl = vd.vl();
441 let Some(vs2) = vs2.with_same_vl(vl) else {
442 cold_path();
443 return;
444 };
445 let mask_buf = snapshot_mask(env.read_vregs(), vm);
446
447 for i in vl.indices() {
448 let val = if mask_bit(&mask_buf, i) {
449 scalar
450 } else {
451 env.read_vregs()
452 .read(vs2, i)
453 .expect("`vs2` has the same `vl` as `vd`, checked above; qed")
454 };
455 env.write_vregs()
456 .write(vd, i, val)
457 .expect("`i < vl` of `vd`; qed");
458 }
459 env.mark_vs_dirty();
460}
461
462#[inline(always)]
471#[doc(hidden)]
472#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
473pub fn execute_compress<Reg, Env>(
474 env: &mut Env,
475 vd: VRegGroup<Env::Hart>,
476 vs2: VRegGroup<Env::Hart>,
477 vs1: VReg,
478) where
479 Reg: Register,
480 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
481{
482 let vl = vd.vl();
483 let Some(vs2) = vs2.with_same_vl(vl) else {
484 cold_path();
485 return;
486 };
487 let vs1_buf = *env.read_vregs().get(vs1);
489 let mut out_indices = vl.indices();
490 for i in vl.indices() {
491 if !mask_bit(&vs1_buf, i) {
492 continue;
493 }
494 let val = env
495 .read_vregs()
496 .read(vs2, i)
497 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
498 let Some(out_idx) = out_indices.next() else {
501 break;
502 };
503 env.write_vregs()
504 .write(vd, out_idx, val)
505 .expect("`out_idx < vl` of `vd`; qed");
506 }
507 env.mark_vs_dirty();
508}
509
510#[inline(always)]
519#[doc(hidden)]
520#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
521pub fn execute_whole_reg_move<const COUNT: usize, Hart>(
522 vregs: &mut VectorRegisterFile<Hart>,
523 dst_base: VReg,
524 src_base: VReg,
525) -> Option<()>
526where
527 Hart: VectorHartConfig,
528{
529 let registers = vregs.as_bytes_mut();
530 let src = *registers
533 .get(usize::from(src_base.to_bits())..)?
534 .first_chunk::<COUNT>()?;
535 *registers
536 .get_mut(usize::from(dst_base.to_bits())..)?
537 .first_chunk_mut::<COUNT>()? = src;
538 Some(())
539}