use super::*;
use crate::arch::regs::vpr::Vpr;
use crate::exec::compute::vector::context::{VecExecResult, VecOperand};
use crate::isa::op::{VecAluOp, VecClass, VectorOp};
use crate::isa::rvv::{ElemIdx, Vlen};
fn make_vpr() -> Vpr {
Vpr::new(Vlen::new_unchecked(128))
}
fn alu(op: VectorOp) -> VecAluOp {
match op.class() {
VecClass::Alu(op) => op,
other => panic!("{op:?} is not an ALU op: {other:?}"),
}
}
fn run(
op: VectorOp,
vpr: &mut Vpr,
vd: VRegIdx,
vs2: VRegIdx,
operand1: VecOperand,
sew: Sew,
vl: usize,
) -> VecExecResult {
vec_execute(
alu(op),
vpr,
vd,
vs2,
operand1,
sew,
vl,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
)
}
#[test]
fn test_vadd_e8() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 100);
let _ = run(VectorOp::VAdd, &mut vpr, vd, vs2, VecOperand::Scalar(55), Sew::E8, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E8), 155);
}
#[test]
fn test_vwmaccus_vx_signed_vs2() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 0x80);
let rs1: u64 = (-8_i64) as u64;
let _ = run(VectorOp::VWMaccUS, &mut vpr, vd, vs2, VecOperand::Scalar(rs1), Sew::E8, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 0x8400);
}
#[test]
fn test_vwmaccsu_vv_signed_unsigned() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs1 = VRegIdx::new(2);
let vs2 = VRegIdx::new(3);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 0x80);
vpr.write_element(vs1, ElemIdx::new(0), Sew::E8, 0x80);
let _ = run(VectorOp::VWMaccSU, &mut vpr, vd, vs2, VecOperand::Vector(vs1), Sew::E8, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 0xc000);
}
#[test]
fn test_vadd_e16() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E16, 1000);
let _ = run(VectorOp::VAdd, &mut vpr, vd, vs2, VecOperand::Scalar(2345), Sew::E16, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 3345);
}
#[test]
fn test_vadd_e32() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 0x8000_0000);
let _ = run(VectorOp::VAdd, &mut vpr, vd, vs2, VecOperand::Scalar(0x8000_0000), Sew::E32, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 0);
}
#[test]
fn test_vadd_e64() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E64, 0xFFFF_FFFF_FFFF_FFFE);
let _ = run(VectorOp::VAdd, &mut vpr, vd, vs2, VecOperand::Scalar(3), Sew::E64, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E64), 1);
}
#[test]
fn test_vadd_vv_multiple_elements() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(3);
let vs2 = VRegIdx::new(4);
let vs1 = VRegIdx::new(5);
for i in 0..4 {
vpr.write_element(vs2, ElemIdx::new(i), Sew::E32, (i as u64) * 10);
vpr.write_element(vs1, ElemIdx::new(i), Sew::E32, (i as u64) + 1);
}
let _ = run(VectorOp::VAdd, &mut vpr, vd, vs2, VecOperand::Vector(vs1), Sew::E32, 4);
for i in 0..4 {
let expected = (i as u64) * 10 + (i as u64) + 1;
assert_eq!(vpr.read_element(vd, ElemIdx::new(i), Sew::E32), expected);
}
}
#[test]
fn test_vmslt_signed() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 0xFF);
let _ = run(VectorOp::VMSlt, &mut vpr, vd, vs2, VecOperand::Scalar(1), Sew::E8, 1);
assert!(vpr.read_mask_bit(vd, ElemIdx::new(0)));
}
#[test]
fn test_vmseq() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 42);
vpr.write_element(vs2, ElemIdx::new(1), Sew::E32, 43);
let _ = run(VectorOp::VMSeq, &mut vpr, vd, vs2, VecOperand::Scalar(42), Sew::E32, 2);
assert!(vpr.read_mask_bit(vd, ElemIdx::new(0)));
assert!(!vpr.read_mask_bit(vd, ElemIdx::new(1)));
}
#[test]
fn test_vdivu_by_zero() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 42);
let _ = run(VectorOp::VDivU, &mut vpr, vd, vs2, VecOperand::Scalar(0), Sew::E32, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 0xFFFF_FFFF);
}
#[test]
fn test_vdiv_by_zero() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E16, 100);
let _ = run(VectorOp::VDiv, &mut vpr, vd, vs2, VecOperand::Scalar(0), Sew::E16, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 0xFFFF);
}
#[test]
fn test_vremu_by_zero() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 42);
let _ = run(VectorOp::VRemU, &mut vpr, vd, vs2, VecOperand::Scalar(0), Sew::E32, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 42);
}
#[test]
fn test_vdiv_signed_overflow() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 0x8000_0000);
let _ = run(VectorOp::VDiv, &mut vpr, vd, vs2, VecOperand::Scalar(0xFFFF_FFFF), Sew::E32, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 0x8000_0000);
}
#[test]
fn test_vwaddu() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(2);
let vs2 = VRegIdx::new(4);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E16, 0xFFFF);
let res = vec_execute(
alu(VectorOp::VWAddU),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(1),
Sew::E16,
1,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
);
assert!(!res.vxsat);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 0x10000);
}
#[test]
fn test_vwaddu_mf8_widen() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(4);
let vs2 = VRegIdx::new(8);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 5);
vpr.write_element(vs2, ElemIdx::new(1), Sew::E8, 7);
for i in 0..16usize {
vpr.write_element(vd, ElemIdx::new(i), Sew::E8, 0xAA);
}
let _ = vec_execute(
alu(VectorOp::VWAddU),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(3),
Sew::E8,
2,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::Mf8,
true,
Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 0x0008);
assert_eq!(vpr.read_element(vd, ElemIdx::new(1), Sew::E16), 0x000a);
for i in 4..16 {
assert_eq!(vpr.read_element(vd, ElemIdx::new(i), Sew::E8), 0xAA, "tail byte {i} clobbered");
}
}
#[test]
fn test_vwadd_signed() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(2);
let vs2 = VRegIdx::new(4);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 0xFF);
let _ = vec_execute(
alu(VectorOp::VWAdd),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(0xFE),
Sew::E8,
1,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
);
let result = vpr.read_element(vd, ElemIdx::new(0), Sew::E16);
assert_eq!(result, 0xFFFD);
}
#[test]
fn test_vsaddu_saturation() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 200);
let res = run(VectorOp::VSAddU, &mut vpr, vd, vs2, VecOperand::Scalar(100), Sew::E8, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E8), 0xFF);
assert!(res.vxsat);
}
#[test]
fn test_vsaddu_no_saturation() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 100);
let res = run(VectorOp::VSAddU, &mut vpr, vd, vs2, VecOperand::Scalar(50), Sew::E8, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E8), 150);
assert!(!res.vxsat);
}
#[test]
fn test_masked_operation() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
let v0 = VRegIdx::new(0);
vpr.write_mask_bit(v0, ElemIdx::new(0), true);
vpr.write_mask_bit(v0, ElemIdx::new(1), false);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 10);
vpr.write_element(vs2, ElemIdx::new(1), Sew::E32, 20);
vpr.write_element(vd, ElemIdx::new(0), Sew::E32, 0xDEAD);
vpr.write_element(vd, ElemIdx::new(1), Sew::E32, 0xBEEF);
let _ = vec_execute(
alu(VectorOp::VAdd),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(5),
Sew::E32,
2,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
false, Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 15);
assert_eq!(vpr.read_element(vd, ElemIdx::new(1), Sew::E32), 0xBEEF);
}
#[test]
fn test_tail_agnostic() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 10);
vpr.write_element(vd, ElemIdx::new(1), Sew::E32, 0x1234);
let _ = vec_execute(
alu(VectorOp::VAdd),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(5),
Sew::E32,
1, 0,
MaskPolicy::Undisturbed,
TailPolicy::Agnostic,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 15);
assert_eq!(vpr.read_element(vd, ElemIdx::new(1), Sew::E32), Sew::E32.ones());
}
#[test]
fn test_vmerge() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(3);
let vs2 = VRegIdx::new(4);
let v0 = VRegIdx::new(0);
vpr.write_mask_bit(v0, ElemIdx::new(0), false);
vpr.write_mask_bit(v0, ElemIdx::new(1), true);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 0xAAAA);
vpr.write_element(vs2, ElemIdx::new(1), Sew::E32, 0xBBBB);
let _ = vec_execute(
alu(VectorOp::VMerge),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(0xCCCC),
Sew::E32,
2,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
false, Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 0xAAAA);
assert_eq!(vpr.read_element(vd, ElemIdx::new(1), Sew::E32), 0xCCCC);
}
#[test]
fn test_vmacc() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 7);
vpr.write_element(vd, ElemIdx::new(0), Sew::E32, 100);
let _ = run(VectorOp::VMacc, &mut vpr, vd, vs2, VecOperand::Scalar(3), Sew::E32, 1);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 121);
}
#[test]
fn test_vsext_vf2() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 0xFF);
let _ = vec_execute(
alu(VectorOp::VSextVf2),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(0), Sew::E16,
1,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 0xFFFF);
}
#[test]
fn test_vzext_vf2() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E8, 0xFF);
let _ = vec_execute(
alu(VectorOp::VZextVf2),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(0),
Sew::E16,
1,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E16), 0x00FF);
}
#[test]
fn test_vadc() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
let v0 = VRegIdx::new(0);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E32, 10);
vpr.write_mask_bit(v0, ElemIdx::new(0), true);
let _ = vec_execute(
alu(VectorOp::VAdc),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(20),
Sew::E32,
1,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
false, Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E32), 31);
}
#[test]
fn test_vnsrl() {
let mut vpr = make_vpr();
let vd = VRegIdx::new(1);
let vs2 = VRegIdx::new(2);
vpr.write_element(vs2, ElemIdx::new(0), Sew::E16, 0x1234);
let _ = vec_execute(
alu(VectorOp::VNSrl),
&mut vpr,
vd,
vs2,
VecOperand::Scalar(8),
Sew::E8, 1,
0,
MaskPolicy::Undisturbed,
TailPolicy::Undisturbed,
Vlmul::M1,
true,
Vxrm::RoundToNearestUp,
);
assert_eq!(vpr.read_element(vd, ElemIdx::new(0), Sew::E8), 0x12);
}