use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VISVersion {
VIS1,
VIS2,
VIS3,
VIS4,
}
impl VISVersion {
pub fn has_fma(&self) -> bool {
matches!(self, VISVersion::VIS3 | VISVersion::VIS4)
}
pub fn has_partial_store(&self) -> bool {
matches!(self, VISVersion::VIS2 | VISVersion::VIS3 | VISVersion::VIS4)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VISElementSize {
Byte8,
Half16,
Float32,
Double64,
}
impl VISElementSize {
pub fn bits(&self) -> u8 {
match self {
VISElementSize::Byte8 => 8,
VISElementSize::Half16 => 16,
VISElementSize::Float32 => 32,
VISElementSize::Double64 => 64,
}
}
pub fn elements(&self) -> u8 {
64 / self.bits()
}
}
pub const VIS_FP_REG_COUNT: usize = 32;
pub const VIS_REG_BITS: usize = 64;
#[derive(Debug, Clone, Copy)]
pub struct VISGSR {
pub scale_factor: u8,
pub align_addr_offset: u8,
pub mask: u8,
}
impl VISGSR {
pub fn new() -> Self {
VISGSR {
scale_factor: 0,
align_addr_offset: 0,
mask: 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VISOpcodes {
PADD,
PSUB,
PMUL,
PDIST,
PDISTN,
FPADD16,
FPADD32,
FPSUB16,
FPSUB32,
FPMUL,
FPMULADD,
FPACK16,
FPACK32,
FPACKFIX,
FAND,
FANDNOT,
FOR,
FORNOT,
FXOR,
FXNOR,
FNAND,
FNOR,
FCMP,
FCMEQ16,
FCMEQ32,
FCMNE16,
FCMNE32,
FCMGT16,
FCMGT32,
FCMLE16,
FCMLE32,
FALIGNDATA,
FSRC1,
FSRC2,
FPMERGE,
FPMERGE2,
FEXPAND,
ARRAY8,
ARRAY16,
ARRAY32,
EDGE8,
EDGE16,
EDGE32,
EDGE8N,
EDGE16N,
EDGE32N,
EDGE8L,
EDGE16L,
EDGE32L,
BMASK,
BSHUFFLE,
PST8,
PST16,
PST32,
FMOVSGEZ,
FMOVSLEZ,
FMOVDGTE,
FMOVDLTE,
FCHKSM16,
FLCMPS,
}
#[derive(Debug, Clone)]
pub struct VISSelectedOp {
pub opcode: VISOpcodes,
pub dst_reg: usize,
pub src1_reg: usize,
pub src2_reg: Option<usize>,
pub immediate: Option<i64>,
pub offset: Option<i64>,
}
#[derive(Debug, Clone)]
pub struct VISInstructionSelector {
pub vis_version: VISVersion,
pub is_64bit: bool,
pub gsr: VISGSR,
pub vreg_map: HashMap<usize, usize>,
pub selected_ops: Vec<VISSelectedOp>,
}
impl VISInstructionSelector {
pub fn new(version: VISVersion) -> Self {
VISInstructionSelector {
vis_version: version,
is_64bit: true,
gsr: VISGSR::new(),
vreg_map: HashMap::new(),
selected_ops: Vec::new(),
}
}
fn push(&mut self, opcode: VISOpcodes, dst: usize, src1: usize, src2: Option<usize>) {
self.selected_ops.push(VISSelectedOp {
opcode,
dst_reg: dst,
src1_reg: src1,
src2_reg: src2,
immediate: None,
offset: None,
});
}
pub fn select_padd(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::PADD, d, s1, Some(s2));
}
pub fn select_psub(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::PSUB, d, s1, Some(s2));
}
pub fn select_pmul(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::PMUL, d, s1, Some(s2));
}
pub fn select_pdist(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::PDIST, d, s1, Some(s2));
}
pub fn select_fpadd16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPADD16, d, s1, Some(s2));
}
pub fn select_fpadd32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPADD32, d, s1, Some(s2));
}
pub fn select_fpsub16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPSUB16, d, s1, Some(s2));
}
pub fn select_fpsub32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPSUB32, d, s1, Some(s2));
}
pub fn select_fpmul(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPMUL, d, s1, Some(s2));
}
pub fn select_fpmuladd(&mut self, d: usize, s1: usize, s2: usize, s3: usize) {
if self.vis_version.has_fma() {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::FPMULADD,
dst_reg: d,
src1_reg: s1,
src2_reg: Some(s2),
immediate: Some(s3 as i64),
offset: None,
});
}
}
pub fn select_fpack16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPACK16, d, s1, Some(s2));
}
pub fn select_fpack32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPACK32, d, s1, Some(s2));
}
pub fn select_fpackfix(&mut self, d: usize, s1: usize) {
self.push(VISOpcodes::FPACKFIX, d, s1, None);
}
pub fn select_fand(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FAND, d, s1, Some(s2));
}
pub fn select_fandnot(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FANDNOT, d, s1, Some(s2));
}
pub fn select_for(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FOR, d, s1, Some(s2));
}
pub fn select_fornot(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FORNOT, d, s1, Some(s2));
}
pub fn select_fxor(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FXOR, d, s1, Some(s2));
}
pub fn select_fxnor(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FXNOR, d, s1, Some(s2));
}
pub fn select_fnand(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FNAND, d, s1, Some(s2));
}
pub fn select_fnor(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FNOR, d, s1, Some(s2));
}
pub fn select_fcmp(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMP, d, s1, Some(s2));
}
pub fn select_fcmpeq16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMEQ16, d, s1, Some(s2));
}
pub fn select_fcmpeq32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMEQ32, d, s1, Some(s2));
}
pub fn select_fcmpne16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMNE16, d, s1, Some(s2));
}
pub fn select_fcmpne32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMNE32, d, s1, Some(s2));
}
pub fn select_fcmpgt16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMGT16, d, s1, Some(s2));
}
pub fn select_fcmpgt32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMGT32, d, s1, Some(s2));
}
pub fn select_fcmle16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMLE16, d, s1, Some(s2));
}
pub fn select_fcmle32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FCMLE32, d, s1, Some(s2));
}
pub fn select_faligndata(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FALIGNDATA, d, s1, Some(s2));
}
pub fn select_fsrc1(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FSRC1, d, s1, Some(s2));
}
pub fn select_fsrc2(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FSRC2, d, s1, Some(s2));
}
pub fn select_fpmerge(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::FPMERGE, d, s1, Some(s2));
}
pub fn select_array8(&mut self, d: usize, base: usize, offset: usize) {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::ARRAY8,
dst_reg: d,
src1_reg: base,
src2_reg: None,
immediate: None,
offset: Some(offset as i64),
});
}
pub fn select_array16(&mut self, d: usize, base: usize, offset: usize) {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::ARRAY16,
dst_reg: d,
src1_reg: base,
src2_reg: None,
immediate: None,
offset: Some(offset as i64),
});
}
pub fn select_array32(&mut self, d: usize, base: usize, offset: usize) {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::ARRAY32,
dst_reg: d,
src1_reg: base,
src2_reg: None,
immediate: None,
offset: Some(offset as i64),
});
}
pub fn select_edge8(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::EDGE8, d, s1, Some(s2));
}
pub fn select_edge16(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::EDGE16, d, s1, Some(s2));
}
pub fn select_edge32(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::EDGE32, d, s1, Some(s2));
}
pub fn select_bmask(&mut self, d: usize, s1: usize, s2: usize) {
self.push(VISOpcodes::BMASK, d, s1, Some(s2));
}
pub fn select_pst8(&mut self, src: usize, base: usize, offset: usize) {
if self.vis_version.has_partial_store() {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::PST8,
dst_reg: 0,
src1_reg: src,
src2_reg: None,
immediate: None,
offset: Some(offset as i64),
});
}
}
pub fn select_pst16(&mut self, src: usize, base: usize, offset: usize) {
if self.vis_version.has_partial_store() {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::PST16,
dst_reg: 0,
src1_reg: src,
src2_reg: None,
immediate: None,
offset: Some(offset as i64),
});
}
}
pub fn select_pst32(&mut self, src: usize, base: usize, offset: usize) {
if self.vis_version.has_partial_store() {
self.selected_ops.push(VISSelectedOp {
opcode: VISOpcodes::PST32,
dst_reg: 0,
src1_reg: src,
src2_reg: None,
immediate: None,
offset: Some(offset as i64),
});
}
}
fn has_partial_store(&self) -> bool {
self.vis_version.has_partial_store()
}
}
pub fn lower_vector_add_to_vis(
isel: &mut VISInstructionSelector,
dst: usize,
s1: usize,
s2: usize,
element_bits: u8,
is_float: bool,
) {
if is_float {
if element_bits == 16 {
isel.select_fpadd16(dst, s1, s2);
} else {
isel.select_fpadd32(dst, s1, s2);
}
} else {
isel.select_padd(dst, s1, s2);
}
}
pub fn lower_vector_sub_to_vis(
isel: &mut VISInstructionSelector,
dst: usize,
s1: usize,
s2: usize,
element_bits: u8,
is_float: bool,
) {
if is_float {
if element_bits == 16 {
isel.select_fpsub16(dst, s1, s2);
} else {
isel.select_fpsub32(dst, s1, s2);
}
} else {
isel.select_psub(dst, s1, s2);
}
}
pub fn lower_vector_mul_to_vis(
isel: &mut VISInstructionSelector,
dst: usize,
s1: usize,
s2: usize,
is_float: bool,
) {
if is_float {
isel.select_fpmul(dst, s1, s2);
} else {
isel.select_pmul(dst, s1, s2);
}
}
pub fn lower_vector_cmp_to_vis(
isel: &mut VISInstructionSelector,
dst: usize,
s1: usize,
s2: usize,
element_bits: u8,
pred: &str,
) {
match (element_bits, pred) {
(16, "eq") => isel.select_fcmpeq16(dst, s1, s2),
(32, "eq") => isel.select_fcmpeq32(dst, s1, s2),
(16, "ne") => isel.select_fcmpne16(dst, s1, s2),
(32, "ne") => isel.select_fcmpne32(dst, s1, s2),
(16, "gt") => isel.select_fcmpgt16(dst, s1, s2),
(32, "gt") => isel.select_fcmpgt32(dst, s1, s2),
(16, "le") => isel.select_fcmle16(dst, s1, s2),
(32, "le") => isel.select_fcmle32(dst, s1, s2),
_ => isel.select_fcmp(dst, s1, s2),
}
}
pub fn lower_vector_logical_to_vis(
isel: &mut VISInstructionSelector,
dst: usize,
s1: usize,
s2: usize,
op: &str,
) {
match op {
"and" => isel.select_fand(dst, s1, s2),
"andnot" => isel.select_fandnot(dst, s1, s2),
"or" => isel.select_for(dst, s1, s2),
"ornot" => isel.select_fornot(dst, s1, s2),
"xor" => isel.select_fxor(dst, s1, s2),
"xnor" => isel.select_fxnor(dst, s1, s2),
"nand" => isel.select_fnand(dst, s1, s2),
"nor" => isel.select_fnor(dst, s1, s2),
_ => {}
}
}
pub fn emit_vis_assembly(ops: &[VISSelectedOp]) -> Vec<String> {
let mut asm = Vec::new();
for op in ops {
let s2 = op.src2_reg.map_or("0".to_string(), |r| format!("%f{}", r));
let line = match op.opcode {
VISOpcodes::PADD => format!(" padd %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::PSUB => format!(" psub %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::PMUL => format!(" pmul %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::PDIST => {
format!(" pdist %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPADD16 => {
format!(" fpadd16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPADD32 => {
format!(" fpadd32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPSUB16 => {
format!(" fpsub16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPSUB32 => {
format!(" fpsub32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPMUL => {
format!(" fpmul %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FAND => format!(" fand %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::FANDNOT => {
format!(" fandnot %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FOR => format!(" for %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::FXOR => format!(" fxor %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::FXNOR => {
format!(" fxnor %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FNAND => {
format!(" fnand %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FNOR => format!(" fnor %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2),
VISOpcodes::FCMEQ16 => {
format!(" fcmpeq16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMEQ32 => {
format!(" fcmpeq32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMNE16 => {
format!(" fcmpne16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMNE32 => {
format!(" fcmpne32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMGT16 => {
format!(" fcmpgt16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMGT32 => {
format!(" fcmpgt32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMLE16 => {
format!(" fcmple16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FCMLE32 => {
format!(" fcmple32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPMERGE => {
format!(" fpmerge %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPMERGE2 => {
format!(" fpmerge2 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FALIGNDATA => format!(
" faligndata %f{}, %f{}, %f{}",
op.dst_reg, op.src1_reg, s2
),
VISOpcodes::FSRC1 => {
format!(" fsrc1 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FSRC2 => {
format!(" fsrc2 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPACK16 => {
format!(" fpack16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPACK32 => {
format!(" fpack32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPACKFIX => format!(" fpackfix %f{}, %f{}", op.dst_reg, op.src1_reg),
VISOpcodes::ARRAY8 => format!(
" array8 %f{}, [%o{} + {}]",
op.dst_reg,
op.src1_reg,
op.offset.unwrap_or(0)
),
VISOpcodes::ARRAY16 => format!(
" array16 %f{}, [%o{} + {}]",
op.dst_reg,
op.src1_reg,
op.offset.unwrap_or(0)
),
VISOpcodes::ARRAY32 => format!(
" array32 %f{}, [%o{} + {}]",
op.dst_reg,
op.src1_reg,
op.offset.unwrap_or(0)
),
VISOpcodes::EDGE8 => {
format!(" edge8 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::EDGE16 => {
format!(" edge16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::EDGE32 => {
format!(" edge32 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::BMASK => {
format!(" bmask %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::BSHUFFLE => {
format!(" bshuffle %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::PST8 => format!(
" pst8 %f{}, [%o{} + {}]",
op.src1_reg,
0,
op.offset.unwrap_or(0)
),
VISOpcodes::PST16 => format!(
" pst16 %f{}, [%o{} + {}]",
op.src1_reg,
0,
op.offset.unwrap_or(0)
),
VISOpcodes::PST32 => format!(
" pst32 %f{}, [%o{} + {}]",
op.src1_reg,
0,
op.offset.unwrap_or(0)
),
VISOpcodes::FMOVSGEZ => {
format!(" fmovsgez %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FMOVSLEZ => {
format!(" fmovslez %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FMOVDGTE => {
format!(" fmovdgte %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FMOVDLTE => {
format!(" fmovdlte %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FEXPAND => format!(" fexpand %f{}, %f{}", op.dst_reg, op.src1_reg),
VISOpcodes::FLCMPS => format!(" flcmps %f{}, %f{}", op.dst_reg, op.src1_reg),
VISOpcodes::FCHKSM16 => {
format!(" fchksm16 %f{}, %f{}, %f{}", op.dst_reg, op.src1_reg, s2)
}
VISOpcodes::FPMULADD => {
let s3 = op.immediate.map_or("0".to_string(), |i| format!("%f{}", i));
format!(
" fpmuladd %f{}, %f{}, %f{}, %f{}",
op.dst_reg, op.src1_reg, s2, s3
)
}
_ => format!(" ; unsupported VIS op"),
};
asm.push(line);
}
asm
}
pub fn emit_vis_function(func_name: &str, ops: &[VISSelectedOp]) -> String {
let mut out = String::new();
out.push_str(&format!("{}:\n", func_name));
out.push_str(" save %sp, -96, %sp\n");
out.push_str(" .word 0x81B00020 ! VIS: wr %g0, VIS_MODE\n");
for line in emit_vis_assembly(ops) {
out.push_str(&line);
out.push('\n');
}
out.push_str(" ret\n");
out.push_str(" restore\n");
out
}
pub fn vis_descriptor_table() -> Vec<(&'static str, VISVersion, u8, bool)> {
vec![
("padd", VISVersion::VIS1, 3, false),
("psub", VISVersion::VIS1, 3, false),
("pmul", VISVersion::VIS1, 3, false),
("pdist", VISVersion::VIS1, 3, false),
("fpadd16", VISVersion::VIS1, 3, false),
("fpadd32", VISVersion::VIS1, 3, false),
("fpsub16", VISVersion::VIS1, 3, false),
("fpsub32", VISVersion::VIS1, 3, false),
("fpmul", VISVersion::VIS1, 3, false),
("fand", VISVersion::VIS1, 3, false),
("fandnot", VISVersion::VIS1, 3, false),
("for", VISVersion::VIS1, 3, false),
("fornot", VISVersion::VIS1, 3, false),
("fxor", VISVersion::VIS1, 3, false),
("fxnor", VISVersion::VIS1, 3, false),
("fnand", VISVersion::VIS1, 3, false),
("fnor", VISVersion::VIS1, 3, false),
("fcmpeq16", VISVersion::VIS1, 3, false),
("fcmpeq32", VISVersion::VIS1, 3, false),
("fcmpne16", VISVersion::VIS1, 3, false),
("fcmpne32", VISVersion::VIS1, 3, false),
("fcmpgt16", VISVersion::VIS1, 3, false),
("fcmpgt32", VISVersion::VIS1, 3, false),
("fcmple16", VISVersion::VIS1, 3, false),
("fcmple32", VISVersion::VIS1, 3, false),
("fpack16", VISVersion::VIS1, 3, true),
("fpack32", VISVersion::VIS1, 3, true),
("fpackfix", VISVersion::VIS1, 2, true),
("faligndata", VISVersion::VIS1, 3, true),
("fsrc1", VISVersion::VIS1, 3, false),
("fsrc2", VISVersion::VIS1, 3, false),
("fpmerge", VISVersion::VIS1, 3, false),
("array8", VISVersion::VIS1, 2, false),
("array16", VISVersion::VIS1, 2, false),
("array32", VISVersion::VIS1, 2, false),
("edge8", VISVersion::VIS2, 3, false),
("edge16", VISVersion::VIS2, 3, false),
("edge32", VISVersion::VIS2, 3, false),
("edge8n", VISVersion::VIS2, 3, false),
("edge16n", VISVersion::VIS2, 3, false),
("edge32n", VISVersion::VIS2, 3, false),
("edge8l", VISVersion::VIS2, 3, false),
("edge16l", VISVersion::VIS2, 3, false),
("edge32l", VISVersion::VIS2, 3, false),
("bmask", VISVersion::VIS2, 3, false),
("bshuffle", VISVersion::VIS2, 3, false),
("pst8", VISVersion::VIS2, 2, false),
("pst16", VISVersion::VIS2, 2, false),
("pst32", VISVersion::VIS2, 2, false),
("fmovsgez", VISVersion::VIS3, 3, false),
("fmovslez", VISVersion::VIS3, 3, false),
("fmovdgte", VISVersion::VIS3, 3, false),
("fmovdlte", VISVersion::VIS3, 3, false),
("fpmuladd", VISVersion::VIS3, 4, false),
("fchksm16", VISVersion::VIS3, 3, false),
("flcmps", VISVersion::VIS3, 2, false),
("pdistn", VISVersion::VIS3, 3, false),
("fexpand", VISVersion::VIS3, 2, false),
("fpmerge2", VISVersion::VIS3, 3, false),
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vis_version_fma() {
assert!(VISVersion::VIS3.has_fma());
assert!(!VISVersion::VIS1.has_fma());
assert!(VISVersion::VIS4.has_fma());
}
#[test]
fn test_vis_element_bits() {
assert_eq!(VISElementSize::Byte8.bits(), 8);
assert_eq!(VISElementSize::Half16.bits(), 16);
assert_eq!(VISElementSize::Float32.bits(), 32);
assert_eq!(VISElementSize::Double64.bits(), 64);
}
#[test]
fn test_vis_element_count() {
assert_eq!(VISElementSize::Byte8.elements(), 8);
assert_eq!(VISElementSize::Float32.elements(), 2);
assert_eq!(VISElementSize::Double64.elements(), 1);
}
#[test]
fn test_select_integer_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_padd(0, 1, 2);
isel.select_psub(1, 2, 3);
isel.select_pmul(2, 3, 4);
isel.select_pdist(3, 4, 5);
assert_eq!(isel.selected_ops.len(), 4);
}
#[test]
fn test_select_float_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fpadd16(0, 1, 2);
isel.select_fpadd32(1, 2, 3);
isel.select_fpsub16(2, 3, 4);
isel.select_fpsub32(3, 4, 5);
isel.select_fpmul(4, 5, 6);
assert_eq!(isel.selected_ops.len(), 5);
}
#[test]
fn test_select_logical_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fand(0, 1, 2);
isel.select_for(1, 2, 3);
isel.select_fxor(2, 3, 4);
isel.select_fxnor(3, 4, 5);
isel.select_fnor(4, 5, 6);
assert_eq!(isel.selected_ops.len(), 5);
}
#[test]
fn test_select_compare_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fcmpeq16(0, 1, 2);
isel.select_fcmpne32(1, 2, 3);
isel.select_fcmpgt16(2, 3, 4);
isel.select_fcmpgt32(3, 4, 5);
isel.select_fcmle16(4, 5, 6);
isel.select_fcmle32(5, 6, 7);
assert_eq!(isel.selected_ops.len(), 6);
}
#[test]
fn test_select_permute_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_faligndata(0, 1, 2);
isel.select_fsrc1(1, 2, 3);
isel.select_fsrc2(2, 3, 4);
isel.select_fpmerge(3, 4, 5);
assert_eq!(isel.selected_ops.len(), 4);
}
#[test]
fn test_select_memory_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_array8(0, 1, 0);
isel.select_array16(1, 1, 8);
isel.select_array32(2, 1, 16);
assert_eq!(isel.selected_ops.len(), 3);
}
#[test]
fn test_select_edge_ops() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS2);
isel.select_edge8(0, 1, 2);
isel.select_edge16(1, 2, 3);
isel.select_edge32(2, 3, 4);
isel.select_bmask(3, 4, 5);
assert_eq!(isel.selected_ops.len(), 4);
}
#[test]
fn test_select_fma() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS3);
isel.select_fpmuladd(0, 1, 2, 3);
assert_eq!(isel.selected_ops.len(), 1);
}
#[test]
fn test_select_fma_not_available() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fpmuladd(0, 1, 2, 3);
assert_eq!(isel.selected_ops.len(), 0);
}
#[test]
fn test_select_partial_store() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS2);
isel.select_pst8(0, 1, 0);
isel.select_pst16(1, 2, 8);
isel.select_pst32(2, 3, 16);
assert_eq!(isel.selected_ops.len(), 3);
}
#[test]
fn test_select_pack() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fpack16(0, 1, 2);
isel.select_fpack32(1, 2, 3);
isel.select_fpackfix(2, 3);
assert_eq!(isel.selected_ops.len(), 3);
}
#[test]
fn test_lower_vector_add_int() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
lower_vector_add_to_vis(&mut isel, 0, 1, 2, 8, false);
assert_eq!(isel.selected_ops[0].opcode, VISOpcodes::PADD);
}
#[test]
fn test_lower_vector_add_float16() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
lower_vector_add_to_vis(&mut isel, 0, 1, 2, 16, true);
assert_eq!(isel.selected_ops[0].opcode, VISOpcodes::FPADD16);
}
#[test]
fn test_lower_vector_add_float32() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
lower_vector_add_to_vis(&mut isel, 0, 1, 2, 32, true);
assert_eq!(isel.selected_ops[0].opcode, VISOpcodes::FPADD32);
}
#[test]
fn test_lower_vector_cmp_all() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
for (bits, pred) in &[
(16, "eq"),
(32, "eq"),
(16, "gt"),
(32, "gt"),
(16, "le"),
(32, "le"),
] {
lower_vector_cmp_to_vis(&mut isel, 0, 1, 2, *bits, pred);
}
assert_eq!(isel.selected_ops.len(), 6);
}
#[test]
fn test_emit_padd_assembly() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_padd(0, 1, 2);
let asm = emit_vis_assembly(&isel.selected_ops);
assert!(asm[0].contains("padd"));
}
#[test]
fn test_emit_fpadd16_assembly() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fpadd16(0, 1, 2);
let asm = emit_vis_assembly(&isel.selected_ops);
assert!(asm[0].contains("fpadd16"));
}
#[test]
fn test_emit_logical_assembly() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fand(0, 1, 2);
isel.select_fxor(0, 1, 2);
let asm = emit_vis_assembly(&isel.selected_ops);
assert!(asm[0].contains("fand"));
assert!(asm[1].contains("fxor"));
}
#[test]
fn test_emit_array_assembly() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_array8(0, 1, 0);
let asm = emit_vis_assembly(&isel.selected_ops);
assert!(asm[0].contains("array8"));
}
#[test]
fn test_emit_edge_assembly() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS2);
isel.select_edge8(0, 1, 2);
let asm = emit_vis_assembly(&isel.selected_ops);
assert!(asm[0].contains("edge8"));
}
#[test]
fn test_emit_partial_store() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS2);
isel.select_pst8(0, 1, 0);
let asm = emit_vis_assembly(&isel.selected_ops);
assert!(asm[0].contains("pst8"));
}
#[test]
fn test_emit_vis_function() {
let mut isel = VISInstructionSelector::new(VISVersion::VIS1);
isel.select_fpadd16(0, 1, 2);
isel.select_fpmul(0, 2, 3);
let func = emit_vis_function("vis_kernel", &isel.selected_ops);
assert!(func.contains("vis_kernel:"));
assert!(func.contains("fpadd16"));
assert!(func.contains("ret"));
}
#[test]
fn test_descriptor_table() {
let table = vis_descriptor_table();
assert!(table.len() >= 50);
assert!(table.iter().any(|(n, _, _, _)| *n == "padd"));
assert!(table.iter().any(|(n, _, _, _)| *n == "fpadd16"));
assert!(table.iter().any(|(n, _, _, _)| *n == "edge8"));
assert!(table.iter().any(|(n, _, _, _)| *n == "fpmuladd"));
}
}