diff options
author | iximeow <me@iximeow.net> | 2021-10-31 12:37:07 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2021-10-31 12:37:07 -0700 |
commit | a54ad2dffffc8c66917c75786045f7c0cdc7d5eb (patch) | |
tree | 5eca16ddb97d85fc288e0722039b004549539245 /src/armv8/a64.rs | |
parent | f7df8cf15d5ff4a8ede83bad9ea0c2ba7dbd8040 (diff) |
SIMD load/store (multiple structure)
in addition to the decoding support, objdump reporting of `{}` selection
of multiple registers seems to be inconsistent. stick to the manual's
preferred `{v1, v2, v3, v4}` nomenclature instead of `{v1-v4}`.
reorder a few tests in test_openblas_simd_loadstore to group
instructions by decode category
Diffstat (limited to 'src/armv8/a64.rs')
-rw-r--r-- | src/armv8/a64.rs | 117 |
1 files changed, 115 insertions, 2 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index e62d3b6..da0df7c 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -3644,11 +3644,124 @@ impl Decoder<ARMv8> for InstDecoder { }, 0b00100 => { // AdvSIMD load/store multiple structures - return Err(DecodeError::IncompleteDecoder); + let Rt = word & 0x1f; + let Rn = (word >> 5) & 0x1f; + let size = (word >> 10) & 0x03; + let opcode_bits = (word >> 12) & 0x0f; + let Rm = (word >> 16) & 0x1f; + if Rm != 0 { + return Err(DecodeError::InvalidOperand); + } + let L = (word >> 22) & 0x01; + let Q = (word >> 30) & 0x01; + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + const OPCODES: &[Result<(Opcode, u8), DecodeError>] = &[ + // opcode == 0b0000 + Ok((Opcode::ST4, 4)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::ST1, 4)), + Err(DecodeError::InvalidOpcode), + // opcode == 0b0100 + Ok((Opcode::ST3, 3)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::ST1, 3)), + Ok((Opcode::ST1, 1)), + // opcode == 0b1000 + Ok((Opcode::ST2, 2)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::ST1, 2)), + Err(DecodeError::InvalidOpcode), + ]; + + let (opcode, num_regs) = OPCODES[opcode_bits as usize]?; + + inst.opcode = if L == 0 { + opcode + } else { + if opcode == Opcode::ST1 { + Opcode::LD1 + } else if opcode == Opcode::ST2 { + Opcode::LD2 + } else if opcode == Opcode::ST3 { + Opcode::LD3 + } else { + Opcode::LD4 + } + }; + const SIZES: [SIMDSizeCode; 4] = [ + SIMDSizeCode::B, + SIMDSizeCode::H, + SIMDSizeCode::S, + SIMDSizeCode::D, + ]; + inst.operands = [ + Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], num_regs), + Operand::RegPostIndex(Rn as u16, 0), + Operand::Nothing, + Operand::Nothing, + ]; }, 0b00101 => { // AdvSIMD load/store multiple structures (post-indexed) - return Err(DecodeError::IncompleteDecoder); + let Rt = word & 0x1f; + let Rn = (word >> 5) & 0x1f; + let size = (word >> 10) & 0x03; + let opcode_bits = (word >> 12) & 0x0f; + let Rm = (word >> 16) & 0x1f; + let L = (word >> 22) & 0x01; + let Q = (word >> 30) & 0x01; + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + const OPCODES: &[Result<(Opcode, u8), DecodeError>] = &[ + // opcode == 0b0000 + Ok((Opcode::ST4, 4)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::ST1, 4)), + Err(DecodeError::InvalidOpcode), + // opcode == 0b0100 + Ok((Opcode::ST3, 3)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::ST1, 3)), + Ok((Opcode::ST1, 1)), + // opcode == 0b1000 + Ok((Opcode::ST2, 2)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::ST1, 2)), + Err(DecodeError::InvalidOpcode), + ]; + + let (opcode, num_regs) = OPCODES[opcode_bits as usize]?; + + inst.opcode = if L == 0 { + opcode + } else { + if opcode == Opcode::ST1 { + Opcode::LD1 + } else if opcode == Opcode::ST2 { + Opcode::LD2 + } else if opcode == Opcode::ST3 { + Opcode::LD3 + } else { + Opcode::LD4 + } + }; + const SIZES: [SIMDSizeCode; 4] = [ + SIMDSizeCode::B, + SIMDSizeCode::H, + SIMDSizeCode::S, + SIMDSizeCode::D, + ]; + inst.operands = [ + Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], num_regs), + if Rm == 31 { + Operand::RegPostIndex(Rn as u16, (datasize.width() * (num_regs as u16)) as i32) + } else { + Operand::RegPostIndexReg(Rn as u16, Rm as u16) + }, + Operand::Nothing, + Operand::Nothing, + ]; }, 0b00110 => { // AdvSIMD load/store single structure |