diff options
-rw-r--r-- | src/armv8/a64.rs | 1167 | ||||
-rw-r--r-- | test/armv8/a64.rs | 2 |
2 files changed, 1162 insertions, 7 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 534fc58..5531c8f 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -1082,6 +1082,216 @@ impl Display for Instruction { Opcode::FCMPE => { write!(fmt, "fcmpe")?; } + Opcode::FMUL => { + write!(fmt, "fmul"); + } + Opcode::FDIV => { + write!(fmt, "fdiv"); + } + Opcode::FADD => { + write!(fmt, "fadd"); + } + Opcode::FSUB => { + write!(fmt, "fsub"); + } + Opcode::FMAX => { + write!(fmt, "fmax"); + } + Opcode::FMIN => { + write!(fmt, "fmin"); + } + Opcode::FMAXNM => { + write!(fmt, "fmaxnm"); + } + Opcode::FMINNM => { + write!(fmt, "fminnm"); + } + Opcode::FNMUL => { + write!(fmt, "fnmul"); + } + Opcode::FCSEL => { + write!(fmt, "fcsel"); + } + Opcode::FCCMP => { + write!(fmt, "fccmp"); + } + Opcode::FCCMPE => { + write!(fmt, "fccmpe"); + } + Opcode::FMULX => { + write!(fmt, "fmulx"); + } + Opcode::FMLSL => { + write!(fmt, "fmlsl"); + } + Opcode::FMLAL => { + write!(fmt, "fmlal"); + } + Opcode::SQRDMLSH => { + write!(fmt, "sqrdmlsh"); + } + Opcode::UDOT => { + write!(fmt, "udot"); + } + Opcode::SQRDMLAH => { + write!(fmt, "sqrdmlah"); + } + Opcode::UMULL => { + write!(fmt, "umull"); + } + Opcode::UMULL2 => { + write!(fmt, "umull2"); + } + Opcode::UMLSL => { + write!(fmt, "umlsl"); + } + Opcode::UMLSL2 => { + write!(fmt, "umlsl2"); + } + Opcode::MLS => { + write!(fmt, "mls"); + } + Opcode::UMLAL => { + write!(fmt, "umlal"); + } + Opcode::UMLAL2 => { + write!(fmt, "umlal2"); + } + Opcode::MLA => { + write!(fmt, "mla"); + } + Opcode::SDOT => { + write!(fmt, "sdot"); + } + Opcode::SQRDMULH2 => { + write!(fmt, "sqrdmulh2"); + } + Opcode::SQDMULH => { + write!(fmt, "sqdmulh"); + } + Opcode::SQDMULH2 => { + write!(fmt, "sqdmulh2"); + } + Opcode::SQDMULL => { + write!(fmt, "sqdmull"); + } + Opcode::SQDMULL2 => { + write!(fmt, "sqdmull2"); + } + Opcode::SMULL => { + write!(fmt, "smull"); + } + Opcode::SMULL2 => { + write!(fmt, "smull2"); + } + Opcode::MUL => { + write!(fmt, "mul"); + } + Opcode::SQDMLSL => { + write!(fmt, "sqdmlsl"); + } + Opcode::SQDMLSL2 => { + write!(fmt, "sqdmlsl2"); + } + Opcode::SMLSL => { + write!(fmt, "smlsl"); + } + Opcode::SMLSL2 => { + write!(fmt, "smlsl2"); + } + Opcode::SQDMLAL => { + write!(fmt, "sqdmlal"); + } + Opcode::SQDMLAL2 => { + write!(fmt, "sqdmlal2"); + } + Opcode::SMLAL => { + write!(fmt, "smlal"); + } + Opcode::SMLAL2 => { + write!(fmt, "smlal2"); + } + Opcode::SQRDMULH => { + write!(fmt, "sqrdmulh"); + } + Opcode::FCMLA => { + write!(fmt, "fcmla"); + } + Opcode::SSHR => { + write!(fmt, "sshr"); + } + Opcode::SSRA => { + write!(fmt, "ssra"); + } + Opcode::SRSHR => { + write!(fmt, "srshr"); + } + Opcode::SRSRA => { + write!(fmt, "srsra"); + } + Opcode::SHL => { + write!(fmt, "shl"); + } + Opcode::SQSHL => { + write!(fmt, "sqshl"); + } + Opcode::SHRN => { + write!(fmt, "shrn"); + } + Opcode::RSHRN => { + write!(fmt, "rshrn"); + } + Opcode::SQSHRN => { + write!(fmt, "sqshrn"); + } + Opcode::SQRSHRN => { + write!(fmt, "sqrshrn"); + } + Opcode::SSHLL => { + write!(fmt, "sshll"); + } + Opcode::USHLL => { + write!(fmt, "sshll"); + } + Opcode::USHR => { + write!(fmt, "ushr"); + } + Opcode::USRA => { + write!(fmt, "usra"); + } + Opcode::URSHR => { + write!(fmt, "urshr"); + } + Opcode::URSRA => { + write!(fmt, "ursra"); + } + Opcode::SRI => { + write!(fmt, "sri"); + } + Opcode::SLI => { + write!(fmt, "sli"); + } + Opcode::SQSHLU => { + write!(fmt, "sqshlu"); + } + Opcode::UQSHL => { + write!(fmt, "uqshl"); + } + Opcode::SQSHRUN => { + write!(fmt, "sqshrun"); + } + Opcode::SQRSHRUN => { + write!(fmt, "sqrshrun"); + } + Opcode::UQSHRN => { + write!(fmt, "uqshrn"); + } + Opcode::UQRSHRN => { + write!(fmt, "uqrshrn"); + } + Opcode::SSHLL => { + write!(fmt, "sshll"); + } }; if self.operands[0] != Operand::Nothing { @@ -1320,6 +1530,75 @@ pub enum Opcode { FCVT, FCMP, FCMPE, + FMUL, + FDIV, + FADD, + FSUB, + FMAX, + FMIN, + FMAXNM, + FMINNM, + FNMUL, + FCSEL, + FCCMP, + FCCMPE, + FMULX, + FMLSL, + FMLAL, + SQRDMLSH, + UDOT, + SQRDMLAH, + UMULL, + UMULL2, + UMLSL, + UMLSL2, + MLS, + UMLAL, + UMLAL2, + MLA, + SDOT, + SQRDMULH2, + SQDMULH, + SQDMULH2, + SQDMULL, + SQDMULL2, + SMULL, + SMULL2, + MUL, + SQDMLSL, + SQDMLSL2, + SMLSL, + SMLSL2, + SQDMLAL, + SQDMLAL2, + SMLAL, + SMLAL2, + SQRDMULH, + FCMLA, + SSHR, + SSRA, + SRSHR, + SRSRA, + SHL, + SQSHL, + SHRN, + RSHRN, + SQSHRN, + SQRSHRN, + SSHLL, + USHR, + USRA, + URSHR, + URSRA, + SRI, + SLI, + SQSHLU, + UQSHL, + SQSHRUN, + SQRSHRUN, + UQSHRN, + UQRSHRN, + USHLL, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -1363,6 +1642,8 @@ pub enum Operand { Nothing, Register(SizeCode, u16), SIMDRegister(SIMDSizeCode, u16), + SIMDRegisterElements(SIMDSizeCode, u16, SIMDSizeCode), + SIMDRegisterElementsLane(SIMDSizeCode, u16, SIMDSizeCode, u8), SIMDRegisterGroup(SIMDSizeCode, u16, SIMDSizeCode, u8), SIMDRegisterGroupLane(u16, SIMDSizeCode, u8, u8), RegisterOrSP(SizeCode, u16), @@ -1418,6 +1699,14 @@ impl Display for Operand { SIMDSizeCode::Q => { write!(fmt, "q{}", reg) } } } + Operand::SIMDRegisterElements(vector_width, reg, lane_width) => { + let num_items = vector_width.width() / lane_width.width(); + + write!(fmt, "v{}.{}{}", reg, num_items, lane_width.name()) + } + Operand::SIMDRegisterElementsLane(_vector_width, reg, lane_width, lane) => { + write!(fmt, "v{}.{}[{}]", reg, lane_width.name(), lane) + } Operand::SIMDRegisterGroup(vector_width, reg, lane_width, group_size) => { let num_items = vector_width.width() / lane_width.width(); let format_reg = |f: &mut fmt::Formatter, reg, elems, lane_size: SIMDSizeCode| { @@ -1661,17 +1950,802 @@ impl Decoder<ARMv8> for InstDecoder { let op2 = (word >> 19) & 0b1111; let op1 = (word >> 23) & 0b11; let op0 = (word >> 28) & 0b1111; - if (op0 & 0b0101) != 0b0001 { - // op0 != x0x1 - return Err(DecodeError::IncompleteDecoder); - } else { + if (op0 & 0b0101) == 0b0101 { + // op0 = x1x1, 11x1 is unallocated and 01x1 is many categories + } else if (op0 & 0b1001) == 0b0000 { + let op3_low = (op3 & 1) == 1; + + if op1 >= 0b10 { + if op3_low { + if op1 == 0b11 { + return Err(DecodeError::InvalidOpcode); + } + // `Advanced SIMD {modified,shift by} immediate` + if op2 != 0b0000 { + // `shift by` + let Rd = word & 0b1_1111; + let Rn = (word >> 5) & 0b1_1111; + let opcode = (word >> 11) & 0b11111; + let immb = (word >> 16) & 0b111; + let immh = (word >> 19) & 0b1111; + + let Q = (word >> 30) & 1; + let U = (word >> 29) & 1; + + if immh == 0b0001 && (opcode == 0b11100 || opcode == 0b11111) { + return Err(DecodeError::InvalidOperand); + }; + + if immh >= 0b1000 && Q == 0 { + return Err(DecodeError::InvalidOperand); + } + + let (T, shift) = if immh > 0b0111 { + (SIMDSizeCode::D, ((immh << 3) | immb) & 0b0111_111) + } else if immh > 0b0011 { + (SIMDSizeCode::S, ((immh << 3) | immb) & 0b0011_111) + } else if immh > 0b0001 { + (SIMDSizeCode::H, ((immh << 3) | immb) & 0b0101_111) + } else { + (SIMDSizeCode::B, ((immh << 3) | immb) & 0b0000_111) + }; + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + const OPCODES: &[Result<Opcode, DecodeError>] = &[ + Ok(Opcode::SSHR), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SSRA), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SRSHR), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SRSRA), Err(DecodeError::InvalidOpcode), + // 0b01000 + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SHL), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SQSHL), Err(DecodeError::InvalidOpcode), + // 0b10000 + Ok(Opcode::SHRN), Ok(Opcode::RSHRN), + Ok(Opcode::SQSHRN), Ok(Opcode::SQRSHRN), + Ok(Opcode::SSHLL), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + // 0b11000 + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SCVTF), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Ok(Opcode::FCVTZS), + // U == 1 + Ok(Opcode::USHR), Err(DecodeError::InvalidOpcode), + Ok(Opcode::USRA), Err(DecodeError::InvalidOpcode), + Ok(Opcode::URSHR), Err(DecodeError::InvalidOpcode), + Ok(Opcode::URSRA), Err(DecodeError::InvalidOpcode), + // 0b01000 + Ok(Opcode::SRI), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SLI), Err(DecodeError::InvalidOpcode), + Ok(Opcode::SQSHLU), Err(DecodeError::InvalidOpcode), + Ok(Opcode::UQSHL), Err(DecodeError::InvalidOpcode), + // 0b10000 + Ok(Opcode::SQSHRUN), Ok(Opcode::SQRSHRUN), + Ok(Opcode::UQSHRN), Ok(Opcode::UQRSHRN), + Ok(Opcode::USHLL), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + // 0b11000 + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Ok(Opcode::UCVTF), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Ok(Opcode::FCVTZU), + ]; + inst.opcode = OPCODES[((U << 5) | opcode) as usize]?; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, T), + Operand::SIMDRegisterElements(datasize, Rn as u16, T), + Operand::Immediate(shift), + Operand::Nothing, + ]; + } else { + // `modified` + } + } else { + // `Advanced SIMD vector x indexed element` + let Rd = word & 0b1_1111; + let Rn = (word >> 5) & 0b1_1111; + let opcode = (word >> 12) & 0b1111; + let Rm = (word >> 16) & 0b1111; + + let Q = (word >> 30) & 1; + let U = (word >> 29) & 1; + let size = (word >> 22) & 0b11; + let L = (word >> 21) & 1; + let M = (word >> 20) & 1; + let H = (word >> 11) & 1; + + match (U << 4) | opcode { + 0b0_0010 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SMLAL2 + } else { + Opcode::SMLAL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_0011 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SQDMLAL2 + } else { + Opcode::SQDMLAL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_0110 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SMLSL2 + } else { + Opcode::SMLSL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_0111 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SQDMLSL2 + } else { + Opcode::SQDMLSL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1000 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let elemsize = if size == 0b01 { + SIMDSizeCode::H + } else { + SIMDSizeCode::S + }; + + inst.opcode = Opcode::MUL; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, elemsize), + Operand::SIMDRegisterElements(datasize, Rn as u16, elemsize), + Operand::SIMDRegisterElementsLane(datasize, Rm as u16, elemsize, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1010 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SMULL2 + } else { + Opcode::SMULL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1011 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SQDMULL2 + } else { + Opcode::SQDMULL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1100 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SQDMULH2 + } else { + Opcode::SQDMULH + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1101 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::SQRDMULH2 + } else { + Opcode::SQRDMULH + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1110 => { + if size != 0b10 { + return Err(DecodeError::InvalidOperand); + } + + let Rm = (M << 4) | Rm; + let index = (H << 1) | L; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.opcode = Opcode::SDOT; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::B), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::B, index as u8), + Operand::Nothing, + ]; + }, + 0b0_1111 => { + return Err(DecodeError::InvalidOpcode); + } + 0b0_0000 => { + if size < 0b10 { + return Err(DecodeError::InvalidOpcode); + } + // FMLAL + } + 0b0_0001 => { + // FMLA (not size=0b01) + } + 0b0_0100 => { + // FMLSL (not size<0b10) + } + 0b0_0101 => { + // FMLS (not size=0b01) + } + 0b0_1001 => { + // FMUL (not size=0b01) + } + 0b1_0000 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let elemsize = if size == 0b01 { + SIMDSizeCode::H + } else { + SIMDSizeCode::S + }; + + inst.opcode = Opcode::MLA; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, elemsize), + Operand::SIMDRegisterElements(datasize, Rn as u16, elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, elemsize, index as u8), + Operand::Nothing, + ]; + } + 0b1_0010 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::UMLAL2 + } else { + Opcode::UMLAL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + } + 0b1_0100 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let elemsize = if size == 0b01 { + SIMDSizeCode::H + } else { + SIMDSizeCode::S + }; + + inst.opcode = Opcode::MLS; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, elemsize), + Operand::SIMDRegisterElements(datasize, Rn as u16, elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, elemsize, index as u8), + Operand::Nothing, + ]; + } + 0b1_0110 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::UMLSL2 + } else { + Opcode::UMLSL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + } + 0b1_1010 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = if Q == 1 { + Opcode::UMULL2 + } else { + Opcode::UMULL + }; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + } + 0b1_1011 => { + return Err(DecodeError::InvalidOpcode); + } + 0b1_1101 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = Opcode::SQRDMLAH; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + } + 0b1_1110 => { + if size != 0b10 { + return Err(DecodeError::InvalidOperand); + } + + let Rm = (M << 4) | Rm; + let index = (H << 1) | L; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.opcode = Opcode::UDOT; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::B), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::B, index as u8), + Operand::Nothing, + ]; + } + 0b1_1111 => { + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b01 { + (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) + } else { + (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) + }; + + inst.opcode = Opcode::SQRDMLSH; + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + } + 0b1_1000 => { + if size < 0b10 { + return Err(DecodeError::InvalidOpcode); + } + let index = (H << 2) | (L << 1) | M; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.opcode = Opcode::FMLAL; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElementsLane(datasize, Rm as u16, SIMDSizeCode::H, index as u8), + Operand::Nothing, + ]; + } + 0b1_1100 => { + if size < 0b10 { + return Err(DecodeError::InvalidOpcode); + } + let index = (H << 2) | (L << 1) | M; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.opcode = Opcode::FMLSL; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElementsLane(datasize, Rm as u16, SIMDSizeCode::H, index as u8), + Operand::Nothing, + ]; + } + 0b1_1001 => { + if size == 0b01 { + return Err(DecodeError::InvalidOpcode); + } + let index = (H << 2) | (L << 1) | M; + + let (index, Rm) = if size == 0b10 { + let index = (H << 2) | (L << 1) | M; + let Rm = (M << 4) | Rm; + (index, Rm) + } else { + let index = (H << 1) | L; + (index, Rm) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (Ta, Tb_elemsize, Ts) = if size == 0b00 { + (SIMDSizeCode::H, SIMDSizeCode::H, SIMDSizeCode::S) + } else if size == 0b10 { + (SIMDSizeCode::S, SIMDSizeCode::S, SIMDSizeCode::S) + } else /* if size == 0b11 */ { + (SIMDSizeCode::D, SIMDSizeCode::D, SIMDSizeCode::D) + }; + + inst.opcode = Opcode::FMULX; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, Ta), + Operand::SIMDRegisterElements(datasize, Rn as u16, Tb_elemsize), + Operand::SIMDRegisterElementsLane(datasize, Rm as u16, Ts, index as u8), + Operand::Nothing, + ]; + } + 0b1_0001 | + 0b1_0011 | + 0b1_0101 | + 0b1_0111 => { + // opcode == 0xx1 + // arm v8.3 + + if size == 0b00 || size == 0b11 { + return Err(DecodeError::InvalidOpcode); + } + + if size == 0b01 && Q == 1 { + return Err(DecodeError::InvalidOperand); + } + + let index = (H << 2) | (L << 1) | M; + + let index = if size == 0b10 { + H + } else { + (H << 1) | L + }; + let Rm = (M << 4) | Rm; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + let (T, Ts) = if size == 0b01 { + (SIMDSizeCode::H, SIMDSizeCode::H) + } else /* if size == 0b10 */ { + (SIMDSizeCode::S, SIMDSizeCode::S) + }; + + let rot = (word >> 13) & 0b11; + let rot = rot * 90; + + inst.opcode = Opcode::FCMLA; + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, T), + Operand::SIMDRegisterElements(datasize, Rn as u16, T), + Operand::SIMDRegisterElementsLane(datasize, Rm as u16, Ts, index as u8), + Operand::Immediate(rot), + ]; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + } else { + } + } else if (op0 & 0b0101) == 0b0001 { // op0 == x0x1 (floating-point ops or unallocated - op1, op2, op3 are // self-contained from here) if op1 & 0b10 == 0b00 { if op2 & 0b0100 == 0b0000 { // op2 = x0xx // `Conversion between floating-point and fixed-point` - let sf = (word >> 31); + let sf = word >> 31; let S = (word >> 29) & 1; let ty = (word >> 22) & 0b11; let mode = (word >> 19) & 0b11; @@ -1747,7 +2821,7 @@ impl Decoder<ARMv8> for InstDecoder { return Err(DecodeError::IncompleteDecoder); } else if (op3 & 0b000_111111) == 0b000_000000 { // op2 = x1xx, op3 = xxx000000 - let sf = (word >> 31); + let sf = word >> 31; let S = (word >> 29) & 1; let ty = (word >> 22) & 0b11; let mode = (word >> 19) & 0b11; @@ -1825,10 +2899,88 @@ impl Decoder<ARMv8> for InstDecoder { // op3 = xxxxxxxx1 // `Floating-point conditional compare` or // `Floating-point conditional select` + let ty = (word >> 22) & 0b11; + let Rm = (word >> 16) & 0b1_1111; + let cond = (word >> 12) & 0b1111; + let Rn = (word >> 5) & 0b1_1111; + + let precision = if ty == 0b00 { + SIMDSizeCode::S + } else if ty == 0b01 { + SIMDSizeCode::D + } else if ty == 0b11 { + SIMDSizeCode::H + } else { + return Err(DecodeError::InvalidOperand); + }; + if ((word >> 11) & 1) == 0 { + // fp compare + let nzcv = word & 0b1111; + inst.opcode = if (word >> 4) & 1 == 0 { + Opcode::FCCMP + } else { + Opcode::FCCMPE + }; + inst.operands = [ + Operand::SIMDRegister(precision, Rn as u16), + Operand::SIMDRegister(precision, Rm as u16), + Operand::Immediate(nzcv), + Operand::ConditionCode(cond as u8), + ]; + } else { + // fp select + let Rd = word & 0b1_1111; + inst.opcode = Opcode::FCSEL; + inst.operands = [ + Operand::SIMDRegister(precision, Rd as u16), + Operand::SIMDRegister(precision, Rn as u16), + Operand::SIMDRegister(precision, Rm as u16), + Operand::ConditionCode(cond as u8), + ]; + } } 1 => { // op3 = xxxxxxx10 // `Floating-point data-processing (2 source)` + let ty = (word >> 22) & 0b11; + let Rm = (word >> 16) & 0b1_1111; + let opcode = (word >> 12) & 0b1111; + let Rn = (word >> 5) & 0b1_1111; + let Rd = word & 0b1_1111; + + if opcode > 0b1000 { + return Err(DecodeError::InvalidOpcode); + } + + let precision = if ty == 0b00 { + SIMDSizeCode::S + } else if ty == 0b01 { + SIMDSizeCode::D + } else if ty == 0b11 { + SIMDSizeCode::H + } else { + return Err(DecodeError::InvalidOperand); + }; + + const OPCODES: &[Opcode] = &[ + Opcode::FMUL, + Opcode::FDIV, + Opcode::FADD, + Opcode::FSUB, + Opcode::FMAX, + Opcode::FMIN, + Opcode::FMAXNM, + Opcode::FMINNM, + Opcode::FNMUL, + ]; + + inst.opcode = OPCODES[opcode as usize]; + inst.operands = [ + Operand::SIMDRegister(precision, Rd as u16), + Operand::SIMDRegister(precision, Rn as u16), + Operand::SIMDRegister(precision, Rm as u16), + Operand::Nothing, + ]; } 2 => { // op3 = xxxxxx100 @@ -2038,6 +3190,9 @@ impl Decoder<ARMv8> for InstDecoder { Operand::SIMDRegister(precision, Ra), ]; } + } else { + // op0 != 0xx0, op0 != x0x1 + return Err(DecodeError::IncompleteDecoder); } } Section::Unallocated => { diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index e78daaf..8b40a20 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -4098,7 +4098,7 @@ fn test_openblas_simd_ops() { ([0x02, 0x1d, 0x21, 0x0e], "and v2.8b, v8.8b, v1.8b"), ([0x21, 0x1c, 0x22, 0x0e], "and v1.8b, v1.8b, v2.8b"), ([0x21, 0x1c, 0x32, 0x0e], "and v1.8b, v1.8b, v18.8b"), - ([0x08, 0x54, 0x22, 0x0f], "shl v8.2s, v0.2s, 2"), + ([0x08, 0x54, 0x22, 0x0f], "shl v8.2s, v0.2s, 0x2"), ([0xfe, 0x43, 0x60, 0x1e], "fmov d30, d31"), ([0x54, 0xc2, 0x20, 0x1e], "fabs s20, s18"), ([0xf7, 0xc3, 0x60, 0x1e], "fabs d23, d31"), |