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 |