| Index: runtime/vm/simulator_arm64.cc
|
| ===================================================================
|
| --- runtime/vm/simulator_arm64.cc (revision 36692)
|
| +++ runtime/vm/simulator_arm64.cc (working copy)
|
| @@ -2319,6 +2319,35 @@
|
| } else if ((U == 1) && (opcode == 0x1f)) {
|
| // Format(instr, "vdiv'vsz 'vd, 'vn, 'vm");
|
| res = bit_cast<int32_t, float>(vn_flt / vm_flt);
|
| + } else if ((U == 0) && (opcode == 0x1c)) {
|
| + // Format(instr, "vceq'vsz 'vd, 'vn, 'vm");
|
| + res = (vn_flt == vm_flt) ? 0xffffffff : 0;
|
| + } else if ((U == 1) && (opcode == 0x1c)) {
|
| + if (instr->Bit(23) == 1) {
|
| + // Format(instr, "vcgt'vsz 'vd, 'vn, 'vm");
|
| + res = (vn_flt > vm_flt) ? 0xffffffff : 0;
|
| + } else {
|
| + // Format(instr, "vcge'vsz 'vd, 'vn, 'vm");
|
| + res = (vn_flt >= vm_flt) ? 0xffffffff : 0;
|
| + }
|
| + } else if ((U == 0) && (opcode == 0x1e)) {
|
| + if (instr->Bit(23) == 1) {
|
| + // Format(instr, "vmin'vsz 'vd, 'vn, 'vm");
|
| + const float m = (vn_flt > vm_flt) ? vm_flt : vn_flt;
|
| + res = bit_cast<int32_t, float>(m);
|
| + } else {
|
| + // Format(instr, "vmax'vsz 'vd, 'vn, 'vm");
|
| + const float m = (vn_flt < vm_flt) ? vm_flt : vn_flt;
|
| + res = bit_cast<int32_t, float>(m);
|
| + }
|
| + } else if ((U == 0) && (opcode == 0x1f)) {
|
| + if (instr->Bit(23) == 0) {
|
| + // Format(instr, "vrecps'vsz 'vd, 'vn, 'vm");
|
| + res = bit_cast<int32_t, float>(2.0 - (vn_flt * vm_flt));
|
| + } else {
|
| + // Format(instr, "vrsqrt'vsz 'vd, 'vn, 'vm");
|
| + res = bit_cast<int32_t, float>((3.0 - vn_flt * vm_flt) / 2.0);
|
| + }
|
| } else {
|
| UnimplementedInstruction(instr);
|
| return;
|
| @@ -2364,6 +2393,27 @@
|
| } else if ((U == 1) && (opcode == 0x1f)) {
|
| // Format(instr, "vdiv'vsz 'vd, 'vn, 'vm");
|
| res = bit_cast<int64_t, double>(vn_dbl / vm_dbl);
|
| + } else if ((U == 0) && (opcode == 0x1c)) {
|
| + // Format(instr, "vceq'vsz 'vd, 'vn, 'vm");
|
| + res = (vn_dbl == vm_dbl) ? 0xffffffffffffffffLL : 0;
|
| + } else if ((U == 1) && (opcode == 0x1c)) {
|
| + if (instr->Bit(23) == 1) {
|
| + // Format(instr, "vcgt'vsz 'vd, 'vn, 'vm");
|
| + res = (vn_dbl > vm_dbl) ? 0xffffffffffffffffLL : 0;
|
| + } else {
|
| + // Format(instr, "vcge'vsz 'vd, 'vn, 'vm");
|
| + res = (vn_dbl >= vm_dbl) ? 0xffffffffffffffffLL : 0;
|
| + }
|
| + } else if ((U == 0) && (opcode == 0x1e)) {
|
| + if (instr->Bit(23) == 1) {
|
| + // Format(instr, "vmin'vsz 'vd, 'vn, 'vm");
|
| + const double m = (vn_dbl > vm_dbl) ? vm_dbl : vn_dbl;
|
| + res = bit_cast<int64_t, double>(m);
|
| + } else {
|
| + // Format(instr, "vmax'vsz 'vd, 'vn, 'vm");
|
| + const double m = (vn_dbl < vm_dbl) ? vm_dbl : vn_dbl;
|
| + res = bit_cast<int64_t, double>(m);
|
| + }
|
| } else {
|
| UnimplementedInstruction(instr);
|
| return;
|
| @@ -2374,6 +2424,91 @@
|
| }
|
|
|
|
|
| +static float arm_reciprocal_sqrt_estimate(float a) {
|
| + // From the ARM Architecture Reference Manual A2-87.
|
| + if (isinf(a) || (fabs(a) >= exp2f(126))) return 0.0;
|
| + else if (a == 0.0) return INFINITY;
|
| + else if (isnan(a)) return a;
|
| +
|
| + uint32_t a_bits = bit_cast<uint32_t, float>(a);
|
| + uint64_t scaled;
|
| + if (((a_bits >> 23) & 1) != 0) {
|
| + // scaled = '0 01111111101' : operand<22:0> : Zeros(29)
|
| + scaled = (static_cast<uint64_t>(0x3fd) << 52) |
|
| + ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
|
| + } else {
|
| + // scaled = '0 01111111110' : operand<22:0> : Zeros(29)
|
| + scaled = (static_cast<uint64_t>(0x3fe) << 52) |
|
| + ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
|
| + }
|
| + // result_exp = (380 - UInt(operand<30:23>) DIV 2;
|
| + int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
|
| +
|
| + double scaled_d = bit_cast<double, uint64_t>(scaled);
|
| + ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
|
| +
|
| + double r;
|
| + if (scaled_d < 0.5) {
|
| + // range 0.25 <= a < 0.5
|
| +
|
| + // a in units of 1/512 rounded down.
|
| + int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
|
| + // reciprocal root r.
|
| + r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
|
| + } else {
|
| + // range 0.5 <= a < 1.0
|
| +
|
| + // a in units of 1/256 rounded down.
|
| + int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
|
| + // reciprocal root r.
|
| + r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
|
| + }
|
| + // r in units of 1/256 rounded to nearest.
|
| + int32_t s = static_cast<int>(256.0 * r + 0.5);
|
| + double estimate = static_cast<double>(s) / 256.0;
|
| + ASSERT((estimate >= 1.0) && (estimate <= (511.0/256.0)));
|
| +
|
| + // result = 0 : result_exp<7:0> : estimate<51:29>
|
| + int32_t result_bits = ((result_exp & 0xff) << 23) |
|
| + ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
|
| + return bit_cast<float, int32_t>(result_bits);
|
| +}
|
| +
|
| +
|
| +static float arm_recip_estimate(float a) {
|
| + // From the ARM Architecture Reference Manual A2-85.
|
| + if (isinf(a) || (fabs(a) >= exp2f(126))) return 0.0;
|
| + else if (a == 0.0) return INFINITY;
|
| + else if (isnan(a)) return a;
|
| +
|
| + uint32_t a_bits = bit_cast<uint32_t, float>(a);
|
| + // scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
|
| + uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
|
| + ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
|
| + // result_exp = 253 - UInt(a<30:23>)
|
| + int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
|
| + ASSERT((result_exp >= 1) && (result_exp <= 252));
|
| +
|
| + double scaled_d = bit_cast<double, uint64_t>(scaled);
|
| + ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
|
| +
|
| + // a in units of 1/512 rounded down.
|
| + int32_t q = static_cast<int32_t>(scaled_d * 512.0);
|
| + // reciprocal r.
|
| + double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
|
| + // r in units of 1/256 rounded to nearest.
|
| + int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
|
| + double estimate = static_cast<double>(s) / 256.0;
|
| + ASSERT((estimate >= 1.0) && (estimate <= (511.0/256.0)));
|
| +
|
| + // result = sign : result_exp<7:0> : estimate<51:29>
|
| + int32_t result_bits =
|
| + (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
|
| + ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
|
| + return bit_cast<float, int32_t>(result_bits);
|
| +}
|
| +
|
| +
|
| void Simulator::DecodeSIMDTwoReg(Instr* instr) {
|
| const int32_t Q = instr->Bit(30);
|
| const int32_t U = instr->Bit(29);
|
| @@ -2382,7 +2517,12 @@
|
| const VRegister vd = instr->VdField();
|
| const VRegister vn = instr->VnField();
|
|
|
| - if ((Q == 1) && (U == 1) && (op == 5)) {
|
| + if (Q != 1) {
|
| + UnimplementedInstruction(instr);
|
| + return;
|
| + }
|
| +
|
| + if ((U == 1) && (op == 5)) {
|
| // Format(instr, "vnot 'vd, 'vn");
|
| for (int i = 0; i < 2; i++) {
|
| set_vregisterd(vd, i, ~get_vregisterd(vn, i));
|
| @@ -2423,6 +2563,48 @@
|
| } else {
|
| UnimplementedInstruction(instr);
|
| }
|
| + } else if ((U == 1) && (op == 0x1f)) {
|
| + if (sz == 2) {
|
| + // Format(instr, "vsqrts 'vd, 'vn");
|
| + for (int i = 0; i < 4; i++) {
|
| + const int32_t vn_val = get_vregisters(vn, i);
|
| + const float vn_flt = bit_cast<float, int32_t>(vn_val);
|
| + set_vregisters(vd, i, bit_cast<int32_t, float>(sqrtf(vn_flt)));
|
| + }
|
| + } else if (sz == 3) {
|
| + // Format(instr, "vsqrtd 'vd, 'vn");
|
| + for (int i = 0; i < 2; i++) {
|
| + const int64_t vn_val = get_vregisterd(vn, i);
|
| + const double vn_dbl = bit_cast<double, int64_t>(vn_val);
|
| + set_vregisterd(vd, i, bit_cast<int64_t, double>(sqrt(vn_dbl)));
|
| + }
|
| + } else {
|
| + UnimplementedInstruction(instr);
|
| + }
|
| + } else if ((U == 0) && (op == 0x1d)) {
|
| + if (sz != 2) {
|
| + UnimplementedInstruction(instr);
|
| + return;
|
| + }
|
| + // Format(instr, "vrecpes 'vd, 'vn");
|
| + for (int i = 0; i < 4; i++) {
|
| + const int32_t vn_val = get_vregisters(vn, i);
|
| + const float vn_flt = bit_cast<float, int32_t>(vn_val);
|
| + const float re = arm_recip_estimate(vn_flt);
|
| + set_vregisters(vd, i, bit_cast<int32_t, float>(re));
|
| + }
|
| + } else if ((U == 1) && (op == 0x1d)) {
|
| + if (sz != 2) {
|
| + UnimplementedInstruction(instr);
|
| + return;
|
| + }
|
| + // Format(instr, "vrsqrtes 'vd, 'vn");
|
| + for (int i = 0; i < 4; i++) {
|
| + const int32_t vn_val = get_vregisters(vn, i);
|
| + const float vn_flt = bit_cast<float, int32_t>(vn_val);
|
| + const float re = arm_reciprocal_sqrt_estimate(vn_flt);
|
| + set_vregisters(vd, i, bit_cast<int32_t, float>(re));
|
| + }
|
| } else {
|
| UnimplementedInstruction(instr);
|
| }
|
|
|