1use crate::v::vector_registers::{VLENB_USIZE, VectorRegisterFile, VectorRegistersExt};
4pub use crate::v::zvexx::arith::zvexx_arith_helpers::check_vreg_group_alignment;
5use crate::v::zvexx::load::zvexx_load_helpers::{mask_bit, snapshot_mask};
6use crate::v::zvexx::zvexx_helpers::INSTRUCTION_SIZE;
7use crate::{ExecutionError, PackedAddress, ProgramCounter};
8use ab_riscv_primitives::prelude::*;
9use core::hint::cold_path;
10use core::ptr;
11
12#[inline(always)]
17#[doc(hidden)]
18#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
19pub fn check_no_overlap<Reg, Memory, PC>(
20 program_counter: &PC,
21 a: VReg,
22 b: VReg,
23 count: VRegGroupSize,
24) -> Result<(), ExecutionError<Reg::Type>>
25where
26 Reg: Register,
27 PC: ProgramCounter<Reg::Type, Memory>,
28{
29 let a_start = u16::from(a.to_bits());
30 let b_start = u16::from(b.to_bits());
31 let count = u16::from(count.get());
32 if a_start < b_start + count && b_start < a_start + count {
36 cold_path();
37 return Err(ExecutionError::IllegalInstruction {
38 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
39 });
40 }
41 Ok(())
42}
43
44#[inline(always)]
50#[doc(hidden)]
51#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
52pub fn check_no_overlap_asymmetric<Reg, Memory, PC>(
53 program_counter: &PC,
54 a: VReg,
55 a_count: VRegGroupSize,
56 b: VReg,
57 b_count: VRegGroupSize,
58) -> Result<(), ExecutionError<Reg::Type>>
59where
60 Reg: Register,
61 PC: ProgramCounter<Reg::Type, Memory>,
62{
63 let a_start = u16::from(a.to_bits());
64 let b_start = u16::from(b.to_bits());
65 let a_count = u16::from(a_count.get());
66 let b_count = u16::from(b_count.get());
67 if a_start < b_start + b_count && b_start < a_start + a_count {
70 cold_path();
71 return Err(ExecutionError::IllegalInstruction {
72 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
73 });
74 }
75 Ok(())
76}
77
78#[inline(always)]
93#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
94pub fn sign_extend_to_reg<Reg>(val: u64, sew: Vsew) -> Reg::Type
95where
96 Reg: Register,
97{
98 let sew_bits = u32::from(sew.bits_width());
99 let shift = u64::BITS - sew_bits;
101 let sign_extended = (val.cast_signed() << shift) >> shift;
103 let raw = sign_extended.cast_unsigned();
104 if Reg::XLEN == u64::BITS as u8 {
105 let lo = Reg::Type::from(raw as u32);
107 let hi = Reg::Type::from((raw >> u32::BITS) as u32);
108 lo | (hi << 32u8)
109 } else {
110 Reg::Type::from(raw as u32)
112 }
113}
114
115#[inline(always)]
125#[doc(hidden)]
126#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
127pub unsafe fn execute_slideup<Reg, Env>(
128 env: &mut Env,
129 vd: VReg,
130 vs2: VReg,
131 vm: bool,
132 sew: Vsew,
133 offset: u64,
134) where
135 Reg: Register,
136 Env: VectorRegistersExt<Reg>,
137 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
138{
139 let vl = env.vl();
140 let vstart = env.vstart();
141 let first = vstart.max(Vstart::from(offset.saturating_truncate::<u16>()));
144 let range = first.range_to(vl);
145
146 if vm && !range.is_empty() {
149 let len = range.len() * usize::from(sew.bytes_width());
150 let src_first = *range.start() - offset.saturating_truncate::<u16>();
152 let src = VectorRegisterFile::<{ Env::VLEN }>::element_offset(vs2, src_first, sew);
153 let dst = VectorRegisterFile::<{ Env::VLEN }>::element_offset(vd, *range.start(), sew);
154 let bytes = env.write_vregs().as_bytes_mut().as_flattened_mut();
155 unsafe {
161 let bytes = bytes.as_mut_ptr();
162 ptr::copy(bytes.byte_add(src), bytes.byte_add(dst), len);
163 }
164 env.mark_vs_dirty();
165 env.reset_vstart();
166 return;
167 }
168
169 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
171 for i in range {
172 if !mask_bit(&mask_buf, i) {
173 continue;
174 }
175 let src_idx = i - offset.saturating_truncate::<u16>();
176 let val = unsafe { env.read_vregs().read_element(vs2, src_idx, sew) };
178 unsafe {
180 env.write_vregs().write_element(vd, i, sew, val);
181 }
182 }
183 env.mark_vs_dirty();
184 env.reset_vstart();
185}
186
187#[inline(always)]
196#[doc(hidden)]
197#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
198pub unsafe fn execute_slidedown<Reg, Env>(
199 env: &mut Env,
200 vd: VReg,
201 vs2: VReg,
202 vm: bool,
203 sew: Vsew,
204 vlmax: Vl,
205 offset: u64,
206) where
207 Reg: Register,
208 Env: VectorRegistersExt<Reg>,
209 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
210{
211 let vl = env.vl();
212 let vstart = env.vstart();
213
214 let range = vstart.range_to(vl);
215
216 if vm && !range.is_empty() {
219 let elem_bytes = usize::from(sew.bytes_width());
220 let first = *range.start();
221 let with_source = u64::from(vlmax)
223 .saturating_sub(offset)
224 .saturating_sub(u64::from(first));
225 let copied = usize::try_from(with_source)
226 .map_or(range.len(), |with_source| with_source.min(range.len()));
227 let copied_len = copied * elem_bytes;
228 let len = range.len() * elem_bytes;
229 let dst = VectorRegisterFile::<{ Env::VLEN }>::element_offset(vd, first, sew);
230 let bytes = env.write_vregs().as_bytes_mut().as_flattened_mut();
231 unsafe {
239 if copied > 0 {
240 let src_first = first + offset.saturating_truncate::<u16>();
241 let src = VectorRegisterFile::<{ Env::VLEN }>::element_offset(vs2, src_first, sew);
242 let bytes = bytes.as_mut_ptr();
243 ptr::copy(bytes.byte_add(src), bytes.byte_add(dst), copied_len);
244 }
245 bytes.get_unchecked_mut(dst + copied_len..dst + len).fill(0);
246 }
247 env.mark_vs_dirty();
248 env.reset_vstart();
249 return;
250 }
251
252 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
254 for i in range {
255 if !mask_bit(&mask_buf, i) {
256 continue;
257 }
258 let val = if let Some(src_idx) = u64::from(i).checked_add(offset)
261 && src_idx < u64::from(vlmax)
262 {
263 unsafe { env.read_vregs().read_element(vs2, src_idx as u16, sew) }
265 } else {
266 0
267 };
268 unsafe {
270 env.write_vregs().write_element(vd, i, sew, val);
271 }
272 }
273 env.mark_vs_dirty();
274 env.reset_vstart();
275}
276
277#[inline(always)]
288#[doc(hidden)]
289#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
290pub unsafe fn execute_slide1up<Reg, Env>(
291 env: &mut Env,
292 vd: VReg,
293 vs2: VReg,
294 vm: bool,
295 sew: Vsew,
296 scalar: u64,
297) where
298 Reg: Register,
299 Env: VectorRegistersExt<Reg>,
300 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
301{
302 let vl = env.vl();
303 let vstart = env.vstart();
304 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
306 for i in vstart.range_to(vl) {
307 if !mask_bit(&mask_buf, i) {
308 continue;
309 }
310 let val = if i == 0 {
311 scalar
312 } else {
313 unsafe { env.read_vregs().read_element(vs2, i - 1, sew) }
315 };
316 unsafe {
318 env.write_vregs().write_element(vd, i, sew, val);
319 }
320 }
321 env.mark_vs_dirty();
322 env.reset_vstart();
323}
324
325#[inline(always)]
340#[doc(hidden)]
341#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
342pub unsafe fn execute_slide1down<Reg, Env>(
343 env: &mut Env,
344 vd: VReg,
345 vs2: VReg,
346 vm: bool,
347 sew: Vsew,
348 scalar: u64,
349) where
350 Reg: Register,
351 Env: VectorRegistersExt<Reg>,
352 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
353{
354 let vl = env.vl();
355 let vstart = env.vstart();
356 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
358 let range = vstart.range_to(vl);
359 for i in range.clone() {
360 if !mask_bit(&mask_buf, i) {
361 continue;
362 }
363 let val = if i < *range.end() {
364 unsafe { env.read_vregs().read_element(vs2, i + 1, sew) }
366 } else {
367 scalar
368 };
369 unsafe {
371 env.write_vregs().write_element(vd, i, sew, val);
372 }
373 }
374 env.mark_vs_dirty();
375 env.reset_vstart();
376}
377
378#[inline(always)]
385#[doc(hidden)]
386#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
387pub unsafe fn execute_rgather_vv<Reg, Env>(
388 env: &mut Env,
389 vd: VReg,
390 vs2: VReg,
391 vs1: VReg,
392 vm: bool,
393 sew: Vsew,
394 vlmax: Vl,
395) where
396 Reg: Register,
397 Env: VectorRegistersExt<Reg>,
398 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
399{
400 let vl = env.vl();
401 let vstart = env.vstart();
402 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
404 for i in vstart.range_to(vl) {
405 if !mask_bit(&mask_buf, i) {
406 continue;
407 }
408 let index = unsafe { env.read_vregs().read_element(vs1, i, sew) };
410 let val = if index < u64::from(vlmax) {
411 unsafe { env.read_vregs().read_element(vs2, index as u16, sew) }
413 } else {
414 0u64
415 };
416 unsafe {
418 env.write_vregs().write_element(vd, i, sew, val);
419 }
420 }
421 env.mark_vs_dirty();
422 env.reset_vstart();
423}
424
425#[inline(always)]
432#[doc(hidden)]
433#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
434pub unsafe fn execute_rgather_scalar<Reg, Env>(
435 env: &mut Env,
436 vd: VReg,
437 vs2: VReg,
438 vm: bool,
439 sew: Vsew,
440 vlmax: Vl,
441 index: u64,
442) where
443 Reg: Register,
444 Env: VectorRegistersExt<Reg>,
445 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
446{
447 let vl = env.vl();
448 let vstart = env.vstart();
449 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
451 let val = if index < u64::from(vlmax) {
453 unsafe { env.read_vregs().read_element(vs2, index as u16, sew) }
455 } else {
456 0u64
457 };
458 for i in vstart.range_to(vl) {
459 if !mask_bit(&mask_buf, i) {
460 continue;
461 }
462 unsafe {
464 env.write_vregs().write_element(vd, i, sew, val);
465 }
466 }
467 env.mark_vs_dirty();
468 env.reset_vstart();
469}
470
471#[inline(always)]
483#[expect(clippy::too_many_arguments, reason = "Internal API")]
484#[doc(hidden)]
485#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
486pub unsafe fn execute_rgatherei16<Reg, Env>(
487 env: &mut Env,
488 vd: VReg,
489 vs2: VReg,
490 vs1: VReg,
491 vm: bool,
492 sew: Vsew,
493 vlmax: Vl,
494 index_group_regs: VRegGroupSize,
495) where
496 Reg: Register,
497 Env: VectorRegistersExt<Reg>,
498 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
499{
500 let index_group_regs = index_group_regs.get();
501 let vl = env.vl();
502 let vstart = env.vstart();
503 let index_capacity = u32::from(index_group_regs) * (Env::VLEN.bytes() / 2);
506 debug_assert!(
509 vl <= vlmax && u32::from(vl) <= index_capacity,
510 "vl={vl} exceeds vlmax={vlmax} or index_capacity={index_capacity}"
511 );
512 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
514 for i in vstart.range_to(vl) {
515 if !mask_bit(&mask_buf, i) {
516 continue;
517 }
518 let index = unsafe { env.read_vregs().read_element(vs1, i, Vsew::E16) };
522 let val = if index < u64::from(vlmax) {
523 unsafe { env.read_vregs().read_element(vs2, index as u16, sew) }
525 } else {
526 0u64
527 };
528 unsafe {
530 env.write_vregs().write_element(vd, i, sew, val);
531 }
532 }
533 env.mark_vs_dirty();
534 env.reset_vstart();
535}
536
537#[inline(always)]
548#[doc(hidden)]
549#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
550pub unsafe fn execute_merge_vv<Reg, Env>(
551 env: &mut Env,
552 vd: VReg,
553 vs2: VReg,
554 vs1: VReg,
555 vm: bool,
556 sew: Vsew,
557) where
558 Reg: Register,
559 Env: VectorRegistersExt<Reg>,
560 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
561{
562 let vl = env.vl();
563 let vstart = env.vstart();
564 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
567 for i in vstart.range_to(vl) {
568 let mask_set = mask_bit(&mask_buf, i);
569 let val = if mask_set {
570 unsafe { env.read_vregs().read_element(vs1, i, sew) }
572 } else {
573 unsafe { env.read_vregs().read_element(vs2, i, sew) }
576 };
577 unsafe {
579 env.write_vregs().write_element(vd, i, sew, val);
580 }
581 }
582 env.mark_vs_dirty();
583 env.reset_vstart();
584}
585
586#[inline(always)]
597#[doc(hidden)]
598#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
599pub unsafe fn execute_merge_scalar<Reg, Env>(
600 env: &mut Env,
601 vd: VReg,
602 vs2: VReg,
603 vm: bool,
604 sew: Vsew,
605 scalar: u64,
606) where
607 Reg: Register,
608 Env: VectorRegistersExt<Reg>,
609 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
610{
611 let vl = env.vl();
612 let vstart = env.vstart();
613 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
615
616 for i in vstart.range_to(vl) {
617 let val = if mask_bit(&mask_buf, i) {
618 scalar
619 } else {
620 unsafe { env.read_vregs().read_element(vs2, i, sew) }
622 };
623 unsafe {
625 env.write_vregs().write_element(vd, i, sew, val);
626 }
627 }
628 env.mark_vs_dirty();
629 env.reset_vstart();
630}
631
632#[inline(always)]
643#[doc(hidden)]
644#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
645pub unsafe fn execute_compress<Reg, Env>(
646 env: &mut Env,
647 vd: VReg,
648 vs2: VReg,
649 vs1: VReg,
650 vl: Vl,
651 sew: Vsew,
652) where
653 Reg: Register,
654 Env: VectorRegistersExt<Reg>,
655 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
656{
657 let mask_bytes = usize::from(vl.bytes());
658 let vreg = env.read_vregs();
659 let mut vs1_buf = [0u8; VLENB_USIZE::<{ Env::VLEN }>];
660 unsafe {
662 vs1_buf
663 .get_unchecked_mut(..mask_bytes)
664 .copy_from_slice(vreg.get(vs1).get_unchecked(..mask_bytes));
665 }
666 let mut out_idx = 0;
667 for i in Vstart::ZERO.range_to(vl) {
668 if !mask_bit(&vs1_buf, i) {
669 continue;
670 }
671 let val = unsafe { env.read_vregs().read_element(vs2, i, sew) };
673 unsafe {
675 env.write_vregs().write_element(vd, out_idx, sew, val);
676 }
677 out_idx += 1;
678 }
679 env.mark_vs_dirty();
680 env.reset_vstart();
681}
682
683#[inline(always)]
694#[doc(hidden)]
695#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
696pub unsafe fn execute_whole_reg_move<const COUNT: usize, const VLEN: Vlen>(
697 vregs: &mut VectorRegisterFile<VLEN>,
698 dst_base: VReg,
699 src_base: VReg,
700) {
701 let mut tmp = [[0u8; _]; COUNT];
704 for (k, item) in tmp.iter_mut().enumerate() {
705 let src = unsafe { VReg::from_bits(src_base.to_bits() + k as u8).unwrap_unchecked() };
707 *item = *vregs.get(src);
708 }
709 for (k, item) in tmp.iter().enumerate() {
710 let dst = unsafe { VReg::from_bits(dst_base.to_bits() + k as u8).unwrap_unchecked() };
712 *vregs.get_mut(dst) = *item;
713 }
714}