| Index: src/arm/simulator-arm.cc
|
| diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
|
| index 4d1c6e5b08a1534c13fbe58e7bfff427ea04cce7..e2bcd952a6c08df63c8bc3565c5e7c38a170d8d4 100644
|
| --- a/src/arm/simulator-arm.cc
|
| +++ b/src/arm/simulator-arm.cc
|
| @@ -901,6 +901,18 @@ void Simulator::set_d_register(int dreg, const uint32_t* value) {
|
| }
|
|
|
| template <typename T>
|
| +void Simulator::get_d_register(int dreg, T* value) {
|
| + DCHECK((dreg >= 0) && (dreg < num_d_registers));
|
| + memcpy(value, vfp_registers_ + dreg * 2, kDoubleSize);
|
| +}
|
| +
|
| +template <typename T>
|
| +void Simulator::set_d_register(int dreg, const T* value) {
|
| + DCHECK((dreg >= 0) && (dreg < num_d_registers));
|
| + memcpy(vfp_registers_ + dreg * 2, value, kDoubleSize);
|
| +}
|
| +
|
| +template <typename T>
|
| void Simulator::get_q_register(int qreg, T* value) {
|
| DCHECK((qreg >= 0) && (qreg < num_q_registers));
|
| memcpy(value, vfp_registers_ + qreg * 4, kSimd128Size);
|
| @@ -912,7 +924,6 @@ void Simulator::set_q_register(int qreg, const T* value) {
|
| memcpy(vfp_registers_ + qreg * 4, value, kSimd128Size);
|
| }
|
|
|
| -
|
| // Raw access to the PC register.
|
| void Simulator::set_pc(int32_t value) {
|
| pc_modified_ = true;
|
| @@ -4007,6 +4018,11 @@ T Clamp(int64_t value) {
|
| }
|
|
|
| template <typename T>
|
| +T MinMax(T a, T b, bool is_min) {
|
| + return is_min ? std::min(a, b) : std::max(a, b);
|
| +}
|
| +
|
| +template <typename T>
|
| void AddSaturate(Simulator* simulator, int Vd, int Vm, int Vn) {
|
| static const int kLanes = 16 / sizeof(T);
|
| T src1[kLanes], src2[kLanes];
|
| @@ -4180,10 +4196,7 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| get_q_register(Vn, src1);
|
| get_q_register(Vm, src2);
|
| for (int i = 0; i < 16; i++) {
|
| - if (min)
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - else
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| set_q_register(Vd, src1);
|
| break;
|
| @@ -4193,10 +4206,7 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| get_q_register(Vn, src1);
|
| get_q_register(Vm, src2);
|
| for (int i = 0; i < 8; i++) {
|
| - if (min)
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - else
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| set_q_register(Vd, src1);
|
| break;
|
| @@ -4206,10 +4216,7 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| get_q_register(Vn, src1);
|
| get_q_register(Vm, src2);
|
| for (int i = 0; i < 4; i++) {
|
| - if (min)
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - else
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| set_q_register(Vd, src1);
|
| break;
|
| @@ -4344,6 +4351,48 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| }
|
| break;
|
| }
|
| + case 0xa: {
|
| + // vpmin/vpmax.s<size> Dd, Dm, Dn.
|
| + NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
|
| + bool min = instr->Bit(4) != 0;
|
| + switch (size) {
|
| + case Neon8: {
|
| + int8_t dst[8], src1[8], src2[8];
|
| + get_d_register(Vn, src1);
|
| + get_d_register(Vm, src2);
|
| + for (int i = 0; i < 4; i++) {
|
| + dst[i + 0] = MinMax(src1[i * 2], src1[i * 2 + 1], min);
|
| + dst[i + 4] = MinMax(src2[i * 2], src2[i * 2 + 1], min);
|
| + }
|
| + set_d_register(Vd, dst);
|
| + break;
|
| + }
|
| + case Neon16: {
|
| + int16_t dst[4], src1[4], src2[4];
|
| + get_d_register(Vn, src1);
|
| + get_d_register(Vm, src2);
|
| + for (int i = 0; i < 2; i++) {
|
| + dst[i + 0] = MinMax(src1[i * 2], src1[i * 2 + 1], min);
|
| + dst[i + 2] = MinMax(src2[i * 2], src2[i * 2 + 1], min);
|
| + }
|
| + set_d_register(Vd, dst);
|
| + break;
|
| + }
|
| + case Neon32: {
|
| + int32_t dst[2], src1[2], src2[2];
|
| + get_d_register(Vn, src1);
|
| + get_d_register(Vm, src2);
|
| + dst[0] = MinMax(src1[0], src1[1], min);
|
| + dst[1] = MinMax(src2[0], src2[1], min);
|
| + set_d_register(Vd, dst);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + break;
|
| + }
|
| case 0xd: {
|
| if (instr->Bit(4) == 0) {
|
| float src1[4], src2[4];
|
| @@ -4398,16 +4447,10 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| }
|
| }
|
| } else {
|
| - if (instr->Bit(21) == 1) {
|
| - // vmin.f32 Qd, Qm, Qn.
|
| - for (int i = 0; i < 4; i++) {
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - }
|
| - } else {
|
| - // vmax.f32 Qd, Qm, Qn.
|
| - for (int i = 0; i < 4; i++) {
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| - }
|
| + // vmin/vmax.f32 Qd, Qm, Qn.
|
| + bool min = instr->Bit(21) == 1;
|
| + for (int i = 0; i < 4; i++) {
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| }
|
| set_q_register(Vd, src1);
|
| @@ -4693,10 +4736,7 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| get_q_register(Vn, src1);
|
| get_q_register(Vm, src2);
|
| for (int i = 0; i < 16; i++) {
|
| - if (min)
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - else
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| set_q_register(Vd, src1);
|
| break;
|
| @@ -4706,10 +4746,7 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| get_q_register(Vn, src1);
|
| get_q_register(Vm, src2);
|
| for (int i = 0; i < 8; i++) {
|
| - if (min)
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - else
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| set_q_register(Vd, src1);
|
| break;
|
| @@ -4719,10 +4756,7 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| get_q_register(Vn, src1);
|
| get_q_register(Vm, src2);
|
| for (int i = 0; i < 4; i++) {
|
| - if (min)
|
| - src1[i] = std::min(src1[i], src2[i]);
|
| - else
|
| - src1[i] = std::max(src1[i], src2[i]);
|
| + src1[i] = MinMax(src1[i], src2[i], min);
|
| }
|
| set_q_register(Vd, src1);
|
| break;
|
| @@ -4813,6 +4847,48 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| }
|
| break;
|
| }
|
| + case 0xa: {
|
| + // vpmin/vpmax.u<size> Dd, Dm, Dn.
|
| + NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
|
| + bool min = instr->Bit(4) != 0;
|
| + switch (size) {
|
| + case Neon8: {
|
| + uint8_t dst[8], src1[8], src2[8];
|
| + get_d_register(Vn, src1);
|
| + get_d_register(Vm, src2);
|
| + for (int i = 0; i < 4; i++) {
|
| + dst[i + 0] = MinMax(src1[i * 2], src1[i * 2 + 1], min);
|
| + dst[i + 4] = MinMax(src2[i * 2], src2[i * 2 + 1], min);
|
| + }
|
| + set_d_register(Vd, dst);
|
| + break;
|
| + }
|
| + case Neon16: {
|
| + uint16_t dst[4], src1[4], src2[4];
|
| + get_d_register(Vn, src1);
|
| + get_d_register(Vm, src2);
|
| + for (int i = 0; i < 2; i++) {
|
| + dst[i + 0] = MinMax(src1[i * 2], src1[i * 2 + 1], min);
|
| + dst[i + 2] = MinMax(src2[i * 2], src2[i * 2 + 1], min);
|
| + }
|
| + set_d_register(Vd, dst);
|
| + break;
|
| + }
|
| + case Neon32: {
|
| + uint32_t dst[2], src1[2], src2[2];
|
| + get_d_register(Vn, src1);
|
| + get_d_register(Vm, src2);
|
| + dst[0] = MinMax(src1[0], src1[1], min);
|
| + dst[1] = MinMax(src2[0], src2[1], min);
|
| + set_d_register(Vd, dst);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + break;
|
| + }
|
| case 0xd: {
|
| if (instr->Bit(21) == 0 && instr->Bit(6) == 1 && instr->Bit(4) == 1) {
|
| // vmul.f32 Qd, Qn, Qm
|
|
|