aboutsummaryrefslogtreecommitdiff
path: root/src/armv8/a64.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-10-31 12:37:07 -0700
committeriximeow <me@iximeow.net>2021-10-31 12:37:07 -0700
commita54ad2dffffc8c66917c75786045f7c0cdc7d5eb (patch)
tree5eca16ddb97d85fc288e0722039b004549539245 /src/armv8/a64.rs
parentf7df8cf15d5ff4a8ede83bad9ea0c2ba7dbd8040 (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.rs117
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