| Index: src/arm/simulator-arm.cc
|
| diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
|
| index e3067bb19330e65329da006c7706fd5549061cc9..1f7e1466921d94f00cb0413a7a54f1aca3f54718 100644
|
| --- a/src/arm/simulator-arm.cc
|
| +++ b/src/arm/simulator-arm.cc
|
| @@ -4223,6 +4223,34 @@ void ArithmeticShiftRight(Simulator* simulator, int Vd, int Vm, int shift) {
|
| }
|
|
|
| template <typename T, int SIZE>
|
| +void ShiftLeftAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
|
| + static const int kElems = SIZE / sizeof(T);
|
| + T src[kElems];
|
| + T dst[kElems];
|
| + simulator->get_neon_register<T, SIZE>(Vm, src);
|
| + simulator->get_neon_register<T, SIZE>(Vd, dst);
|
| + uint64_t mask = (1llu << shift) - 1llu;
|
| + for (int i = 0; i < kElems; i++) {
|
| + dst[i] = (src[i] << shift) | (dst[i] & mask);
|
| + }
|
| + simulator->set_neon_register<T, SIZE>(Vd, dst);
|
| +}
|
| +
|
| +template <typename T, int SIZE>
|
| +void ShiftRightAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
|
| + static const int kElems = SIZE / sizeof(T);
|
| + T src[kElems];
|
| + T dst[kElems];
|
| + simulator->get_neon_register<T, SIZE>(Vm, src);
|
| + simulator->get_neon_register<T, SIZE>(Vd, dst);
|
| + uint64_t mask = ~((1llu << (kBitsPerByte * SIZE - shift)) - 1llu);
|
| + for (int i = 0; i < kElems; i++) {
|
| + dst[i] = (src[i] >> shift) | (dst[i] & mask);
|
| + }
|
| + simulator->set_neon_register<T, SIZE>(Vd, dst);
|
| +}
|
| +
|
| +template <typename T, int SIZE>
|
| void CompareEqual(Simulator* simulator, int Vd, int Vm, int Vn) {
|
| static const int kElems = SIZE / sizeof(T);
|
| T src1[kElems], src2[kElems];
|
| @@ -4995,14 +5023,40 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| set_neon_register(vd, mval);
|
| }
|
| } else if (instr->Bits(11, 7) == 0x18) {
|
| - // vdup.32 Qd, Sm.
|
| - int vd = instr->VFPDRegValue(kSimd128Precision);
|
| + // vdup.<size> Dd, Dm[index].
|
| + // vdup.<size> Qd, Dm[index].
|
| int vm = instr->VFPMRegValue(kDoublePrecision);
|
| - int index = instr->Bit(19);
|
| - uint32_t s_data = get_s_register(vm * 2 + index);
|
| - uint32_t q_data[4];
|
| - for (int i = 0; i < 4; i++) q_data[i] = s_data;
|
| - set_neon_register(vd, q_data);
|
| + int imm4 = instr->Bits(19, 16);
|
| + int size = 0, index = 0, mask = 0;
|
| + if ((imm4 & 0x1) != 0) {
|
| + size = 8;
|
| + index = imm4 >> 1;
|
| + mask = 0xffu;
|
| + } else if ((imm4 & 0x2) != 0) {
|
| + size = 16;
|
| + index = imm4 >> 2;
|
| + mask = 0xffffu;
|
| + } else {
|
| + size = 32;
|
| + index = imm4 >> 3;
|
| + mask = 0xffffffffu;
|
| + }
|
| + uint64_t d_data;
|
| + get_d_register(vm, &d_data);
|
| + uint32_t scalar = (d_data >> (size * index)) & mask;
|
| + uint32_t duped = scalar;
|
| + for (int i = 1; i < 32 / size; i++) {
|
| + scalar <<= size;
|
| + duped |= scalar;
|
| + }
|
| + uint32_t result[4] = {duped, duped, duped, duped};
|
| + if (instr->Bit(6) == 0) {
|
| + int vd = instr->VFPDRegValue(kDoublePrecision);
|
| + set_d_register(vd, result);
|
| + } else {
|
| + int vd = instr->VFPDRegValue(kSimd128Precision);
|
| + set_neon_register(vd, result);
|
| + }
|
| } else if (instr->Bits(19, 16) == 0 && instr->Bits(11, 6) == 0x17) {
|
| // vmvn Qd, Qm.
|
| int vd = instr->VFPDRegValue(kSimd128Precision);
|
| @@ -5379,6 +5433,58 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| UNREACHABLE();
|
| break;
|
| }
|
| + } else if (instr->Bits(11, 8) == 0x5 && instr->Bit(6) == 0 &&
|
| + instr->Bit(4) == 1) {
|
| + // vsli.<size> Dd, Dm, shift
|
| + int imm7 = instr->Bits(21, 16);
|
| + if (instr->Bit(7) != 0) imm7 += 64;
|
| + int size = base::bits::RoundDownToPowerOfTwo32(imm7);
|
| + int shift = imm7 - size;
|
| + int Vd = instr->VFPDRegValue(kDoublePrecision);
|
| + int Vm = instr->VFPMRegValue(kDoublePrecision);
|
| + switch (size) {
|
| + case 8:
|
| + ShiftLeftAndInsert<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + case 16:
|
| + ShiftLeftAndInsert<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + case 32:
|
| + ShiftLeftAndInsert<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + case 64:
|
| + ShiftLeftAndInsert<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + } else if (instr->Bits(11, 8) == 0x4 && instr->Bit(6) == 0 &&
|
| + instr->Bit(4) == 1) {
|
| + // vsri.<size> Dd, Dm, shift
|
| + int imm7 = instr->Bits(21, 16);
|
| + if (instr->Bit(7) != 0) imm7 += 64;
|
| + int size = base::bits::RoundDownToPowerOfTwo32(imm7);
|
| + int shift = 2 * size - imm7;
|
| + int Vd = instr->VFPDRegValue(kDoublePrecision);
|
| + int Vm = instr->VFPMRegValue(kDoublePrecision);
|
| + switch (size) {
|
| + case 8:
|
| + ShiftRightAndInsert<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + case 16:
|
| + ShiftRightAndInsert<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + case 32:
|
| + ShiftRightAndInsert<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + case 64:
|
| + ShiftRightAndInsert<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| } else {
|
| UNIMPLEMENTED();
|
| }
|
|
|