use crate::exec::compute::vector::context::{VecExecCtx, VecExecResult, VecOperand, mask_active};
use crate::exec::compute::vector::regfile::VectorRegFile;
use crate::isa::fp::FpFlags;
use crate::isa::op::{PermuteOp, SlideOffset};
use crate::isa::rvv::{ElemIdx, Sew, VRegIdx, Vlmax};
#[derive(Clone, Copy, Debug)]
pub struct PermuteSources {
pub operand1: VecOperand,
pub vs1: VRegIdx,
pub rs1: u64,
}
pub fn vec_permute_execute(
op: PermuteOp,
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
sources: PermuteSources,
ctx: &VecExecCtx,
) -> VecExecResult {
match op {
PermuteOp::MvXS => exec_vmv_xs(vpr, vs2, ctx),
PermuteOp::MvSX => exec_vmv_sx(vpr, vd, sources.rs1, ctx),
PermuteOp::SlideUp(offset) => {
exec_slideup(vpr, vd, vs2, slide_offset(offset, sources.rs1), ctx)
}
PermuteOp::SlideDown(offset) => {
exec_slidedown(vpr, vd, vs2, slide_offset(offset, sources.rs1), ctx)
}
PermuteOp::Slide1Up => exec_slide1up(vpr, vd, vs2, sources.rs1, ctx),
PermuteOp::Slide1Down => exec_slide1down(vpr, vd, vs2, sources.rs1, ctx),
PermuteOp::Rgather => exec_rgather(vpr, vd, vs2, &sources.operand1, ctx),
PermuteOp::RgatherEi16 => exec_rgather_ei16(vpr, vd, vs2, sources.vs1, ctx),
PermuteOp::Compress => exec_compress(vpr, vd, vs2, sources.vs1, ctx),
PermuteOp::WholeMove(nregs) => exec_whole_reg_move(vpr, vd, vs2, nregs),
}
}
const fn slide_offset(offset: SlideOffset, rs1: u64) -> usize {
match offset {
SlideOffset::Rs1 => rs1 as usize,
SlideOffset::Imm(imm) => imm as usize,
}
}
#[inline]
const fn no_flags_result(scalar: Option<u64>) -> VecExecResult {
VecExecResult { vxsat: false, scalar_result: scalar, fp_flags: FpFlags::NONE }
}
fn exec_vmv_xs(vpr: &impl VectorRegFile, vs2: VRegIdx, ctx: &VecExecCtx) -> VecExecResult {
let val = vpr.read_element(vs2, ElemIdx::new(0), ctx.sew);
let sign_extended = ctx.sew.sign_extend(val) as u64;
no_flags_result(Some(sign_extended))
}
fn exec_vmv_sx(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
rs1: u64,
ctx: &VecExecCtx,
) -> VecExecResult {
let scalar = rs1 & ctx.sew.mask();
if ctx.vl > 0 {
vpr.write_element(vd, ElemIdx::new(0), ctx.sew, scalar);
}
if ctx.vta.is_agnostic() {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
for i in 1..vlmax {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
}
no_flags_result(None)
}
fn exec_slideup(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
offset: usize,
ctx: &VecExecCtx,
) -> VecExecResult {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
for i in 0..vlmax {
if i < ctx.vstart {
continue;
}
if i >= ctx.vl {
if ctx.vta.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if !ctx.vm && !mask_active(vpr, i) {
if ctx.vma.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if i >= offset {
let src_idx = i - offset;
let val = vpr.read_element(vs2, ElemIdx::new(src_idx), ctx.sew);
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, val);
}
}
no_flags_result(None)
}
fn exec_slidedown(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
offset: usize,
ctx: &VecExecCtx,
) -> VecExecResult {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
for i in 0..vlmax {
if i < ctx.vstart {
continue;
}
if i >= ctx.vl {
if ctx.vta.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if !ctx.vm && !mask_active(vpr, i) {
if ctx.vma.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
let src_idx = i.saturating_add(offset);
let val =
if src_idx < vlmax { vpr.read_element(vs2, ElemIdx::new(src_idx), ctx.sew) } else { 0 };
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, val);
}
no_flags_result(None)
}
fn exec_slide1up(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
rs1: u64,
ctx: &VecExecCtx,
) -> VecExecResult {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
let scalar = rs1 & ctx.sew.mask();
for i in 0..vlmax {
if i < ctx.vstart {
continue;
}
if i >= ctx.vl {
if ctx.vta.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if !ctx.vm && !mask_active(vpr, i) {
if ctx.vma.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
let val = if i == 0 { scalar } else { vpr.read_element(vs2, ElemIdx::new(i - 1), ctx.sew) };
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, val);
}
no_flags_result(None)
}
fn exec_slide1down(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
rs1: u64,
ctx: &VecExecCtx,
) -> VecExecResult {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
let scalar = rs1 & ctx.sew.mask();
for i in 0..vlmax {
if i < ctx.vstart {
continue;
}
if i >= ctx.vl {
if ctx.vta.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if !ctx.vm && !mask_active(vpr, i) {
if ctx.vma.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
let val = if i == ctx.vl - 1 {
scalar
} else {
vpr.read_element(vs2, ElemIdx::new(i + 1), ctx.sew)
};
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, val);
}
no_flags_result(None)
}
fn exec_rgather(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
operand1: &VecOperand,
ctx: &VecExecCtx,
) -> VecExecResult {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
for i in 0..vlmax {
if i < ctx.vstart {
continue;
}
if i >= ctx.vl {
if ctx.vta.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if !ctx.vm && !mask_active(vpr, i) {
if ctx.vma.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
let index = match operand1 {
VecOperand::Vector(vs1) => vpr.read_element(*vs1, ElemIdx::new(i), ctx.sew) as usize,
VecOperand::Scalar(v) => *v as usize,
VecOperand::Immediate(v) => *v as u64 as usize,
};
let val =
if index >= vlmax { 0 } else { vpr.read_element(vs2, ElemIdx::new(index), ctx.sew) };
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, val);
}
no_flags_result(None)
}
fn exec_rgather_ei16(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
vs1: VRegIdx,
ctx: &VecExecCtx,
) -> VecExecResult {
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
for i in 0..vlmax {
if i < ctx.vstart {
continue;
}
if i >= ctx.vl {
if ctx.vta.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
if !ctx.vm && !mask_active(vpr, i) {
if ctx.vma.is_agnostic() {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
continue;
}
let index = vpr.read_element(vs1, ElemIdx::new(i), Sew::E16) as usize;
let val =
if index >= vlmax { 0 } else { vpr.read_element(vs2, ElemIdx::new(index), ctx.sew) };
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, val);
}
no_flags_result(None)
}
fn exec_compress(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
vs1: VRegIdx,
ctx: &VecExecCtx,
) -> VecExecResult {
let mut dst = 0usize;
for i in ctx.vstart..ctx.vl {
if vpr.read_mask_bit(vs1, ElemIdx::new(i)) {
let val = vpr.read_element(vs2, ElemIdx::new(i), ctx.sew);
vpr.write_element(vd, ElemIdx::new(dst), ctx.sew, val);
dst += 1;
}
}
let vlmax = Vlmax::compute(vpr.vlen(), ctx.sew, ctx.vlmul).as_usize();
if ctx.vta.is_agnostic() {
for i in dst..vlmax {
vpr.write_element(vd, ElemIdx::new(i), ctx.sew, ctx.sew.ones());
}
}
no_flags_result(None)
}
fn exec_whole_reg_move(
vpr: &mut impl VectorRegFile,
vd: VRegIdx,
vs2: VRegIdx,
nregs: u8,
) -> VecExecResult {
for offset in 0..nregs {
let src = VRegIdx::new(vs2.as_u8() + offset);
let dst = VRegIdx::new(vd.as_u8() + offset);
vpr.copy_reg(dst, src);
}
no_flags_result(None)
}