| use crate::isa::riscv64::inst::AllocationConsumer; |
| use crate::isa::riscv64::inst::EmitState; |
| use crate::isa::riscv64::lower::isle::generated_code::{ |
| VecAMode, VecAluOpRImm5, VecAluOpRR, VecAluOpRRImm5, VecAluOpRRR, VecAluOpRRRImm5, VecAvl, |
| VecElementWidth, VecLmul, VecMaskMode, VecOpCategory, VecOpMasking, VecTailMode, |
| }; |
| use crate::machinst::RegClass; |
| use crate::Reg; |
| use core::fmt; |
| |
| use super::{Type, UImm5}; |
| |
| impl VecAvl { |
| pub fn _static(size: u32) -> Self { |
| VecAvl::Static { |
| size: UImm5::maybe_from_u8(size as u8).expect("Invalid size for AVL"), |
| } |
| } |
| |
| pub fn is_static(&self) -> bool { |
| match self { |
| VecAvl::Static { .. } => true, |
| } |
| } |
| |
| pub fn unwrap_static(&self) -> UImm5 { |
| match self { |
| VecAvl::Static { size } => *size, |
| } |
| } |
| } |
| |
| // TODO: Can we tell ISLE to derive this? |
| impl Copy for VecAvl {} |
| |
| // TODO: Can we tell ISLE to derive this? |
| impl PartialEq for VecAvl { |
| fn eq(&self, other: &Self) -> bool { |
| match (self, other) { |
| (VecAvl::Static { size: lhs }, VecAvl::Static { size: rhs }) => lhs == rhs, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecAvl { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| match self { |
| VecAvl::Static { size } => write!(f, "{}", size), |
| } |
| } |
| } |
| |
| impl VecElementWidth { |
| pub fn from_type(ty: Type) -> Self { |
| Self::from_bits(ty.lane_bits()) |
| } |
| |
| pub fn from_bits(bits: u32) -> Self { |
| match bits { |
| 8 => VecElementWidth::E8, |
| 16 => VecElementWidth::E16, |
| 32 => VecElementWidth::E32, |
| 64 => VecElementWidth::E64, |
| _ => panic!("Invalid number of bits for VecElementWidth: {}", bits), |
| } |
| } |
| |
| pub fn bits(&self) -> u32 { |
| match self { |
| VecElementWidth::E8 => 8, |
| VecElementWidth::E16 => 16, |
| VecElementWidth::E32 => 32, |
| VecElementWidth::E64 => 64, |
| } |
| } |
| |
| pub fn encode(&self) -> u32 { |
| match self { |
| VecElementWidth::E8 => 0b000, |
| VecElementWidth::E16 => 0b001, |
| VecElementWidth::E32 => 0b010, |
| VecElementWidth::E64 => 0b011, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecElementWidth { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!(f, "e{}", self.bits()) |
| } |
| } |
| |
| impl VecLmul { |
| pub fn encode(&self) -> u32 { |
| match self { |
| VecLmul::LmulF8 => 0b101, |
| VecLmul::LmulF4 => 0b110, |
| VecLmul::LmulF2 => 0b111, |
| VecLmul::Lmul1 => 0b000, |
| VecLmul::Lmul2 => 0b001, |
| VecLmul::Lmul4 => 0b010, |
| VecLmul::Lmul8 => 0b011, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecLmul { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| match self { |
| VecLmul::LmulF8 => write!(f, "mf8"), |
| VecLmul::LmulF4 => write!(f, "mf4"), |
| VecLmul::LmulF2 => write!(f, "mf2"), |
| VecLmul::Lmul1 => write!(f, "m1"), |
| VecLmul::Lmul2 => write!(f, "m2"), |
| VecLmul::Lmul4 => write!(f, "m4"), |
| VecLmul::Lmul8 => write!(f, "m8"), |
| } |
| } |
| } |
| |
| impl VecTailMode { |
| pub fn encode(&self) -> u32 { |
| match self { |
| VecTailMode::Agnostic => 1, |
| VecTailMode::Undisturbed => 0, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecTailMode { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| match self { |
| VecTailMode::Agnostic => write!(f, "ta"), |
| VecTailMode::Undisturbed => write!(f, "tu"), |
| } |
| } |
| } |
| |
| impl VecMaskMode { |
| pub fn encode(&self) -> u32 { |
| match self { |
| VecMaskMode::Agnostic => 1, |
| VecMaskMode::Undisturbed => 0, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecMaskMode { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| match self { |
| VecMaskMode::Agnostic => write!(f, "ma"), |
| VecMaskMode::Undisturbed => write!(f, "mu"), |
| } |
| } |
| } |
| |
| /// Vector Type (VType) |
| /// |
| /// vtype provides the default type used to interpret the contents of the vector register file. |
| #[derive(Clone, Copy, Debug, PartialEq)] |
| pub struct VType { |
| pub sew: VecElementWidth, |
| pub lmul: VecLmul, |
| pub tail_mode: VecTailMode, |
| pub mask_mode: VecMaskMode, |
| } |
| |
| impl VType { |
| // https://github.com/riscv/riscv-v-spec/blob/master/vtype-format.adoc |
| pub fn encode(&self) -> u32 { |
| let mut bits = 0; |
| bits |= self.lmul.encode(); |
| bits |= self.sew.encode() << 3; |
| bits |= self.tail_mode.encode() << 6; |
| bits |= self.mask_mode.encode() << 7; |
| bits |
| } |
| } |
| |
| impl fmt::Display for VType { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!( |
| f, |
| "{}, {}, {}, {}", |
| self.sew, self.lmul, self.tail_mode, self.mask_mode |
| ) |
| } |
| } |
| |
| /// Vector State (VState) |
| /// |
| /// VState represents the state of the vector unit that each instruction expects before execution. |
| /// Unlike VType or any of the other types here, VState is not a part of the RISC-V ISA. It is |
| /// used by our instruction emission code to ensure that the vector unit is in the correct state. |
| #[derive(Clone, Copy, Debug, PartialEq)] |
| pub struct VState { |
| pub avl: VecAvl, |
| pub vtype: VType, |
| } |
| |
| impl VState { |
| pub fn from_type(ty: Type) -> Self { |
| VState { |
| avl: VecAvl::_static(ty.lane_count()), |
| vtype: VType { |
| sew: VecElementWidth::from_type(ty), |
| lmul: VecLmul::Lmul1, |
| tail_mode: VecTailMode::Agnostic, |
| mask_mode: VecMaskMode::Agnostic, |
| }, |
| } |
| } |
| } |
| |
| impl fmt::Display for VState { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!(f, "#avl={}, #vtype=({})", self.avl, self.vtype) |
| } |
| } |
| |
| impl VecOpCategory { |
| pub fn encode(&self) -> u32 { |
| // See: https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#101-vector-arithmetic-instruction-encoding |
| match self { |
| VecOpCategory::OPIVV => 0b000, |
| VecOpCategory::OPFVV => 0b001, |
| VecOpCategory::OPMVV => 0b010, |
| VecOpCategory::OPIVI => 0b011, |
| VecOpCategory::OPIVX => 0b100, |
| VecOpCategory::OPFVF => 0b101, |
| VecOpCategory::OPMVX => 0b110, |
| VecOpCategory::OPCFG => 0b111, |
| } |
| } |
| } |
| |
| impl VecOpMasking { |
| pub fn encode(&self) -> u32 { |
| match self { |
| VecOpMasking::Enabled { .. } => 0, |
| VecOpMasking::Disabled => 1, |
| } |
| } |
| |
| pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self { |
| match self { |
| VecOpMasking::Enabled { reg } => VecOpMasking::Enabled { |
| reg: allocs.next(*reg), |
| }, |
| VecOpMasking::Disabled => VecOpMasking::Disabled, |
| } |
| } |
| } |
| |
| impl VecAluOpRRRImm5 { |
| pub fn opcode(&self) -> u32 { |
| // Vector Opcode |
| 0x57 |
| } |
| pub fn funct3(&self) -> u32 { |
| self.category().encode() |
| } |
| |
| pub fn funct6(&self) -> u32 { |
| // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc |
| match self { |
| VecAluOpRRRImm5::VslideupVI => 0b001110, |
| } |
| } |
| |
| pub fn category(&self) -> VecOpCategory { |
| match self { |
| VecAluOpRRRImm5::VslideupVI => VecOpCategory::OPIVI, |
| } |
| } |
| |
| pub fn imm_is_unsigned(&self) -> bool { |
| match self { |
| VecAluOpRRRImm5::VslideupVI => true, |
| } |
| } |
| |
| /// Some instructions do not allow the source and destination registers to overlap. |
| pub fn forbids_src_dst_overlaps(&self) -> bool { |
| match self { |
| VecAluOpRRRImm5::VslideupVI => true, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecAluOpRRRImm5 { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let mut s = format!("{self:?}"); |
| s.make_ascii_lowercase(); |
| let (opcode, category) = s.split_at(s.len() - 2); |
| f.write_str(&format!("{opcode}.{category}")) |
| } |
| } |
| |
| impl VecAluOpRRR { |
| pub fn opcode(&self) -> u32 { |
| // Vector Opcode |
| 0x57 |
| } |
| pub fn funct3(&self) -> u32 { |
| self.category().encode() |
| } |
| pub fn funct6(&self) -> u32 { |
| // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc |
| match self { |
| VecAluOpRRR::VaddVV |
| | VecAluOpRRR::VaddVX |
| | VecAluOpRRR::VfaddVV |
| | VecAluOpRRR::VfaddVF => 0b000000, |
| VecAluOpRRR::VsubVV |
| | VecAluOpRRR::VsubVX |
| | VecAluOpRRR::VfsubVV |
| | VecAluOpRRR::VfsubVF => 0b000010, |
| VecAluOpRRR::VrsubVX => 0b000011, |
| VecAluOpRRR::VmulVV | VecAluOpRRR::VmulVX => 0b100101, |
| VecAluOpRRR::VmulhVV | VecAluOpRRR::VmulhVX => 0b100111, |
| VecAluOpRRR::VmulhuVV |
| | VecAluOpRRR::VmulhuVX |
| | VecAluOpRRR::VfmulVV |
| | VecAluOpRRR::VfmulVF => 0b100100, |
| VecAluOpRRR::VsmulVV | VecAluOpRRR::VsmulVX => 0b100111, |
| VecAluOpRRR::VsllVV | VecAluOpRRR::VsllVX => 0b100101, |
| VecAluOpRRR::VsrlVV | VecAluOpRRR::VsrlVX => 0b101000, |
| VecAluOpRRR::VsraVV | VecAluOpRRR::VsraVX => 0b101001, |
| VecAluOpRRR::VandVV | VecAluOpRRR::VandVX => 0b001001, |
| VecAluOpRRR::VorVV | VecAluOpRRR::VorVX => 0b001010, |
| VecAluOpRRR::VxorVV | VecAluOpRRR::VxorVX => 0b001011, |
| VecAluOpRRR::VminuVV | VecAluOpRRR::VminuVX | VecAluOpRRR::VredminuVS => 0b000100, |
| VecAluOpRRR::VminVV | VecAluOpRRR::VminVX => 0b000101, |
| VecAluOpRRR::VmaxuVV | VecAluOpRRR::VmaxuVX | VecAluOpRRR::VredmaxuVS => 0b000110, |
| VecAluOpRRR::VmaxVV | VecAluOpRRR::VmaxVX => 0b000111, |
| VecAluOpRRR::VslidedownVX => 0b001111, |
| VecAluOpRRR::VfrsubVF => 0b100111, |
| VecAluOpRRR::VmergeVVM |
| | VecAluOpRRR::VmergeVXM |
| | VecAluOpRRR::VfmergeVFM |
| | VecAluOpRRR::VcompressVM => 0b010111, |
| VecAluOpRRR::VfdivVV |
| | VecAluOpRRR::VfdivVF |
| | VecAluOpRRR::VsadduVV |
| | VecAluOpRRR::VsadduVX => 0b100000, |
| VecAluOpRRR::VfrdivVF | VecAluOpRRR::VsaddVV | VecAluOpRRR::VsaddVX => 0b100001, |
| VecAluOpRRR::VfminVV => 0b000100, |
| VecAluOpRRR::VfmaxVV => 0b000110, |
| VecAluOpRRR::VssubuVV | VecAluOpRRR::VssubuVX => 0b100010, |
| VecAluOpRRR::VssubVV | VecAluOpRRR::VssubVX => 0b100011, |
| VecAluOpRRR::VfsgnjVV | VecAluOpRRR::VfsgnjVF => 0b001000, |
| VecAluOpRRR::VfsgnjnVV => 0b001001, |
| VecAluOpRRR::VfsgnjxVV => 0b001010, |
| VecAluOpRRR::VrgatherVV | VecAluOpRRR::VrgatherVX => 0b001100, |
| VecAluOpRRR::VwadduVV | VecAluOpRRR::VwadduVX => 0b110000, |
| VecAluOpRRR::VwaddVV | VecAluOpRRR::VwaddVX => 0b110001, |
| VecAluOpRRR::VwsubuVV | VecAluOpRRR::VwsubuVX => 0b110010, |
| VecAluOpRRR::VwsubVV | VecAluOpRRR::VwsubVX => 0b110011, |
| VecAluOpRRR::VwadduWV | VecAluOpRRR::VwadduWX => 0b110100, |
| VecAluOpRRR::VwaddWV | VecAluOpRRR::VwaddWX => 0b110101, |
| VecAluOpRRR::VwsubuWV | VecAluOpRRR::VwsubuWX => 0b110110, |
| VecAluOpRRR::VwsubWV | VecAluOpRRR::VwsubWX => 0b110111, |
| VecAluOpRRR::VmseqVV |
| | VecAluOpRRR::VmseqVX |
| | VecAluOpRRR::VmfeqVV |
| | VecAluOpRRR::VmfeqVF => 0b011000, |
| VecAluOpRRR::VmsneVV |
| | VecAluOpRRR::VmsneVX |
| | VecAluOpRRR::VmfleVV |
| | VecAluOpRRR::VmfleVF |
| | VecAluOpRRR::VmandMM => 0b011001, |
| VecAluOpRRR::VmsltuVV | VecAluOpRRR::VmsltuVX | VecAluOpRRR::VmorMM => 0b011010, |
| VecAluOpRRR::VmsltVV |
| | VecAluOpRRR::VmsltVX |
| | VecAluOpRRR::VmfltVV |
| | VecAluOpRRR::VmfltVF => 0b011011, |
| VecAluOpRRR::VmsleuVV |
| | VecAluOpRRR::VmsleuVX |
| | VecAluOpRRR::VmfneVV |
| | VecAluOpRRR::VmfneVF => 0b011100, |
| VecAluOpRRR::VmsleVV |
| | VecAluOpRRR::VmsleVX |
| | VecAluOpRRR::VmfgtVF |
| | VecAluOpRRR::VmnandMM => 0b011101, |
| VecAluOpRRR::VmsgtuVX | VecAluOpRRR::VmnorMM => 0b011110, |
| VecAluOpRRR::VmsgtVX | VecAluOpRRR::VmfgeVF => 0b011111, |
| } |
| } |
| |
| pub fn category(&self) -> VecOpCategory { |
| match self { |
| VecAluOpRRR::VaddVV |
| | VecAluOpRRR::VsaddVV |
| | VecAluOpRRR::VsadduVV |
| | VecAluOpRRR::VsubVV |
| | VecAluOpRRR::VssubVV |
| | VecAluOpRRR::VssubuVV |
| | VecAluOpRRR::VsmulVV |
| | VecAluOpRRR::VsllVV |
| | VecAluOpRRR::VsrlVV |
| | VecAluOpRRR::VsraVV |
| | VecAluOpRRR::VandVV |
| | VecAluOpRRR::VorVV |
| | VecAluOpRRR::VxorVV |
| | VecAluOpRRR::VminuVV |
| | VecAluOpRRR::VminVV |
| | VecAluOpRRR::VmaxuVV |
| | VecAluOpRRR::VmaxVV |
| | VecAluOpRRR::VmergeVVM |
| | VecAluOpRRR::VrgatherVV |
| | VecAluOpRRR::VmseqVV |
| | VecAluOpRRR::VmsneVV |
| | VecAluOpRRR::VmsltuVV |
| | VecAluOpRRR::VmsltVV |
| | VecAluOpRRR::VmsleuVV |
| | VecAluOpRRR::VmsleVV => VecOpCategory::OPIVV, |
| VecAluOpRRR::VwaddVV |
| | VecAluOpRRR::VwaddWV |
| | VecAluOpRRR::VwadduVV |
| | VecAluOpRRR::VwadduWV |
| | VecAluOpRRR::VwsubVV |
| | VecAluOpRRR::VwsubWV |
| | VecAluOpRRR::VwsubuVV |
| | VecAluOpRRR::VwsubuWV |
| | VecAluOpRRR::VmulVV |
| | VecAluOpRRR::VmulhVV |
| | VecAluOpRRR::VmulhuVV |
| | VecAluOpRRR::VredmaxuVS |
| | VecAluOpRRR::VredminuVS |
| | VecAluOpRRR::VcompressVM |
| | VecAluOpRRR::VmandMM |
| | VecAluOpRRR::VmorMM |
| | VecAluOpRRR::VmnandMM |
| | VecAluOpRRR::VmnorMM => VecOpCategory::OPMVV, |
| VecAluOpRRR::VwaddVX |
| | VecAluOpRRR::VwadduVX |
| | VecAluOpRRR::VwadduWX |
| | VecAluOpRRR::VwaddWX |
| | VecAluOpRRR::VwsubVX |
| | VecAluOpRRR::VwsubuVX |
| | VecAluOpRRR::VwsubuWX |
| | VecAluOpRRR::VwsubWX |
| | VecAluOpRRR::VmulVX |
| | VecAluOpRRR::VmulhVX |
| | VecAluOpRRR::VmulhuVX => VecOpCategory::OPMVX, |
| VecAluOpRRR::VaddVX |
| | VecAluOpRRR::VsaddVX |
| | VecAluOpRRR::VsadduVX |
| | VecAluOpRRR::VsubVX |
| | VecAluOpRRR::VssubVX |
| | VecAluOpRRR::VssubuVX |
| | VecAluOpRRR::VrsubVX |
| | VecAluOpRRR::VsmulVX |
| | VecAluOpRRR::VsllVX |
| | VecAluOpRRR::VsrlVX |
| | VecAluOpRRR::VsraVX |
| | VecAluOpRRR::VandVX |
| | VecAluOpRRR::VorVX |
| | VecAluOpRRR::VxorVX |
| | VecAluOpRRR::VminuVX |
| | VecAluOpRRR::VminVX |
| | VecAluOpRRR::VmaxuVX |
| | VecAluOpRRR::VmaxVX |
| | VecAluOpRRR::VslidedownVX |
| | VecAluOpRRR::VmergeVXM |
| | VecAluOpRRR::VrgatherVX |
| | VecAluOpRRR::VmseqVX |
| | VecAluOpRRR::VmsneVX |
| | VecAluOpRRR::VmsltuVX |
| | VecAluOpRRR::VmsltVX |
| | VecAluOpRRR::VmsleuVX |
| | VecAluOpRRR::VmsleVX |
| | VecAluOpRRR::VmsgtuVX |
| | VecAluOpRRR::VmsgtVX => VecOpCategory::OPIVX, |
| VecAluOpRRR::VfaddVV |
| | VecAluOpRRR::VfsubVV |
| | VecAluOpRRR::VfmulVV |
| | VecAluOpRRR::VfdivVV |
| | VecAluOpRRR::VfmaxVV |
| | VecAluOpRRR::VfminVV |
| | VecAluOpRRR::VfsgnjVV |
| | VecAluOpRRR::VfsgnjnVV |
| | VecAluOpRRR::VfsgnjxVV |
| | VecAluOpRRR::VmfeqVV |
| | VecAluOpRRR::VmfneVV |
| | VecAluOpRRR::VmfltVV |
| | VecAluOpRRR::VmfleVV => VecOpCategory::OPFVV, |
| VecAluOpRRR::VfaddVF |
| | VecAluOpRRR::VfsubVF |
| | VecAluOpRRR::VfrsubVF |
| | VecAluOpRRR::VfmulVF |
| | VecAluOpRRR::VfdivVF |
| | VecAluOpRRR::VfrdivVF |
| | VecAluOpRRR::VfmergeVFM |
| | VecAluOpRRR::VfsgnjVF |
| | VecAluOpRRR::VmfeqVF |
| | VecAluOpRRR::VmfneVF |
| | VecAluOpRRR::VmfltVF |
| | VecAluOpRRR::VmfleVF |
| | VecAluOpRRR::VmfgtVF |
| | VecAluOpRRR::VmfgeVF => VecOpCategory::OPFVF, |
| } |
| } |
| |
| // vs1 is the only variable source, vs2 is fixed. |
| pub fn vs1_regclass(&self) -> RegClass { |
| match self.category() { |
| VecOpCategory::OPIVV | VecOpCategory::OPFVV | VecOpCategory::OPMVV => RegClass::Vector, |
| VecOpCategory::OPIVX | VecOpCategory::OPMVX => RegClass::Int, |
| VecOpCategory::OPFVF => RegClass::Float, |
| _ => unreachable!(), |
| } |
| } |
| |
| /// Some instructions do not allow the source and destination registers to overlap. |
| pub fn forbids_src_dst_overlaps(&self) -> bool { |
| match self { |
| VecAluOpRRR::VrgatherVV |
| | VecAluOpRRR::VrgatherVX |
| | VecAluOpRRR::VcompressVM |
| | VecAluOpRRR::VwadduVV |
| | VecAluOpRRR::VwadduVX |
| | VecAluOpRRR::VwaddVV |
| | VecAluOpRRR::VwaddVX |
| | VecAluOpRRR::VwadduWV |
| | VecAluOpRRR::VwadduWX |
| | VecAluOpRRR::VwaddWV |
| | VecAluOpRRR::VwaddWX |
| | VecAluOpRRR::VwsubuVV |
| | VecAluOpRRR::VwsubuVX |
| | VecAluOpRRR::VwsubVV |
| | VecAluOpRRR::VwsubVX |
| | VecAluOpRRR::VwsubuWV |
| | VecAluOpRRR::VwsubuWX |
| | VecAluOpRRR::VwsubWV |
| | VecAluOpRRR::VwsubWX => true, |
| _ => false, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecAluOpRRR { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let suffix_length = match self { |
| VecAluOpRRR::VmergeVVM | VecAluOpRRR::VmergeVXM | VecAluOpRRR::VfmergeVFM => 3, |
| _ => 2, |
| }; |
| |
| let mut s = format!("{self:?}"); |
| s.make_ascii_lowercase(); |
| let (opcode, category) = s.split_at(s.len() - suffix_length); |
| f.write_str(&format!("{opcode}.{category}")) |
| } |
| } |
| |
| impl VecAluOpRRImm5 { |
| pub fn opcode(&self) -> u32 { |
| // Vector Opcode |
| 0x57 |
| } |
| pub fn funct3(&self) -> u32 { |
| self.category().encode() |
| } |
| |
| pub fn funct6(&self) -> u32 { |
| // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc |
| match self { |
| VecAluOpRRImm5::VaddVI => 0b000000, |
| VecAluOpRRImm5::VrsubVI => 0b000011, |
| VecAluOpRRImm5::VsllVI => 0b100101, |
| VecAluOpRRImm5::VsrlVI => 0b101000, |
| VecAluOpRRImm5::VsraVI => 0b101001, |
| VecAluOpRRImm5::VandVI => 0b001001, |
| VecAluOpRRImm5::VorVI => 0b001010, |
| VecAluOpRRImm5::VxorVI => 0b001011, |
| VecAluOpRRImm5::VslidedownVI => 0b001111, |
| VecAluOpRRImm5::VssrlVI => 0b101010, |
| VecAluOpRRImm5::VmergeVIM => 0b010111, |
| VecAluOpRRImm5::VsadduVI => 0b100000, |
| VecAluOpRRImm5::VsaddVI => 0b100001, |
| VecAluOpRRImm5::VrgatherVI => 0b001100, |
| VecAluOpRRImm5::VmvrV => 0b100111, |
| VecAluOpRRImm5::VnclipWI => 0b101111, |
| VecAluOpRRImm5::VnclipuWI => 0b101110, |
| VecAluOpRRImm5::VmseqVI => 0b011000, |
| VecAluOpRRImm5::VmsneVI => 0b011001, |
| VecAluOpRRImm5::VmsleuVI => 0b011100, |
| VecAluOpRRImm5::VmsleVI => 0b011101, |
| VecAluOpRRImm5::VmsgtuVI => 0b011110, |
| VecAluOpRRImm5::VmsgtVI => 0b011111, |
| } |
| } |
| |
| pub fn category(&self) -> VecOpCategory { |
| match self { |
| VecAluOpRRImm5::VaddVI |
| | VecAluOpRRImm5::VrsubVI |
| | VecAluOpRRImm5::VsllVI |
| | VecAluOpRRImm5::VsrlVI |
| | VecAluOpRRImm5::VsraVI |
| | VecAluOpRRImm5::VandVI |
| | VecAluOpRRImm5::VorVI |
| | VecAluOpRRImm5::VxorVI |
| | VecAluOpRRImm5::VssrlVI |
| | VecAluOpRRImm5::VslidedownVI |
| | VecAluOpRRImm5::VmergeVIM |
| | VecAluOpRRImm5::VsadduVI |
| | VecAluOpRRImm5::VsaddVI |
| | VecAluOpRRImm5::VrgatherVI |
| | VecAluOpRRImm5::VmvrV |
| | VecAluOpRRImm5::VnclipWI |
| | VecAluOpRRImm5::VnclipuWI |
| | VecAluOpRRImm5::VmseqVI |
| | VecAluOpRRImm5::VmsneVI |
| | VecAluOpRRImm5::VmsleuVI |
| | VecAluOpRRImm5::VmsleVI |
| | VecAluOpRRImm5::VmsgtuVI |
| | VecAluOpRRImm5::VmsgtVI => VecOpCategory::OPIVI, |
| } |
| } |
| |
| pub fn imm_is_unsigned(&self) -> bool { |
| match self { |
| VecAluOpRRImm5::VsllVI |
| | VecAluOpRRImm5::VsrlVI |
| | VecAluOpRRImm5::VssrlVI |
| | VecAluOpRRImm5::VsraVI |
| | VecAluOpRRImm5::VslidedownVI |
| | VecAluOpRRImm5::VrgatherVI |
| | VecAluOpRRImm5::VmvrV |
| | VecAluOpRRImm5::VnclipWI |
| | VecAluOpRRImm5::VnclipuWI => true, |
| VecAluOpRRImm5::VaddVI |
| | VecAluOpRRImm5::VrsubVI |
| | VecAluOpRRImm5::VandVI |
| | VecAluOpRRImm5::VorVI |
| | VecAluOpRRImm5::VxorVI |
| | VecAluOpRRImm5::VmergeVIM |
| | VecAluOpRRImm5::VsadduVI |
| | VecAluOpRRImm5::VsaddVI |
| | VecAluOpRRImm5::VmseqVI |
| | VecAluOpRRImm5::VmsneVI |
| | VecAluOpRRImm5::VmsleuVI |
| | VecAluOpRRImm5::VmsleVI |
| | VecAluOpRRImm5::VmsgtuVI |
| | VecAluOpRRImm5::VmsgtVI => false, |
| } |
| } |
| |
| /// Some instructions do not allow the source and destination registers to overlap. |
| pub fn forbids_src_dst_overlaps(&self) -> bool { |
| match self { |
| VecAluOpRRImm5::VrgatherVI => true, |
| _ => false, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecAluOpRRImm5 { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let suffix_length = match self { |
| VecAluOpRRImm5::VmergeVIM => 3, |
| _ => 2, |
| }; |
| |
| let mut s = format!("{self:?}"); |
| s.make_ascii_lowercase(); |
| let (opcode, category) = s.split_at(s.len() - suffix_length); |
| f.write_str(&format!("{opcode}.{category}")) |
| } |
| } |
| |
| impl VecAluOpRR { |
| pub fn opcode(&self) -> u32 { |
| // Vector Opcode |
| 0x57 |
| } |
| |
| pub fn funct3(&self) -> u32 { |
| self.category().encode() |
| } |
| |
| pub fn funct6(&self) -> u32 { |
| // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc |
| match self { |
| VecAluOpRR::VmvSX | VecAluOpRR::VmvXS | VecAluOpRR::VfmvSF | VecAluOpRR::VfmvFS => { |
| 0b010000 |
| } |
| VecAluOpRR::VzextVF2 |
| | VecAluOpRR::VzextVF4 |
| | VecAluOpRR::VzextVF8 |
| | VecAluOpRR::VsextVF2 |
| | VecAluOpRR::VsextVF4 |
| | VecAluOpRR::VsextVF8 => 0b010010, |
| VecAluOpRR::VfsqrtV => 0b010011, |
| VecAluOpRR::VmvVV | VecAluOpRR::VmvVX | VecAluOpRR::VfmvVF => 0b010111, |
| } |
| } |
| |
| pub fn category(&self) -> VecOpCategory { |
| match self { |
| VecAluOpRR::VmvSX => VecOpCategory::OPMVX, |
| VecAluOpRR::VmvXS |
| | VecAluOpRR::VzextVF2 |
| | VecAluOpRR::VzextVF4 |
| | VecAluOpRR::VzextVF8 |
| | VecAluOpRR::VsextVF2 |
| | VecAluOpRR::VsextVF4 |
| | VecAluOpRR::VsextVF8 => VecOpCategory::OPMVV, |
| VecAluOpRR::VfmvSF | VecAluOpRR::VfmvVF => VecOpCategory::OPFVF, |
| VecAluOpRR::VfmvFS | VecAluOpRR::VfsqrtV => VecOpCategory::OPFVV, |
| VecAluOpRR::VmvVV => VecOpCategory::OPIVV, |
| VecAluOpRR::VmvVX => VecOpCategory::OPIVX, |
| } |
| } |
| |
| /// Returns the auxiliary encoding field for the instruction, if any. |
| pub fn aux_encoding(&self) -> u32 { |
| match self { |
| // VRXUNARY0 |
| VecAluOpRR::VmvSX => 0b00000, |
| // VWXUNARY0 |
| VecAluOpRR::VmvXS => 0b00000, |
| // VRFUNARY0 |
| VecAluOpRR::VfmvSF => 0b00000, |
| // VWFUNARY0 |
| VecAluOpRR::VfmvFS => 0b00000, |
| // VFUNARY1 |
| VecAluOpRR::VfsqrtV => 0b00000, |
| // VXUNARY0 |
| VecAluOpRR::VzextVF8 => 0b00010, |
| VecAluOpRR::VsextVF8 => 0b00011, |
| VecAluOpRR::VzextVF4 => 0b00100, |
| VecAluOpRR::VsextVF4 => 0b00101, |
| VecAluOpRR::VzextVF2 => 0b00110, |
| VecAluOpRR::VsextVF2 => 0b00111, |
| // These don't have a explicit encoding table, but Section 11.16 Vector Integer Move Instruction states: |
| // > The first operand specifier (vs2) must contain v0, and any other vector register number in vs2 is reserved. |
| VecAluOpRR::VmvVV | VecAluOpRR::VmvVX | VecAluOpRR::VfmvVF => 0, |
| } |
| } |
| |
| /// Most of these opcodes have the source register encoded in the VS2 field and |
| /// the `aux_encoding` field in VS1. However some special snowflakes have it the |
| /// other way around. As far as I can tell only vmv.v.* are backwards. |
| pub fn vs_is_vs2_encoded(&self) -> bool { |
| match self { |
| VecAluOpRR::VmvXS |
| | VecAluOpRR::VfmvFS |
| | VecAluOpRR::VfsqrtV |
| | VecAluOpRR::VzextVF2 |
| | VecAluOpRR::VzextVF4 |
| | VecAluOpRR::VzextVF8 |
| | VecAluOpRR::VsextVF2 |
| | VecAluOpRR::VsextVF4 |
| | VecAluOpRR::VsextVF8 => true, |
| VecAluOpRR::VmvSX |
| | VecAluOpRR::VfmvSF |
| | VecAluOpRR::VmvVV |
| | VecAluOpRR::VmvVX |
| | VecAluOpRR::VfmvVF => false, |
| } |
| } |
| |
| pub fn dst_regclass(&self) -> RegClass { |
| match self { |
| VecAluOpRR::VfmvSF |
| | VecAluOpRR::VmvSX |
| | VecAluOpRR::VmvVV |
| | VecAluOpRR::VmvVX |
| | VecAluOpRR::VfmvVF |
| | VecAluOpRR::VfsqrtV |
| | VecAluOpRR::VzextVF2 |
| | VecAluOpRR::VzextVF4 |
| | VecAluOpRR::VzextVF8 |
| | VecAluOpRR::VsextVF2 |
| | VecAluOpRR::VsextVF4 |
| | VecAluOpRR::VsextVF8 => RegClass::Vector, |
| VecAluOpRR::VmvXS => RegClass::Int, |
| VecAluOpRR::VfmvFS => RegClass::Float, |
| } |
| } |
| |
| pub fn src_regclass(&self) -> RegClass { |
| match self { |
| VecAluOpRR::VmvXS |
| | VecAluOpRR::VfmvFS |
| | VecAluOpRR::VmvVV |
| | VecAluOpRR::VfsqrtV |
| | VecAluOpRR::VzextVF2 |
| | VecAluOpRR::VzextVF4 |
| | VecAluOpRR::VzextVF8 |
| | VecAluOpRR::VsextVF2 |
| | VecAluOpRR::VsextVF4 |
| | VecAluOpRR::VsextVF8 => RegClass::Vector, |
| VecAluOpRR::VfmvSF | VecAluOpRR::VfmvVF => RegClass::Float, |
| VecAluOpRR::VmvSX | VecAluOpRR::VmvVX => RegClass::Int, |
| } |
| } |
| |
| /// Some instructions do not allow the source and destination registers to overlap. |
| pub fn forbids_src_dst_overlaps(&self) -> bool { |
| match self { |
| VecAluOpRR::VzextVF2 |
| | VecAluOpRR::VzextVF4 |
| | VecAluOpRR::VzextVF8 |
| | VecAluOpRR::VsextVF2 |
| | VecAluOpRR::VsextVF4 |
| | VecAluOpRR::VsextVF8 => true, |
| _ => false, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecAluOpRR { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| f.write_str(match self { |
| VecAluOpRR::VmvSX => "vmv.s.x", |
| VecAluOpRR::VmvXS => "vmv.x.s", |
| VecAluOpRR::VfmvSF => "vfmv.s.f", |
| VecAluOpRR::VfmvFS => "vfmv.f.s", |
| VecAluOpRR::VfsqrtV => "vfsqrt.v", |
| VecAluOpRR::VzextVF2 => "vzext.vf2", |
| VecAluOpRR::VzextVF4 => "vzext.vf4", |
| VecAluOpRR::VzextVF8 => "vzext.vf8", |
| VecAluOpRR::VsextVF2 => "vsext.vf2", |
| VecAluOpRR::VsextVF4 => "vsext.vf4", |
| VecAluOpRR::VsextVF8 => "vsext.vf8", |
| VecAluOpRR::VmvVV => "vmv.v.v", |
| VecAluOpRR::VmvVX => "vmv.v.x", |
| VecAluOpRR::VfmvVF => "vfmv.v.f", |
| }) |
| } |
| } |
| |
| impl VecAluOpRImm5 { |
| pub fn opcode(&self) -> u32 { |
| // Vector Opcode |
| 0x57 |
| } |
| pub fn funct3(&self) -> u32 { |
| self.category().encode() |
| } |
| |
| pub fn funct6(&self) -> u32 { |
| // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc |
| match self { |
| VecAluOpRImm5::VmvVI => 0b010111, |
| } |
| } |
| |
| pub fn category(&self) -> VecOpCategory { |
| match self { |
| VecAluOpRImm5::VmvVI => VecOpCategory::OPIVI, |
| } |
| } |
| |
| /// Returns the auxiliary encoding field for the instruction, if any. |
| pub fn aux_encoding(&self) -> u32 { |
| match self { |
| // These don't have a explicit encoding table, but Section 11.16 Vector Integer Move Instruction states: |
| // > The first operand specifier (vs2) must contain v0, and any other vector register number in vs2 is reserved. |
| VecAluOpRImm5::VmvVI => 0, |
| } |
| } |
| } |
| |
| impl fmt::Display for VecAluOpRImm5 { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| f.write_str(match self { |
| VecAluOpRImm5::VmvVI => "vmv.v.i", |
| }) |
| } |
| } |
| |
| impl VecAMode { |
| pub fn get_base_register(&self) -> Option<Reg> { |
| match self { |
| VecAMode::UnitStride { base, .. } => base.get_base_register(), |
| } |
| } |
| |
| pub fn get_allocatable_register(&self) -> Option<Reg> { |
| match self { |
| VecAMode::UnitStride { base, .. } => base.get_allocatable_register(), |
| } |
| } |
| |
| pub(crate) fn with_allocs(self, allocs: &mut AllocationConsumer<'_>) -> Self { |
| match self { |
| VecAMode::UnitStride { base } => VecAMode::UnitStride { |
| base: base.with_allocs(allocs), |
| }, |
| } |
| } |
| |
| pub(crate) fn get_offset_with_state(&self, state: &EmitState) -> i64 { |
| match self { |
| VecAMode::UnitStride { base, .. } => base.get_offset_with_state(state), |
| } |
| } |
| |
| /// `mop` field, described in Table 7 of Section 7.2. Vector Load/Store Addressing Modes |
| /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes |
| pub fn mop(&self) -> u32 { |
| match self { |
| VecAMode::UnitStride { .. } => 0b00, |
| } |
| } |
| |
| /// `lumop` field, described in Table 9 of Section 7.2. Vector Load/Store Addressing Modes |
| /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes |
| pub fn lumop(&self) -> u32 { |
| match self { |
| VecAMode::UnitStride { .. } => 0b00000, |
| } |
| } |
| |
| /// `sumop` field, described in Table 10 of Section 7.2. Vector Load/Store Addressing Modes |
| /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes |
| pub fn sumop(&self) -> u32 { |
| match self { |
| VecAMode::UnitStride { .. } => 0b00000, |
| } |
| } |
| |
| /// The `nf[2:0]` field encodes the number of fields in each segment. For regular vector loads and |
| /// stores, nf=0, indicating that a single value is moved between a vector register group and memory |
| /// at each element position. Larger values in the nf field are used to access multiple contiguous |
| /// fields within a segment as described in Section 7.8 Vector Load/Store Segment Instructions. |
| /// |
| /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes |
| pub fn nf(&self) -> u32 { |
| match self { |
| VecAMode::UnitStride { .. } => 0b000, |
| } |
| } |
| } |