Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Unified Diff: test/cctest/test-assembler-a64.cc

Issue 199083005: A64: Fix a few simulation inaccuracies. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/a64/utils-a64.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-assembler-a64.cc
diff --git a/test/cctest/test-assembler-a64.cc b/test/cctest/test-assembler-a64.cc
index 252c39bbbd880e2fafb2855abf89523e300af363..695bd255262dd1ff110b7f3be90f43b923ec2661 100644
--- a/test/cctest/test-assembler-a64.cc
+++ b/test/cctest/test-assembler-a64.cc
@@ -4915,31 +4915,35 @@ TEST(fadd) {
SETUP();
START();
- __ Fmov(s13, -0.0);
- __ Fmov(s14, kFP32PositiveInfinity);
- __ Fmov(s15, kFP32NegativeInfinity);
- __ Fmov(s16, 3.25);
- __ Fmov(s17, 1.0);
- __ Fmov(s18, 0);
+ __ Fmov(s14, -0.0f);
+ __ Fmov(s15, kFP32PositiveInfinity);
+ __ Fmov(s16, kFP32NegativeInfinity);
+ __ Fmov(s17, 3.25f);
+ __ Fmov(s18, 1.0f);
+ __ Fmov(s19, 0.0f);
__ Fmov(d26, -0.0);
__ Fmov(d27, kFP64PositiveInfinity);
__ Fmov(d28, kFP64NegativeInfinity);
- __ Fmov(d29, 0);
+ __ Fmov(d29, 0.0);
__ Fmov(d30, -2.0);
__ Fmov(d31, 2.25);
- __ Fadd(s0, s16, s17);
- __ Fadd(s1, s17, s18);
- __ Fadd(s2, s13, s17);
- __ Fadd(s3, s14, s17);
- __ Fadd(s4, s15, s17);
+ __ Fadd(s0, s17, s18);
+ __ Fadd(s1, s18, s19);
+ __ Fadd(s2, s14, s18);
+ __ Fadd(s3, s15, s18);
+ __ Fadd(s4, s16, s18);
+ __ Fadd(s5, s15, s16);
+ __ Fadd(s6, s16, s15);
- __ Fadd(d5, d30, d31);
- __ Fadd(d6, d29, d31);
- __ Fadd(d7, d26, d31);
- __ Fadd(d8, d27, d31);
- __ Fadd(d9, d28, d31);
+ __ Fadd(d7, d30, d31);
+ __ Fadd(d8, d29, d31);
+ __ Fadd(d9, d26, d31);
+ __ Fadd(d10, d27, d31);
+ __ Fadd(d11, d28, d31);
+ __ Fadd(d12, d27, d28);
+ __ Fadd(d13, d28, d27);
END();
RUN();
@@ -4949,11 +4953,15 @@ TEST(fadd) {
ASSERT_EQUAL_FP32(1.0, s2);
ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s3);
ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s4);
- ASSERT_EQUAL_FP64(0.25, d5);
- ASSERT_EQUAL_FP64(2.25, d6);
- ASSERT_EQUAL_FP64(2.25, d7);
- ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d8);
- ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d9);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6);
+ ASSERT_EQUAL_FP64(0.25, d7);
+ ASSERT_EQUAL_FP64(2.25, d8);
+ ASSERT_EQUAL_FP64(2.25, d9);
+ ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d10);
+ ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d11);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13);
TEARDOWN();
}
@@ -4964,31 +4972,35 @@ TEST(fsub) {
SETUP();
START();
- __ Fmov(s13, -0.0);
- __ Fmov(s14, kFP32PositiveInfinity);
- __ Fmov(s15, kFP32NegativeInfinity);
- __ Fmov(s16, 3.25);
- __ Fmov(s17, 1.0);
- __ Fmov(s18, 0);
+ __ Fmov(s14, -0.0f);
+ __ Fmov(s15, kFP32PositiveInfinity);
+ __ Fmov(s16, kFP32NegativeInfinity);
+ __ Fmov(s17, 3.25f);
+ __ Fmov(s18, 1.0f);
+ __ Fmov(s19, 0.0f);
__ Fmov(d26, -0.0);
__ Fmov(d27, kFP64PositiveInfinity);
__ Fmov(d28, kFP64NegativeInfinity);
- __ Fmov(d29, 0);
+ __ Fmov(d29, 0.0);
__ Fmov(d30, -2.0);
__ Fmov(d31, 2.25);
- __ Fsub(s0, s16, s17);
- __ Fsub(s1, s17, s18);
- __ Fsub(s2, s13, s17);
- __ Fsub(s3, s17, s14);
- __ Fsub(s4, s17, s15);
+ __ Fsub(s0, s17, s18);
+ __ Fsub(s1, s18, s19);
+ __ Fsub(s2, s14, s18);
+ __ Fsub(s3, s18, s15);
+ __ Fsub(s4, s18, s16);
+ __ Fsub(s5, s15, s15);
+ __ Fsub(s6, s16, s16);
- __ Fsub(d5, d30, d31);
- __ Fsub(d6, d29, d31);
- __ Fsub(d7, d26, d31);
- __ Fsub(d8, d31, d27);
- __ Fsub(d9, d31, d28);
+ __ Fsub(d7, d30, d31);
+ __ Fsub(d8, d29, d31);
+ __ Fsub(d9, d26, d31);
+ __ Fsub(d10, d31, d27);
+ __ Fsub(d11, d31, d28);
+ __ Fsub(d12, d27, d27);
+ __ Fsub(d13, d28, d28);
END();
RUN();
@@ -4998,11 +5010,15 @@ TEST(fsub) {
ASSERT_EQUAL_FP32(-1.0, s2);
ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s3);
ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s4);
- ASSERT_EQUAL_FP64(-4.25, d5);
- ASSERT_EQUAL_FP64(-2.25, d6);
- ASSERT_EQUAL_FP64(-2.25, d7);
- ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d8);
- ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d9);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6);
+ ASSERT_EQUAL_FP64(-4.25, d7);
+ ASSERT_EQUAL_FP64(-2.25, d8);
+ ASSERT_EQUAL_FP64(-2.25, d9);
+ ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d10);
+ ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d11);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13);
TEARDOWN();
}
@@ -5013,32 +5029,36 @@ TEST(fmul) {
SETUP();
START();
- __ Fmov(s13, -0.0);
- __ Fmov(s14, kFP32PositiveInfinity);
- __ Fmov(s15, kFP32NegativeInfinity);
- __ Fmov(s16, 3.25);
- __ Fmov(s17, 2.0);
- __ Fmov(s18, 0);
- __ Fmov(s19, -2.0);
+ __ Fmov(s14, -0.0f);
+ __ Fmov(s15, kFP32PositiveInfinity);
+ __ Fmov(s16, kFP32NegativeInfinity);
+ __ Fmov(s17, 3.25f);
+ __ Fmov(s18, 2.0f);
+ __ Fmov(s19, 0.0f);
+ __ Fmov(s20, -2.0f);
__ Fmov(d26, -0.0);
__ Fmov(d27, kFP64PositiveInfinity);
__ Fmov(d28, kFP64NegativeInfinity);
- __ Fmov(d29, 0);
+ __ Fmov(d29, 0.0);
__ Fmov(d30, -2.0);
__ Fmov(d31, 2.25);
- __ Fmul(s0, s16, s17);
- __ Fmul(s1, s17, s18);
- __ Fmul(s2, s13, s13);
- __ Fmul(s3, s14, s19);
- __ Fmul(s4, s15, s19);
+ __ Fmul(s0, s17, s18);
+ __ Fmul(s1, s18, s19);
+ __ Fmul(s2, s14, s14);
+ __ Fmul(s3, s15, s20);
+ __ Fmul(s4, s16, s20);
+ __ Fmul(s5, s15, s19);
+ __ Fmul(s6, s19, s16);
- __ Fmul(d5, d30, d31);
- __ Fmul(d6, d29, d31);
- __ Fmul(d7, d26, d26);
- __ Fmul(d8, d27, d30);
- __ Fmul(d9, d28, d30);
+ __ Fmul(d7, d30, d31);
+ __ Fmul(d8, d29, d31);
+ __ Fmul(d9, d26, d26);
+ __ Fmul(d10, d27, d30);
+ __ Fmul(d11, d28, d30);
+ __ Fmul(d12, d27, d29);
+ __ Fmul(d13, d29, d28);
END();
RUN();
@@ -5048,18 +5068,23 @@ TEST(fmul) {
ASSERT_EQUAL_FP32(0.0, s2);
ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s3);
ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s4);
- ASSERT_EQUAL_FP64(-4.5, d5);
- ASSERT_EQUAL_FP64(0.0, d6);
- ASSERT_EQUAL_FP64(0.0, d7);
- ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d8);
- ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d9);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6);
+ ASSERT_EQUAL_FP64(-4.5, d7);
+ ASSERT_EQUAL_FP64(0.0, d8);
+ ASSERT_EQUAL_FP64(0.0, d9);
+ ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d10);
+ ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d11);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13);
TEARDOWN();
}
-static void FmaddFmsubDoubleHelper(double n, double m, double a,
- double fmadd, double fmsub) {
+static void FmaddFmsubHelper(double n, double m, double a,
+ double fmadd, double fmsub,
+ double fnmadd, double fnmsub) {
SETUP();
START();
@@ -5076,8 +5101,8 @@ static void FmaddFmsubDoubleHelper(double n, double m, double a,
ASSERT_EQUAL_FP64(fmadd, d28);
ASSERT_EQUAL_FP64(fmsub, d29);
- ASSERT_EQUAL_FP64(-fmadd, d30);
- ASSERT_EQUAL_FP64(-fmsub, d31);
+ ASSERT_EQUAL_FP64(fnmadd, d30);
+ ASSERT_EQUAL_FP64(fnmsub, d31);
TEARDOWN();
}
@@ -5085,105 +5110,67 @@ static void FmaddFmsubDoubleHelper(double n, double m, double a,
TEST(fmadd_fmsub_double) {
INIT_V8();
- double inputs[] = {
- // Normal numbers, including -0.0.
- DBL_MAX, DBL_MIN, 3.25, 2.0, 0.0,
- -DBL_MAX, -DBL_MIN, -3.25, -2.0, -0.0,
- // Infinities.
- kFP64NegativeInfinity, kFP64PositiveInfinity,
- // Subnormal numbers.
- rawbits_to_double(0x000fffffffffffff),
- rawbits_to_double(0x0000000000000001),
- rawbits_to_double(0x000123456789abcd),
- -rawbits_to_double(0x000fffffffffffff),
- -rawbits_to_double(0x0000000000000001),
- -rawbits_to_double(0x000123456789abcd),
- // NaN.
- kFP64QuietNaN,
- -kFP64QuietNaN,
- };
- const int count = sizeof(inputs) / sizeof(inputs[0]);
-
- for (int in = 0; in < count; in++) {
- double n = inputs[in];
- for (int im = 0; im < count; im++) {
- double m = inputs[im];
- for (int ia = 0; ia < count; ia++) {
- double a = inputs[ia];
- double fmadd = fma(n, m, a);
- double fmsub = fma(-n, m, a);
-
- FmaddFmsubDoubleHelper(n, m, a, fmadd, fmsub);
- }
- }
- }
-}
-
-
-TEST(fmadd_fmsub_double_rounding) {
- INIT_V8();
- // Make sure we run plenty of tests where an intermediate rounding stage would
- // produce an incorrect result.
- const int limit = 1000;
- int count_fmadd = 0;
- int count_fmsub = 0;
-
- uint16_t seed[3] = {42, 43, 44};
- seed48(seed);
- while ((count_fmadd < limit) || (count_fmsub < limit)) {
- double n, m, a;
- uint32_t r[2];
- ASSERT(sizeof(r) == sizeof(n));
+ // It's hard to check the result of fused operations because the only way to
+ // calculate the result is using fma, which is what the simulator uses anyway.
+ // TODO(jbramley): Add tests to check behaviour against a hardware trace.
- r[0] = mrand48();
- r[1] = mrand48();
- memcpy(&n, r, sizeof(r));
- r[0] = mrand48();
- r[1] = mrand48();
- memcpy(&m, r, sizeof(r));
- r[0] = mrand48();
- r[1] = mrand48();
- memcpy(&a, r, sizeof(r));
+ // Basic operation.
+ FmaddFmsubHelper(1.0, 2.0, 3.0, 5.0, 1.0, -5.0, -1.0);
+ FmaddFmsubHelper(-1.0, 2.0, 3.0, 1.0, 5.0, -1.0, -5.0);
- if (!std::isfinite(a) || !std::isfinite(n) || !std::isfinite(m)) {
- continue;
- }
+ // Check the sign of exact zeroes.
+ // n m a fmadd fmsub fnmadd fnmsub
+ FmaddFmsubHelper(-0.0, +0.0, -0.0, -0.0, +0.0, +0.0, +0.0);
+ FmaddFmsubHelper(+0.0, +0.0, -0.0, +0.0, -0.0, +0.0, +0.0);
+ FmaddFmsubHelper(+0.0, +0.0, +0.0, +0.0, +0.0, -0.0, +0.0);
+ FmaddFmsubHelper(-0.0, +0.0, +0.0, +0.0, +0.0, +0.0, -0.0);
+ FmaddFmsubHelper(+0.0, -0.0, -0.0, -0.0, +0.0, +0.0, +0.0);
+ FmaddFmsubHelper(-0.0, -0.0, -0.0, +0.0, -0.0, +0.0, +0.0);
+ FmaddFmsubHelper(-0.0, -0.0, +0.0, +0.0, +0.0, -0.0, +0.0);
+ FmaddFmsubHelper(+0.0, -0.0, +0.0, +0.0, +0.0, +0.0, -0.0);
- // Calculate the expected results.
- double fmadd = fma(n, m, a);
- double fmsub = fma(-n, m, a);
-
- bool test_fmadd = (fmadd != (a + n * m));
- bool test_fmsub = (fmsub != (a - n * m));
-
- // If rounding would produce a different result, increment the test count.
- count_fmadd += test_fmadd;
- count_fmsub += test_fmsub;
-
- if (test_fmadd || test_fmsub) {
- FmaddFmsubDoubleHelper(n, m, a, fmadd, fmsub);
- }
- }
+ // Check NaN generation.
+ FmaddFmsubHelper(kFP64PositiveInfinity, 0.0, 42.0,
+ kFP64DefaultNaN, kFP64DefaultNaN,
+ kFP64DefaultNaN, kFP64DefaultNaN);
+ FmaddFmsubHelper(0.0, kFP64PositiveInfinity, 42.0,
+ kFP64DefaultNaN, kFP64DefaultNaN,
+ kFP64DefaultNaN, kFP64DefaultNaN);
+ FmaddFmsubHelper(kFP64PositiveInfinity, 1.0, kFP64PositiveInfinity,
+ kFP64PositiveInfinity, // inf + ( inf * 1) = inf
+ kFP64DefaultNaN, // inf + (-inf * 1) = NaN
+ kFP64NegativeInfinity, // -inf + (-inf * 1) = -inf
+ kFP64DefaultNaN); // -inf + ( inf * 1) = NaN
+ FmaddFmsubHelper(kFP64NegativeInfinity, 1.0, kFP64PositiveInfinity,
+ kFP64DefaultNaN, // inf + (-inf * 1) = NaN
+ kFP64PositiveInfinity, // inf + ( inf * 1) = inf
+ kFP64DefaultNaN, // -inf + ( inf * 1) = NaN
+ kFP64NegativeInfinity); // -inf + (-inf * 1) = -inf
}
-static void FmaddFmsubFloatHelper(float n, float m, float a,
- float fmadd, float fmsub) {
+static void FmaddFmsubHelper(float n, float m, float a,
+ float fmadd, float fmsub,
+ float fnmadd, float fnmsub) {
SETUP();
START();
__ Fmov(s0, n);
__ Fmov(s1, m);
__ Fmov(s2, a);
- __ Fmadd(s30, s0, s1, s2);
- __ Fmsub(s31, s0, s1, s2);
+ __ Fmadd(s28, s0, s1, s2);
+ __ Fmsub(s29, s0, s1, s2);
+ __ Fnmadd(s30, s0, s1, s2);
+ __ Fnmsub(s31, s0, s1, s2);
END();
RUN();
- ASSERT_EQUAL_FP32(fmadd, s30);
- ASSERT_EQUAL_FP32(fmsub, s31);
+ ASSERT_EQUAL_FP32(fmadd, s28);
+ ASSERT_EQUAL_FP32(fmsub, s29);
+ ASSERT_EQUAL_FP32(fnmadd, s30);
+ ASSERT_EQUAL_FP32(fnmsub, s31);
TEARDOWN();
}
@@ -5191,83 +5178,188 @@ static void FmaddFmsubFloatHelper(float n, float m, float a,
TEST(fmadd_fmsub_float) {
INIT_V8();
- float inputs[] = {
- // Normal numbers, including -0.0f.
- FLT_MAX, FLT_MIN, 3.25f, 2.0f, 0.0f,
- -FLT_MAX, -FLT_MIN, -3.25f, -2.0f, -0.0f,
- // Infinities.
- kFP32NegativeInfinity, kFP32PositiveInfinity,
- // Subnormal numbers.
- rawbits_to_float(0x07ffffff),
- rawbits_to_float(0x00000001),
- rawbits_to_float(0x01234567),
- -rawbits_to_float(0x07ffffff),
- -rawbits_to_float(0x00000001),
- -rawbits_to_float(0x01234567),
- // NaN.
- kFP32QuietNaN,
- -kFP32QuietNaN,
- };
- const int count = sizeof(inputs) / sizeof(inputs[0]);
-
- for (int in = 0; in < count; in++) {
- float n = inputs[in];
- for (int im = 0; im < count; im++) {
- float m = inputs[im];
- for (int ia = 0; ia < count; ia++) {
- float a = inputs[ia];
- float fmadd = fmaf(n, m, a);
- float fmsub = fmaf(-n, m, a);
-
- FmaddFmsubFloatHelper(n, m, a, fmadd, fmsub);
- }
- }
- }
-}
-
-
-TEST(fmadd_fmsub_float_rounding) {
- INIT_V8();
- // Make sure we run plenty of tests where an intermediate rounding stage would
- // produce an incorrect result.
- const int limit = 1000;
- int count_fmadd = 0;
- int count_fmsub = 0;
-
- uint16_t seed[3] = {42, 43, 44};
- seed48(seed);
-
- while ((count_fmadd < limit) || (count_fmsub < limit)) {
- float n, m, a;
- uint32_t r;
- ASSERT(sizeof(r) == sizeof(n));
-
- r = mrand48();
- memcpy(&n, &r, sizeof(r));
- r = mrand48();
- memcpy(&m, &r, sizeof(r));
- r = mrand48();
- memcpy(&a, &r, sizeof(r));
-
- if (!std::isfinite(a) || !std::isfinite(n) || !std::isfinite(m)) {
- continue;
- }
-
- // Calculate the expected results.
- float fmadd = fmaf(n, m, a);
- float fmsub = fmaf(-n, m, a);
-
- bool test_fmadd = (fmadd != (a + n * m));
- bool test_fmsub = (fmsub != (a - n * m));
-
- // If rounding would produce a different result, increment the test count.
- count_fmadd += test_fmadd;
- count_fmsub += test_fmsub;
-
- if (test_fmadd || test_fmsub) {
- FmaddFmsubFloatHelper(n, m, a, fmadd, fmsub);
- }
- }
+ // It's hard to check the result of fused operations because the only way to
+ // calculate the result is using fma, which is what the simulator uses anyway.
+ // TODO(jbramley): Add tests to check behaviour against a hardware trace.
+
+ // Basic operation.
+ FmaddFmsubHelper(1.0f, 2.0f, 3.0f, 5.0f, 1.0f, -5.0f, -1.0f);
+ FmaddFmsubHelper(-1.0f, 2.0f, 3.0f, 1.0f, 5.0f, -1.0f, -5.0f);
+
+ // Check the sign of exact zeroes.
+ // n m a fmadd fmsub fnmadd fnmsub
+ FmaddFmsubHelper(-0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, +0.0f);
+ FmaddFmsubHelper(+0.0f, +0.0f, -0.0f, +0.0f, -0.0f, +0.0f, +0.0f);
+ FmaddFmsubHelper(+0.0f, +0.0f, +0.0f, +0.0f, +0.0f, -0.0f, +0.0f);
+ FmaddFmsubHelper(-0.0f, +0.0f, +0.0f, +0.0f, +0.0f, +0.0f, -0.0f);
+ FmaddFmsubHelper(+0.0f, -0.0f, -0.0f, -0.0f, +0.0f, +0.0f, +0.0f);
+ FmaddFmsubHelper(-0.0f, -0.0f, -0.0f, +0.0f, -0.0f, +0.0f, +0.0f);
+ FmaddFmsubHelper(-0.0f, -0.0f, +0.0f, +0.0f, +0.0f, -0.0f, +0.0f);
+ FmaddFmsubHelper(+0.0f, -0.0f, +0.0f, +0.0f, +0.0f, +0.0f, -0.0f);
+
+ // Check NaN generation.
+ FmaddFmsubHelper(kFP32PositiveInfinity, 0.0f, 42.0f,
+ kFP32DefaultNaN, kFP32DefaultNaN,
+ kFP32DefaultNaN, kFP32DefaultNaN);
+ FmaddFmsubHelper(0.0f, kFP32PositiveInfinity, 42.0f,
+ kFP32DefaultNaN, kFP32DefaultNaN,
+ kFP32DefaultNaN, kFP32DefaultNaN);
+ FmaddFmsubHelper(kFP32PositiveInfinity, 1.0f, kFP32PositiveInfinity,
+ kFP32PositiveInfinity, // inf + ( inf * 1) = inf
+ kFP32DefaultNaN, // inf + (-inf * 1) = NaN
+ kFP32NegativeInfinity, // -inf + (-inf * 1) = -inf
+ kFP32DefaultNaN); // -inf + ( inf * 1) = NaN
+ FmaddFmsubHelper(kFP32NegativeInfinity, 1.0f, kFP32PositiveInfinity,
+ kFP32DefaultNaN, // inf + (-inf * 1) = NaN
+ kFP32PositiveInfinity, // inf + ( inf * 1) = inf
+ kFP32DefaultNaN, // -inf + ( inf * 1) = NaN
+ kFP32NegativeInfinity); // -inf + (-inf * 1) = -inf
+}
+
+
+TEST(fmadd_fmsub_double_nans) {
+ INIT_V8();
+ // Make sure that NaN propagation works correctly.
+ double s1 = rawbits_to_double(0x7ff5555511111111);
+ double s2 = rawbits_to_double(0x7ff5555522222222);
+ double sa = rawbits_to_double(0x7ff55555aaaaaaaa);
+ double q1 = rawbits_to_double(0x7ffaaaaa11111111);
+ double q2 = rawbits_to_double(0x7ffaaaaa22222222);
+ double qa = rawbits_to_double(0x7ffaaaaaaaaaaaaa);
+ ASSERT(IsSignallingNaN(s1));
+ ASSERT(IsSignallingNaN(s2));
+ ASSERT(IsSignallingNaN(sa));
+ ASSERT(IsQuietNaN(q1));
+ ASSERT(IsQuietNaN(q2));
+ ASSERT(IsQuietNaN(qa));
+
+ // The input NaNs after passing through ProcessNaN.
+ double s1_proc = rawbits_to_double(0x7ffd555511111111);
+ double s2_proc = rawbits_to_double(0x7ffd555522222222);
+ double sa_proc = rawbits_to_double(0x7ffd5555aaaaaaaa);
+ double q1_proc = q1;
+ double q2_proc = q2;
+ double qa_proc = qa;
+ ASSERT(IsQuietNaN(s1_proc));
+ ASSERT(IsQuietNaN(s2_proc));
+ ASSERT(IsQuietNaN(sa_proc));
+ ASSERT(IsQuietNaN(q1_proc));
+ ASSERT(IsQuietNaN(q2_proc));
+ ASSERT(IsQuietNaN(qa_proc));
+
+ // Quiet NaNs are propagated.
+ FmaddFmsubHelper(q1, 0, 0, q1_proc, -q1_proc, -q1_proc, q1_proc);
+ FmaddFmsubHelper(0, q2, 0, q2_proc, q2_proc, q2_proc, q2_proc);
+ FmaddFmsubHelper(0, 0, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+ FmaddFmsubHelper(q1, q2, 0, q1_proc, -q1_proc, -q1_proc, q1_proc);
+ FmaddFmsubHelper(0, q2, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+ FmaddFmsubHelper(q1, 0, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+ FmaddFmsubHelper(q1, q2, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+
+ // Signalling NaNs are propagated, and made quiet.
+ FmaddFmsubHelper(s1, 0, 0, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(0, s2, 0, s2_proc, s2_proc, s2_proc, s2_proc);
+ FmaddFmsubHelper(0, 0, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, 0, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(0, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, 0, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+
+ // Signalling NaNs take precedence over quiet NaNs.
+ FmaddFmsubHelper(s1, q2, qa, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(q1, s2, qa, s2_proc, s2_proc, s2_proc, s2_proc);
+ FmaddFmsubHelper(q1, q2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, qa, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(q1, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, q2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+
+ // A NaN generated by the intermediate op1 * op2 overrides a quiet NaN in a.
+ FmaddFmsubHelper(0, kFP64PositiveInfinity, qa,
+ kFP64DefaultNaN, kFP64DefaultNaN,
+ kFP64DefaultNaN, kFP64DefaultNaN);
+ FmaddFmsubHelper(kFP64PositiveInfinity, 0, qa,
+ kFP64DefaultNaN, kFP64DefaultNaN,
+ kFP64DefaultNaN, kFP64DefaultNaN);
+ FmaddFmsubHelper(0, kFP64NegativeInfinity, qa,
+ kFP64DefaultNaN, kFP64DefaultNaN,
+ kFP64DefaultNaN, kFP64DefaultNaN);
+ FmaddFmsubHelper(kFP64NegativeInfinity, 0, qa,
+ kFP64DefaultNaN, kFP64DefaultNaN,
+ kFP64DefaultNaN, kFP64DefaultNaN);
+}
+
+
+TEST(fmadd_fmsub_float_nans) {
+ INIT_V8();
+ // Make sure that NaN propagation works correctly.
+ float s1 = rawbits_to_float(0x7f951111);
+ float s2 = rawbits_to_float(0x7f952222);
+ float sa = rawbits_to_float(0x7f95aaaa);
+ float q1 = rawbits_to_float(0x7fea1111);
+ float q2 = rawbits_to_float(0x7fea2222);
+ float qa = rawbits_to_float(0x7feaaaaa);
+ ASSERT(IsSignallingNaN(s1));
+ ASSERT(IsSignallingNaN(s2));
+ ASSERT(IsSignallingNaN(sa));
+ ASSERT(IsQuietNaN(q1));
+ ASSERT(IsQuietNaN(q2));
+ ASSERT(IsQuietNaN(qa));
+
+ // The input NaNs after passing through ProcessNaN.
+ float s1_proc = rawbits_to_float(0x7fd51111);
+ float s2_proc = rawbits_to_float(0x7fd52222);
+ float sa_proc = rawbits_to_float(0x7fd5aaaa);
+ float q1_proc = q1;
+ float q2_proc = q2;
+ float qa_proc = qa;
+ ASSERT(IsQuietNaN(s1_proc));
+ ASSERT(IsQuietNaN(s2_proc));
+ ASSERT(IsQuietNaN(sa_proc));
+ ASSERT(IsQuietNaN(q1_proc));
+ ASSERT(IsQuietNaN(q2_proc));
+ ASSERT(IsQuietNaN(qa_proc));
+
+ // Quiet NaNs are propagated.
+ FmaddFmsubHelper(q1, 0, 0, q1_proc, -q1_proc, -q1_proc, q1_proc);
+ FmaddFmsubHelper(0, q2, 0, q2_proc, q2_proc, q2_proc, q2_proc);
+ FmaddFmsubHelper(0, 0, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+ FmaddFmsubHelper(q1, q2, 0, q1_proc, -q1_proc, -q1_proc, q1_proc);
+ FmaddFmsubHelper(0, q2, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+ FmaddFmsubHelper(q1, 0, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+ FmaddFmsubHelper(q1, q2, qa, qa_proc, qa_proc, -qa_proc, -qa_proc);
+
+ // Signalling NaNs are propagated, and made quiet.
+ FmaddFmsubHelper(s1, 0, 0, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(0, s2, 0, s2_proc, s2_proc, s2_proc, s2_proc);
+ FmaddFmsubHelper(0, 0, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, 0, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(0, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, 0, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+
+ // Signalling NaNs take precedence over quiet NaNs.
+ FmaddFmsubHelper(s1, q2, qa, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(q1, s2, qa, s2_proc, s2_proc, s2_proc, s2_proc);
+ FmaddFmsubHelper(q1, q2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, qa, s1_proc, -s1_proc, -s1_proc, s1_proc);
+ FmaddFmsubHelper(q1, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, q2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+ FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, -sa_proc, -sa_proc);
+
+ // A NaN generated by the intermediate op1 * op2 overrides a quiet NaN in a.
+ FmaddFmsubHelper(0, kFP32PositiveInfinity, qa,
+ kFP32DefaultNaN, kFP32DefaultNaN,
+ kFP32DefaultNaN, kFP32DefaultNaN);
+ FmaddFmsubHelper(kFP32PositiveInfinity, 0, qa,
+ kFP32DefaultNaN, kFP32DefaultNaN,
+ kFP32DefaultNaN, kFP32DefaultNaN);
+ FmaddFmsubHelper(0, kFP32NegativeInfinity, qa,
+ kFP32DefaultNaN, kFP32DefaultNaN,
+ kFP32DefaultNaN, kFP32DefaultNaN);
+ FmaddFmsubHelper(kFP32NegativeInfinity, 0, qa,
+ kFP32DefaultNaN, kFP32DefaultNaN,
+ kFP32DefaultNaN, kFP32DefaultNaN);
}
@@ -5276,45 +5368,54 @@ TEST(fdiv) {
SETUP();
START();
- __ Fmov(s13, -0.0);
- __ Fmov(s14, kFP32PositiveInfinity);
- __ Fmov(s15, kFP32NegativeInfinity);
- __ Fmov(s16, 3.25);
- __ Fmov(s17, 2.0);
- __ Fmov(s18, 2.0);
- __ Fmov(s19, -2.0);
+ __ Fmov(s14, -0.0f);
+ __ Fmov(s15, kFP32PositiveInfinity);
+ __ Fmov(s16, kFP32NegativeInfinity);
+ __ Fmov(s17, 3.25f);
+ __ Fmov(s18, 2.0f);
+ __ Fmov(s19, 2.0f);
+ __ Fmov(s20, -2.0f);
__ Fmov(d26, -0.0);
__ Fmov(d27, kFP64PositiveInfinity);
__ Fmov(d28, kFP64NegativeInfinity);
- __ Fmov(d29, 0);
+ __ Fmov(d29, 0.0);
__ Fmov(d30, -2.0);
__ Fmov(d31, 2.25);
- __ Fdiv(s0, s16, s17);
- __ Fdiv(s1, s17, s18);
- __ Fdiv(s2, s13, s17);
- __ Fdiv(s3, s17, s14);
- __ Fdiv(s4, s17, s15);
- __ Fdiv(d5, d31, d30);
- __ Fdiv(d6, d29, d31);
- __ Fdiv(d7, d26, d31);
- __ Fdiv(d8, d31, d27);
- __ Fdiv(d9, d31, d28);
- END();
-
- RUN();
-
- ASSERT_EQUAL_FP32(1.625, s0);
- ASSERT_EQUAL_FP32(1.0, s1);
- ASSERT_EQUAL_FP32(-0.0, s2);
- ASSERT_EQUAL_FP32(0.0, s3);
- ASSERT_EQUAL_FP32(-0.0, s4);
- ASSERT_EQUAL_FP64(-1.125, d5);
- ASSERT_EQUAL_FP64(0.0, d6);
- ASSERT_EQUAL_FP64(-0.0, d7);
+ __ Fdiv(s0, s17, s18);
+ __ Fdiv(s1, s18, s19);
+ __ Fdiv(s2, s14, s18);
+ __ Fdiv(s3, s18, s15);
+ __ Fdiv(s4, s18, s16);
+ __ Fdiv(s5, s15, s16);
+ __ Fdiv(s6, s14, s14);
+
+ __ Fdiv(d7, d31, d30);
+ __ Fdiv(d8, d29, d31);
+ __ Fdiv(d9, d26, d31);
+ __ Fdiv(d10, d31, d27);
+ __ Fdiv(d11, d31, d28);
+ __ Fdiv(d12, d28, d27);
+ __ Fdiv(d13, d29, d29);
+ END();
+
+ RUN();
+
+ ASSERT_EQUAL_FP32(1.625f, s0);
+ ASSERT_EQUAL_FP32(1.0f, s1);
+ ASSERT_EQUAL_FP32(-0.0f, s2);
+ ASSERT_EQUAL_FP32(0.0f, s3);
+ ASSERT_EQUAL_FP32(-0.0f, s4);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6);
+ ASSERT_EQUAL_FP64(-1.125, d7);
ASSERT_EQUAL_FP64(0.0, d8);
ASSERT_EQUAL_FP64(-0.0, d9);
+ ASSERT_EQUAL_FP64(0.0, d10);
+ ASSERT_EQUAL_FP64(-0.0, d11);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13);
TEARDOWN();
}
@@ -5324,16 +5425,15 @@ static float MinMaxHelper(float n,
float m,
bool min,
float quiet_nan_substitute = 0.0) {
- const uint64_t kFP32QuietNaNMask = 0x00400000UL;
uint32_t raw_n = float_to_rawbits(n);
uint32_t raw_m = float_to_rawbits(m);
- if (std::isnan(n) && ((raw_n & kFP32QuietNaNMask) == 0)) {
+ if (std::isnan(n) && ((raw_n & kSQuietNanMask) == 0)) {
// n is signalling NaN.
- return n;
- } else if (std::isnan(m) && ((raw_m & kFP32QuietNaNMask) == 0)) {
+ return rawbits_to_float(raw_n | kSQuietNanMask);
+ } else if (std::isnan(m) && ((raw_m & kSQuietNanMask) == 0)) {
// m is signalling NaN.
- return m;
+ return rawbits_to_float(raw_m | kSQuietNanMask);
} else if (quiet_nan_substitute == 0.0) {
if (std::isnan(n)) {
// n is quiet NaN.
@@ -5366,16 +5466,15 @@ static double MinMaxHelper(double n,
double m,
bool min,
double quiet_nan_substitute = 0.0) {
- const uint64_t kFP64QuietNaNMask = 0x0008000000000000UL;
uint64_t raw_n = double_to_rawbits(n);
uint64_t raw_m = double_to_rawbits(m);
- if (std::isnan(n) && ((raw_n & kFP64QuietNaNMask) == 0)) {
+ if (std::isnan(n) && ((raw_n & kDQuietNanMask) == 0)) {
// n is signalling NaN.
- return n;
- } else if (std::isnan(m) && ((raw_m & kFP64QuietNaNMask) == 0)) {
+ return rawbits_to_double(raw_n | kDQuietNanMask);
+ } else if (std::isnan(m) && ((raw_m & kDQuietNanMask) == 0)) {
// m is signalling NaN.
- return m;
+ return rawbits_to_double(raw_m | kDQuietNanMask);
} else if (quiet_nan_substitute == 0.0) {
if (std::isnan(n)) {
// n is quiet NaN.
@@ -5430,21 +5529,42 @@ static void FminFmaxDoubleHelper(double n, double m, double min, double max,
TEST(fmax_fmin_d) {
INIT_V8();
+ // Use non-standard NaNs to check that the payload bits are preserved.
+ double snan = rawbits_to_double(0x7ff5555512345678);
+ double qnan = rawbits_to_double(0x7ffaaaaa87654321);
+
+ double snan_processed = rawbits_to_double(0x7ffd555512345678);
+ double qnan_processed = qnan;
+
+ ASSERT(IsSignallingNaN(snan));
+ ASSERT(IsQuietNaN(qnan));
+ ASSERT(IsQuietNaN(snan_processed));
+ ASSERT(IsQuietNaN(qnan_processed));
+
// Bootstrap tests.
FminFmaxDoubleHelper(0, 0, 0, 0, 0, 0);
FminFmaxDoubleHelper(0, 1, 0, 1, 0, 1);
FminFmaxDoubleHelper(kFP64PositiveInfinity, kFP64NegativeInfinity,
kFP64NegativeInfinity, kFP64PositiveInfinity,
kFP64NegativeInfinity, kFP64PositiveInfinity);
- FminFmaxDoubleHelper(kFP64SignallingNaN, 0,
- kFP64SignallingNaN, kFP64SignallingNaN,
- kFP64SignallingNaN, kFP64SignallingNaN);
- FminFmaxDoubleHelper(kFP64QuietNaN, 0,
- kFP64QuietNaN, kFP64QuietNaN,
+ FminFmaxDoubleHelper(snan, 0,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
+ FminFmaxDoubleHelper(0, snan,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
+ FminFmaxDoubleHelper(qnan, 0,
+ qnan_processed, qnan_processed,
0, 0);
- FminFmaxDoubleHelper(kFP64QuietNaN, kFP64SignallingNaN,
- kFP64SignallingNaN, kFP64SignallingNaN,
- kFP64SignallingNaN, kFP64SignallingNaN);
+ FminFmaxDoubleHelper(0, qnan,
+ qnan_processed, qnan_processed,
+ 0, 0);
+ FminFmaxDoubleHelper(qnan, snan,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
+ FminFmaxDoubleHelper(snan, qnan,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
// Iterate over all combinations of inputs.
double inputs[] = { DBL_MAX, DBL_MIN, 1.0, 0.0,
@@ -5494,21 +5614,42 @@ static void FminFmaxFloatHelper(float n, float m, float min, float max,
TEST(fmax_fmin_s) {
INIT_V8();
+ // Use non-standard NaNs to check that the payload bits are preserved.
+ float snan = rawbits_to_float(0x7f951234);
+ float qnan = rawbits_to_float(0x7fea8765);
+
+ float snan_processed = rawbits_to_float(0x7fd51234);
+ float qnan_processed = qnan;
+
+ ASSERT(IsSignallingNaN(snan));
+ ASSERT(IsQuietNaN(qnan));
+ ASSERT(IsQuietNaN(snan_processed));
+ ASSERT(IsQuietNaN(qnan_processed));
+
// Bootstrap tests.
FminFmaxFloatHelper(0, 0, 0, 0, 0, 0);
FminFmaxFloatHelper(0, 1, 0, 1, 0, 1);
FminFmaxFloatHelper(kFP32PositiveInfinity, kFP32NegativeInfinity,
kFP32NegativeInfinity, kFP32PositiveInfinity,
kFP32NegativeInfinity, kFP32PositiveInfinity);
- FminFmaxFloatHelper(kFP32SignallingNaN, 0,
- kFP32SignallingNaN, kFP32SignallingNaN,
- kFP32SignallingNaN, kFP32SignallingNaN);
- FminFmaxFloatHelper(kFP32QuietNaN, 0,
- kFP32QuietNaN, kFP32QuietNaN,
+ FminFmaxFloatHelper(snan, 0,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
+ FminFmaxFloatHelper(0, snan,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
+ FminFmaxFloatHelper(qnan, 0,
+ qnan_processed, qnan_processed,
0, 0);
- FminFmaxFloatHelper(kFP32QuietNaN, kFP32SignallingNaN,
- kFP32SignallingNaN, kFP32SignallingNaN,
- kFP32SignallingNaN, kFP32SignallingNaN);
+ FminFmaxFloatHelper(0, qnan,
+ qnan_processed, qnan_processed,
+ 0, 0);
+ FminFmaxFloatHelper(qnan, snan,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
+ FminFmaxFloatHelper(snan, qnan,
+ snan_processed, snan_processed,
+ snan_processed, snan_processed);
// Iterate over all combinations of inputs.
float inputs[] = { FLT_MAX, FLT_MIN, 1.0, 0.0,
@@ -5809,12 +5950,14 @@ TEST(fsqrt) {
__ Fmov(s19, 65536.0);
__ Fmov(s20, -0.0);
__ Fmov(s21, kFP32PositiveInfinity);
- __ Fmov(d22, 0.0);
- __ Fmov(d23, 1.0);
- __ Fmov(d24, 0.25);
- __ Fmov(d25, 4294967296.0);
- __ Fmov(d26, -0.0);
- __ Fmov(d27, kFP64PositiveInfinity);
+ __ Fmov(s22, -1.0);
+ __ Fmov(d23, 0.0);
+ __ Fmov(d24, 1.0);
+ __ Fmov(d25, 0.25);
+ __ Fmov(d26, 4294967296.0);
+ __ Fmov(d27, -0.0);
+ __ Fmov(d28, kFP64PositiveInfinity);
+ __ Fmov(d29, -1.0);
__ Fsqrt(s0, s16);
__ Fsqrt(s1, s17);
@@ -5822,12 +5965,14 @@ TEST(fsqrt) {
__ Fsqrt(s3, s19);
__ Fsqrt(s4, s20);
__ Fsqrt(s5, s21);
- __ Fsqrt(d6, d22);
+ __ Fsqrt(s6, s22);
__ Fsqrt(d7, d23);
__ Fsqrt(d8, d24);
__ Fsqrt(d9, d25);
__ Fsqrt(d10, d26);
__ Fsqrt(d11, d27);
+ __ Fsqrt(d12, d28);
+ __ Fsqrt(d13, d29);
END();
RUN();
@@ -5838,12 +5983,14 @@ TEST(fsqrt) {
ASSERT_EQUAL_FP32(256.0, s3);
ASSERT_EQUAL_FP32(-0.0, s4);
ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5);
- ASSERT_EQUAL_FP64(0.0, d6);
- ASSERT_EQUAL_FP64(1.0, d7);
- ASSERT_EQUAL_FP64(0.5, d8);
- ASSERT_EQUAL_FP64(65536.0, d9);
- ASSERT_EQUAL_FP64(-0.0, d10);
- ASSERT_EQUAL_FP64(kFP32PositiveInfinity, d11);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6);
+ ASSERT_EQUAL_FP64(0.0, d7);
+ ASSERT_EQUAL_FP64(1.0, d8);
+ ASSERT_EQUAL_FP64(0.5, d9);
+ ASSERT_EQUAL_FP64(65536.0, d10);
+ ASSERT_EQUAL_FP64(-0.0, d11);
+ ASSERT_EQUAL_FP64(kFP32PositiveInfinity, d12);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13);
TEARDOWN();
}
@@ -9853,6 +10000,558 @@ TEST(barriers) {
}
+TEST(process_nan_double) {
+ INIT_V8();
+ // Make sure that NaN propagation works correctly.
+ double sn = rawbits_to_double(0x7ff5555511111111);
+ double qn = rawbits_to_double(0x7ffaaaaa11111111);
+ ASSERT(IsSignallingNaN(sn));
+ ASSERT(IsQuietNaN(qn));
+
+ // The input NaNs after passing through ProcessNaN.
+ double sn_proc = rawbits_to_double(0x7ffd555511111111);
+ double qn_proc = qn;
+ ASSERT(IsQuietNaN(sn_proc));
+ ASSERT(IsQuietNaN(qn_proc));
+
+ SETUP();
+ START();
+
+ // Execute a number of instructions which all use ProcessNaN, and check that
+ // they all handle the NaN correctly.
+ __ Fmov(d0, sn);
+ __ Fmov(d10, qn);
+
+ // Operations that always propagate NaNs unchanged, even signalling NaNs.
+ // - Signalling NaN
+ __ Fmov(d1, d0);
+ __ Fabs(d2, d0);
+ __ Fneg(d3, d0);
+ // - Quiet NaN
+ __ Fmov(d11, d10);
+ __ Fabs(d12, d10);
+ __ Fneg(d13, d10);
+
+ // Operations that use ProcessNaN.
+ // - Signalling NaN
+ __ Fsqrt(d4, d0);
+ __ Frinta(d5, d0);
+ __ Frintn(d6, d0);
+ __ Frintz(d7, d0);
+ // - Quiet NaN
+ __ Fsqrt(d14, d10);
+ __ Frinta(d15, d10);
+ __ Frintn(d16, d10);
+ __ Frintz(d17, d10);
+
+ // The behaviour of fcvt is checked in TEST(fcvt_sd).
+
+ END();
+ RUN();
+
+ uint64_t qn_raw = double_to_rawbits(qn);
+ uint64_t sn_raw = double_to_rawbits(sn);
+
+ // - Signalling NaN
+ ASSERT_EQUAL_FP64(sn, d1);
+ ASSERT_EQUAL_FP64(rawbits_to_double(sn_raw & ~kDSignMask), d2);
+ ASSERT_EQUAL_FP64(rawbits_to_double(sn_raw ^ kDSignMask), d3);
+ // - Quiet NaN
+ ASSERT_EQUAL_FP64(qn, d11);
+ ASSERT_EQUAL_FP64(rawbits_to_double(qn_raw & ~kDSignMask), d12);
+ ASSERT_EQUAL_FP64(rawbits_to_double(qn_raw ^ kDSignMask), d13);
+
+ // - Signalling NaN
+ ASSERT_EQUAL_FP64(sn_proc, d4);
+ ASSERT_EQUAL_FP64(sn_proc, d5);
+ ASSERT_EQUAL_FP64(sn_proc, d6);
+ ASSERT_EQUAL_FP64(sn_proc, d7);
+ // - Quiet NaN
+ ASSERT_EQUAL_FP64(qn_proc, d14);
+ ASSERT_EQUAL_FP64(qn_proc, d15);
+ ASSERT_EQUAL_FP64(qn_proc, d16);
+ ASSERT_EQUAL_FP64(qn_proc, d17);
+
+ TEARDOWN();
+}
+
+
+TEST(process_nan_float) {
+ INIT_V8();
+ // Make sure that NaN propagation works correctly.
+ float sn = rawbits_to_float(0x7f951111);
+ float qn = rawbits_to_float(0x7fea1111);
+ ASSERT(IsSignallingNaN(sn));
+ ASSERT(IsQuietNaN(qn));
+
+ // The input NaNs after passing through ProcessNaN.
+ float sn_proc = rawbits_to_float(0x7fd51111);
+ float qn_proc = qn;
+ ASSERT(IsQuietNaN(sn_proc));
+ ASSERT(IsQuietNaN(qn_proc));
+
+ SETUP();
+ START();
+
+ // Execute a number of instructions which all use ProcessNaN, and check that
+ // they all handle the NaN correctly.
+ __ Fmov(s0, sn);
+ __ Fmov(s10, qn);
+
+ // Operations that always propagate NaNs unchanged, even signalling NaNs.
+ // - Signalling NaN
+ __ Fmov(s1, s0);
+ __ Fabs(s2, s0);
+ __ Fneg(s3, s0);
+ // - Quiet NaN
+ __ Fmov(s11, s10);
+ __ Fabs(s12, s10);
+ __ Fneg(s13, s10);
+
+ // Operations that use ProcessNaN.
+ // - Signalling NaN
+ __ Fsqrt(s4, s0);
+ __ Frinta(s5, s0);
+ __ Frintn(s6, s0);
+ __ Frintz(s7, s0);
+ // - Quiet NaN
+ __ Fsqrt(s14, s10);
+ __ Frinta(s15, s10);
+ __ Frintn(s16, s10);
+ __ Frintz(s17, s10);
+
+ // The behaviour of fcvt is checked in TEST(fcvt_sd).
+
+ END();
+ RUN();
+
+ uint32_t qn_raw = float_to_rawbits(qn);
+ uint32_t sn_raw = float_to_rawbits(sn);
+
+ // - Signalling NaN
+ ASSERT_EQUAL_FP32(sn, s1);
+ ASSERT_EQUAL_FP32(rawbits_to_float(sn_raw & ~kSSignMask), s2);
+ ASSERT_EQUAL_FP32(rawbits_to_float(sn_raw ^ kSSignMask), s3);
+ // - Quiet NaN
+ ASSERT_EQUAL_FP32(qn, s11);
+ ASSERT_EQUAL_FP32(rawbits_to_float(qn_raw & ~kSSignMask), s12);
+ ASSERT_EQUAL_FP32(rawbits_to_float(qn_raw ^ kSSignMask), s13);
+
+ // - Signalling NaN
+ ASSERT_EQUAL_FP32(sn_proc, s4);
+ ASSERT_EQUAL_FP32(sn_proc, s5);
+ ASSERT_EQUAL_FP32(sn_proc, s6);
+ ASSERT_EQUAL_FP32(sn_proc, s7);
+ // - Quiet NaN
+ ASSERT_EQUAL_FP32(qn_proc, s14);
+ ASSERT_EQUAL_FP32(qn_proc, s15);
+ ASSERT_EQUAL_FP32(qn_proc, s16);
+ ASSERT_EQUAL_FP32(qn_proc, s17);
+
+ TEARDOWN();
+}
+
+
+static void ProcessNaNsHelper(double n, double m, double expected) {
+ ASSERT(isnan(n) || isnan(m));
+ ASSERT(isnan(expected));
+
+ SETUP();
+ START();
+
+ // Execute a number of instructions which all use ProcessNaNs, and check that
+ // they all propagate NaNs correctly.
+ __ Fmov(d0, n);
+ __ Fmov(d1, m);
+
+ __ Fadd(d2, d0, d1);
+ __ Fsub(d3, d0, d1);
+ __ Fmul(d4, d0, d1);
+ __ Fdiv(d5, d0, d1);
+ __ Fmax(d6, d0, d1);
+ __ Fmin(d7, d0, d1);
+
+ END();
+ RUN();
+
+ ASSERT_EQUAL_FP64(expected, d2);
+ ASSERT_EQUAL_FP64(expected, d3);
+ ASSERT_EQUAL_FP64(expected, d4);
+ ASSERT_EQUAL_FP64(expected, d5);
+ ASSERT_EQUAL_FP64(expected, d6);
+ ASSERT_EQUAL_FP64(expected, d7);
+
+ TEARDOWN();
+}
+
+
+TEST(process_nans_double) {
+ INIT_V8();
+ // Make sure that NaN propagation works correctly.
+ double sn = rawbits_to_double(0x7ff5555511111111);
+ double sm = rawbits_to_double(0x7ff5555522222222);
+ double qn = rawbits_to_double(0x7ffaaaaa11111111);
+ double qm = rawbits_to_double(0x7ffaaaaa22222222);
+ ASSERT(IsSignallingNaN(sn));
+ ASSERT(IsSignallingNaN(sm));
+ ASSERT(IsQuietNaN(qn));
+ ASSERT(IsQuietNaN(qm));
+
+ // The input NaNs after passing through ProcessNaN.
+ double sn_proc = rawbits_to_double(0x7ffd555511111111);
+ double sm_proc = rawbits_to_double(0x7ffd555522222222);
+ double qn_proc = qn;
+ double qm_proc = qm;
+ ASSERT(IsQuietNaN(sn_proc));
+ ASSERT(IsQuietNaN(sm_proc));
+ ASSERT(IsQuietNaN(qn_proc));
+ ASSERT(IsQuietNaN(qm_proc));
+
+ // Quiet NaNs are propagated.
+ ProcessNaNsHelper(qn, 0, qn_proc);
+ ProcessNaNsHelper(0, qm, qm_proc);
+ ProcessNaNsHelper(qn, qm, qn_proc);
+
+ // Signalling NaNs are propagated, and made quiet.
+ ProcessNaNsHelper(sn, 0, sn_proc);
+ ProcessNaNsHelper(0, sm, sm_proc);
+ ProcessNaNsHelper(sn, sm, sn_proc);
+
+ // Signalling NaNs take precedence over quiet NaNs.
+ ProcessNaNsHelper(sn, qm, sn_proc);
+ ProcessNaNsHelper(qn, sm, sm_proc);
+ ProcessNaNsHelper(sn, sm, sn_proc);
+}
+
+
+static void ProcessNaNsHelper(float n, float m, float expected) {
+ ASSERT(isnan(n) || isnan(m));
+ ASSERT(isnan(expected));
+
+ SETUP();
+ START();
+
+ // Execute a number of instructions which all use ProcessNaNs, and check that
+ // they all propagate NaNs correctly.
+ __ Fmov(s0, n);
+ __ Fmov(s1, m);
+
+ __ Fadd(s2, s0, s1);
+ __ Fsub(s3, s0, s1);
+ __ Fmul(s4, s0, s1);
+ __ Fdiv(s5, s0, s1);
+ __ Fmax(s6, s0, s1);
+ __ Fmin(s7, s0, s1);
+
+ END();
+ RUN();
+
+ ASSERT_EQUAL_FP32(expected, s2);
+ ASSERT_EQUAL_FP32(expected, s3);
+ ASSERT_EQUAL_FP32(expected, s4);
+ ASSERT_EQUAL_FP32(expected, s5);
+ ASSERT_EQUAL_FP32(expected, s6);
+ ASSERT_EQUAL_FP32(expected, s7);
+
+ TEARDOWN();
+}
+
+
+TEST(process_nans_float) {
+ INIT_V8();
+ // Make sure that NaN propagation works correctly.
+ float sn = rawbits_to_float(0x7f951111);
+ float sm = rawbits_to_float(0x7f952222);
+ float qn = rawbits_to_float(0x7fea1111);
+ float qm = rawbits_to_float(0x7fea2222);
+ ASSERT(IsSignallingNaN(sn));
+ ASSERT(IsSignallingNaN(sm));
+ ASSERT(IsQuietNaN(qn));
+ ASSERT(IsQuietNaN(qm));
+
+ // The input NaNs after passing through ProcessNaN.
+ float sn_proc = rawbits_to_float(0x7fd51111);
+ float sm_proc = rawbits_to_float(0x7fd52222);
+ float qn_proc = qn;
+ float qm_proc = qm;
+ ASSERT(IsQuietNaN(sn_proc));
+ ASSERT(IsQuietNaN(sm_proc));
+ ASSERT(IsQuietNaN(qn_proc));
+ ASSERT(IsQuietNaN(qm_proc));
+
+ // Quiet NaNs are propagated.
+ ProcessNaNsHelper(qn, 0, qn_proc);
+ ProcessNaNsHelper(0, qm, qm_proc);
+ ProcessNaNsHelper(qn, qm, qn_proc);
+
+ // Signalling NaNs are propagated, and made quiet.
+ ProcessNaNsHelper(sn, 0, sn_proc);
+ ProcessNaNsHelper(0, sm, sm_proc);
+ ProcessNaNsHelper(sn, sm, sn_proc);
+
+ // Signalling NaNs take precedence over quiet NaNs.
+ ProcessNaNsHelper(sn, qm, sn_proc);
+ ProcessNaNsHelper(qn, sm, sm_proc);
+ ProcessNaNsHelper(sn, sm, sn_proc);
+}
+
+
+static void DefaultNaNHelper(float n, float m, float a) {
+ ASSERT(isnan(n) || isnan(m) || isnan(a));
+
+ bool test_1op = isnan(n);
+ bool test_2op = isnan(n) || isnan(m);
+
+ SETUP();
+ START();
+
+ // Enable Default-NaN mode in the FPCR.
+ __ Mrs(x0, FPCR);
+ __ Orr(x1, x0, DN_mask);
+ __ Msr(FPCR, x1);
+
+ // Execute a number of instructions which all use ProcessNaNs, and check that
+ // they all produce the default NaN.
+ __ Fmov(s0, n);
+ __ Fmov(s1, m);
+ __ Fmov(s2, a);
+
+ if (test_1op) {
+ // Operations that always propagate NaNs unchanged, even signalling NaNs.
+ __ Fmov(s10, s0);
+ __ Fabs(s11, s0);
+ __ Fneg(s12, s0);
+
+ // Operations that use ProcessNaN.
+ __ Fsqrt(s13, s0);
+ __ Frinta(s14, s0);
+ __ Frintn(s15, s0);
+ __ Frintz(s16, s0);
+
+ // Fcvt usually has special NaN handling, but it respects default-NaN mode.
+ __ Fcvt(d17, s0);
+ }
+
+ if (test_2op) {
+ __ Fadd(s18, s0, s1);
+ __ Fsub(s19, s0, s1);
+ __ Fmul(s20, s0, s1);
+ __ Fdiv(s21, s0, s1);
+ __ Fmax(s22, s0, s1);
+ __ Fmin(s23, s0, s1);
+ }
+
+ __ Fmadd(s24, s0, s1, s2);
+ __ Fmsub(s25, s0, s1, s2);
+ __ Fnmadd(s26, s0, s1, s2);
+ __ Fnmsub(s27, s0, s1, s2);
+
+ // Restore FPCR.
+ __ Msr(FPCR, x0);
+
+ END();
+ RUN();
+
+ if (test_1op) {
+ uint32_t n_raw = float_to_rawbits(n);
+ ASSERT_EQUAL_FP32(n, s10);
+ ASSERT_EQUAL_FP32(rawbits_to_float(n_raw & ~kSSignMask), s11);
+ ASSERT_EQUAL_FP32(rawbits_to_float(n_raw ^ kSSignMask), s12);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s13);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s14);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s15);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s16);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d17);
+ }
+
+ if (test_2op) {
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s18);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s19);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s20);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s21);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s22);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s23);
+ }
+
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s24);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s25);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s26);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s27);
+
+ TEARDOWN();
+}
+
+
+TEST(default_nan_float) {
+ INIT_V8();
+ float sn = rawbits_to_float(0x7f951111);
+ float sm = rawbits_to_float(0x7f952222);
+ float sa = rawbits_to_float(0x7f95aaaa);
+ float qn = rawbits_to_float(0x7fea1111);
+ float qm = rawbits_to_float(0x7fea2222);
+ float qa = rawbits_to_float(0x7feaaaaa);
+ ASSERT(IsSignallingNaN(sn));
+ ASSERT(IsSignallingNaN(sm));
+ ASSERT(IsSignallingNaN(sa));
+ ASSERT(IsQuietNaN(qn));
+ ASSERT(IsQuietNaN(qm));
+ ASSERT(IsQuietNaN(qa));
+
+ // - Signalling NaNs
+ DefaultNaNHelper(sn, 0.0f, 0.0f);
+ DefaultNaNHelper(0.0f, sm, 0.0f);
+ DefaultNaNHelper(0.0f, 0.0f, sa);
+ DefaultNaNHelper(sn, sm, 0.0f);
+ DefaultNaNHelper(0.0f, sm, sa);
+ DefaultNaNHelper(sn, 0.0f, sa);
+ DefaultNaNHelper(sn, sm, sa);
+ // - Quiet NaNs
+ DefaultNaNHelper(qn, 0.0f, 0.0f);
+ DefaultNaNHelper(0.0f, qm, 0.0f);
+ DefaultNaNHelper(0.0f, 0.0f, qa);
+ DefaultNaNHelper(qn, qm, 0.0f);
+ DefaultNaNHelper(0.0f, qm, qa);
+ DefaultNaNHelper(qn, 0.0f, qa);
+ DefaultNaNHelper(qn, qm, qa);
+ // - Mixed NaNs
+ DefaultNaNHelper(qn, sm, sa);
+ DefaultNaNHelper(sn, qm, sa);
+ DefaultNaNHelper(sn, sm, qa);
+ DefaultNaNHelper(qn, qm, sa);
+ DefaultNaNHelper(sn, qm, qa);
+ DefaultNaNHelper(qn, sm, qa);
+ DefaultNaNHelper(qn, qm, qa);
+}
+
+
+static void DefaultNaNHelper(double n, double m, double a) {
+ ASSERT(isnan(n) || isnan(m) || isnan(a));
+
+ bool test_1op = isnan(n);
+ bool test_2op = isnan(n) || isnan(m);
+
+ SETUP();
+ START();
+
+ // Enable Default-NaN mode in the FPCR.
+ __ Mrs(x0, FPCR);
+ __ Orr(x1, x0, DN_mask);
+ __ Msr(FPCR, x1);
+
+ // Execute a number of instructions which all use ProcessNaNs, and check that
+ // they all produce the default NaN.
+ __ Fmov(d0, n);
+ __ Fmov(d1, m);
+ __ Fmov(d2, a);
+
+ if (test_1op) {
+ // Operations that always propagate NaNs unchanged, even signalling NaNs.
+ __ Fmov(d10, d0);
+ __ Fabs(d11, d0);
+ __ Fneg(d12, d0);
+
+ // Operations that use ProcessNaN.
+ __ Fsqrt(d13, d0);
+ __ Frinta(d14, d0);
+ __ Frintn(d15, d0);
+ __ Frintz(d16, d0);
+
+ // Fcvt usually has special NaN handling, but it respects default-NaN mode.
+ __ Fcvt(s17, d0);
+ }
+
+ if (test_2op) {
+ __ Fadd(d18, d0, d1);
+ __ Fsub(d19, d0, d1);
+ __ Fmul(d20, d0, d1);
+ __ Fdiv(d21, d0, d1);
+ __ Fmax(d22, d0, d1);
+ __ Fmin(d23, d0, d1);
+ }
+
+ __ Fmadd(d24, d0, d1, d2);
+ __ Fmsub(d25, d0, d1, d2);
+ __ Fnmadd(d26, d0, d1, d2);
+ __ Fnmsub(d27, d0, d1, d2);
+
+ // Restore FPCR.
+ __ Msr(FPCR, x0);
+
+ END();
+ RUN();
+
+ if (test_1op) {
+ uint64_t n_raw = double_to_rawbits(n);
+ ASSERT_EQUAL_FP64(n, d10);
+ ASSERT_EQUAL_FP64(rawbits_to_double(n_raw & ~kDSignMask), d11);
+ ASSERT_EQUAL_FP64(rawbits_to_double(n_raw ^ kDSignMask), d12);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d14);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d15);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d16);
+ ASSERT_EQUAL_FP32(kFP32DefaultNaN, s17);
+ }
+
+ if (test_2op) {
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d18);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d19);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d20);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d21);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d22);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d23);
+ }
+
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d24);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d25);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d26);
+ ASSERT_EQUAL_FP64(kFP64DefaultNaN, d27);
+
+ TEARDOWN();
+}
+
+
+TEST(default_nan_double) {
+ INIT_V8();
+ double sn = rawbits_to_double(0x7ff5555511111111);
+ double sm = rawbits_to_double(0x7ff5555522222222);
+ double sa = rawbits_to_double(0x7ff55555aaaaaaaa);
+ double qn = rawbits_to_double(0x7ffaaaaa11111111);
+ double qm = rawbits_to_double(0x7ffaaaaa22222222);
+ double qa = rawbits_to_double(0x7ffaaaaaaaaaaaaa);
+ ASSERT(IsSignallingNaN(sn));
+ ASSERT(IsSignallingNaN(sm));
+ ASSERT(IsSignallingNaN(sa));
+ ASSERT(IsQuietNaN(qn));
+ ASSERT(IsQuietNaN(qm));
+ ASSERT(IsQuietNaN(qa));
+
+ // - Signalling NaNs
+ DefaultNaNHelper(sn, 0.0, 0.0);
+ DefaultNaNHelper(0.0, sm, 0.0);
+ DefaultNaNHelper(0.0, 0.0, sa);
+ DefaultNaNHelper(sn, sm, 0.0);
+ DefaultNaNHelper(0.0, sm, sa);
+ DefaultNaNHelper(sn, 0.0, sa);
+ DefaultNaNHelper(sn, sm, sa);
+ // - Quiet NaNs
+ DefaultNaNHelper(qn, 0.0, 0.0);
+ DefaultNaNHelper(0.0, qm, 0.0);
+ DefaultNaNHelper(0.0, 0.0, qa);
+ DefaultNaNHelper(qn, qm, 0.0);
+ DefaultNaNHelper(0.0, qm, qa);
+ DefaultNaNHelper(qn, 0.0, qa);
+ DefaultNaNHelper(qn, qm, qa);
+ // - Mixed NaNs
+ DefaultNaNHelper(qn, sm, sa);
+ DefaultNaNHelper(sn, qm, sa);
+ DefaultNaNHelper(sn, sm, qa);
+ DefaultNaNHelper(qn, qm, sa);
+ DefaultNaNHelper(sn, qm, qa);
+ DefaultNaNHelper(qn, sm, qa);
+ DefaultNaNHelper(qn, qm, qa);
+}
+
+
TEST(call_no_relocation) {
Address call_start;
Address return_address;
« no previous file with comments | « src/a64/utils-a64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698