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(); |
} |