Skip to content

Commit 6e042ef

Browse files
mralephcommit-bot@chromium.org
authored andcommitted
[vm/simarm] Fix VRECPS/VRSQRTSQS instruction implementation.
This instruction handles 0.0 and infinity operands specially because otherwise it produces NaN where it should produce appropriate infinity or zero. Fixes #24399 Fixes #26675 Fixes #38844 This relands commit 3da9c34 Change-Id: I116cea3b6c27b5dc16741f9652fbbb9a3ec1194e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121705 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
1 parent 974d289 commit 6e042ef

File tree

4 files changed

+178
-187
lines changed

4 files changed

+178
-187
lines changed

runtime/vm/compiler/assembler/assembler_arm_test.cc

Lines changed: 50 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,54 @@
1414
namespace dart {
1515
namespace compiler {
1616

17+
TEST_CASE(ReciprocalOps) {
18+
EXPECT_EQ(true, isinf(ReciprocalEstimate(-0.0f)));
19+
EXPECT_EQ(true, signbit(ReciprocalEstimate(-0.0f)));
20+
EXPECT_EQ(true, isinf(ReciprocalEstimate(0.0f)));
21+
EXPECT_EQ(true, !signbit(ReciprocalEstimate(0.0f)));
22+
EXPECT_EQ(true, isnan(ReciprocalEstimate(NAN)));
23+
24+
#define AS_UINT32(v) (bit_cast<uint32_t, float>(v))
25+
#define EXPECT_BITWISE_EQ(a, b) EXPECT_EQ(AS_UINT32(a), AS_UINT32(b))
26+
27+
EXPECT_BITWISE_EQ(0.0f, ReciprocalEstimate(kPosInfinity));
28+
EXPECT_BITWISE_EQ(-0.0f, ReciprocalEstimate(kNegInfinity));
29+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(0.0f, kPosInfinity));
30+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(0.0f, kNegInfinity));
31+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(-0.0f, kPosInfinity));
32+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(-0.0f, kNegInfinity));
33+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kPosInfinity, 0.0f));
34+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kNegInfinity, 0.0f));
35+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kPosInfinity, -0.0f));
36+
EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kNegInfinity, -0.0f));
37+
EXPECT_EQ(true, isnan(ReciprocalStep(NAN, 1.0f)));
38+
EXPECT_EQ(true, isnan(ReciprocalStep(1.0f, NAN)));
39+
40+
EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(-1.0f)));
41+
EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(kNegInfinity)));
42+
EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(-1.0f)));
43+
EXPECT_EQ(true, isinf(ReciprocalSqrtEstimate(-0.0f)));
44+
EXPECT_EQ(true, signbit(ReciprocalSqrtEstimate(-0.0f)));
45+
EXPECT_EQ(true, isinf(ReciprocalSqrtEstimate(0.0f)));
46+
EXPECT_EQ(true, !signbit(ReciprocalSqrtEstimate(0.0f)));
47+
EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(NAN)));
48+
EXPECT_BITWISE_EQ(0.0f, ReciprocalSqrtEstimate(kPosInfinity));
49+
50+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(0.0f, kPosInfinity));
51+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(0.0f, kNegInfinity));
52+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(-0.0f, kPosInfinity));
53+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(-0.0f, kNegInfinity));
54+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kPosInfinity, 0.0f));
55+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kNegInfinity, 0.0f));
56+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kPosInfinity, -0.0f));
57+
EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kNegInfinity, -0.0f));
58+
EXPECT_EQ(true, isnan(ReciprocalSqrtStep(NAN, 1.0f)));
59+
EXPECT_EQ(true, isnan(ReciprocalSqrtStep(1.0f, NAN)));
60+
61+
#undef AS_UINT32
62+
#undef EXPECT_BITWISE_EQ
63+
}
64+
1765
#define __ assembler->
1866

1967
ASSEMBLER_TEST_GENERATE(Simple, assembler) {
@@ -3430,43 +3478,6 @@ ASSEMBLER_TEST_RUN(Vmaxqs, test) {
34303478
}
34313479
}
34323480

3433-
// This is the same function as in the Simulator.
3434-
static float arm_recip_estimate(float a) {
3435-
// From the ARM Architecture Reference Manual A2-85.
3436-
if (isinf(a) || (fabs(a) >= exp2f(126)))
3437-
return 0.0;
3438-
else if (a == 0.0)
3439-
return kPosInfinity;
3440-
else if (isnan(a))
3441-
return a;
3442-
3443-
uint32_t a_bits = bit_cast<uint32_t, float>(a);
3444-
// scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
3445-
uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
3446-
((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
3447-
// result_exp = 253 - UInt(a<30:23>)
3448-
int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
3449-
ASSERT((result_exp >= 1) && (result_exp <= 252));
3450-
3451-
double scaled_d = bit_cast<double, uint64_t>(scaled);
3452-
ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
3453-
3454-
// a in units of 1/512 rounded down.
3455-
int32_t q = static_cast<int32_t>(scaled_d * 512.0);
3456-
// reciprocal r.
3457-
double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
3458-
// r in units of 1/256 rounded to nearest.
3459-
int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
3460-
double estimate = static_cast<double>(s) / 256.0;
3461-
ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
3462-
3463-
// result = sign : result_exp<7:0> : estimate<51:29>
3464-
int32_t result_bits =
3465-
(a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
3466-
((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
3467-
return bit_cast<float, int32_t>(result_bits);
3468-
}
3469-
34703481
ASSEMBLER_TEST_GENERATE(Vrecpeqs, assembler) {
34713482
if (TargetCPUFeatures::neon_supported()) {
34723483
__ LoadSImmediate(S4, 147.0);
@@ -3483,7 +3494,7 @@ ASSEMBLER_TEST_RUN(Vrecpeqs, test) {
34833494
if (TargetCPUFeatures::neon_supported()) {
34843495
typedef float (*Vrecpeqs)() DART_UNUSED;
34853496
float res = EXECUTE_TEST_CODE_FLOAT(Vrecpeqs, test->entry());
3486-
EXPECT_FLOAT_EQ(arm_recip_estimate(147.0), res, 0.0001f);
3497+
EXPECT_FLOAT_EQ(ReciprocalEstimate(147.0), res, 0.0001f);
34873498
}
34883499
}
34893500

@@ -3540,60 +3551,6 @@ ASSEMBLER_TEST_RUN(Reciprocal, test) {
35403551
}
35413552
}
35423553

3543-
static float arm_reciprocal_sqrt_estimate(float a) {
3544-
// From the ARM Architecture Reference Manual A2-87.
3545-
if (isinf(a) || (fabs(a) >= exp2f(126)))
3546-
return 0.0;
3547-
else if (a == 0.0)
3548-
return kPosInfinity;
3549-
else if (isnan(a))
3550-
return a;
3551-
3552-
uint32_t a_bits = bit_cast<uint32_t, float>(a);
3553-
uint64_t scaled;
3554-
if (((a_bits >> 23) & 1) != 0) {
3555-
// scaled = '0 01111111101' : operand<22:0> : Zeros(29)
3556-
scaled = (static_cast<uint64_t>(0x3fd) << 52) |
3557-
((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
3558-
} else {
3559-
// scaled = '0 01111111110' : operand<22:0> : Zeros(29)
3560-
scaled = (static_cast<uint64_t>(0x3fe) << 52) |
3561-
((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
3562-
}
3563-
// result_exp = (380 - UInt(operand<30:23>) DIV 2;
3564-
int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
3565-
3566-
double scaled_d = bit_cast<double, uint64_t>(scaled);
3567-
ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
3568-
3569-
double r;
3570-
if (scaled_d < 0.5) {
3571-
// range 0.25 <= a < 0.5
3572-
3573-
// a in units of 1/512 rounded down.
3574-
int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
3575-
// reciprocal root r.
3576-
r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
3577-
} else {
3578-
// range 0.5 <= a < 1.0
3579-
3580-
// a in units of 1/256 rounded down.
3581-
int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
3582-
// reciprocal root r.
3583-
r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
3584-
}
3585-
// r in units of 1/256 rounded to nearest.
3586-
int32_t s = static_cast<int>(256.0 * r + 0.5);
3587-
double estimate = static_cast<double>(s) / 256.0;
3588-
ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
3589-
3590-
// result = 0 : result_exp<7:0> : estimate<51:29>
3591-
int32_t result_bits =
3592-
((result_exp & 0xff) << 23) |
3593-
((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
3594-
return bit_cast<float, int32_t>(result_bits);
3595-
}
3596-
35973554
ASSEMBLER_TEST_GENERATE(Vrsqrteqs, assembler) {
35983555
if (TargetCPUFeatures::neon_supported()) {
35993556
__ LoadSImmediate(S4, 147.0);
@@ -3611,7 +3568,7 @@ ASSEMBLER_TEST_RUN(Vrsqrteqs, test) {
36113568
if (TargetCPUFeatures::neon_supported()) {
36123569
typedef float (*Vrsqrteqs)() DART_UNUSED;
36133570
float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrteqs, test->entry());
3614-
EXPECT_FLOAT_EQ(arm_reciprocal_sqrt_estimate(147.0), res, 0.0001f);
3571+
EXPECT_FLOAT_EQ(ReciprocalSqrtEstimate(147.0), res, 0.0001f);
36153572
}
36163573
}
36173574

runtime/vm/constants_arm.cc

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace arch_arm {
99

10+
using dart::bit_cast;
11+
1012
const char* cpu_reg_names[kNumberOfCpuRegisters] = {
1113
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1214
"r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
@@ -25,4 +27,116 @@ const Register CallingConventions::ArgumentRegisters[] = {R0, R1, R2, R3};
2527
// one element to appease MSVC.
2628
const FpuRegister CallingConventions::FpuArgumentRegisters[] = {Q0};
2729

30+
float ReciprocalEstimate(float a) {
31+
// From the ARM Architecture Reference Manual A2-85.
32+
if (isinf(a) || (fabs(a) >= exp2f(126)))
33+
return a >= 0.0f ? 0.0f : -0.0f;
34+
else if (a == 0.0f)
35+
return 1.0f / a;
36+
else if (isnan(a))
37+
return a;
38+
39+
uint32_t a_bits = bit_cast<uint32_t, float>(a);
40+
// scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
41+
uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
42+
((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
43+
// result_exp = 253 - UInt(a<30:23>)
44+
int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
45+
ASSERT((result_exp >= 1) && (result_exp <= 252));
46+
47+
double scaled_d = bit_cast<double, uint64_t>(scaled);
48+
ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
49+
50+
// a in units of 1/512 rounded down.
51+
int32_t q = static_cast<int32_t>(scaled_d * 512.0);
52+
// reciprocal r.
53+
double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
54+
// r in units of 1/256 rounded to nearest.
55+
int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
56+
double estimate = static_cast<double>(s) / 256.0;
57+
ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
58+
59+
// result = sign : result_exp<7:0> : estimate<51:29>
60+
int32_t result_bits =
61+
(a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
62+
((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
63+
return bit_cast<float, int32_t>(result_bits);
64+
}
65+
66+
float ReciprocalStep(float op1, float op2) {
67+
float p;
68+
if ((isinf(op1) && op2 == 0.0f) || (op1 == 0.0f && isinf(op2))) {
69+
p = 0.0f;
70+
} else {
71+
p = op1 * op2;
72+
}
73+
return 2.0f - p;
74+
}
75+
76+
float ReciprocalSqrtEstimate(float a) {
77+
// From the ARM Architecture Reference Manual A2-87.
78+
if (a < 0.0f)
79+
return NAN;
80+
else if (isinf(a) || (fabs(a) >= exp2f(126)))
81+
return 0.0f;
82+
else if (a == 0.0)
83+
return 1.0f / a;
84+
else if (isnan(a))
85+
return a;
86+
87+
uint32_t a_bits = bit_cast<uint32_t, float>(a);
88+
uint64_t scaled;
89+
if (((a_bits >> 23) & 1) != 0) {
90+
// scaled = '0 01111111101' : operand<22:0> : Zeros(29)
91+
scaled = (static_cast<uint64_t>(0x3fd) << 52) |
92+
((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
93+
} else {
94+
// scaled = '0 01111111110' : operand<22:0> : Zeros(29)
95+
scaled = (static_cast<uint64_t>(0x3fe) << 52) |
96+
((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
97+
}
98+
// result_exp = (380 - UInt(operand<30:23>) DIV 2;
99+
int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
100+
101+
double scaled_d = bit_cast<double, uint64_t>(scaled);
102+
ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
103+
104+
double r;
105+
if (scaled_d < 0.5) {
106+
// range 0.25 <= a < 0.5
107+
108+
// a in units of 1/512 rounded down.
109+
int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
110+
// reciprocal root r.
111+
r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
112+
} else {
113+
// range 0.5 <= a < 1.0
114+
115+
// a in units of 1/256 rounded down.
116+
int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
117+
// reciprocal root r.
118+
r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
119+
}
120+
// r in units of 1/256 rounded to nearest.
121+
int32_t s = static_cast<int>(256.0 * r + 0.5);
122+
double estimate = static_cast<double>(s) / 256.0;
123+
ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
124+
125+
// result = 0 : result_exp<7:0> : estimate<51:29>
126+
int32_t result_bits =
127+
((result_exp & 0xff) << 23) |
128+
((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
129+
return bit_cast<float, int32_t>(result_bits);
130+
}
131+
132+
float ReciprocalSqrtStep(float op1, float op2) {
133+
float p;
134+
if ((isinf(op1) && op2 == 0.0f) || (op1 == 0.0f && isinf(op2))) {
135+
p = 0.0f;
136+
} else {
137+
p = op1 * op2;
138+
}
139+
return (3.0f - p) / 2.0f;
140+
}
141+
28142
} // namespace arch_arm

runtime/vm/constants_arm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,16 @@ class Instr {
822822
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
823823
};
824824

825+
// Floating-point reciprocal estimate and step (see pages A2-85 and A2-86 of
826+
// ARM Architecture Reference Manual ARMv7-A edition).
827+
float ReciprocalEstimate(float op);
828+
float ReciprocalStep(float op1, float op2);
829+
830+
// Floating-point reciprocal square root estimate and step (see pages A2-87 to
831+
// A2-90 of ARM Architecture Reference Manual ARMv7-A edition).
832+
float ReciprocalSqrtEstimate(float op);
833+
float ReciprocalSqrtStep(float op1, float op2);
834+
825835
} // namespace arch_arm
826836

827837
#endif // RUNTIME_VM_CONSTANTS_ARM_H_

0 commit comments

Comments
 (0)