in runtime/vm/simulator_arm.cc [2896:3383]
void Simulator::DecodeSIMDDataProcessing(Instr* instr) {
ASSERT(instr->ConditionField() == kSpecialCondition);
if (instr->Bit(6) == 1) {
// Q = 1, Using 128-bit Q registers.
const QRegister qd = instr->QdField();
const QRegister qn = instr->QnField();
const QRegister qm = instr->QmField();
simd_value_t s8d;
simd_value_t s8n;
simd_value_t s8m;
get_qregister(qn, &s8n);
get_qregister(qm, &s8m);
int8_t* s8d_8 = reinterpret_cast<int8_t*>(&s8d);
int8_t* s8n_8 = reinterpret_cast<int8_t*>(&s8n);
int8_t* s8m_8 = reinterpret_cast<int8_t*>(&s8m);
uint8_t* s8d_u8 = reinterpret_cast<uint8_t*>(&s8d);
uint8_t* s8n_u8 = reinterpret_cast<uint8_t*>(&s8n);
uint8_t* s8m_u8 = reinterpret_cast<uint8_t*>(&s8m);
int16_t* s8d_16 = reinterpret_cast<int16_t*>(&s8d);
int16_t* s8n_16 = reinterpret_cast<int16_t*>(&s8n);
int16_t* s8m_16 = reinterpret_cast<int16_t*>(&s8m);
uint16_t* s8d_u16 = reinterpret_cast<uint16_t*>(&s8d);
uint16_t* s8n_u16 = reinterpret_cast<uint16_t*>(&s8n);
uint16_t* s8m_u16 = reinterpret_cast<uint16_t*>(&s8m);
int32_t* s8d_32 = reinterpret_cast<int32_t*>(&s8d);
int32_t* s8n_32 = reinterpret_cast<int32_t*>(&s8n);
int32_t* s8m_32 = reinterpret_cast<int32_t*>(&s8m);
uint32_t* s8d_u32 = reinterpret_cast<uint32_t*>(&s8d);
uint32_t* s8m_u32 = reinterpret_cast<uint32_t*>(&s8m);
int64_t* s8d_64 = reinterpret_cast<int64_t*>(&s8d);
int64_t* s8n_64 = reinterpret_cast<int64_t*>(&s8n);
int64_t* s8m_64 = reinterpret_cast<int64_t*>(&s8m);
uint64_t* s8d_u64 = reinterpret_cast<uint64_t*>(&s8d);
uint64_t* s8m_u64 = reinterpret_cast<uint64_t*>(&s8m);
if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
(instr->Bits(23, 2) == 0)) {
// Uses q registers.
// Format(instr, "vadd.'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_8[i] + s8m_8[i];
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_16[i] + s8m_16[i];
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u + s8m.data_[i].u;
}
} else if (size == 3) {
for (int i = 0; i < 2; i++) {
s8d_64[i] = s8n_64[i] + s8m_64[i];
}
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
(instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) {
// Format(instr, "vadd.F32 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = s8n.data_[i].f + s8m.data_[i].f;
}
} else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
(instr->Bits(23, 2) == 2)) {
// Format(instr, "vsub.'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_8[i] - s8m_8[i];
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_16[i] - s8m_16[i];
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u - s8m.data_[i].u;
}
} else if (size == 3) {
for (int i = 0; i < 2; i++) {
s8d_64[i] = s8n_64[i] - s8m_64[i];
}
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
(instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) {
// Format(instr, "vsub.F32 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = s8n.data_[i].f - s8m.data_[i].f;
}
} else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 0)) {
// Format(instr, "vmul.'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_8[i] * s8m_8[i];
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_16[i] * s8m_16[i];
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u * s8m.data_[i].u;
}
} else if (size == 3) {
UnimplementedInstruction(instr);
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) {
// Format(instr, "vmul.F32 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = s8n.data_[i].f * s8m.data_[i].f;
}
} else if ((instr->Bits(8, 4) == 4) && (instr->Bit(4) == 0) &&
(instr->Bit(23) == 0) && (instr->Bits(25, 3) == 1)) {
// Format(instr, "vshlqu'sz 'qd, 'qm, 'qn");
// Format(instr, "vshlqi'sz 'qd, 'qm, 'qn");
const bool signd = instr->Bit(24) == 0;
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
int8_t shift = s8n_8[i];
if (shift > 0) {
s8d_u8[i] = s8m_u8[i] << shift;
} else if (shift < 0) {
if (signd) {
s8d_8[i] = s8m_8[i] >> (-shift);
} else {
s8d_u8[i] = s8m_u8[i] >> (-shift);
}
}
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
int8_t shift = s8n_8[i * 2];
if (shift > 0) {
s8d_u16[i] = s8m_u16[i] << shift;
} else if (shift < 0) {
if (signd) {
s8d_16[i] = s8m_16[i] >> (-shift);
} else {
s8d_u16[i] = s8m_u16[i] >> (-shift);
}
}
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
int8_t shift = s8n_8[i * 4];
if (shift > 0) {
s8d_u32[i] = s8m_u32[i] << shift;
} else if (shift < 0) {
if (signd) {
s8d_32[i] = s8m_32[i] >> (-shift);
} else {
s8d_u32[i] = s8m_u32[i] >> (-shift);
}
}
}
} else {
ASSERT(size == 3);
for (int i = 0; i < 2; i++) {
int8_t shift = s8n_8[i * 8];
if (shift > 0) {
s8d_u64[i] = s8m_u64[i] << shift;
} else if (shift < 0) {
if (signd) {
s8d_64[i] = s8m_64[i] >> (-shift);
} else {
s8d_u64[i] = s8m_u64[i] >> (-shift);
}
}
}
}
} else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
(instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
// Format(instr, "veorq 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u ^ s8m.data_[i].u;
}
} else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vornq 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u | ~s8m.data_[i].u;
}
} else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
(instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
if (qm == qn) {
// Format(instr, "vmovq 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8m.data_[i].u;
}
} else {
// Format(instr, "vorrq 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u | s8m.data_[i].u;
}
}
} else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
(instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vandq 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u & s8m.data_[i].u;
}
} else if ((instr->Bits(7, 5) == 11) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 5) == 7) &&
(instr->Bits(16, 4) == 0)) {
// Format(instr, "vmvnq 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = ~s8m.data_[i].u;
}
} else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vminqs 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = fminf(s8n.data_[i].f, s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vmaxqs 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = fmaxf(s8n.data_[i].f, s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) {
// Format(instr, "vabsqs 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = fabsf(s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bit(7) == 1) && (instr->Bits(16, 4) == 9)) {
// Format(instr, "vnegqs 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = -s8m.data_[i].f;
}
} else if ((instr->Bits(7, 5) == 10) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bits(16, 4) == 11)) {
// Format(instr, "vrecpeq 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = ReciprocalEstimate(s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
(instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vrecpsq 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = ReciprocalStep(s8n.data_[i].f, s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bit(7) == 1) && (instr->Bits(16, 4) == 11)) {
// Format(instr, "vrsqrteqs 'qd, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = ReciprocalSqrtEstimate(s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
(instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vrsqrtsqs 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = ReciprocalSqrtStep(s8n.data_[i].f, s8m.data_[i].f);
}
} else if ((instr->Bits(8, 4) == 12) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bit(7) == 0)) {
DRegister dm = instr->DmField();
int64_t dm_value = get_dregister_bits(dm);
int32_t imm4 = instr->Bits(16, 4);
int32_t idx;
if ((imm4 & 1) != 0) {
// Format(instr, "vdupb 'qd, 'dm['imm4_vdup]");
int8_t* dm_b = reinterpret_cast<int8_t*>(&dm_value);
idx = imm4 >> 1;
int8_t val = dm_b[idx];
for (int i = 0; i < 16; i++) {
s8d_8[i] = val;
}
} else if ((imm4 & 2) != 0) {
// Format(instr, "vduph 'qd, 'dm['imm4_vdup]");
int16_t* dm_h = reinterpret_cast<int16_t*>(&dm_value);
idx = imm4 >> 2;
int16_t val = dm_h[idx];
for (int i = 0; i < 8; i++) {
s8d_16[i] = val;
}
} else if ((imm4 & 4) != 0) {
// Format(instr, "vdupw 'qd, 'dm['imm4_vdup]");
int32_t* dm_w = reinterpret_cast<int32_t*>(&dm_value);
idx = imm4 >> 3;
int32_t val = dm_w[idx];
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = val;
}
} else {
UnimplementedInstruction(instr);
}
} else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) {
// Format(instr, "vzipqw 'qd, 'qm");
get_qregister(qd, &s8d);
// Interleave the elements with the low words in qd, and the high words
// in qm.
simd_value_swap(&s8d, 3, &s8m, 2);
simd_value_swap(&s8d, 3, &s8m, 1);
simd_value_swap(&s8d, 2, &s8m, 0);
simd_value_swap(&s8d, 2, &s8d, 1);
set_qregister(qm, s8m); // Writes both qd and qm.
} else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 2)) {
// Format(instr, "vceqq'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_8[i] == s8m_8[i] ? 0xff : 0;
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_16[i] == s8m_16[i] ? 0xffff : 0;
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u == s8m.data_[i].u ? 0xffffffff : 0;
}
} else if (size == 3) {
UnimplementedInstruction(instr);
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
// Format(instr, "vceqqs 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].f == s8m.data_[i].f ? 0xffffffff : 0;
}
} else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 0)) {
// Format(instr, "vcgeq'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_8[i] >= s8m_8[i] ? 0xff : 0;
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_16[i] >= s8m_16[i] ? 0xffff : 0;
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n_32[i] >= s8m_32[i] ? 0xffffffff : 0;
}
} else if (size == 3) {
UnimplementedInstruction(instr);
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 2)) {
// Format(instr, "vcugeq'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_u8[i] >= s8m_u8[i] ? 0xff : 0;
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_u16[i] >= s8m_u16[i] ? 0xffff : 0;
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u >= s8m.data_[i].u ? 0xffffffff : 0;
}
} else if (size == 3) {
UnimplementedInstruction(instr);
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
// Format(instr, "vcgeqs 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].f >= s8m.data_[i].f ? 0xffffffff : 0;
}
} else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
(instr->Bits(23, 2) == 0)) {
// Format(instr, "vcgtq'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_8[i] > s8m_8[i] ? 0xff : 0;
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_16[i] > s8m_16[i] ? 0xffff : 0;
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n_32[i] > s8m_32[i] ? 0xffffffff : 0;
}
} else if (size == 3) {
UnimplementedInstruction(instr);
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
(instr->Bits(23, 2) == 2)) {
// Format(instr, "vcugtq'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
if (size == 0) {
for (int i = 0; i < 16; i++) {
s8d_8[i] = s8n_u8[i] > s8m_u8[i] ? 0xff : 0;
}
} else if (size == 1) {
for (int i = 0; i < 8; i++) {
s8d_16[i] = s8n_u16[i] > s8m_u16[i] ? 0xffff : 0;
}
} else if (size == 2) {
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].u > s8m.data_[i].u ? 0xffffffff : 0;
}
} else if (size == 3) {
UnimplementedInstruction(instr);
} else {
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 2)) {
// Format(instr, "vcgtqs 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].u = s8n.data_[i].f > s8m.data_[i].f ? 0xffffffff : 0;
}
} else {
UnimplementedInstruction(instr);
}
set_qregister(qd, s8d);
} else {
// Q == 0, Uses 64-bit D registers.
if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) &&
(instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) {
// Format(instr, "vtbl 'dd, 'dtbllist, 'dm");
DRegister dd = instr->DdField();
DRegister dm = instr->DmField();
int reg_count = instr->Bits(8, 2) + 1;
int start = (instr->Bit(7) << 4) | instr->Bits(16, 4);
int64_t table[4];
for (int i = 0; i < reg_count; i++) {
DRegister d = static_cast<DRegister>(start + i);
table[i] = get_dregister_bits(d);
}
for (int i = reg_count; i < 4; i++) {
table[i] = 0;
}
int64_t dm_value = get_dregister_bits(dm);
int64_t result;
int8_t* dm_bytes = reinterpret_cast<int8_t*>(&dm_value);
int8_t* result_bytes = reinterpret_cast<int8_t*>(&result);
int8_t* table_bytes = reinterpret_cast<int8_t*>(&table[0]);
for (int i = 0; i < 8; i++) {
int idx = dm_bytes[i];
if ((idx >= 0) && (idx < 256)) {
result_bytes[i] = table_bytes[idx];
} else {
result_bytes[i] = 0;
}
}
set_dregister_bits(dd, result);
} else {
UnimplementedInstruction(instr);
}
}
}