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::arith::zvexx_arith_helpers::{read_element_u64, write_element_u64};
6use crate::v::zvexx::load::zvexx_load_helpers::{mask_bit, snapshot_mask};
7use crate::v::zvexx::zvexx_helpers::INSTRUCTION_SIZE;
8use crate::{ExecutionError, PackedAddress, ProgramCounter};
9use ab_riscv_primitives::prelude::*;
10use core::hint::cold_path;
11use core::num::NonZeroU8;
12
13#[inline(always)]
18#[doc(hidden)]
19#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
20pub fn check_no_overlap<Reg, Memory, PC>(
21 program_counter: &PC,
22 a: VReg,
23 b: VReg,
24 count: NonZeroU8,
25) -> Result<(), ExecutionError<Reg::Type>>
26where
27 Reg: Register,
28 PC: ProgramCounter<Reg::Type, Memory>,
29{
30 let a_start = u16::from(a.to_bits());
31 let b_start = u16::from(b.to_bits());
32 let count = u16::from(count.get());
33 if a_start < b_start + count && b_start < a_start + count {
37 cold_path();
38 return Err(ExecutionError::IllegalInstruction {
39 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
40 });
41 }
42 Ok(())
43}
44
45#[inline(always)]
51#[doc(hidden)]
52#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
53pub fn check_no_overlap_asymmetric<Reg, Memory, PC>(
54 program_counter: &PC,
55 a: VReg,
56 a_count: NonZeroU8,
57 b: VReg,
58 b_count: NonZeroU8,
59) -> Result<(), ExecutionError<Reg::Type>>
60where
61 Reg: Register,
62 PC: ProgramCounter<Reg::Type, Memory>,
63{
64 let a_start = u16::from(a.to_bits());
65 let b_start = u16::from(b.to_bits());
66 let a_count = u16::from(a_count.get());
67 let b_count = u16::from(b_count.get());
68 if a_start < b_start + b_count && b_start < a_start + a_count {
71 cold_path();
72 return Err(ExecutionError::IllegalInstruction {
73 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
74 });
75 }
76 Ok(())
77}
78
79#[inline(always)]
84#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
85pub unsafe fn read_element_0_u64<const VLEN: Vlen>(
86 vregs: &VectorRegisterFile<VLEN>,
87 base_reg: VReg,
88 sew: Vsew,
89) -> u64 {
90 let sew_bytes = usize::from(sew.bytes_width());
91 let reg = vregs.get(base_reg);
92 let mut buf = [0u8; 8];
93 unsafe {
95 buf.get_unchecked_mut(..sew_bytes)
96 .copy_from_slice(reg.get_unchecked(..sew_bytes));
97 }
98 u64::from_le_bytes(buf)
99}
100
101#[inline(always)]
106#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
107pub unsafe fn write_element_0_u64<const VLEN: Vlen>(
108 vregs: &mut VectorRegisterFile<VLEN>,
109 base_reg: VReg,
110 sew: Vsew,
111 value: u64,
112) {
113 let sew_bytes = usize::from(sew.bytes_width());
114 let buf = value.to_le_bytes();
115 let reg = vregs.get_mut(base_reg);
116 unsafe {
118 reg.get_unchecked_mut(..sew_bytes)
119 .copy_from_slice(buf.get_unchecked(..sew_bytes));
120 }
121}
122
123#[inline(always)]
138#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
139pub fn sign_extend_to_reg<Reg>(val: u64, sew: Vsew) -> Reg::Type
140where
141 Reg: Register,
142{
143 let sew_bits = u32::from(sew.bits_width());
144 let shift = u64::BITS - sew_bits;
146 let sign_extended = (val.cast_signed() << shift) >> shift;
148 let raw = sign_extended.cast_unsigned();
149 if Reg::XLEN == u64::BITS as u8 {
150 let lo = Reg::Type::from(raw as u32);
152 let hi = Reg::Type::from((raw >> u32::BITS) as u32);
153 lo | (hi << 32u8)
154 } else {
155 Reg::Type::from(raw as u32)
157 }
158}
159
160#[inline(always)]
170#[doc(hidden)]
171#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
172pub unsafe fn execute_slideup<Reg, Env>(
173 env: &mut Env,
174 vd: VReg,
175 vs2: VReg,
176 vm: bool,
177 sew: Vsew,
178 offset: u64,
179) where
180 Reg: Register,
181 Env: VectorRegistersExt<Reg>,
182 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
183{
184 let vl = env.vl();
185 let vstart = env.vstart();
186 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
188 for i in vstart
191 .max(Vstart::from(offset.saturating_truncate::<u16>()))
192 .range_to(vl)
193 {
194 if !mask_bit(&mask_buf, i) {
195 continue;
196 }
197 let src_idx = i - offset.saturating_truncate::<u16>();
198 let val = unsafe { read_element_u64(env.read_vregs(), vs2, src_idx, sew) };
200 unsafe {
202 write_element_u64(env.write_vregs(), vd, i, sew, val);
203 }
204 }
205 env.mark_vs_dirty();
206 env.reset_vstart();
207}
208
209#[inline(always)]
218#[doc(hidden)]
219#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
220pub unsafe fn execute_slidedown<Reg, Env>(
221 env: &mut Env,
222 vd: VReg,
223 vs2: VReg,
224 vm: bool,
225 sew: Vsew,
226 vlmax: Vl,
227 offset: u64,
228) where
229 Reg: Register,
230 Env: VectorRegistersExt<Reg>,
231 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
232{
233 let vl = env.vl();
234 let vstart = env.vstart();
235 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
237 for i in vstart.range_to(vl) {
238 if !mask_bit(&mask_buf, i) {
239 continue;
240 }
241 let val = if let Some(src_idx) = u64::from(i).checked_add(offset)
244 && src_idx < u64::from(vlmax)
245 {
246 unsafe { read_element_u64(env.read_vregs(), vs2, src_idx as u16, sew) }
248 } else {
249 0
250 };
251 unsafe {
253 write_element_u64(env.write_vregs(), vd, i, sew, val);
254 }
255 }
256 env.mark_vs_dirty();
257 env.reset_vstart();
258}
259
260#[inline(always)]
271#[doc(hidden)]
272#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
273pub unsafe fn execute_slide1up<Reg, Env>(
274 env: &mut Env,
275 vd: VReg,
276 vs2: VReg,
277 vm: bool,
278 sew: Vsew,
279 scalar: u64,
280) where
281 Reg: Register,
282 Env: VectorRegistersExt<Reg>,
283 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
284{
285 let vl = env.vl();
286 let vstart = env.vstart();
287 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
289 for i in vstart.range_to(vl) {
290 if !mask_bit(&mask_buf, i) {
291 continue;
292 }
293 let val = if i == 0 {
294 scalar
295 } else {
296 unsafe { read_element_u64(env.read_vregs(), vs2, i - 1, sew) }
298 };
299 unsafe {
301 write_element_u64(env.write_vregs(), vd, i, sew, val);
302 }
303 }
304 env.mark_vs_dirty();
305 env.reset_vstart();
306}
307
308#[inline(always)]
323#[doc(hidden)]
324#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
325pub unsafe fn execute_slide1down<Reg, Env>(
326 env: &mut Env,
327 vd: VReg,
328 vs2: VReg,
329 vm: bool,
330 sew: Vsew,
331 scalar: u64,
332) where
333 Reg: Register,
334 Env: VectorRegistersExt<Reg>,
335 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
336{
337 let vl = env.vl();
338 let vstart = env.vstart();
339 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
341 let range = vstart.range_to(vl);
342 for i in range.clone() {
343 if !mask_bit(&mask_buf, i) {
344 continue;
345 }
346 let val = if i < *range.end() {
347 unsafe { read_element_u64(env.read_vregs(), vs2, i + 1, sew) }
349 } else {
350 scalar
351 };
352 unsafe {
354 write_element_u64(env.write_vregs(), vd, i, sew, val);
355 }
356 }
357 env.mark_vs_dirty();
358 env.reset_vstart();
359}
360
361#[inline(always)]
368#[doc(hidden)]
369#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
370pub unsafe fn execute_rgather_vv<Reg, Env>(
371 env: &mut Env,
372 vd: VReg,
373 vs2: VReg,
374 vs1: VReg,
375 vm: bool,
376 sew: Vsew,
377 vlmax: Vl,
378) where
379 Reg: Register,
380 Env: VectorRegistersExt<Reg>,
381 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
382{
383 let vl = env.vl();
384 let vstart = env.vstart();
385 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
387 for i in vstart.range_to(vl) {
388 if !mask_bit(&mask_buf, i) {
389 continue;
390 }
391 let index = unsafe { read_element_u64(env.read_vregs(), vs1, i, sew) };
393 let val = if index < u64::from(vlmax) {
394 unsafe { read_element_u64(env.read_vregs(), vs2, index as u16, sew) }
396 } else {
397 0u64
398 };
399 unsafe {
401 write_element_u64(env.write_vregs(), vd, i, sew, val);
402 }
403 }
404 env.mark_vs_dirty();
405 env.reset_vstart();
406}
407
408#[inline(always)]
415#[doc(hidden)]
416#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
417pub unsafe fn execute_rgather_scalar<Reg, Env>(
418 env: &mut Env,
419 vd: VReg,
420 vs2: VReg,
421 vm: bool,
422 sew: Vsew,
423 vlmax: Vl,
424 index: u64,
425) where
426 Reg: Register,
427 Env: VectorRegistersExt<Reg>,
428 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
429{
430 let vl = env.vl();
431 let vstart = env.vstart();
432 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
434 let val = if index < u64::from(vlmax) {
436 unsafe { read_element_u64(env.read_vregs(), vs2, index as u16, sew) }
438 } else {
439 0u64
440 };
441 for i in vstart.range_to(vl) {
442 if !mask_bit(&mask_buf, i) {
443 continue;
444 }
445 unsafe {
447 write_element_u64(env.write_vregs(), vd, i, sew, val);
448 }
449 }
450 env.mark_vs_dirty();
451 env.reset_vstart();
452}
453
454#[inline(always)]
466#[expect(clippy::too_many_arguments, reason = "Internal API")]
467#[doc(hidden)]
468#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
469pub unsafe fn execute_rgatherei16<Reg, Env>(
470 env: &mut Env,
471 vd: VReg,
472 vs2: VReg,
473 vs1: VReg,
474 vm: bool,
475 sew: Vsew,
476 vlmax: Vl,
477 index_group_regs: NonZeroU8,
478) where
479 Reg: Register,
480 Env: VectorRegistersExt<Reg>,
481 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
482{
483 let index_group_regs = index_group_regs.get();
484 let vl = env.vl();
485 let vstart = env.vstart();
486 let index_capacity = u32::from(index_group_regs) * (Env::VLEN.bytes() / 2);
489 debug_assert!(
492 vl <= vlmax && u32::from(vl) <= index_capacity,
493 "vl={vl} exceeds vlmax={vlmax} or index_capacity={index_capacity}"
494 );
495 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
497 for i in vstart.range_to(vl) {
498 if !mask_bit(&mask_buf, i) {
499 continue;
500 }
501 let index = unsafe { read_element_u64(env.read_vregs(), vs1, i, Vsew::E16) };
505 let val = if index < u64::from(vlmax) {
506 unsafe { read_element_u64(env.read_vregs(), vs2, index as u16, sew) }
508 } else {
509 0u64
510 };
511 unsafe {
513 write_element_u64(env.write_vregs(), vd, i, sew, val);
514 }
515 }
516 env.mark_vs_dirty();
517 env.reset_vstart();
518}
519
520#[inline(always)]
531#[doc(hidden)]
532#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
533pub unsafe fn execute_merge_vv<Reg, Env>(
534 env: &mut Env,
535 vd: VReg,
536 vs2: VReg,
537 vs1: VReg,
538 vm: bool,
539 sew: Vsew,
540) where
541 Reg: Register,
542 Env: VectorRegistersExt<Reg>,
543 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
544{
545 let vl = env.vl();
546 let vstart = env.vstart();
547 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
550 for i in vstart.range_to(vl) {
551 let mask_set = mask_bit(&mask_buf, i);
552 let val = if mask_set {
553 unsafe { read_element_u64(env.read_vregs(), vs1, i, sew) }
555 } else {
556 unsafe { read_element_u64(env.read_vregs(), vs2, i, sew) }
559 };
560 unsafe {
562 write_element_u64(env.write_vregs(), vd, i, sew, val);
563 }
564 }
565 env.mark_vs_dirty();
566 env.reset_vstart();
567}
568
569#[inline(always)]
580#[doc(hidden)]
581#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
582pub unsafe fn execute_merge_scalar<Reg, Env>(
583 env: &mut Env,
584 vd: VReg,
585 vs2: VReg,
586 vm: bool,
587 sew: Vsew,
588 scalar: u64,
589) where
590 Reg: Register,
591 Env: VectorRegistersExt<Reg>,
592 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
593{
594 let vl = env.vl();
595 let vstart = env.vstart();
596 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
598
599 for i in vstart.range_to(vl) {
600 let val = if mask_bit(&mask_buf, i) {
601 scalar
602 } else {
603 unsafe { read_element_u64(env.read_vregs(), vs2, i, sew) }
605 };
606 unsafe {
608 write_element_u64(env.write_vregs(), vd, i, sew, val);
609 }
610 }
611 env.mark_vs_dirty();
612 env.reset_vstart();
613}
614
615#[inline(always)]
626#[doc(hidden)]
627#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
628pub unsafe fn execute_compress<Reg, Env>(
629 env: &mut Env,
630 vd: VReg,
631 vs2: VReg,
632 vs1: VReg,
633 vl: Vl,
634 sew: Vsew,
635) where
636 Reg: Register,
637 Env: VectorRegistersExt<Reg>,
638 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
639{
640 let mask_bytes = usize::from(vl.bytes());
641 let vreg = env.read_vregs();
642 let mut vs1_buf = [0u8; VLENB_USIZE::<{ Env::VLEN }>];
643 unsafe {
645 vs1_buf
646 .get_unchecked_mut(..mask_bytes)
647 .copy_from_slice(vreg.get(vs1).get_unchecked(..mask_bytes));
648 }
649 let mut out_idx = 0;
650 for i in Vstart::ZERO.range_to(vl) {
651 if !mask_bit(&vs1_buf, i) {
652 continue;
653 }
654 let val = unsafe { read_element_u64(env.read_vregs(), vs2, i, sew) };
656 unsafe {
658 write_element_u64(env.write_vregs(), vd, out_idx, sew, val);
659 }
660 out_idx += 1;
661 }
662 env.mark_vs_dirty();
663 env.reset_vstart();
664}
665
666#[inline(always)]
677#[doc(hidden)]
678#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
679pub unsafe fn execute_whole_reg_move<const COUNT: usize, const VLEN: Vlen>(
680 vregs: &mut VectorRegisterFile<VLEN>,
681 dst_base: VReg,
682 src_base: VReg,
683) {
684 let mut tmp = [[0u8; _]; COUNT];
687 for (k, item) in tmp.iter_mut().enumerate() {
688 let src = unsafe { VReg::from_bits(src_base.to_bits() + k as u8).unwrap_unchecked() };
690 *item = *vregs.get(src);
691 }
692 for (k, item) in tmp.iter().enumerate() {
693 let dst = unsafe { VReg::from_bits(dst_base.to_bits() + k as u8).unwrap_unchecked() };
695 *vregs.get_mut(dst) = *item;
696 }
697}