diff options
-rw-r--r-- | src/armv8/a64.rs | 302 | ||||
-rw-r--r-- | test/armv8/a64.rs | 114 |
2 files changed, 399 insertions, 17 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 4dc5483..e6ed329 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -650,6 +650,16 @@ impl Display for Instruction { write!(fmt, "dup")?; } } + Opcode::UMOV => { + if let (Operand::Register(reg_sz, _), Operand::SIMDRegisterElementsLane(_, _, elem_sz, _)) = (self.operands[0], self.operands[1]) { + if (reg_sz == SizeCode::W && elem_sz == SIMDSizeCode::S) || + (reg_sz == SizeCode::X && elem_sz == SIMDSizeCode::D) { + return write!(fmt, "mov {}, {}", self.operands[0], self.operands[1]); + } else { + write!(fmt, "umov")?; + } + } + } other => { write!(fmt, "{}", other)?; } }; @@ -1228,6 +1238,8 @@ pub enum Opcode { TBL, TBX, + + FCADD, } impl Display for Opcode { @@ -1988,6 +2000,7 @@ impl Display for Opcode { Opcode::STLLR => "stllr", Opcode::TBL => "tbl", Opcode::TBX => "tbx", + Opcode::FCADD => "fcadd", Opcode::Bcc(cond) => { return write!(fmt, "b.{}", Operand::ConditionCode(cond)); @@ -2325,7 +2338,7 @@ impl Display for Operand { write!(fmt, "#{:x}", i) }, Operand::ImmediateDouble(d) => { - write!(fmt, "{:}", d) + write!(fmt, "#{:0.1}", d) }, Operand::Imm16(i) => { write!(fmt, "#{:x}", *i) @@ -3628,6 +3641,59 @@ impl Decoder<ARMv8> for InstDecoder { Operand::SIMDRegisterElements(datasize, Rm as u16, T), Operand::Nothing, ]; + } else if op2 == 0b1111 && op3 & 0b110000011 == 0b000000010 { + // `Advanced SIMD two-register miscellaneous (FP16)` + let Rd = (word >> 0) & 0b11111; + let Rn = (word >> 5) & 0b11111; + let opc = (word >> 12) & 0b11111; + let a = (word >> 23) & 1; + let u = (word >> 29) & 1; + let q = (word >> 30) & 1; + + let vec_size = if q == 0 { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + + inst.opcode = match (u, a, opc) { + (0, 0, 0b11000) => Opcode::FRINTN, + (0, 0, 0b11001) => Opcode::FRINTM, + (0, 0, 0b11010) => Opcode::FCVTNS, + (0, 0, 0b11011) => Opcode::FCVTMS, + (0, 0, 0b11100) => Opcode::FCVTAS, + (0, 0, 0b11101) => Opcode::SCVTF, + (0, 1, 0b01100) => Opcode::FCMGT, + (0, 1, 0b01101) => Opcode::FCMEQ, + (0, 1, 0b01110) => Opcode::FCMLT, + (0, 1, 0b01111) => Opcode::FABS, + (0, 1, 0b11000) => Opcode::FRINTP, + (0, 1, 0b11001) => Opcode::FRINTZ, + (0, 1, 0b11010) => Opcode::FCVTPS, + (0, 1, 0b11011) => Opcode::FCVTZS, + (0, 1, 0b11101) => Opcode::FRECPE, + (1, 0, 0b11000) => Opcode::FRINTA, + (1, 0, 0b11001) => Opcode::FRINTX, + (1, 0, 0b11010) => Opcode::FCVTNU, + (1, 0, 0b11011) => Opcode::FCVTMU, + (1, 0, 0b11100) => Opcode::FCVTAU, + (1, 0, 0b11101) => Opcode::UCVTF, + (1, 1, 0b01100) => Opcode::FCMGE, + (1, 1, 0b01101) => Opcode::FCMLE, + (1, 1, 0b01111) => Opcode::FNEG, + (1, 1, 0b11001) => Opcode::FRINTI, + (1, 1, 0b11010) => Opcode::FCVTPU, + (1, 1, 0b11011) => Opcode::FCVTZU, + (1, 1, 0b11101) => Opcode::FRSQRTE, + (1, 1, 0b11111) => Opcode::FSQRT, + _ => { return Err(DecodeError::InvalidOpcode); } + }; + inst.operands = [ + Operand::SIMDRegisterElements(vec_size, Rd as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElements(vec_size, Rn as u16, SIMDSizeCode::H), + Operand::Nothing, + Operand::Nothing, + ]; } else if op3 & 0b11 == 0b00 { // `Advanced SIMD three different` let opcode = (word >> 12) & 0b1111; @@ -3679,12 +3745,28 @@ impl Decoder<ARMv8> for InstDecoder { ][size as usize]?; inst.opcode = OPCODES[((U << 5) | (opcode << 1) | Q) as usize]?; - inst.operands = [ - Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), - Operand::SIMDRegisterElements(datasize, Rn as u16, Tb), - Operand::SIMDRegisterElements(datasize, Rm as u16, Tb), - Operand::Nothing, - ]; + if opcode == 0b001 || opcode == 0b011 { + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rn as u16, Ta), + Operand::SIMDRegisterElements(datasize, Rm as u16, Tb), + Operand::Nothing, + ]; + } else if opcode == 0b100 || opcode == 0b110 { + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, Tb), + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rn as u16, Ta), + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rm as u16, Ta), + Operand::Nothing, + ]; + } else { + inst.operands = [ + Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(datasize, Rn as u16, Tb), + Operand::SIMDRegisterElements(datasize, Rm as u16, Tb), + Operand::Nothing, + ]; + } } else if op3 & 0b11_00000_11 == 0b00_00000_10 { // op3 == 00xxxx10: // could be either `Advanced SIMD across lanes` or `Advanced SIMD @@ -3727,9 +3809,9 @@ impl Decoder<ARMv8> for InstDecoder { ]; const TABLE_E: &'static OperandSizeTable = &[ - Ok((D, B, D, H)), Ok((Q, H, Q, H)), - Ok((D, H, D, S)), Ok((Q, S, Q, S)), - Ok((D, S, D, D)), Ok((Q, D, Q, D)), + Ok((D, B, Q, H)), Ok((Q, H, Q, H)), + Ok((D, H, Q, S)), Ok((Q, S, Q, S)), + Ok((D, S, Q, D)), Ok((Q, D, Q, D)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; @@ -3760,8 +3842,8 @@ impl Decoder<ARMv8> for InstDecoder { const TABLE_I: &'static OperandSizeTable = &[ Ok((D, S, D, S)), Ok((Q, S, Q, S)), Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), - Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), - Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), + Ok((D, S, D, S)), Ok((Q, S, Q, S)), + Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), ]; if op2 & 0b0111 == 0b0100 { @@ -3882,14 +3964,14 @@ impl Decoder<ARMv8> for InstDecoder { } else { OPCODES_U1_LOW[opcode as usize]? }; - (opc, table[(((size & 1) << 1) | q) as usize]?) + (opc, table[((size << 1) | q) as usize]?) } else { let (opc, table) = if U == 0 { OPCODES_U0_HIGH[(((opcode - 0b10100) << 1) | (size >> 1)) as usize]? } else { OPCODES_U1_HIGH[(((opcode - 0b10100) << 1) | (size >> 1)) as usize]? }; - (opc, table[(((size & 1) << 1) | q) as usize]?) + (opc, table[((size << 1) | q) as usize]?) }; if opc == Opcode::FCVTL && q != 0 { @@ -3903,6 +3985,11 @@ impl Decoder<ARMv8> for InstDecoder { Operand::Nothing, Operand::Nothing, ]; + if [Opcode::CMGE, Opcode::CMLE, Opcode::CMGT, Opcode::CMEQ, Opcode::CMLT].contains(&inst.opcode) { + inst.operands[2] = Operand::Imm64(0); + } else if [Opcode::FCMGE, Opcode::FCMLE, Opcode::FCMGT, Opcode::FCMEQ, Opcode::FCMLT].contains(&inst.opcode) { + inst.operands[2] = Operand::ImmediateDouble(0.0); + } } else if op2 & 0b0111 == 0b0110 { // `Advanced SIMD across lanes` @@ -3911,6 +3998,9 @@ impl Decoder<ARMv8> for InstDecoder { let u = (word >> 29) & 1 == 1; let q = (word >> 30) & 1 == 1; + let opc_bits = opcode; + let size_bits = size; + let (size, opcode) = if opcode == 0b01100 { let opcode = if size == 0b00 { Opcode::FMAXNMV @@ -3997,10 +4087,28 @@ impl Decoder<ARMv8> for InstDecoder { (size, opcode) }; + let scalar_size = if opc_bits == 0b00011 { + if size_bits == 0b00 { + SIMDSizeCode::H + } else if size_bits == 0b01 { + SIMDSizeCode::S + } else { + SIMDSizeCode::D + } + } else { + size + }; + + let vec_size = if !q { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + inst.opcode = opcode; inst.operands = [ - Operand::SIMDRegister(size, Rd as u16), - Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rn as u16, size), + Operand::SIMDRegister(scalar_size, Rd as u16), + Operand::SIMDRegisterElements(vec_size, Rn as u16, size), Operand::Nothing, Operand::Nothing, ]; @@ -4011,7 +4119,164 @@ impl Decoder<ARMv8> for InstDecoder { } } else { // op2 == x0xx - if op3 & 0b000100001 == 0b000000001 { + if op3 & 0b000100001 == 0b000100001 { + // `Advanced SIMD three same extra`` + let Rd = (word >> 0) & 0b11111; + let Rn = (word >> 5) & 0b11111; + let opcode = (word >> 11) & 0b1111; + let Rm = (word >> 16) & 0b11111; + let sz = (word >> 22) & 0b11; + let u = (word >> 29) & 1; + let q = (word >> 30) & 1; + + if opcode == 0b0010 { + // sdot/udot + inst.opcode = if u == 0 { + Opcode::SDOT + } else { + Opcode::UDOT + }; + let vec_size = if q == 0 { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + inst.operands = [ + Operand::SIMDRegisterElements(vec_size, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(vec_size, Rn as u16, SIMDSizeCode::B), + Operand::SIMDRegisterElements(vec_size, Rm as u16, SIMDSizeCode::B), + Operand::Nothing, + ]; + } else { + if u == 0 { + return Err(DecodeError::InvalidOpcode); + } + if opcode & 0b1110 == 0b0000 { + // sqrdml{a,s}h + inst.opcode = if opcode == 0b0000 { + Opcode::SQRDMLAH + } else { + Opcode::SQRDMLSH + }; + let vec_size = if q == 0 { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + let elem_size = if sz == 0b01 { + SIMDSizeCode::H + } else if sz == 0b10 { + SIMDSizeCode::S + } else { + return Err(DecodeError::InvalidOperand); + }; + inst.operands = [ + Operand::SIMDRegisterElements(vec_size, Rd as u16, elem_size), + Operand::SIMDRegisterElements(vec_size, Rn as u16, elem_size), + Operand::SIMDRegisterElements(vec_size, Rm as u16, elem_size), + Operand::Nothing, + ]; + } else if opcode & 0b1100 == 0b1000 { + // fcmla + let rot = (word >> 11) & 0b11; + + let vec_size = if q == 0 { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + let elem_size = if sz == 0b01 { + SIMDSizeCode::H + } else if sz == 0b10 { + SIMDSizeCode::S + } else { + if q == 0 { + return Err(DecodeError::InvalidOperand); + } + SIMDSizeCode::D + }; + inst.opcode = Opcode::FCMLA; + inst.operands = [ + Operand::SIMDRegisterElements(vec_size, Rd as u16, elem_size), + Operand::SIMDRegisterElements(vec_size, Rn as u16, elem_size), + Operand::SIMDRegisterElements(vec_size, Rm as u16, elem_size), + Operand::Imm16(rot as u16), + ]; + } else if opcode & 0b1101 == 0b1100 { + // fcadd + let rot = (word >> 12) & 1; + + let vec_size = if q == 0 { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + let elem_size = if sz == 0b01 { + SIMDSizeCode::H + } else if sz == 0b10 { + SIMDSizeCode::S + } else { + if q == 0 { + return Err(DecodeError::InvalidOperand); + } + SIMDSizeCode::D + }; + inst.opcode = Opcode::FCADD; + inst.operands = [ + Operand::SIMDRegisterElements(vec_size, Rd as u16, elem_size), + Operand::SIMDRegisterElements(vec_size, Rn as u16, elem_size), + Operand::SIMDRegisterElements(vec_size, Rm as u16, elem_size), + Operand::Imm16(rot as u16), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + } else if op2 & 0b1100 == 0b1000 && op3 & 0b000110001 == 0b000000001 { + // `Advanced SIMD three same (FP16)` + let Rd = (word >> 0) & 0b11111; + let Rn = (word >> 5) & 0b11111; + let opc = (word >> 11) & 0b111; + let Rm = (word >> 16) & 0b11111; + let a = (word >> 23) & 1; + let u = (word >> 29) & 1; + let q = (word >> 30) & 1; + + const OPCODES: &[Result<Opcode, DecodeError>; 32] = &[ + Ok(Opcode::FMAXNM), Ok(Opcode::FMLA), + Ok(Opcode::FADD), Ok(Opcode::FMULX), + Ok(Opcode::FCMEQ), Err(DecodeError::InvalidOpcode), + Ok(Opcode::FMAX), Ok(Opcode::FRECPS), + Ok(Opcode::FMINNM), Ok(Opcode::FMLS), + Ok(Opcode::FSUB), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Ok(Opcode::FMIN), Ok(Opcode::FRSQRTS), + Ok(Opcode::FMAXNMP), Err(DecodeError::InvalidOpcode), + Ok(Opcode::FADDP), Ok(Opcode::FMUL), + Ok(Opcode::FCMGE), Ok(Opcode::FACGE), + Ok(Opcode::FMAXP), Ok(Opcode::FDIV), + Ok(Opcode::FMINNMP), Err(DecodeError::InvalidOpcode), + Ok(Opcode::FABD), Err(DecodeError::InvalidOpcode), + Ok(Opcode::FCMGT), Ok(Opcode::FACGT), + Ok(Opcode::FMINP), Err(DecodeError::InvalidOpcode), + ]; + + let vec_size = if q == 0 { + SIMDSizeCode::D + } else { + SIMDSizeCode::Q + }; + + let uaopc = (u << 4) | (a << 3) | opc; + + inst.opcode = OPCODES[uaopc as usize]?; + inst.operands = [ + Operand::SIMDRegisterElements(vec_size, Rd as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElements(vec_size, Rn as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElements(vec_size, Rm as u16, SIMDSizeCode::H), + Operand::Nothing, + ]; + } else if op3 & 0b000100001 == 0b000000001 { // `Advanced SIMD copy` let Rd = (word >> 0) & 0b11111; let Rn = (word >> 5) & 0b11111; @@ -5313,6 +5578,9 @@ impl Decoder<ARMv8> for InstDecoder { Operand::Nothing, Operand::Nothing, ]; + if [Opcode::FCMGE, Opcode::FCMLE, Opcode::FCMGT, Opcode::FCMEQ, Opcode::FCMLT].contains(&inst.opcode) { + inst.operands[2] = Operand::ImmediateDouble(0.0); + } } else if op2 & 0b0111 == 0b110 { // `Advanced SIMD scalar pairwise` let Rd = word & 0b11111; diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 2523a92..9b65618 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -4430,3 +4430,117 @@ fn test_tbl() { assert!(errs.is_empty()); } + +#[test] +fn test_saddw() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x10, 0x20, 0x0e], "saddw v0.8h, v0.8h, v0.8b"), + ([0x00, 0x60, 0x20, 0x0e], "subhn v0.8b, v0.8h, v0.8h"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_vector_cmge() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x98, 0x20, 0x0e], "cmeq v0.8b, v0.8b, #0"), + ([0x00, 0xc8, 0xa0, 0x0e], "fcmgt v0.2s, v0.2s, #0.0"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_xtn() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x28, 0x21, 0x0e], "xtn v0.8b, v0.8h"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_saddlv() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x38, 0x30, 0x0e], "saddlv h0, v0.8b"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_simd_same_three_fp16() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x04, 0x40, 0x0e], "fmaxnm v0.4h, v0.4h, v0.4h"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_simd_two_register_misc_fp16() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x88, 0x79, 0x0e], "frintn v0.4h, v0.4h"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_simd_three_same_extra() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x94, 0x90, 0x0e], "sdot v0.2s, v0.8b, v0.8b"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_rev64() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x08, 0xa0, 0x0e], "rev64 v0.2s, v0.2s"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} |