// Copyright 2019, VIXL authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ARM Limited nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include #include #include #include #include "test-runner.h" #include "test-utils.h" #include "aarch64/test-utils-aarch64.h" #include "aarch64/cpu-aarch64.h" #include "aarch64/disasm-aarch64.h" #include "aarch64/macro-assembler-aarch64.h" #include "aarch64/simulator-aarch64.h" #include "test-assembler-aarch64.h" namespace vixl { namespace aarch64 { TEST(load_store_float) { SETUP_WITH_FEATURES(CPUFeatures::kFP); float src[3] = {1.0, 2.0, 3.0}; float dst[3] = {0.0, 0.0, 0.0}; uintptr_t src_base = reinterpret_cast(src); uintptr_t dst_base = reinterpret_cast(dst); START(); __ Mov(x17, src_base); __ Mov(x18, dst_base); __ Mov(x19, src_base); __ Mov(x20, dst_base); __ Mov(x21, src_base); __ Mov(x22, dst_base); __ Ldr(s0, MemOperand(x17, sizeof(src[0]))); __ Str(s0, MemOperand(x18, sizeof(dst[0]), PostIndex)); __ Ldr(s1, MemOperand(x19, sizeof(src[0]), PostIndex)); __ Str(s1, MemOperand(x20, 2 * sizeof(dst[0]), PreIndex)); __ Ldr(s2, MemOperand(x21, 2 * sizeof(src[0]), PreIndex)); __ Str(s2, MemOperand(x22, sizeof(dst[0]))); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(2.0, s0); ASSERT_EQUAL_FP32(2.0, dst[0]); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(1.0, dst[2]); ASSERT_EQUAL_FP32(3.0, s2); ASSERT_EQUAL_FP32(3.0, dst[1]); ASSERT_EQUAL_64(src_base, x17); ASSERT_EQUAL_64(dst_base + sizeof(dst[0]), x18); ASSERT_EQUAL_64(src_base + sizeof(src[0]), x19); ASSERT_EQUAL_64(dst_base + 2 * sizeof(dst[0]), x20); ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x21); ASSERT_EQUAL_64(dst_base, x22); } } TEST(load_store_double) { SETUP_WITH_FEATURES(CPUFeatures::kFP); double src[3] = {1.0, 2.0, 3.0}; double dst[3] = {0.0, 0.0, 0.0}; uintptr_t src_base = reinterpret_cast(src); uintptr_t dst_base = reinterpret_cast(dst); START(); __ Mov(x17, src_base); __ Mov(x18, dst_base); __ Mov(x19, src_base); __ Mov(x20, dst_base); __ Mov(x21, src_base); __ Mov(x22, dst_base); __ Ldr(d0, MemOperand(x17, sizeof(src[0]))); __ Str(d0, MemOperand(x18, sizeof(dst[0]), PostIndex)); __ Ldr(d1, MemOperand(x19, sizeof(src[0]), PostIndex)); __ Str(d1, MemOperand(x20, 2 * sizeof(dst[0]), PreIndex)); __ Ldr(d2, MemOperand(x21, 2 * sizeof(src[0]), PreIndex)); __ Str(d2, MemOperand(x22, sizeof(dst[0]))); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(2.0, d0); ASSERT_EQUAL_FP64(2.0, dst[0]); ASSERT_EQUAL_FP64(1.0, d1); ASSERT_EQUAL_FP64(1.0, dst[2]); ASSERT_EQUAL_FP64(3.0, d2); ASSERT_EQUAL_FP64(3.0, dst[1]); ASSERT_EQUAL_64(src_base, x17); ASSERT_EQUAL_64(dst_base + sizeof(dst[0]), x18); ASSERT_EQUAL_64(src_base + sizeof(src[0]), x19); ASSERT_EQUAL_64(dst_base + 2 * sizeof(dst[0]), x20); ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x21); ASSERT_EQUAL_64(dst_base, x22); } } TEST(ldp_stp_float) { SETUP_WITH_FEATURES(CPUFeatures::kFP); float src[2] = {1.0, 2.0}; float dst[3] = {0.0, 0.0, 0.0}; uintptr_t src_base = reinterpret_cast(src); uintptr_t dst_base = reinterpret_cast(dst); START(); __ Mov(x16, src_base); __ Mov(x17, dst_base); __ Ldp(s31, s0, MemOperand(x16, 2 * sizeof(src[0]), PostIndex)); __ Stp(s0, s31, MemOperand(x17, sizeof(dst[1]), PreIndex)); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s31); ASSERT_EQUAL_FP32(2.0, s0); ASSERT_EQUAL_FP32(0.0, dst[0]); ASSERT_EQUAL_FP32(2.0, dst[1]); ASSERT_EQUAL_FP32(1.0, dst[2]); ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x16); ASSERT_EQUAL_64(dst_base + sizeof(dst[1]), x17); } } TEST(ldp_stp_double) { SETUP_WITH_FEATURES(CPUFeatures::kFP); double src[2] = {1.0, 2.0}; double dst[3] = {0.0, 0.0, 0.0}; uintptr_t src_base = reinterpret_cast(src); uintptr_t dst_base = reinterpret_cast(dst); START(); __ Mov(x16, src_base); __ Mov(x17, dst_base); __ Ldp(d31, d0, MemOperand(x16, 2 * sizeof(src[0]), PostIndex)); __ Stp(d0, d31, MemOperand(x17, sizeof(dst[1]), PreIndex)); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.0, d31); ASSERT_EQUAL_FP64(2.0, d0); ASSERT_EQUAL_FP64(0.0, dst[0]); ASSERT_EQUAL_FP64(2.0, dst[1]); ASSERT_EQUAL_FP64(1.0, dst[2]); ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x16); ASSERT_EQUAL_64(dst_base + sizeof(dst[1]), x17); } } TEST(ldnp_stnp_offset_float) { SETUP_WITH_FEATURES(CPUFeatures::kFP); float src[3] = {1.2, 2.3, 3.4}; float dst[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; uintptr_t src_base = reinterpret_cast(src); uintptr_t dst_base = reinterpret_cast(dst); START(); __ Mov(x16, src_base); __ Mov(x17, dst_base); __ Mov(x18, src_base + 12); __ Mov(x19, dst_base + 24); // Ensure address set up has happened before executing non-temporal ops. __ Dmb(InnerShareable, BarrierAll); __ Ldnp(s0, s1, MemOperand(x16)); __ Ldnp(s2, s3, MemOperand(x16, 4)); __ Ldnp(s5, s4, MemOperand(x18, -8)); __ Stnp(s1, s0, MemOperand(x17)); __ Stnp(s3, s2, MemOperand(x17, 8)); __ Stnp(s4, s5, MemOperand(x19, -8)); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.2, s0); ASSERT_EQUAL_FP32(2.3, s1); ASSERT_EQUAL_FP32(2.3, dst[0]); ASSERT_EQUAL_FP32(1.2, dst[1]); ASSERT_EQUAL_FP32(2.3, s2); ASSERT_EQUAL_FP32(3.4, s3); ASSERT_EQUAL_FP32(3.4, dst[2]); ASSERT_EQUAL_FP32(2.3, dst[3]); ASSERT_EQUAL_FP32(3.4, s4); ASSERT_EQUAL_FP32(2.3, s5); ASSERT_EQUAL_FP32(3.4, dst[4]); ASSERT_EQUAL_FP32(2.3, dst[5]); ASSERT_EQUAL_64(src_base, x16); ASSERT_EQUAL_64(dst_base, x17); ASSERT_EQUAL_64(src_base + 12, x18); ASSERT_EQUAL_64(dst_base + 24, x19); } } TEST(ldnp_stnp_offset_double) { SETUP_WITH_FEATURES(CPUFeatures::kFP); double src[3] = {1.2, 2.3, 3.4}; double dst[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; uintptr_t src_base = reinterpret_cast(src); uintptr_t dst_base = reinterpret_cast(dst); START(); __ Mov(x16, src_base); __ Mov(x17, dst_base); __ Mov(x18, src_base + 24); __ Mov(x19, dst_base + 48); // Ensure address set up has happened before executing non-temporal ops. __ Dmb(InnerShareable, BarrierAll); __ Ldnp(d0, d1, MemOperand(x16)); __ Ldnp(d2, d3, MemOperand(x16, 8)); __ Ldnp(d5, d4, MemOperand(x18, -16)); __ Stnp(d1, d0, MemOperand(x17)); __ Stnp(d3, d2, MemOperand(x17, 16)); __ Stnp(d4, d5, MemOperand(x19, -16)); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.2, d0); ASSERT_EQUAL_FP64(2.3, d1); ASSERT_EQUAL_FP64(2.3, dst[0]); ASSERT_EQUAL_FP64(1.2, dst[1]); ASSERT_EQUAL_FP64(2.3, d2); ASSERT_EQUAL_FP64(3.4, d3); ASSERT_EQUAL_FP64(3.4, dst[2]); ASSERT_EQUAL_FP64(2.3, dst[3]); ASSERT_EQUAL_FP64(3.4, d4); ASSERT_EQUAL_FP64(2.3, d5); ASSERT_EQUAL_FP64(3.4, dst[4]); ASSERT_EQUAL_FP64(2.3, dst[5]); ASSERT_EQUAL_64(src_base, x16); ASSERT_EQUAL_64(dst_base, x17); ASSERT_EQUAL_64(src_base + 24, x18); ASSERT_EQUAL_64(dst_base + 48, x19); } } template void LoadFPValueHelper(T values[], int card) { SETUP_WITH_FEATURES(CPUFeatures::kFP); const bool is_32bits = (sizeof(T) == 4); const VRegister& fp_tgt = is_32bits ? VRegister(s2) : VRegister(d2); const Register& tgt1 = is_32bits ? Register(w1) : Register(x1); const Register& tgt2 = is_32bits ? Register(w2) : Register(x2); START(); __ Mov(x0, 0); // If one of the values differ then x0 will be one. for (int i = 0; i < card; ++i) { __ Mov(tgt1, is_32bits ? FloatToRawbits(values[i]) : DoubleToRawbits(values[i])); __ Ldr(fp_tgt, values[i]); __ Fmov(tgt2, fp_tgt); __ Cmp(tgt1, tgt2); __ Cset(x0, ne); } END(); if (CAN_RUN()) { RUN(); // If one of the values differs, the trace can be used to identify which // one. ASSERT_EQUAL_64(0, x0); } } TEST(ldr_literal_values_d) { static const double kValues[] = {-0.0, 0.0, -1.0, 1.0, -1e10, 1e10}; LoadFPValueHelper(kValues, sizeof(kValues) / sizeof(kValues[0])); } TEST(ldr_literal_values_s) { static const float kValues[] = {-0.0, 0.0, -1.0, 1.0, -1e10, 1e10}; LoadFPValueHelper(kValues, sizeof(kValues) / sizeof(kValues[0])); } TEST(fmov_imm) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(s1, 255.0); __ Fmov(d2, 12.34567); __ Fmov(s3, 0.0); __ Fmov(d4, 0.0); __ Fmov(s5, kFP32PositiveInfinity); __ Fmov(d6, kFP64NegativeInfinity); __ Fmov(h7, RawbitsToFloat16(0x6400U)); __ Fmov(h8, kFP16PositiveInfinity); __ Fmov(s11, 1.0); __ Fmov(h12, RawbitsToFloat16(0x7BFF)); __ Fmov(h13, RawbitsToFloat16(0x57F2)); __ Fmov(d22, -13.0); __ Fmov(h23, RawbitsToFloat16(0xC500U)); __ Fmov(h24, Float16(-5.0)); __ Fmov(h25, Float16(2049.0)); __ Fmov(h21, RawbitsToFloat16(0x6404U)); __ Fmov(h26, RawbitsToFloat16(0x0U)); __ Fmov(h27, RawbitsToFloat16(0x7e00U)); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(255.0, s1); ASSERT_EQUAL_FP64(12.34567, d2); ASSERT_EQUAL_FP32(0.0, s3); ASSERT_EQUAL_FP64(0.0, d4); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d6); ASSERT_EQUAL_FP16(RawbitsToFloat16(0x6400U), h7); ASSERT_EQUAL_FP16(kFP16PositiveInfinity, h8); ASSERT_EQUAL_FP32(1.0, s11); ASSERT_EQUAL_FP16(RawbitsToFloat16(0x7BFF), h12); ASSERT_EQUAL_FP16(RawbitsToFloat16(0x57F2U), h13); ASSERT_EQUAL_FP16(RawbitsToFloat16(0x6404), h21); ASSERT_EQUAL_FP64(-13.0, d22); ASSERT_EQUAL_FP16(Float16(-5.0), h23); ASSERT_EQUAL_FP16(RawbitsToFloat16(0xC500), h24); // 2049 is unpresentable. ASSERT_EQUAL_FP16(RawbitsToFloat16(0x6800), h25); ASSERT_EQUAL_FP16(kFP16PositiveZero, h26); // NaN check. ASSERT_EQUAL_FP16(RawbitsToFloat16(0x7e00), h27); } } TEST(fmov_reg) { SETUP_WITH_FEATURES(CPUFeatures::kNEON, CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h3, RawbitsToFloat16(0xCA80U)); __ Fmov(h7, h3); __ Fmov(h8, -5.0); __ Fmov(w3, h8); __ Fmov(h9, w3); __ Fmov(h8, Float16(1024.0)); __ Fmov(x4, h8); __ Fmov(h10, x4); __ Fmov(s20, 1.0); __ Fmov(w10, s20); __ Fmov(s30, w10); __ Fmov(s5, s20); __ Fmov(d1, -13.0); __ Fmov(x1, d1); __ Fmov(d2, x1); __ Fmov(d4, d1); __ Fmov(d6, RawbitsToDouble(0x0123456789abcdef)); __ Fmov(s6, s6); __ Fmov(d0, 0.0); __ Fmov(v0.D(), 1, x1); __ Fmov(x2, v0.D(), 1); __ Fmov(v3.D(), 1, x4); __ Fmov(v3.D(), 0, x1); __ Fmov(x5, v1.D(), 0); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(RawbitsToFloat16(0xCA80U), h7); ASSERT_EQUAL_FP16(RawbitsToFloat16(0xC500U), h9); ASSERT_EQUAL_32(0x0000C500, w3); ASSERT_EQUAL_64(0x0000000000006400, x4); ASSERT_EQUAL_FP16(RawbitsToFloat16(0x6400), h10); ASSERT_EQUAL_32(FloatToRawbits(1.0), w10); ASSERT_EQUAL_FP32(1.0, s30); ASSERT_EQUAL_FP32(1.0, s5); ASSERT_EQUAL_64(DoubleToRawbits(-13.0), x1); ASSERT_EQUAL_FP64(-13.0, d2); ASSERT_EQUAL_FP64(-13.0, d4); ASSERT_EQUAL_FP32(RawbitsToFloat(0x89abcdef), s6); ASSERT_EQUAL_128(DoubleToRawbits(-13.0), 0x0000000000000000, q0); ASSERT_EQUAL_64(DoubleToRawbits(-13.0), x2); ASSERT_EQUAL_128(0x0000000000006400, DoubleToRawbits(-13.0), q3); ASSERT_EQUAL_64(DoubleToRawbits(-13.0), x5); } } TEST(fadd) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ 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.0); __ Fmov(d30, -2.0); __ Fmov(d31, 2.25); __ 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(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(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(4.25, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(1.0, s2); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s3); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s4); 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); } } TEST(fadd_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h14, -0.0f); __ Fmov(h15, kFP16PositiveInfinity); __ Fmov(h16, kFP16NegativeInfinity); __ Fmov(h17, 3.25f); __ Fmov(h18, 1.0); __ Fmov(h19, 0.0f); __ Fmov(h20, 5.0f); __ Fadd(h0, h17, h18); __ Fadd(h1, h18, h19); __ Fadd(h2, h14, h18); __ Fadd(h3, h15, h18); __ Fadd(h4, h16, h18); __ Fadd(h5, h15, h16); __ Fadd(h6, h16, h15); __ Fadd(h7, h20, h20); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(Float16(4.25), h0); ASSERT_EQUAL_FP16(Float16(1.0), h1); ASSERT_EQUAL_FP16(Float16(1.0), h2); ASSERT_EQUAL_FP16(kFP16PositiveInfinity, h3); ASSERT_EQUAL_FP16(kFP16NegativeInfinity, h4); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h5); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h6); ASSERT_EQUAL_FP16(Float16(10.0), h7); } } TEST(fsub) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ 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.0); __ Fmov(d30, -2.0); __ Fmov(d31, 2.25); __ 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(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(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(2.25, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(-1.0, s2); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s3); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s4); 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); } } TEST(fsub_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h14, -0.0f); __ Fmov(h15, kFP16PositiveInfinity); __ Fmov(h16, kFP16NegativeInfinity); __ Fmov(h17, 3.25f); __ Fmov(h18, 1.0f); __ Fmov(h19, 0.0f); __ Fsub(h0, h17, h18); __ Fsub(h1, h18, h19); __ Fsub(h2, h14, h18); __ Fsub(h3, h18, h15); __ Fsub(h4, h18, h16); __ Fsub(h5, h15, h15); __ Fsub(h6, h16, h16); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(Float16(2.25), h0); ASSERT_EQUAL_FP16(Float16(1.0), h1); ASSERT_EQUAL_FP16(Float16(-1.0), h2); ASSERT_EQUAL_FP16(kFP16NegativeInfinity, h3); ASSERT_EQUAL_FP16(kFP16PositiveInfinity, h4); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h5); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h6); } } TEST(fmul) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ 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.0); __ Fmov(d30, -2.0); __ Fmov(d31, 2.25); __ 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(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(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(6.5, s0); ASSERT_EQUAL_FP32(0.0, s1); ASSERT_EQUAL_FP32(0.0, s2); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s3); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s4); 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); } } TEST(fmul_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h14, -0.0f); __ Fmov(h15, kFP16PositiveInfinity); __ Fmov(h16, kFP16NegativeInfinity); __ Fmov(h17, 3.25f); __ Fmov(h18, 2.0f); __ Fmov(h19, 0.0f); __ Fmov(h20, -2.0f); __ Fmul(h0, h17, h18); __ Fmul(h1, h18, h19); __ Fmul(h2, h14, h14); __ Fmul(h3, h15, h20); __ Fmul(h4, h16, h20); __ Fmul(h5, h15, h19); __ Fmul(h6, h19, h16); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(Float16(6.5), h0); ASSERT_EQUAL_FP16(Float16(0.0), h1); ASSERT_EQUAL_FP16(Float16(0.0), h2); ASSERT_EQUAL_FP16(kFP16NegativeInfinity, h3); ASSERT_EQUAL_FP16(kFP16PositiveInfinity, h4); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h5); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h6); } } TEST(fnmul_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h14, -0.0f); __ Fmov(h15, kFP16PositiveInfinity); __ Fmov(h16, kFP16NegativeInfinity); __ Fmov(h17, 3.25f); __ Fmov(h18, 2.0f); __ Fmov(h19, 0.0f); __ Fmov(h20, -2.0f); __ Fnmul(h0, h17, h18); __ Fnmul(h1, h18, h19); __ Fnmul(h2, h14, h14); __ Fnmul(h3, h15, h20); __ Fnmul(h4, h16, h20); __ Fnmul(h5, h15, h19); __ Fnmul(h6, h19, h16); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(Float16(-6.5), h0); ASSERT_EQUAL_FP16(Float16(-0.0), h1); ASSERT_EQUAL_FP16(Float16(-0.0), h2); ASSERT_EQUAL_FP16(kFP16PositiveInfinity, h3); ASSERT_EQUAL_FP16(kFP16NegativeInfinity, h4); ASSERT_EQUAL_FP16(RawbitsToFloat16(0xfe00), h5); ASSERT_EQUAL_FP16(RawbitsToFloat16(0xfe00), h6); } } static void FmaddFmsubHelper(double n, double m, double a, double fmadd, double fmsub, double fnmadd, double fnmsub) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(d0, n); __ Fmov(d1, m); __ Fmov(d2, a); __ Fmadd(d28, d0, d1, d2); __ Fmsub(d29, d0, d1, d2); __ Fnmadd(d30, d0, d1, d2); __ Fnmsub(d31, d0, d1, d2); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(fmadd, d28); ASSERT_EQUAL_FP64(fmsub, d29); ASSERT_EQUAL_FP64(fnmadd, d30); ASSERT_EQUAL_FP64(fnmsub, d31); } } TEST(fmadd_fmsub_double) { // 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. // 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); // 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); // 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 FmaddFmsubHelper(float n, float m, float a, float fmadd, float fmsub, float fnmadd, float fnmsub) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, n); __ Fmov(s1, m); __ Fmov(s2, a); __ Fmadd(s28, s0, s1, s2); __ Fmsub(s29, s0, s1, s2); __ Fnmadd(s30, s0, s1, s2); __ Fnmsub(s31, s0, s1, s2); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(fmadd, s28); ASSERT_EQUAL_FP32(fmsub, s29); ASSERT_EQUAL_FP32(fnmadd, s30); ASSERT_EQUAL_FP32(fnmsub, s31); } } TEST(fmadd_fmsub_float) { // 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. // 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) { // Make sure that NaN propagation works correctly. double s1 = RawbitsToDouble(0x7ff5555511111111); double s2 = RawbitsToDouble(0x7ff5555522222222); double sa = RawbitsToDouble(0x7ff55555aaaaaaaa); double q1 = RawbitsToDouble(0x7ffaaaaa11111111); double q2 = RawbitsToDouble(0x7ffaaaaa22222222); double qa = RawbitsToDouble(0x7ffaaaaaaaaaaaaa); VIXL_ASSERT(IsSignallingNaN(s1)); VIXL_ASSERT(IsSignallingNaN(s2)); VIXL_ASSERT(IsSignallingNaN(sa)); VIXL_ASSERT(IsQuietNaN(q1)); VIXL_ASSERT(IsQuietNaN(q2)); VIXL_ASSERT(IsQuietNaN(qa)); // The input NaNs after passing through ProcessNaN. double s1_proc = RawbitsToDouble(0x7ffd555511111111); double s2_proc = RawbitsToDouble(0x7ffd555522222222); double sa_proc = RawbitsToDouble(0x7ffd5555aaaaaaaa); double q1_proc = q1; double q2_proc = q2; double qa_proc = qa; VIXL_ASSERT(IsQuietNaN(s1_proc)); VIXL_ASSERT(IsQuietNaN(s2_proc)); VIXL_ASSERT(IsQuietNaN(sa_proc)); VIXL_ASSERT(IsQuietNaN(q1_proc)); VIXL_ASSERT(IsQuietNaN(q2_proc)); VIXL_ASSERT(IsQuietNaN(qa_proc)); // Negated NaNs as it would be done on ARMv8 hardware. double s1_proc_neg = RawbitsToDouble(0xfffd555511111111); double sa_proc_neg = RawbitsToDouble(0xfffd5555aaaaaaaa); double q1_proc_neg = RawbitsToDouble(0xfffaaaaa11111111); double qa_proc_neg = RawbitsToDouble(0xfffaaaaaaaaaaaaa); VIXL_ASSERT(IsQuietNaN(s1_proc_neg)); VIXL_ASSERT(IsQuietNaN(sa_proc_neg)); VIXL_ASSERT(IsQuietNaN(q1_proc_neg)); VIXL_ASSERT(IsQuietNaN(qa_proc_neg)); // Quiet NaNs are propagated. FmaddFmsubHelper(q1, 0, 0, q1_proc, q1_proc_neg, q1_proc_neg, q1_proc); FmaddFmsubHelper(0, q2, 0, q2_proc, q2_proc, q2_proc, q2_proc); FmaddFmsubHelper(0, 0, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); FmaddFmsubHelper(q1, q2, 0, q1_proc, q1_proc_neg, q1_proc_neg, q1_proc); FmaddFmsubHelper(0, q2, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); FmaddFmsubHelper(q1, 0, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); FmaddFmsubHelper(q1, q2, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); // Signalling NaNs are propagated, and made quiet. FmaddFmsubHelper(s1, 0, 0, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(0, s2, 0, s2_proc, s2_proc, s2_proc, s2_proc); FmaddFmsubHelper(0, 0, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, 0, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(0, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, 0, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); // Signalling NaNs take precedence over quiet NaNs. FmaddFmsubHelper(s1, q2, qa, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(q1, s2, qa, s2_proc, s2_proc, s2_proc, s2_proc); FmaddFmsubHelper(q1, q2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, qa, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(q1, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, q2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); // 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) { // Make sure that NaN propagation works correctly. float s1 = RawbitsToFloat(0x7f951111); float s2 = RawbitsToFloat(0x7f952222); float sa = RawbitsToFloat(0x7f95aaaa); float q1 = RawbitsToFloat(0x7fea1111); float q2 = RawbitsToFloat(0x7fea2222); float qa = RawbitsToFloat(0x7feaaaaa); VIXL_ASSERT(IsSignallingNaN(s1)); VIXL_ASSERT(IsSignallingNaN(s2)); VIXL_ASSERT(IsSignallingNaN(sa)); VIXL_ASSERT(IsQuietNaN(q1)); VIXL_ASSERT(IsQuietNaN(q2)); VIXL_ASSERT(IsQuietNaN(qa)); // The input NaNs after passing through ProcessNaN. float s1_proc = RawbitsToFloat(0x7fd51111); float s2_proc = RawbitsToFloat(0x7fd52222); float sa_proc = RawbitsToFloat(0x7fd5aaaa); float q1_proc = q1; float q2_proc = q2; float qa_proc = qa; VIXL_ASSERT(IsQuietNaN(s1_proc)); VIXL_ASSERT(IsQuietNaN(s2_proc)); VIXL_ASSERT(IsQuietNaN(sa_proc)); VIXL_ASSERT(IsQuietNaN(q1_proc)); VIXL_ASSERT(IsQuietNaN(q2_proc)); VIXL_ASSERT(IsQuietNaN(qa_proc)); // Negated NaNs as it would be done on ARMv8 hardware. float s1_proc_neg = RawbitsToFloat(0xffd51111); float sa_proc_neg = RawbitsToFloat(0xffd5aaaa); float q1_proc_neg = RawbitsToFloat(0xffea1111); float qa_proc_neg = RawbitsToFloat(0xffeaaaaa); VIXL_ASSERT(IsQuietNaN(s1_proc_neg)); VIXL_ASSERT(IsQuietNaN(sa_proc_neg)); VIXL_ASSERT(IsQuietNaN(q1_proc_neg)); VIXL_ASSERT(IsQuietNaN(qa_proc_neg)); // Quiet NaNs are propagated. FmaddFmsubHelper(q1, 0, 0, q1_proc, q1_proc_neg, q1_proc_neg, q1_proc); FmaddFmsubHelper(0, q2, 0, q2_proc, q2_proc, q2_proc, q2_proc); FmaddFmsubHelper(0, 0, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); FmaddFmsubHelper(q1, q2, 0, q1_proc, q1_proc_neg, q1_proc_neg, q1_proc); FmaddFmsubHelper(0, q2, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); FmaddFmsubHelper(q1, 0, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); FmaddFmsubHelper(q1, q2, qa, qa_proc, qa_proc, qa_proc_neg, qa_proc_neg); // Signalling NaNs are propagated, and made quiet. FmaddFmsubHelper(s1, 0, 0, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(0, s2, 0, s2_proc, s2_proc, s2_proc, s2_proc); FmaddFmsubHelper(0, 0, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, 0, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(0, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, 0, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); // Signalling NaNs take precedence over quiet NaNs. FmaddFmsubHelper(s1, q2, qa, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(q1, s2, qa, s2_proc, s2_proc, s2_proc, s2_proc); FmaddFmsubHelper(q1, q2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, qa, s1_proc, s1_proc_neg, s1_proc_neg, s1_proc); FmaddFmsubHelper(q1, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, q2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); FmaddFmsubHelper(s1, s2, sa, sa_proc, sa_proc, sa_proc_neg, sa_proc_neg); // 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); } TEST(fdiv) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ 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.0); __ Fmov(d30, -2.0); __ Fmov(d31, 2.25); __ 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(); if (CAN_RUN()) { 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); } } TEST(fdiv_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h14, -0.0f); __ Fmov(h15, kFP16PositiveInfinity); __ Fmov(h16, kFP16NegativeInfinity); __ Fmov(h17, 3.25f); __ Fmov(h18, 2.0f); __ Fmov(h19, 2.0f); __ Fmov(h20, -2.0f); __ Fdiv(h0, h17, h18); __ Fdiv(h1, h18, h19); __ Fdiv(h2, h14, h18); __ Fdiv(h3, h18, h15); __ Fdiv(h4, h18, h16); __ Fdiv(h5, h15, h16); __ Fdiv(h6, h14, h14); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(Float16(1.625f), h0); ASSERT_EQUAL_FP16(Float16(1.0f), h1); ASSERT_EQUAL_FP16(Float16(-0.0f), h2); ASSERT_EQUAL_FP16(Float16(0.0f), h3); ASSERT_EQUAL_FP16(Float16(-0.0f), h4); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h5); ASSERT_EQUAL_FP16(kFP16DefaultNaN, h6); } } static float MinMaxHelper(float n, float m, bool min, float quiet_nan_substitute = 0.0) { const uint64_t kFP32QuietNaNMask = 0x00400000; uint32_t raw_n = FloatToRawbits(n); uint32_t raw_m = FloatToRawbits(m); if (IsNaN(n) && ((raw_n & kFP32QuietNaNMask) == 0)) { // n is signalling NaN. return RawbitsToFloat(raw_n | kFP32QuietNaNMask); } else if (IsNaN(m) && ((raw_m & kFP32QuietNaNMask) == 0)) { // m is signalling NaN. return RawbitsToFloat(raw_m | kFP32QuietNaNMask); } else if (quiet_nan_substitute == 0.0) { if (IsNaN(n)) { // n is quiet NaN. return n; } else if (IsNaN(m)) { // m is quiet NaN. return m; } } else { // Substitute n or m if one is quiet, but not both. if (IsNaN(n) && !IsNaN(m)) { // n is quiet NaN: replace with substitute. n = quiet_nan_substitute; } else if (!IsNaN(n) && IsNaN(m)) { // m is quiet NaN: replace with substitute. m = quiet_nan_substitute; } } if ((n == 0.0) && (m == 0.0) && (copysign(1.0, n) != copysign(1.0, m))) { return min ? -0.0 : 0.0; } return min ? fminf(n, m) : fmaxf(n, m); } static double MinMaxHelper(double n, double m, bool min, double quiet_nan_substitute = 0.0) { const uint64_t kFP64QuietNaNMask = 0x0008000000000000; uint64_t raw_n = DoubleToRawbits(n); uint64_t raw_m = DoubleToRawbits(m); if (IsNaN(n) && ((raw_n & kFP64QuietNaNMask) == 0)) { // n is signalling NaN. return RawbitsToDouble(raw_n | kFP64QuietNaNMask); } else if (IsNaN(m) && ((raw_m & kFP64QuietNaNMask) == 0)) { // m is signalling NaN. return RawbitsToDouble(raw_m | kFP64QuietNaNMask); } else if (quiet_nan_substitute == 0.0) { if (IsNaN(n)) { // n is quiet NaN. return n; } else if (IsNaN(m)) { // m is quiet NaN. return m; } } else { // Substitute n or m if one is quiet, but not both. if (IsNaN(n) && !IsNaN(m)) { // n is quiet NaN: replace with substitute. n = quiet_nan_substitute; } else if (!IsNaN(n) && IsNaN(m)) { // m is quiet NaN: replace with substitute. m = quiet_nan_substitute; } } if ((n == 0.0) && (m == 0.0) && (copysign(1.0, n) != copysign(1.0, m))) { return min ? -0.0 : 0.0; } return min ? fmin(n, m) : fmax(n, m); } static void FminFmaxDoubleHelper( double n, double m, double min, double max, double minnm, double maxnm) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(d0, n); __ Fmov(d1, m); __ Fmin(d28, d0, d1); __ Fmax(d29, d0, d1); __ Fminnm(d30, d0, d1); __ Fmaxnm(d31, d0, d1); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(min, d28); ASSERT_EQUAL_FP64(max, d29); ASSERT_EQUAL_FP64(minnm, d30); ASSERT_EQUAL_FP64(maxnm, d31); } } TEST(fmax_fmin_d) { // Use non-standard NaNs to check that the payload bits are preserved. double snan = RawbitsToDouble(0x7ff5555512345678); double qnan = RawbitsToDouble(0x7ffaaaaa87654321); double snan_processed = RawbitsToDouble(0x7ffd555512345678); double qnan_processed = qnan; VIXL_ASSERT(IsSignallingNaN(snan)); VIXL_ASSERT(IsQuietNaN(qnan)); VIXL_ASSERT(IsQuietNaN(snan_processed)); VIXL_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(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(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, -DBL_MAX, -DBL_MIN, -1.0, -0.0, kFP64PositiveInfinity, kFP64NegativeInfinity, kFP64QuietNaN, kFP64SignallingNaN}; 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]; FminFmaxDoubleHelper(n, m, MinMaxHelper(n, m, true), MinMaxHelper(n, m, false), MinMaxHelper(n, m, true, kFP64PositiveInfinity), MinMaxHelper(n, m, false, kFP64NegativeInfinity)); } } } static void FminFmaxFloatHelper( float n, float m, float min, float max, float minnm, float maxnm) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, n); __ Fmov(s1, m); __ Fmin(s28, s0, s1); __ Fmax(s29, s0, s1); __ Fminnm(s30, s0, s1); __ Fmaxnm(s31, s0, s1); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(min, s28); ASSERT_EQUAL_FP32(max, s29); ASSERT_EQUAL_FP32(minnm, s30); ASSERT_EQUAL_FP32(maxnm, s31); } } TEST(fmax_fmin_s) { // Use non-standard NaNs to check that the payload bits are preserved. float snan = RawbitsToFloat(0x7f951234); float qnan = RawbitsToFloat(0x7fea8765); float snan_processed = RawbitsToFloat(0x7fd51234); float qnan_processed = qnan; VIXL_ASSERT(IsSignallingNaN(snan)); VIXL_ASSERT(IsQuietNaN(qnan)); VIXL_ASSERT(IsQuietNaN(snan_processed)); VIXL_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(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(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, -FLT_MAX, -FLT_MIN, -1.0, -0.0, kFP32PositiveInfinity, kFP32NegativeInfinity, kFP32QuietNaN, kFP32SignallingNaN}; 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]; FminFmaxFloatHelper(n, m, MinMaxHelper(n, m, true), MinMaxHelper(n, m, false), MinMaxHelper(n, m, true, kFP32PositiveInfinity), MinMaxHelper(n, m, false, kFP32NegativeInfinity)); } } } TEST(fccmp) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 0.0); __ Fmov(s17, 0.5); __ Fmov(d18, -0.5); __ Fmov(d19, -1.0); __ Mov(x20, 0); __ Mov(x21, 0x7ff0000000000001); // Double precision NaN. __ Fmov(d21, x21); __ Mov(w22, 0x7f800001); // Single precision NaN. __ Fmov(s22, w22); __ Cmp(x20, 0); __ Fccmp(s16, s16, NoFlag, eq); __ Mrs(x0, NZCV); __ Cmp(x20, 0); __ Fccmp(s16, s16, VFlag, ne); __ Mrs(x1, NZCV); __ Cmp(x20, 0); __ Fccmp(s16, s17, CFlag, ge); __ Mrs(x2, NZCV); __ Cmp(x20, 0); __ Fccmp(s16, s17, CVFlag, lt); __ Mrs(x3, NZCV); __ Cmp(x20, 0); __ Fccmp(d18, d18, ZFlag, le); __ Mrs(x4, NZCV); __ Cmp(x20, 0); __ Fccmp(d18, d18, ZVFlag, gt); __ Mrs(x5, NZCV); __ Cmp(x20, 0); __ Fccmp(d18, d19, ZCVFlag, ls); __ Mrs(x6, NZCV); __ Cmp(x20, 0); __ Fccmp(d18, d19, NFlag, hi); __ Mrs(x7, NZCV); // The Macro Assembler does not allow al or nv as condition. { ExactAssemblyScope scope(&masm, kInstructionSize); __ fccmp(s16, s16, NFlag, al); } __ Mrs(x8, NZCV); { ExactAssemblyScope scope(&masm, kInstructionSize); __ fccmp(d18, d18, NFlag, nv); } __ Mrs(x9, NZCV); __ Cmp(x20, 0); __ Fccmpe(s16, s16, NoFlag, eq); __ Mrs(x10, NZCV); __ Cmp(x20, 0); __ Fccmpe(d18, d19, ZCVFlag, ls); __ Mrs(x11, NZCV); __ Cmp(x20, 0); __ Fccmpe(d21, d21, NoFlag, eq); __ Mrs(x12, NZCV); __ Cmp(x20, 0); __ Fccmpe(s22, s22, NoFlag, eq); __ Mrs(x13, NZCV); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_32(ZCFlag, w0); ASSERT_EQUAL_32(VFlag, w1); ASSERT_EQUAL_32(NFlag, w2); ASSERT_EQUAL_32(CVFlag, w3); ASSERT_EQUAL_32(ZCFlag, w4); ASSERT_EQUAL_32(ZVFlag, w5); ASSERT_EQUAL_32(CFlag, w6); ASSERT_EQUAL_32(NFlag, w7); ASSERT_EQUAL_32(ZCFlag, w8); ASSERT_EQUAL_32(ZCFlag, w9); ASSERT_EQUAL_32(ZCFlag, w10); ASSERT_EQUAL_32(CFlag, w11); ASSERT_EQUAL_32(CVFlag, w12); ASSERT_EQUAL_32(CVFlag, w13); } } TEST(fccmp_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Fmov(h16, Float16(0.0)); __ Fmov(h17, Float16(0.5)); __ Mov(x20, 0); __ Fmov(h21, kFP16DefaultNaN); __ Cmp(x20, 0); __ Fccmp(h16, h16, NoFlag, eq); __ Mrs(x0, NZCV); __ Cmp(x20, 0); __ Fccmp(h16, h16, VFlag, ne); __ Mrs(x1, NZCV); __ Cmp(x20, 0); __ Fccmp(h16, h17, CFlag, ge); __ Mrs(x2, NZCV); __ Cmp(x20, 0); __ Fccmp(h16, h17, CVFlag, lt); __ Mrs(x3, NZCV); // The Macro Assembler does not allow al or nv as condition. { ExactAssemblyScope scope(&masm, kInstructionSize); __ fccmp(h16, h16, NFlag, al); } __ Mrs(x4, NZCV); { ExactAssemblyScope scope(&masm, kInstructionSize); __ fccmp(h16, h16, NFlag, nv); } __ Mrs(x5, NZCV); __ Cmp(x20, 0); __ Fccmpe(h16, h16, NoFlag, eq); __ Mrs(x6, NZCV); __ Cmp(x20, 0); __ Fccmpe(h16, h21, NoFlag, eq); __ Mrs(x7, NZCV); __ Cmp(x20, 0); __ Fccmpe(h21, h16, NoFlag, eq); __ Mrs(x8, NZCV); __ Cmp(x20, 0); __ Fccmpe(h21, h21, NoFlag, eq); __ Mrs(x9, NZCV); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_32(ZCFlag, w0); ASSERT_EQUAL_32(VFlag, w1); ASSERT_EQUAL_32(NFlag, w2); ASSERT_EQUAL_32(CVFlag, w3); ASSERT_EQUAL_32(ZCFlag, w4); ASSERT_EQUAL_32(ZCFlag, w5); ASSERT_EQUAL_32(ZCFlag, w6); ASSERT_EQUAL_32(CVFlag, w7); ASSERT_EQUAL_32(CVFlag, w8); ASSERT_EQUAL_32(CVFlag, w9); } } TEST(fcmp) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); // Some of these tests require a floating-point scratch register assigned to // the macro assembler, but most do not. { UseScratchRegisterScope temps(&masm); temps.ExcludeAll(); temps.Include(ip0, ip1); __ Fmov(s8, 0.0); __ Fmov(s9, 0.5); __ Mov(w18, 0x7f800001); // Single precision NaN. __ Fmov(s18, w18); __ Fcmp(s8, s8); __ Mrs(x0, NZCV); __ Fcmp(s8, s9); __ Mrs(x1, NZCV); __ Fcmp(s9, s8); __ Mrs(x2, NZCV); __ Fcmp(s8, s18); __ Mrs(x3, NZCV); __ Fcmp(s18, s18); __ Mrs(x4, NZCV); __ Fcmp(s8, 0.0); __ Mrs(x5, NZCV); temps.Include(d0); __ Fcmp(s8, 255.0); temps.Exclude(d0); __ Mrs(x6, NZCV); __ Fmov(d19, 0.0); __ Fmov(d20, 0.5); __ Mov(x21, 0x7ff0000000000001); // Double precision NaN. __ Fmov(d21, x21); __ Fcmp(d19, d19); __ Mrs(x10, NZCV); __ Fcmp(d19, d20); __ Mrs(x11, NZCV); __ Fcmp(d20, d19); __ Mrs(x12, NZCV); __ Fcmp(d19, d21); __ Mrs(x13, NZCV); __ Fcmp(d21, d21); __ Mrs(x14, NZCV); __ Fcmp(d19, 0.0); __ Mrs(x15, NZCV); temps.Include(d0); __ Fcmp(d19, 12.3456); temps.Exclude(d0); __ Mrs(x16, NZCV); __ Fcmpe(s8, s8); __ Mrs(x22, NZCV); __ Fcmpe(s8, 0.0); __ Mrs(x23, NZCV); __ Fcmpe(d19, d19); __ Mrs(x24, NZCV); __ Fcmpe(d19, 0.0); __ Mrs(x25, NZCV); __ Fcmpe(s18, s18); __ Mrs(x26, NZCV); __ Fcmpe(d21, d21); __ Mrs(x27, NZCV); } END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_32(ZCFlag, w0); ASSERT_EQUAL_32(NFlag, w1); ASSERT_EQUAL_32(CFlag, w2); ASSERT_EQUAL_32(CVFlag, w3); ASSERT_EQUAL_32(CVFlag, w4); ASSERT_EQUAL_32(ZCFlag, w5); ASSERT_EQUAL_32(NFlag, w6); ASSERT_EQUAL_32(ZCFlag, w10); ASSERT_EQUAL_32(NFlag, w11); ASSERT_EQUAL_32(CFlag, w12); ASSERT_EQUAL_32(CVFlag, w13); ASSERT_EQUAL_32(CVFlag, w14); ASSERT_EQUAL_32(ZCFlag, w15); ASSERT_EQUAL_32(NFlag, w16); ASSERT_EQUAL_32(ZCFlag, w22); ASSERT_EQUAL_32(ZCFlag, w23); ASSERT_EQUAL_32(ZCFlag, w24); ASSERT_EQUAL_32(ZCFlag, w25); ASSERT_EQUAL_32(CVFlag, w26); ASSERT_EQUAL_32(CVFlag, w27); } } TEST(fcmp_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); // Some of these tests require a floating-point scratch register assigned to // the macro assembler, but most do not. { UseScratchRegisterScope temps(&masm); temps.ExcludeAll(); temps.Include(ip0, ip1); __ Fmov(h8, Float16(0.0)); __ Fmov(h9, Float16(0.5)); __ Fmov(h18, kFP16DefaultNaN); __ Fcmp(h8, h8); __ Mrs(x0, NZCV); __ Fcmp(h8, h9); __ Mrs(x1, NZCV); __ Fcmp(h9, h8); __ Mrs(x2, NZCV); __ Fcmp(h8, h18); __ Mrs(x3, NZCV); __ Fcmp(h18, h18); __ Mrs(x4, NZCV); __ Fcmp(h8, 0.0); __ Mrs(x5, NZCV); temps.Include(d0); __ Fcmp(h8, 255.0); temps.Exclude(d0); __ Mrs(x6, NZCV); __ Fcmpe(h8, h8); __ Mrs(x22, NZCV); __ Fcmpe(h8, 0.0); __ Mrs(x23, NZCV); __ Fcmpe(h8, h18); __ Mrs(x24, NZCV); __ Fcmpe(h18, h8); __ Mrs(x25, NZCV); __ Fcmpe(h18, h18); __ Mrs(x26, NZCV); } END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_32(ZCFlag, w0); ASSERT_EQUAL_32(NFlag, w1); ASSERT_EQUAL_32(CFlag, w2); ASSERT_EQUAL_32(CVFlag, w3); ASSERT_EQUAL_32(CVFlag, w4); ASSERT_EQUAL_32(ZCFlag, w5); ASSERT_EQUAL_32(NFlag, w6); ASSERT_EQUAL_32(ZCFlag, w22); ASSERT_EQUAL_32(ZCFlag, w23); ASSERT_EQUAL_32(CVFlag, w24); ASSERT_EQUAL_32(CVFlag, w25); ASSERT_EQUAL_32(CVFlag, w26); } } TEST(fcsel) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Mov(x16, 0); __ Fmov(s16, 1.0); __ Fmov(s17, 2.0); __ Fmov(d18, 3.0); __ Fmov(d19, 4.0); __ Cmp(x16, 0); __ Fcsel(s0, s16, s17, eq); __ Fcsel(s1, s16, s17, ne); __ Fcsel(d2, d18, d19, eq); __ Fcsel(d3, d18, d19, ne); // The Macro Assembler does not allow al or nv as condition. { ExactAssemblyScope scope(&masm, 2 * kInstructionSize); __ fcsel(s4, s16, s17, al); __ fcsel(d5, d18, d19, nv); } END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(2.0, s1); ASSERT_EQUAL_FP64(3.0, d2); ASSERT_EQUAL_FP64(4.0, d3); ASSERT_EQUAL_FP32(1.0, s4); ASSERT_EQUAL_FP64(3.0, d5); } } TEST(fcsel_h) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); __ Mov(x16, 0); __ Fmov(h16, Float16(1.0)); __ Fmov(h17, Float16(2.0)); __ Cmp(x16, 0); __ Fcsel(h0, h16, h17, eq); __ Fcsel(h1, h16, h17, ne); // The Macro Assembler does not allow al or nv as condition. { ExactAssemblyScope scope(&masm, 2 * kInstructionSize); __ fcsel(h4, h16, h17, al); __ fcsel(h5, h16, h17, nv); } END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(Float16(1.0), h0); ASSERT_EQUAL_FP16(Float16(2.0), h1); ASSERT_EQUAL_FP16(Float16(1.0), h4); ASSERT_EQUAL_FP16(Float16(1.0), h5); } } TEST(fneg) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 0.0); __ Fmov(s18, kFP32PositiveInfinity); __ Fmov(d19, 1.0); __ Fmov(d20, 0.0); __ Fmov(d21, kFP64PositiveInfinity); __ Fneg(s0, s16); __ Fneg(s1, s0); __ Fneg(s2, s17); __ Fneg(s3, s2); __ Fneg(s4, s18); __ Fneg(s5, s4); __ Fneg(d6, d19); __ Fneg(d7, d6); __ Fneg(d8, d20); __ Fneg(d9, d8); __ Fneg(d10, d21); __ Fneg(d11, d10); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(-1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(-0.0, s2); ASSERT_EQUAL_FP32(0.0, s3); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s4); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5); ASSERT_EQUAL_FP64(-1.0, d6); ASSERT_EQUAL_FP64(1.0, d7); ASSERT_EQUAL_FP64(-0.0, d8); ASSERT_EQUAL_FP64(0.0, d9); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d10); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d11); } } TEST(fabs) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, -1.0); __ Fmov(s17, -0.0); __ Fmov(s18, kFP32NegativeInfinity); __ Fmov(d19, -1.0); __ Fmov(d20, -0.0); __ Fmov(d21, kFP64NegativeInfinity); __ Fabs(s0, s16); __ Fabs(s1, s0); __ Fabs(s2, s17); __ Fabs(s3, s18); __ Fabs(d4, d19); __ Fabs(d5, d4); __ Fabs(d6, d20); __ Fabs(d7, d21); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(0.0, s2); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s3); ASSERT_EQUAL_FP64(1.0, d4); ASSERT_EQUAL_FP64(1.0, d5); ASSERT_EQUAL_FP64(0.0, d6); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d7); } } TEST(fsqrt) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 0.0); __ Fmov(s17, 1.0); __ Fmov(s18, 0.25); __ Fmov(s19, 65536.0); __ Fmov(s20, -0.0); __ Fmov(s21, kFP32PositiveInfinity); __ 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); __ Fsqrt(s2, s18); __ Fsqrt(s3, s19); __ Fsqrt(s4, s20); __ Fsqrt(s5, s21); __ 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(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(0.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(0.5, s2); ASSERT_EQUAL_FP32(256.0, s3); ASSERT_EQUAL_FP32(-0.0, s4); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5); 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); } } TEST(frint32x_s) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(s13, 1.0); __ Fmov(s14, 1.1); __ Fmov(s15, 1.5); __ Fmov(s16, 1.9); __ Fmov(s17, 2.5); __ Fmov(s18, -1.5); __ Fmov(s19, -2.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0.0); __ Fmov(s23, -0.0); __ Fmov(s24, -0.2); __ Fmov(s25, kFP32DefaultNaN); __ Fmov(s26, INT32_MIN); __ Fmov(s27, INT32_MIN + 0x80); // The next representable FP32. __ Fmov(s28, 0x80000000); __ Fmov(s29, 0x7fffff80); // The largest int32_t representable as FP32. __ Fmov(s30, FLT_MIN); __ Fmov(s31, FLT_MAX); __ Frint32x(s0, s13); __ Frint32x(s1, s14); __ Frint32x(s2, s15); __ Frint32x(s3, s16); __ Frint32x(s4, s17); __ Frint32x(s5, s18); __ Frint32x(s6, s19); __ Frint32x(s7, s20); __ Frint32x(s8, s21); __ Frint32x(s9, s22); __ Frint32x(s10, s23); __ Frint32x(s11, s24); __ Frint32x(s12, s25); __ Frint32x(s13, s26); __ Frint32x(s14, s27); __ Frint32x(s15, s28); __ Frint32x(s16, s29); __ Frint32x(s17, s30); __ Frint32x(s18, s31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(INT32_MIN, s7); ASSERT_EQUAL_FP32(INT32_MIN, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP32(INT32_MIN, s12); // NaN. ASSERT_EQUAL_FP32(INT32_MIN, s13); ASSERT_EQUAL_FP32(INT32_MIN + 0x80, s14); ASSERT_EQUAL_FP32(INT32_MIN, s15); // Out of range. ASSERT_EQUAL_FP32(0x7fffff80, s16); ASSERT_EQUAL_FP32(0, s17); ASSERT_EQUAL_FP32(INT32_MIN, s18); } } TEST(frint32x_d) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(d13, 1.0); __ Fmov(d14, 1.1); __ Fmov(d15, 1.5); __ Fmov(d16, 1.9); __ Fmov(d17, 2.5); __ Fmov(d18, -1.5); __ Fmov(d19, -2.5); __ Fmov(d20, kFP64PositiveInfinity); __ Fmov(d21, kFP64NegativeInfinity); __ Fmov(d22, 0.0); __ Fmov(d23, -0.0); __ Fmov(d24, -0.2); __ Fmov(d25, kFP64DefaultNaN); __ Fmov(d26, INT32_MIN); __ Fmov(d27, INT32_MIN + 1); __ Fmov(d28, INT32_MAX); __ Fmov(d29, INT32_MAX - 1); __ Fmov(d30, FLT_MIN); __ Fmov(d31, FLT_MAX); __ Frint32x(d0, d13); __ Frint32x(d1, d14); __ Frint32x(d2, d15); __ Frint32x(d3, d16); __ Frint32x(d4, d17); __ Frint32x(d5, d18); __ Frint32x(d6, d19); __ Frint32x(d7, d20); __ Frint32x(d8, d21); __ Frint32x(d9, d22); __ Frint32x(d10, d23); __ Frint32x(d11, d24); __ Frint32x(d12, d25); __ Frint32x(d13, d26); __ Frint32x(d14, d27); __ Frint32x(d15, d28); __ Frint32x(d16, d29); __ Frint32x(d17, d30); __ Frint32x(d18, d31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.0, d0); ASSERT_EQUAL_FP64(1.0, d1); ASSERT_EQUAL_FP64(2.0, d2); ASSERT_EQUAL_FP64(2.0, d3); ASSERT_EQUAL_FP64(2.0, d4); ASSERT_EQUAL_FP64(-2.0, d5); ASSERT_EQUAL_FP64(-2.0, d6); ASSERT_EQUAL_FP64(INT32_MIN, d7); ASSERT_EQUAL_FP64(INT32_MIN, d8); ASSERT_EQUAL_FP64(0.0, d9); ASSERT_EQUAL_FP64(-0.0, d10); ASSERT_EQUAL_FP64(-0.0, d11); ASSERT_EQUAL_FP64(INT32_MIN, d12); ASSERT_EQUAL_FP64(INT32_MIN, d13); ASSERT_EQUAL_FP64(INT32_MIN + 1, d14); ASSERT_EQUAL_FP64(INT32_MAX, d15); ASSERT_EQUAL_FP64(INT32_MAX - 1, d16); ASSERT_EQUAL_FP64(0, d17); ASSERT_EQUAL_FP64(INT32_MIN, d18); } } TEST(frint32z_s) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(s13, 1.0); __ Fmov(s14, 1.1); __ Fmov(s15, 1.5); __ Fmov(s16, 1.9); __ Fmov(s17, 2.5); __ Fmov(s18, -1.5); __ Fmov(s19, -2.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0.0); __ Fmov(s23, -0.0); __ Fmov(s24, -0.2); __ Fmov(s25, kFP32DefaultNaN); __ Fmov(s26, INT32_MIN); __ Fmov(s27, INT32_MIN + 0x80); // The next representable FP32. __ Fmov(s28, 0x80000000); __ Fmov(s29, 0x7fffff80); // The largest int32_t representable as FP32. __ Fmov(s30, FLT_MIN); __ Fmov(s31, FLT_MAX); __ Frint32z(s0, s13); __ Frint32z(s1, s14); __ Frint32z(s2, s15); __ Frint32z(s3, s16); __ Frint32z(s4, s17); __ Frint32z(s5, s18); __ Frint32z(s6, s19); __ Frint32z(s7, s20); __ Frint32z(s8, s21); __ Frint32z(s9, s22); __ Frint32z(s10, s23); __ Frint32z(s11, s24); __ Frint32z(s12, s25); __ Frint32z(s13, s26); __ Frint32z(s14, s27); __ Frint32z(s15, s28); __ Frint32z(s16, s29); __ Frint32z(s17, s30); __ Frint32z(s18, s31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(1.0, s2); ASSERT_EQUAL_FP32(1.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-1.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(INT32_MIN, s7); ASSERT_EQUAL_FP32(INT32_MIN, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP32(INT32_MIN, s12); // NaN. ASSERT_EQUAL_FP32(INT32_MIN, s13); ASSERT_EQUAL_FP32(INT32_MIN + 0x80, s14); ASSERT_EQUAL_FP32(INT32_MIN, s15); // Out of range. ASSERT_EQUAL_FP32(0x7fffff80, s16); ASSERT_EQUAL_FP32(0, s17); ASSERT_EQUAL_FP32(INT32_MIN, s18); } } TEST(frint32z_d) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(d13, 1.0); __ Fmov(d14, 1.1); __ Fmov(d15, 1.5); __ Fmov(d16, 1.9); __ Fmov(d17, 2.5); __ Fmov(d18, -1.5); __ Fmov(d19, -2.5); __ Fmov(d20, kFP64PositiveInfinity); __ Fmov(d21, kFP64NegativeInfinity); __ Fmov(d22, 0.0); __ Fmov(d23, -0.0); __ Fmov(d24, -0.2); __ Fmov(d25, kFP64DefaultNaN); __ Fmov(d26, INT32_MIN); __ Fmov(d27, INT32_MIN + 1); __ Fmov(d28, INT32_MAX); __ Fmov(d29, INT32_MAX - 1); __ Fmov(d30, FLT_MIN); __ Fmov(d31, FLT_MAX); __ Frint32z(d0, d13); __ Frint32z(d1, d14); __ Frint32z(d2, d15); __ Frint32z(d3, d16); __ Frint32z(d4, d17); __ Frint32z(d5, d18); __ Frint32z(d6, d19); __ Frint32z(d7, d20); __ Frint32z(d8, d21); __ Frint32z(d9, d22); __ Frint32z(d10, d23); __ Frint32z(d11, d24); __ Frint32z(d12, d25); __ Frint32z(d13, d26); __ Frint32z(d14, d27); __ Frint32z(d15, d28); __ Frint32z(d16, d29); __ Frint32z(d17, d30); __ Frint32z(d18, d31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.0, d0); ASSERT_EQUAL_FP64(1.0, d1); ASSERT_EQUAL_FP64(1.0, d2); ASSERT_EQUAL_FP64(1.0, d3); ASSERT_EQUAL_FP64(2.0, d4); ASSERT_EQUAL_FP64(-1.0, d5); ASSERT_EQUAL_FP64(-2.0, d6); ASSERT_EQUAL_FP64(INT32_MIN, d7); ASSERT_EQUAL_FP64(INT32_MIN, d8); ASSERT_EQUAL_FP64(0.0, d9); ASSERT_EQUAL_FP64(-0.0, d10); ASSERT_EQUAL_FP64(-0.0, d11); ASSERT_EQUAL_FP64(INT32_MIN, d12); ASSERT_EQUAL_FP64(INT32_MIN, d13); ASSERT_EQUAL_FP64(INT32_MIN + 1, d14); ASSERT_EQUAL_FP64(INT32_MAX, d15); ASSERT_EQUAL_FP64(INT32_MAX - 1, d16); ASSERT_EQUAL_FP64(0, d17); ASSERT_EQUAL_FP64(INT32_MIN, d18); } } TEST(frint64x_s) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(s13, 1.0); __ Fmov(s14, 1.1); __ Fmov(s15, 1.5); __ Fmov(s16, 1.9); __ Fmov(s17, 2.5); __ Fmov(s18, -1.5); __ Fmov(s19, -2.5); __ Fmov(s20, kFP64PositiveInfinity); __ Fmov(s21, kFP64NegativeInfinity); __ Fmov(s22, 0.0); __ Fmov(s23, -0.0); __ Fmov(s24, -0.2); __ Fmov(s25, kFP64DefaultNaN); __ Fmov(s26, INT64_MIN); __ Fmov(s27, INT64_MIN + 0x80'00000000); // The next representable FP32. __ Fmov(s28, 0x80000000'00000000); // The largest int64_t representable as FP32. __ Fmov(s29, 0x7fffff80'00000000); __ Fmov(s30, FLT_MIN); __ Fmov(s31, FLT_MAX); __ Frint64x(s0, s13); __ Frint64x(s1, s14); __ Frint64x(s2, s15); __ Frint64x(s3, s16); __ Frint64x(s4, s17); __ Frint64x(s5, s18); __ Frint64x(s6, s19); __ Frint64x(s7, s20); __ Frint64x(s8, s21); __ Frint64x(s9, s22); __ Frint64x(s10, s23); __ Frint64x(s11, s24); __ Frint64x(s12, s25); __ Frint64x(s13, s26); __ Frint64x(s14, s27); __ Frint64x(s15, s28); __ Frint64x(s16, s29); __ Frint64x(s17, s30); __ Frint64x(s18, s31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(INT64_MIN, s7); ASSERT_EQUAL_FP32(INT64_MIN, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP32(INT64_MIN, s12); // Nan. ASSERT_EQUAL_FP32(INT64_MIN, s13); ASSERT_EQUAL_FP32(INT64_MIN + 0x80'00000000, s14); ASSERT_EQUAL_FP32(INT64_MIN, s15); // Out of range. ASSERT_EQUAL_FP32(0x7fffff80'00000000, s16); ASSERT_EQUAL_FP32(0, s17); ASSERT_EQUAL_FP32(INT64_MIN, s18); } } TEST(frint64x_d) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(d13, 1.0); __ Fmov(d14, 1.1); __ Fmov(d15, 1.5); __ Fmov(d16, 1.9); __ Fmov(d17, 2.5); __ Fmov(d18, -1.5); __ Fmov(d19, -2.5); __ Fmov(d20, kFP64PositiveInfinity); __ Fmov(d21, kFP64NegativeInfinity); __ Fmov(d22, 0.0); __ Fmov(d23, -0.0); __ Fmov(d24, -0.2); __ Fmov(d25, kFP64DefaultNaN); __ Fmov(d26, INT64_MIN); __ Fmov(d27, INT64_MIN + 0x400); // The next representable FP64. __ Fmov(d28, 0x80000000'00000000); // The largest int64_t representable as FP64. __ Fmov(d29, 0x7fffffff'fffffc00); __ Fmov(d30, FLT_MIN); __ Fmov(d31, FLT_MAX); __ Frint64x(d0, d13); __ Frint64x(d1, d14); __ Frint64x(d2, d15); __ Frint64x(d3, d16); __ Frint64x(d4, d17); __ Frint64x(d5, d18); __ Frint64x(d6, d19); __ Frint64x(d7, d20); __ Frint64x(d8, d21); __ Frint64x(d9, d22); __ Frint64x(d10, d23); __ Frint64x(d11, d24); __ Frint64x(d12, d25); __ Frint64x(d13, d26); __ Frint64x(d14, d27); __ Frint64x(d15, d28); __ Frint64x(d16, d29); __ Frint64x(d17, d30); __ Frint64x(d18, d31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.0, d0); ASSERT_EQUAL_FP64(1.0, d1); ASSERT_EQUAL_FP64(2.0, d2); ASSERT_EQUAL_FP64(2.0, d3); ASSERT_EQUAL_FP64(2.0, d4); ASSERT_EQUAL_FP64(-2.0, d5); ASSERT_EQUAL_FP64(-2.0, d6); ASSERT_EQUAL_FP64(INT64_MIN, d7); ASSERT_EQUAL_FP64(INT64_MIN, d8); ASSERT_EQUAL_FP64(0.0, d9); ASSERT_EQUAL_FP64(-0.0, d10); ASSERT_EQUAL_FP64(-0.0, d11); ASSERT_EQUAL_FP64(INT64_MIN, d12); // NaN. ASSERT_EQUAL_FP64(INT64_MIN, d13); ASSERT_EQUAL_FP64(INT64_MIN + 0x400, d14); ASSERT_EQUAL_FP64(INT64_MIN, d15); // Out of range. ASSERT_EQUAL_FP64(0x7fffffff'fffffc00, d16); ASSERT_EQUAL_FP64(0, d17); ASSERT_EQUAL_FP64(INT64_MIN, d18); } } TEST(frint64z_s) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(s13, 1.0); __ Fmov(s14, 1.1); __ Fmov(s15, 1.5); __ Fmov(s16, 1.9); __ Fmov(s17, 2.5); __ Fmov(s18, -1.5); __ Fmov(s19, -2.5); __ Fmov(s20, kFP64PositiveInfinity); __ Fmov(s21, kFP64NegativeInfinity); __ Fmov(s22, 0.0); __ Fmov(s23, -0.0); __ Fmov(s24, -0.2); __ Fmov(s25, kFP64DefaultNaN); __ Fmov(s26, INT64_MIN); __ Fmov(s27, INT64_MIN + 0x80'00000000); // The next representable FP32. __ Fmov(s28, 0x80000000'00000000); // The largest int64_t representable as FP32. __ Fmov(s29, 0x7fffff80'00000000); __ Fmov(s30, FLT_MIN); __ Fmov(s31, FLT_MAX); __ Frint64z(s0, s13); __ Frint64z(s1, s14); __ Frint64z(s2, s15); __ Frint64z(s3, s16); __ Frint64z(s4, s17); __ Frint64z(s5, s18); __ Frint64z(s6, s19); __ Frint64z(s7, s20); __ Frint64z(s8, s21); __ Frint64z(s9, s22); __ Frint64z(s10, s23); __ Frint64z(s11, s24); __ Frint64z(s12, s25); __ Frint64z(s13, s26); __ Frint64z(s14, s27); __ Frint64z(s15, s28); __ Frint64z(s16, s29); __ Frint64z(s17, s30); __ Frint64z(s18, s31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(1.0, s2); ASSERT_EQUAL_FP32(1.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-1.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(INT64_MIN, s7); ASSERT_EQUAL_FP32(INT64_MIN, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP32(INT64_MIN, s12); // Nan. ASSERT_EQUAL_FP32(INT64_MIN, s13); ASSERT_EQUAL_FP32(INT64_MIN + 0x80'00000000, s14); ASSERT_EQUAL_FP32(INT64_MIN, s15); // Out of range. ASSERT_EQUAL_FP32(0x7fffff80'00000000, s16); ASSERT_EQUAL_FP32(0, s17); ASSERT_EQUAL_FP32(INT64_MIN, s18); } } TEST(frint64z_d) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); START(); __ Fmov(d13, 1.0); __ Fmov(d14, 1.1); __ Fmov(d15, 1.5); __ Fmov(d16, 1.9); __ Fmov(d17, 2.5); __ Fmov(d18, -1.5); __ Fmov(d19, -2.5); __ Fmov(d20, kFP64PositiveInfinity); __ Fmov(d21, kFP64NegativeInfinity); __ Fmov(d22, 0.0); __ Fmov(d23, -0.0); __ Fmov(d24, -0.2); __ Fmov(d25, kFP64DefaultNaN); __ Fmov(d26, INT64_MIN); __ Fmov(d27, INT64_MIN + 0x400); // The next representable FP64. __ Fmov(d28, 0x80000000'00000000); // The largest int64_t representable as FP64. __ Fmov(d29, 0x7fffffff'fffffc00); __ Fmov(d30, FLT_MIN); __ Fmov(d31, FLT_MAX); __ Frint64z(d0, d13); __ Frint64z(d1, d14); __ Frint64z(d2, d15); __ Frint64z(d3, d16); __ Frint64z(d4, d17); __ Frint64z(d5, d18); __ Frint64z(d6, d19); __ Frint64z(d7, d20); __ Frint64z(d8, d21); __ Frint64z(d9, d22); __ Frint64z(d10, d23); __ Frint64z(d11, d24); __ Frint64z(d12, d25); __ Frint64z(d13, d26); __ Frint64z(d14, d27); __ Frint64z(d15, d28); __ Frint64z(d16, d29); __ Frint64z(d17, d30); __ Frint64z(d18, d31); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.0, d0); ASSERT_EQUAL_FP64(1.0, d1); ASSERT_EQUAL_FP64(1.0, d2); ASSERT_EQUAL_FP64(1.0, d3); ASSERT_EQUAL_FP64(2.0, d4); ASSERT_EQUAL_FP64(-1.0, d5); ASSERT_EQUAL_FP64(-2.0, d6); ASSERT_EQUAL_FP64(INT64_MIN, d7); ASSERT_EQUAL_FP64(INT64_MIN, d8); ASSERT_EQUAL_FP64(0.0, d9); ASSERT_EQUAL_FP64(-0.0, d10); ASSERT_EQUAL_FP64(-0.0, d11); ASSERT_EQUAL_FP64(INT64_MIN, d12); // NaN. ASSERT_EQUAL_FP64(INT64_MIN, d13); ASSERT_EQUAL_FP64(INT64_MIN + 0x400, d14); ASSERT_EQUAL_FP64(INT64_MIN, d15); // Out of range. ASSERT_EQUAL_FP64(0x7fffffff'fffffc00, d16); ASSERT_EQUAL_FP64(0, d17); ASSERT_EQUAL_FP64(INT64_MIN, d18); } } TEST(frinta) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, -0.2); __ Frinta(s0, s16); __ Frinta(s1, s17); __ Frinta(s2, s18); __ Frinta(s3, s19); __ Frinta(s4, s20); __ Frinta(s5, s21); __ Frinta(s6, s22); __ Frinta(s7, s23); __ Frinta(s8, s24); __ Frinta(s9, s25); __ Frinta(s10, s26); __ Frinta(s11, s27); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, -0.2); __ Frinta(d12, d16); __ Frinta(d13, d17); __ Frinta(d14, d18); __ Frinta(d15, d19); __ Frinta(d16, d20); __ Frinta(d17, d21); __ Frinta(d18, d22); __ Frinta(d19, d23); __ Frinta(d20, d24); __ Frinta(d21, d25); __ Frinta(d22, d26); __ Frinta(d23, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(3.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-3.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(1.0, d13); ASSERT_EQUAL_FP64(2.0, d14); ASSERT_EQUAL_FP64(2.0, d15); ASSERT_EQUAL_FP64(3.0, d16); ASSERT_EQUAL_FP64(-2.0, d17); ASSERT_EQUAL_FP64(-3.0, d18); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); ASSERT_EQUAL_FP64(0.0, d21); ASSERT_EQUAL_FP64(-0.0, d22); ASSERT_EQUAL_FP64(-0.0, d23); } } TEST(frinti) { // VIXL only supports the round-to-nearest FPCR mode, so this test has the // same results as frintn. SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, -0.2); __ Frinti(s0, s16); __ Frinti(s1, s17); __ Frinti(s2, s18); __ Frinti(s3, s19); __ Frinti(s4, s20); __ Frinti(s5, s21); __ Frinti(s6, s22); __ Frinti(s7, s23); __ Frinti(s8, s24); __ Frinti(s9, s25); __ Frinti(s10, s26); __ Frinti(s11, s27); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, -0.2); __ Frinti(d12, d16); __ Frinti(d13, d17); __ Frinti(d14, d18); __ Frinti(d15, d19); __ Frinti(d16, d20); __ Frinti(d17, d21); __ Frinti(d18, d22); __ Frinti(d19, d23); __ Frinti(d20, d24); __ Frinti(d21, d25); __ Frinti(d22, d26); __ Frinti(d23, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(1.0, d13); ASSERT_EQUAL_FP64(2.0, d14); ASSERT_EQUAL_FP64(2.0, d15); ASSERT_EQUAL_FP64(2.0, d16); ASSERT_EQUAL_FP64(-2.0, d17); ASSERT_EQUAL_FP64(-2.0, d18); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); ASSERT_EQUAL_FP64(0.0, d21); ASSERT_EQUAL_FP64(-0.0, d22); ASSERT_EQUAL_FP64(-0.0, d23); } } TEST(frintm) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, -0.2); __ Frintm(s0, s16); __ Frintm(s1, s17); __ Frintm(s2, s18); __ Frintm(s3, s19); __ Frintm(s4, s20); __ Frintm(s5, s21); __ Frintm(s6, s22); __ Frintm(s7, s23); __ Frintm(s8, s24); __ Frintm(s9, s25); __ Frintm(s10, s26); __ Frintm(s11, s27); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, -0.2); __ Frintm(d12, d16); __ Frintm(d13, d17); __ Frintm(d14, d18); __ Frintm(d15, d19); __ Frintm(d16, d20); __ Frintm(d17, d21); __ Frintm(d18, d22); __ Frintm(d19, d23); __ Frintm(d20, d24); __ Frintm(d21, d25); __ Frintm(d22, d26); __ Frintm(d23, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(1.0, s2); ASSERT_EQUAL_FP32(1.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-3.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-1.0, s11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(1.0, d13); ASSERT_EQUAL_FP64(1.0, d14); ASSERT_EQUAL_FP64(1.0, d15); ASSERT_EQUAL_FP64(2.0, d16); ASSERT_EQUAL_FP64(-2.0, d17); ASSERT_EQUAL_FP64(-3.0, d18); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); ASSERT_EQUAL_FP64(0.0, d21); ASSERT_EQUAL_FP64(-0.0, d22); ASSERT_EQUAL_FP64(-1.0, d23); } } TEST(frintn) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, -0.2); __ Frintn(s0, s16); __ Frintn(s1, s17); __ Frintn(s2, s18); __ Frintn(s3, s19); __ Frintn(s4, s20); __ Frintn(s5, s21); __ Frintn(s6, s22); __ Frintn(s7, s23); __ Frintn(s8, s24); __ Frintn(s9, s25); __ Frintn(s10, s26); __ Frintn(s11, s27); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, -0.2); __ Frintn(d12, d16); __ Frintn(d13, d17); __ Frintn(d14, d18); __ Frintn(d15, d19); __ Frintn(d16, d20); __ Frintn(d17, d21); __ Frintn(d18, d22); __ Frintn(d19, d23); __ Frintn(d20, d24); __ Frintn(d21, d25); __ Frintn(d22, d26); __ Frintn(d23, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(1.0, d13); ASSERT_EQUAL_FP64(2.0, d14); ASSERT_EQUAL_FP64(2.0, d15); ASSERT_EQUAL_FP64(2.0, d16); ASSERT_EQUAL_FP64(-2.0, d17); ASSERT_EQUAL_FP64(-2.0, d18); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); ASSERT_EQUAL_FP64(0.0, d21); ASSERT_EQUAL_FP64(-0.0, d22); ASSERT_EQUAL_FP64(-0.0, d23); } } TEST(frintp) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, -0.2); __ Frintp(s0, s16); __ Frintp(s1, s17); __ Frintp(s2, s18); __ Frintp(s3, s19); __ Frintp(s4, s20); __ Frintp(s5, s21); __ Frintp(s6, s22); __ Frintp(s7, s23); __ Frintp(s8, s24); __ Frintp(s9, s25); __ Frintp(s10, s26); __ Frintp(s11, s27); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, -0.2); __ Frintp(d12, d16); __ Frintp(d13, d17); __ Frintp(d14, d18); __ Frintp(d15, d19); __ Frintp(d16, d20); __ Frintp(d17, d21); __ Frintp(d18, d22); __ Frintp(d19, d23); __ Frintp(d20, d24); __ Frintp(d21, d25); __ Frintp(d22, d26); __ Frintp(d23, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(2.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(3.0, s4); ASSERT_EQUAL_FP32(-1.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(2.0, d13); ASSERT_EQUAL_FP64(2.0, d14); ASSERT_EQUAL_FP64(2.0, d15); ASSERT_EQUAL_FP64(3.0, d16); ASSERT_EQUAL_FP64(-1.0, d17); ASSERT_EQUAL_FP64(-2.0, d18); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); ASSERT_EQUAL_FP64(0.0, d21); ASSERT_EQUAL_FP64(-0.0, d22); ASSERT_EQUAL_FP64(-0.0, d23); } } TEST(frintx) { // VIXL only supports the round-to-nearest FPCR mode, and it doesn't support // FP exceptions, so this test has the same results as frintn (and frinti). SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, -0.2); __ Frintx(s0, s16); __ Frintx(s1, s17); __ Frintx(s2, s18); __ Frintx(s3, s19); __ Frintx(s4, s20); __ Frintx(s5, s21); __ Frintx(s6, s22); __ Frintx(s7, s23); __ Frintx(s8, s24); __ Frintx(s9, s25); __ Frintx(s10, s26); __ Frintx(s11, s27); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, -0.2); __ Frintx(d12, d16); __ Frintx(d13, d17); __ Frintx(d14, d18); __ Frintx(d15, d19); __ Frintx(d16, d20); __ Frintx(d17, d21); __ Frintx(d18, d22); __ Frintx(d19, d23); __ Frintx(d20, d24); __ Frintx(d21, d25); __ Frintx(d22, d26); __ Frintx(d23, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(2.0, s2); ASSERT_EQUAL_FP32(2.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-2.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP32(-0.0, s11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(1.0, d13); ASSERT_EQUAL_FP64(2.0, d14); ASSERT_EQUAL_FP64(2.0, d15); ASSERT_EQUAL_FP64(2.0, d16); ASSERT_EQUAL_FP64(-2.0, d17); ASSERT_EQUAL_FP64(-2.0, d18); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); ASSERT_EQUAL_FP64(0.0, d21); ASSERT_EQUAL_FP64(-0.0, d22); ASSERT_EQUAL_FP64(-0.0, d23); } } TEST(frintz) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Frintz(s0, s16); __ Frintz(s1, s17); __ Frintz(s2, s18); __ Frintz(s3, s19); __ Frintz(s4, s20); __ Frintz(s5, s21); __ Frintz(s6, s22); __ Frintz(s7, s23); __ Frintz(s8, s24); __ Frintz(s9, s25); __ Frintz(s10, s26); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Frintz(d11, d16); __ Frintz(d12, d17); __ Frintz(d13, d18); __ Frintz(d14, d19); __ Frintz(d15, d20); __ Frintz(d16, d21); __ Frintz(d17, d22); __ Frintz(d18, d23); __ Frintz(d19, d24); __ Frintz(d20, d25); __ Frintz(d21, d26); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0, s0); ASSERT_EQUAL_FP32(1.0, s1); ASSERT_EQUAL_FP32(1.0, s2); ASSERT_EQUAL_FP32(1.0, s3); ASSERT_EQUAL_FP32(2.0, s4); ASSERT_EQUAL_FP32(-1.0, s5); ASSERT_EQUAL_FP32(-2.0, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0, s9); ASSERT_EQUAL_FP32(-0.0, s10); ASSERT_EQUAL_FP64(1.0, d11); ASSERT_EQUAL_FP64(1.0, d12); ASSERT_EQUAL_FP64(1.0, d13); ASSERT_EQUAL_FP64(1.0, d14); ASSERT_EQUAL_FP64(2.0, d15); ASSERT_EQUAL_FP64(-1.0, d16); ASSERT_EQUAL_FP64(-2.0, d17); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d18); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d19); ASSERT_EQUAL_FP64(0.0, d20); ASSERT_EQUAL_FP64(-0.0, d21); } } TEST(fcvt_ds) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, 1.9); __ Fmov(s20, 2.5); __ Fmov(s21, -1.5); __ Fmov(s22, -2.5); __ Fmov(s23, kFP32PositiveInfinity); __ Fmov(s24, kFP32NegativeInfinity); __ Fmov(s25, 0.0); __ Fmov(s26, -0.0); __ Fmov(s27, FLT_MAX); __ Fmov(s28, FLT_MIN); __ Fmov(s29, RawbitsToFloat(0x7fc12345)); // Quiet NaN. __ Fmov(s30, RawbitsToFloat(0x7f812345)); // Signalling NaN. __ Fcvt(d0, s16); __ Fcvt(d1, s17); __ Fcvt(d2, s18); __ Fcvt(d3, s19); __ Fcvt(d4, s20); __ Fcvt(d5, s21); __ Fcvt(d6, s22); __ Fcvt(d7, s23); __ Fcvt(d8, s24); __ Fcvt(d9, s25); __ Fcvt(d10, s26); __ Fcvt(d11, s27); __ Fcvt(d12, s28); __ Fcvt(d13, s29); __ Fcvt(d14, s30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP64(1.0f, d0); ASSERT_EQUAL_FP64(1.1f, d1); ASSERT_EQUAL_FP64(1.5f, d2); ASSERT_EQUAL_FP64(1.9f, d3); ASSERT_EQUAL_FP64(2.5f, d4); ASSERT_EQUAL_FP64(-1.5f, d5); ASSERT_EQUAL_FP64(-2.5f, d6); ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d7); ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d8); ASSERT_EQUAL_FP64(0.0f, d9); ASSERT_EQUAL_FP64(-0.0f, d10); ASSERT_EQUAL_FP64(FLT_MAX, d11); ASSERT_EQUAL_FP64(FLT_MIN, d12); // Check that the NaN payload is preserved according to Aarch64 conversion // rules: // - The sign bit is preserved. // - The top bit of the mantissa is forced to 1 (making it a quiet NaN). // - The remaining mantissa bits are copied until they run out. // - The low-order bits that haven't already been assigned are set to 0. ASSERT_EQUAL_FP64(RawbitsToDouble(0x7ff82468a0000000), d13); ASSERT_EQUAL_FP64(RawbitsToDouble(0x7ff82468a0000000), d14); } } TEST(fcvt_sd) { // Test simple conversions here. Complex behaviour (such as rounding // specifics) are tested in the simulator tests. SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(d16, 1.0); __ Fmov(d17, 1.1); __ Fmov(d18, 1.5); __ Fmov(d19, 1.9); __ Fmov(d20, 2.5); __ Fmov(d21, -1.5); __ Fmov(d22, -2.5); __ Fmov(d23, kFP32PositiveInfinity); __ Fmov(d24, kFP32NegativeInfinity); __ Fmov(d25, 0.0); __ Fmov(d26, -0.0); __ Fmov(d27, FLT_MAX); __ Fmov(d28, FLT_MIN); __ Fmov(d29, RawbitsToDouble(0x7ff82468a0000000)); // Quiet NaN. __ Fmov(d30, RawbitsToDouble(0x7ff02468a0000000)); // Signalling NaN. __ Fcvt(s0, d16); __ Fcvt(s1, d17); __ Fcvt(s2, d18); __ Fcvt(s3, d19); __ Fcvt(s4, d20); __ Fcvt(s5, d21); __ Fcvt(s6, d22); __ Fcvt(s7, d23); __ Fcvt(s8, d24); __ Fcvt(s9, d25); __ Fcvt(s10, d26); __ Fcvt(s11, d27); __ Fcvt(s12, d28); __ Fcvt(s13, d29); __ Fcvt(s14, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP32(1.0f, s0); ASSERT_EQUAL_FP32(1.1f, s1); ASSERT_EQUAL_FP32(1.5f, s2); ASSERT_EQUAL_FP32(1.9f, s3); ASSERT_EQUAL_FP32(2.5f, s4); ASSERT_EQUAL_FP32(-1.5f, s5); ASSERT_EQUAL_FP32(-2.5f, s6); ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); ASSERT_EQUAL_FP32(0.0f, s9); ASSERT_EQUAL_FP32(-0.0f, s10); ASSERT_EQUAL_FP32(FLT_MAX, s11); ASSERT_EQUAL_FP32(FLT_MIN, s12); // Check that the NaN payload is preserved according to Aarch64 conversion // rules: // - The sign bit is preserved. // - The top bit of the mantissa is forced to 1 (making it a quiet NaN). // - The remaining mantissa bits are copied until they run out. // - The low-order bits that haven't already been assigned are set to 0. ASSERT_EQUAL_FP32(RawbitsToFloat(0x7fc12345), s13); ASSERT_EQUAL_FP32(RawbitsToFloat(0x7fc12345), s14); } } TEST(fcvt_half) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); Label done; { // Check all exact conversions from half to float and back. Label ok, fail; __ Mov(w0, 0); for (int i = 0; i < 0xffff; i += 3) { if ((i & 0x7c00) == 0x7c00) continue; __ Mov(w1, i); __ Fmov(s1, w1); __ Fcvt(s2, h1); __ Fcvt(h2, s2); __ Fmov(w2, s2); __ Cmp(w1, w2); __ B(&fail, ne); } __ B(&ok); __ Bind(&fail); __ Mov(w0, 1); __ B(&done); __ Bind(&ok); } { // Check all exact conversions from half to double and back. Label ok, fail; for (int i = 0; i < 0xffff; i += 3) { if ((i & 0x7c00) == 0x7c00) continue; __ Mov(w1, i); __ Fmov(s1, w1); __ Fcvt(d2, h1); __ Fcvt(h2, d2); __ Fmov(w2, s2); __ Cmp(w1, w2); __ B(&fail, ne); } __ B(&ok); __ Bind(&fail); __ Mov(w0, 2); __ Bind(&ok); } __ Bind(&done); // Check some other interesting values. __ Fmov(s0, kFP32PositiveInfinity); __ Fmov(s1, kFP32NegativeInfinity); __ Fmov(s2, 65504); // Max half precision. __ Fmov(s3, 6.10352e-5); // Min positive normal. __ Fmov(s4, 6.09756e-5); // Max subnormal. __ Fmov(s5, 5.96046e-8); // Min positive subnormal. __ Fmov(s6, 5e-9); // Not representable -> zero. __ Fmov(s7, -0.0); __ Fcvt(h0, s0); __ Fcvt(h1, s1); __ Fcvt(h2, s2); __ Fcvt(h3, s3); __ Fcvt(h4, s4); __ Fcvt(h5, s5); __ Fcvt(h6, s6); __ Fcvt(h7, s7); __ Fmov(d20, kFP64PositiveInfinity); __ Fmov(d21, kFP64NegativeInfinity); __ Fmov(d22, 65504); // Max half precision. __ Fmov(d23, 6.10352e-5); // Min positive normal. __ Fmov(d24, 6.09756e-5); // Max subnormal. __ Fmov(d25, 5.96046e-8); // Min positive subnormal. __ Fmov(d26, 5e-9); // Not representable -> zero. __ Fmov(d27, -0.0); __ Fcvt(h20, d20); __ Fcvt(h21, d21); __ Fcvt(h22, d22); __ Fcvt(h23, d23); __ Fcvt(h24, d24); __ Fcvt(h25, d25); __ Fcvt(h26, d26); __ Fcvt(h27, d27); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_32(0, w0); // 1 => float failed, 2 => double failed. ASSERT_EQUAL_128(0, Float16ToRawbits(kFP16PositiveInfinity), q0); ASSERT_EQUAL_128(0, Float16ToRawbits(kFP16NegativeInfinity), q1); ASSERT_EQUAL_128(0, 0x7bff, q2); ASSERT_EQUAL_128(0, 0x0400, q3); ASSERT_EQUAL_128(0, 0x03ff, q4); ASSERT_EQUAL_128(0, 0x0001, q5); ASSERT_EQUAL_128(0, 0, q6); ASSERT_EQUAL_128(0, 0x8000, q7); ASSERT_EQUAL_128(0, Float16ToRawbits(kFP16PositiveInfinity), q20); ASSERT_EQUAL_128(0, Float16ToRawbits(kFP16NegativeInfinity), q21); ASSERT_EQUAL_128(0, 0x7bff, q22); ASSERT_EQUAL_128(0, 0x0400, q23); ASSERT_EQUAL_128(0, 0x03ff, q24); ASSERT_EQUAL_128(0, 0x0001, q25); ASSERT_EQUAL_128(0, 0, q26); ASSERT_EQUAL_128(0, 0x8000, q27); } } TEST(fcvtas) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 2.5); __ Fmov(s3, -2.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0x7fffff80); // Largest float < INT32_MAX. __ Fneg(s7, s6); // Smallest float > INT32_MIN. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 2.5); __ Fmov(d11, -2.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, kWMaxInt - 1); __ Fmov(d15, kWMinInt + 1); __ Fmov(s17, 1.1); __ Fmov(s18, 2.5); __ Fmov(s19, -2.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0x7fffff8000000000); // Largest float < INT64_MAX. __ Fneg(s23, s22); // Smallest float > INT64_MIN. __ Fmov(d24, 1.1); __ Fmov(d25, 2.5); __ Fmov(d26, -2.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0x7ffffffffffffc00); // Largest double < INT64_MAX. __ Fneg(d30, d29); // Smallest double > INT64_MIN. __ Fcvtas(w0, s0); __ Fcvtas(w1, s1); __ Fcvtas(w2, s2); __ Fcvtas(w3, s3); __ Fcvtas(w4, s4); __ Fcvtas(w5, s5); __ Fcvtas(w6, s6); __ Fcvtas(w7, s7); __ Fcvtas(w8, d8); __ Fcvtas(w9, d9); __ Fcvtas(w10, d10); __ Fcvtas(w11, d11); __ Fcvtas(w12, d12); __ Fcvtas(w13, d13); __ Fcvtas(w14, d14); __ Fcvtas(w15, d15); __ Fcvtas(x17, s17); __ Fcvtas(x18, s18); __ Fcvtas(x19, s19); __ Fcvtas(x20, s20); __ Fcvtas(x21, s21); __ Fcvtas(x22, s22); __ Fcvtas(x23, s23); __ Fcvtas(x24, d24); __ Fcvtas(x25, d25); __ Fcvtas(x26, d26); __ Fcvtas(x27, d27); __ Fcvtas(x28, d28); __ Fcvtas(x29, d29); __ Fcvtas(x30, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(3, x2); ASSERT_EQUAL_64(0xfffffffd, x3); ASSERT_EQUAL_64(0x7fffffff, x4); ASSERT_EQUAL_64(0x80000000, x5); ASSERT_EQUAL_64(0x7fffff80, x6); ASSERT_EQUAL_64(0x80000080, x7); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(3, x10); ASSERT_EQUAL_64(0xfffffffd, x11); ASSERT_EQUAL_64(0x7fffffff, x12); ASSERT_EQUAL_64(0x80000000, x13); ASSERT_EQUAL_64(0x7ffffffe, x14); ASSERT_EQUAL_64(0x80000001, x15); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(3, x18); ASSERT_EQUAL_64(0xfffffffffffffffd, x19); ASSERT_EQUAL_64(0x7fffffffffffffff, x20); ASSERT_EQUAL_64(0x8000000000000000, x21); ASSERT_EQUAL_64(0x7fffff8000000000, x22); ASSERT_EQUAL_64(0x8000008000000000, x23); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(3, x25); ASSERT_EQUAL_64(0xfffffffffffffffd, x26); ASSERT_EQUAL_64(0x7fffffffffffffff, x27); ASSERT_EQUAL_64(0x8000000000000000, x28); ASSERT_EQUAL_64(0x7ffffffffffffc00, x29); ASSERT_EQUAL_64(0x8000000000000400, x30); } } TEST(fcvtau) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 2.5); __ Fmov(s3, -2.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0xffffff00); // Largest float < UINT32_MAX. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 2.5); __ Fmov(d11, -2.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, 0xfffffffe); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 2.5); __ Fmov(s19, -2.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0xffffff0000000000); // Largest float < UINT64_MAX. __ Fmov(d24, 1.1); __ Fmov(d25, 2.5); __ Fmov(d26, -2.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0xfffffffffffff800); // Largest double < UINT64_MAX. __ Fmov(s30, 0x100000000); __ Fcvtau(w0, s0); __ Fcvtau(w1, s1); __ Fcvtau(w2, s2); __ Fcvtau(w3, s3); __ Fcvtau(w4, s4); __ Fcvtau(w5, s5); __ Fcvtau(w6, s6); __ Fcvtau(w8, d8); __ Fcvtau(w9, d9); __ Fcvtau(w10, d10); __ Fcvtau(w11, d11); __ Fcvtau(w12, d12); __ Fcvtau(w13, d13); __ Fcvtau(w14, d14); __ Fcvtau(w15, d15); __ Fcvtau(x16, s16); __ Fcvtau(x17, s17); __ Fcvtau(x18, s18); __ Fcvtau(x19, s19); __ Fcvtau(x20, s20); __ Fcvtau(x21, s21); __ Fcvtau(x22, s22); __ Fcvtau(x24, d24); __ Fcvtau(x25, d25); __ Fcvtau(x26, d26); __ Fcvtau(x27, d27); __ Fcvtau(x28, d28); __ Fcvtau(x29, d29); __ Fcvtau(w30, s30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(3, x2); ASSERT_EQUAL_64(0, x3); ASSERT_EQUAL_64(0xffffffff, x4); ASSERT_EQUAL_64(0, x5); ASSERT_EQUAL_64(0xffffff00, x6); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(3, x10); ASSERT_EQUAL_64(0, x11); ASSERT_EQUAL_64(0xffffffff, x12); ASSERT_EQUAL_64(0, x13); ASSERT_EQUAL_64(0xfffffffe, x14); ASSERT_EQUAL_64(1, x16); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(3, x18); ASSERT_EQUAL_64(0, x19); ASSERT_EQUAL_64(0xffffffffffffffff, x20); ASSERT_EQUAL_64(0, x21); ASSERT_EQUAL_64(0xffffff0000000000, x22); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(3, x25); ASSERT_EQUAL_64(0, x26); ASSERT_EQUAL_64(0xffffffffffffffff, x27); ASSERT_EQUAL_64(0, x28); ASSERT_EQUAL_64(0xfffffffffffff800, x29); ASSERT_EQUAL_64(0xffffffff, x30); } } TEST(fcvtms) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 1.5); __ Fmov(s3, -1.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0x7fffff80); // Largest float < INT32_MAX. __ Fneg(s7, s6); // Smallest float > INT32_MIN. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 1.5); __ Fmov(d11, -1.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, kWMaxInt - 1); __ Fmov(d15, kWMinInt + 1); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, -1.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0x7fffff8000000000); // Largest float < INT64_MAX. __ Fneg(s23, s22); // Smallest float > INT64_MIN. __ Fmov(d24, 1.1); __ Fmov(d25, 1.5); __ Fmov(d26, -1.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0x7ffffffffffffc00); // Largest double < INT64_MAX. __ Fneg(d30, d29); // Smallest double > INT64_MIN. __ Fcvtms(w0, s0); __ Fcvtms(w1, s1); __ Fcvtms(w2, s2); __ Fcvtms(w3, s3); __ Fcvtms(w4, s4); __ Fcvtms(w5, s5); __ Fcvtms(w6, s6); __ Fcvtms(w7, s7); __ Fcvtms(w8, d8); __ Fcvtms(w9, d9); __ Fcvtms(w10, d10); __ Fcvtms(w11, d11); __ Fcvtms(w12, d12); __ Fcvtms(w13, d13); __ Fcvtms(w14, d14); __ Fcvtms(w15, d15); __ Fcvtms(x17, s17); __ Fcvtms(x18, s18); __ Fcvtms(x19, s19); __ Fcvtms(x20, s20); __ Fcvtms(x21, s21); __ Fcvtms(x22, s22); __ Fcvtms(x23, s23); __ Fcvtms(x24, d24); __ Fcvtms(x25, d25); __ Fcvtms(x26, d26); __ Fcvtms(x27, d27); __ Fcvtms(x28, d28); __ Fcvtms(x29, d29); __ Fcvtms(x30, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(1, x2); ASSERT_EQUAL_64(0xfffffffe, x3); ASSERT_EQUAL_64(0x7fffffff, x4); ASSERT_EQUAL_64(0x80000000, x5); ASSERT_EQUAL_64(0x7fffff80, x6); ASSERT_EQUAL_64(0x80000080, x7); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(1, x10); ASSERT_EQUAL_64(0xfffffffe, x11); ASSERT_EQUAL_64(0x7fffffff, x12); ASSERT_EQUAL_64(0x80000000, x13); ASSERT_EQUAL_64(0x7ffffffe, x14); ASSERT_EQUAL_64(0x80000001, x15); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(1, x18); ASSERT_EQUAL_64(0xfffffffffffffffe, x19); ASSERT_EQUAL_64(0x7fffffffffffffff, x20); ASSERT_EQUAL_64(0x8000000000000000, x21); ASSERT_EQUAL_64(0x7fffff8000000000, x22); ASSERT_EQUAL_64(0x8000008000000000, x23); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(1, x25); ASSERT_EQUAL_64(0xfffffffffffffffe, x26); ASSERT_EQUAL_64(0x7fffffffffffffff, x27); ASSERT_EQUAL_64(0x8000000000000000, x28); ASSERT_EQUAL_64(0x7ffffffffffffc00, x29); ASSERT_EQUAL_64(0x8000000000000400, x30); } } TEST(fcvtmu) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 1.5); __ Fmov(s3, -1.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0x7fffff80); // Largest float < INT32_MAX. __ Fneg(s7, s6); // Smallest float > INT32_MIN. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 1.5); __ Fmov(d11, -1.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, kWMaxInt - 1); __ Fmov(d15, kWMinInt + 1); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, -1.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0x7fffff8000000000); // Largest float < INT64_MAX. __ Fneg(s23, s22); // Smallest float > INT64_MIN. __ Fmov(d24, 1.1); __ Fmov(d25, 1.5); __ Fmov(d26, -1.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0x7ffffffffffffc00); // Largest double < INT64_MAX. __ Fneg(d30, d29); // Smallest double > INT64_MIN. __ Fcvtmu(w0, s0); __ Fcvtmu(w1, s1); __ Fcvtmu(w2, s2); __ Fcvtmu(w3, s3); __ Fcvtmu(w4, s4); __ Fcvtmu(w5, s5); __ Fcvtmu(w6, s6); __ Fcvtmu(w7, s7); __ Fcvtmu(w8, d8); __ Fcvtmu(w9, d9); __ Fcvtmu(w10, d10); __ Fcvtmu(w11, d11); __ Fcvtmu(w12, d12); __ Fcvtmu(w13, d13); __ Fcvtmu(w14, d14); __ Fcvtmu(x17, s17); __ Fcvtmu(x18, s18); __ Fcvtmu(x19, s19); __ Fcvtmu(x20, s20); __ Fcvtmu(x21, s21); __ Fcvtmu(x22, s22); __ Fcvtmu(x23, s23); __ Fcvtmu(x24, d24); __ Fcvtmu(x25, d25); __ Fcvtmu(x26, d26); __ Fcvtmu(x27, d27); __ Fcvtmu(x28, d28); __ Fcvtmu(x29, d29); __ Fcvtmu(x30, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(1, x2); ASSERT_EQUAL_64(0, x3); ASSERT_EQUAL_64(0xffffffff, x4); ASSERT_EQUAL_64(0, x5); ASSERT_EQUAL_64(0x7fffff80, x6); ASSERT_EQUAL_64(0, x7); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(1, x10); ASSERT_EQUAL_64(0, x11); ASSERT_EQUAL_64(0xffffffff, x12); ASSERT_EQUAL_64(0, x13); ASSERT_EQUAL_64(0x7ffffffe, x14); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(1, x18); ASSERT_EQUAL_64(0, x19); ASSERT_EQUAL_64(0xffffffffffffffff, x20); ASSERT_EQUAL_64(0, x21); ASSERT_EQUAL_64(0x7fffff8000000000, x22); ASSERT_EQUAL_64(0, x23); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(1, x25); ASSERT_EQUAL_64(0, x26); ASSERT_EQUAL_64(0xffffffffffffffff, x27); ASSERT_EQUAL_64(0, x28); ASSERT_EQUAL_64(0x7ffffffffffffc00, x29); ASSERT_EQUAL_64(0, x30); } } TEST(fcvtns) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 1.5); __ Fmov(s3, -1.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0x7fffff80); // Largest float < INT32_MAX. __ Fneg(s7, s6); // Smallest float > INT32_MIN. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 1.5); __ Fmov(d11, -1.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, kWMaxInt - 1); __ Fmov(d15, kWMinInt + 1); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, -1.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0x7fffff8000000000); // Largest float < INT64_MAX. __ Fneg(s23, s22); // Smallest float > INT64_MIN. __ Fmov(d24, 1.1); __ Fmov(d25, 1.5); __ Fmov(d26, -1.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0x7ffffffffffffc00); // Largest double < INT64_MAX. __ Fneg(d30, d29); // Smallest double > INT64_MIN. __ Fcvtns(w0, s0); __ Fcvtns(w1, s1); __ Fcvtns(w2, s2); __ Fcvtns(w3, s3); __ Fcvtns(w4, s4); __ Fcvtns(w5, s5); __ Fcvtns(w6, s6); __ Fcvtns(w7, s7); __ Fcvtns(w8, d8); __ Fcvtns(w9, d9); __ Fcvtns(w10, d10); __ Fcvtns(w11, d11); __ Fcvtns(w12, d12); __ Fcvtns(w13, d13); __ Fcvtns(w14, d14); __ Fcvtns(w15, d15); __ Fcvtns(x17, s17); __ Fcvtns(x18, s18); __ Fcvtns(x19, s19); __ Fcvtns(x20, s20); __ Fcvtns(x21, s21); __ Fcvtns(x22, s22); __ Fcvtns(x23, s23); __ Fcvtns(x24, d24); __ Fcvtns(x25, d25); __ Fcvtns(x26, d26); __ Fcvtns(x27, d27); __ Fcvtns(x28, d28); __ Fcvtns(x29, d29); __ Fcvtns(x30, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(2, x2); ASSERT_EQUAL_64(0xfffffffe, x3); ASSERT_EQUAL_64(0x7fffffff, x4); ASSERT_EQUAL_64(0x80000000, x5); ASSERT_EQUAL_64(0x7fffff80, x6); ASSERT_EQUAL_64(0x80000080, x7); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(2, x10); ASSERT_EQUAL_64(0xfffffffe, x11); ASSERT_EQUAL_64(0x7fffffff, x12); ASSERT_EQUAL_64(0x80000000, x13); ASSERT_EQUAL_64(0x7ffffffe, x14); ASSERT_EQUAL_64(0x80000001, x15); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(2, x18); ASSERT_EQUAL_64(0xfffffffffffffffe, x19); ASSERT_EQUAL_64(0x7fffffffffffffff, x20); ASSERT_EQUAL_64(0x8000000000000000, x21); ASSERT_EQUAL_64(0x7fffff8000000000, x22); ASSERT_EQUAL_64(0x8000008000000000, x23); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(2, x25); ASSERT_EQUAL_64(0xfffffffffffffffe, x26); ASSERT_EQUAL_64(0x7fffffffffffffff, x27); ASSERT_EQUAL_64(0x8000000000000000, x28); ASSERT_EQUAL_64(0x7ffffffffffffc00, x29); ASSERT_EQUAL_64(0x8000000000000400, x30); } } TEST(fcvtnu) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 1.5); __ Fmov(s3, -1.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0xffffff00); // Largest float < UINT32_MAX. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 1.5); __ Fmov(d11, -1.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, 0xfffffffe); __ Fmov(s16, 1.0); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, -1.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0xffffff0000000000); // Largest float < UINT64_MAX. __ Fmov(d24, 1.1); __ Fmov(d25, 1.5); __ Fmov(d26, -1.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0xfffffffffffff800); // Largest double < UINT64_MAX. __ Fmov(s30, 0x100000000); __ Fcvtnu(w0, s0); __ Fcvtnu(w1, s1); __ Fcvtnu(w2, s2); __ Fcvtnu(w3, s3); __ Fcvtnu(w4, s4); __ Fcvtnu(w5, s5); __ Fcvtnu(w6, s6); __ Fcvtnu(w8, d8); __ Fcvtnu(w9, d9); __ Fcvtnu(w10, d10); __ Fcvtnu(w11, d11); __ Fcvtnu(w12, d12); __ Fcvtnu(w13, d13); __ Fcvtnu(w14, d14); __ Fcvtnu(w15, d15); __ Fcvtnu(x16, s16); __ Fcvtnu(x17, s17); __ Fcvtnu(x18, s18); __ Fcvtnu(x19, s19); __ Fcvtnu(x20, s20); __ Fcvtnu(x21, s21); __ Fcvtnu(x22, s22); __ Fcvtnu(x24, d24); __ Fcvtnu(x25, d25); __ Fcvtnu(x26, d26); __ Fcvtnu(x27, d27); __ Fcvtnu(x28, d28); __ Fcvtnu(x29, d29); __ Fcvtnu(w30, s30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(2, x2); ASSERT_EQUAL_64(0, x3); ASSERT_EQUAL_64(0xffffffff, x4); ASSERT_EQUAL_64(0, x5); ASSERT_EQUAL_64(0xffffff00, x6); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(2, x10); ASSERT_EQUAL_64(0, x11); ASSERT_EQUAL_64(0xffffffff, x12); ASSERT_EQUAL_64(0, x13); ASSERT_EQUAL_64(0xfffffffe, x14); ASSERT_EQUAL_64(1, x16); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(2, x18); ASSERT_EQUAL_64(0, x19); ASSERT_EQUAL_64(0xffffffffffffffff, x20); ASSERT_EQUAL_64(0, x21); ASSERT_EQUAL_64(0xffffff0000000000, x22); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(2, x25); ASSERT_EQUAL_64(0, x26); ASSERT_EQUAL_64(0xffffffffffffffff, x27); ASSERT_EQUAL_64(0, x28); ASSERT_EQUAL_64(0xfffffffffffff800, x29); ASSERT_EQUAL_64(0xffffffff, x30); } } TEST(fcvtzs) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 1.5); __ Fmov(s3, -1.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0x7fffff80); // Largest float < INT32_MAX. __ Fneg(s7, s6); // Smallest float > INT32_MIN. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 1.5); __ Fmov(d11, -1.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, kWMaxInt - 1); __ Fmov(d15, kWMinInt + 1); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, -1.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0x7fffff8000000000); // Largest float < INT64_MAX. __ Fneg(s23, s22); // Smallest float > INT64_MIN. __ Fmov(d24, 1.1); __ Fmov(d25, 1.5); __ Fmov(d26, -1.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0x7ffffffffffffc00); // Largest double < INT64_MAX. __ Fneg(d30, d29); // Smallest double > INT64_MIN. __ Fcvtzs(w0, s0); __ Fcvtzs(w1, s1); __ Fcvtzs(w2, s2); __ Fcvtzs(w3, s3); __ Fcvtzs(w4, s4); __ Fcvtzs(w5, s5); __ Fcvtzs(w6, s6); __ Fcvtzs(w7, s7); __ Fcvtzs(w8, d8); __ Fcvtzs(w9, d9); __ Fcvtzs(w10, d10); __ Fcvtzs(w11, d11); __ Fcvtzs(w12, d12); __ Fcvtzs(w13, d13); __ Fcvtzs(w14, d14); __ Fcvtzs(w15, d15); __ Fcvtzs(x17, s17); __ Fcvtzs(x18, s18); __ Fcvtzs(x19, s19); __ Fcvtzs(x20, s20); __ Fcvtzs(x21, s21); __ Fcvtzs(x22, s22); __ Fcvtzs(x23, s23); __ Fcvtzs(x24, d24); __ Fcvtzs(x25, d25); __ Fcvtzs(x26, d26); __ Fcvtzs(x27, d27); __ Fcvtzs(x28, d28); __ Fcvtzs(x29, d29); __ Fcvtzs(x30, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(1, x2); ASSERT_EQUAL_64(0xffffffff, x3); ASSERT_EQUAL_64(0x7fffffff, x4); ASSERT_EQUAL_64(0x80000000, x5); ASSERT_EQUAL_64(0x7fffff80, x6); ASSERT_EQUAL_64(0x80000080, x7); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(1, x10); ASSERT_EQUAL_64(0xffffffff, x11); ASSERT_EQUAL_64(0x7fffffff, x12); ASSERT_EQUAL_64(0x80000000, x13); ASSERT_EQUAL_64(0x7ffffffe, x14); ASSERT_EQUAL_64(0x80000001, x15); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(1, x18); ASSERT_EQUAL_64(0xffffffffffffffff, x19); ASSERT_EQUAL_64(0x7fffffffffffffff, x20); ASSERT_EQUAL_64(0x8000000000000000, x21); ASSERT_EQUAL_64(0x7fffff8000000000, x22); ASSERT_EQUAL_64(0x8000008000000000, x23); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(1, x25); ASSERT_EQUAL_64(0xffffffffffffffff, x26); ASSERT_EQUAL_64(0x7fffffffffffffff, x27); ASSERT_EQUAL_64(0x8000000000000000, x28); ASSERT_EQUAL_64(0x7ffffffffffffc00, x29); ASSERT_EQUAL_64(0x8000000000000400, x30); } } void FjcvtzsHelper(uint64_t value, uint64_t expected, uint32_t expected_z) { SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kJSCVT); START(); __ Fmov(d0, RawbitsToDouble(value)); __ Fjcvtzs(w0, d0); __ Mrs(x1, NZCV); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(expected, x0); ASSERT_EQUAL_32(expected_z, w1); } } TEST(fjcvtzs) { /* Simple values. */ FjcvtzsHelper(0x0000000000000000, 0, ZFlag); // 0.0 FjcvtzsHelper(0x0010000000000000, 0, NoFlag); // The smallest normal value. FjcvtzsHelper(0x3fdfffffffffffff, 0, NoFlag); // The value just below 0.5. FjcvtzsHelper(0x3fe0000000000000, 0, NoFlag); // 0.5 FjcvtzsHelper(0x3fe0000000000001, 0, NoFlag); // The value just above 0.5. FjcvtzsHelper(0x3fefffffffffffff, 0, NoFlag); // The value just below 1.0. FjcvtzsHelper(0x3ff0000000000000, 1, ZFlag); // 1.0 FjcvtzsHelper(0x3ff0000000000001, 1, NoFlag); // The value just above 1.0. FjcvtzsHelper(0x3ff8000000000000, 1, NoFlag); // 1.5 FjcvtzsHelper(0x4024000000000000, 10, ZFlag); // 10 FjcvtzsHelper(0x7fefffffffffffff, 0, NoFlag); // The largest finite value. /* Infinity. */ FjcvtzsHelper(0x7ff0000000000000, 0, NoFlag); /* NaNs. */ /* - Quiet NaNs */ FjcvtzsHelper(0x7ff923456789abcd, 0, NoFlag); FjcvtzsHelper(0x7ff8000000000000, 0, NoFlag); /* - Signalling NaNs */ FjcvtzsHelper(0x7ff123456789abcd, 0, NoFlag); FjcvtzsHelper(0x7ff0000000000001, 0, NoFlag); /* Subnormals. */ /* - A recognisable bit pattern. */ FjcvtzsHelper(0x000123456789abcd, 0, NoFlag); /* - The largest subnormal value. */ FjcvtzsHelper(0x000fffffffffffff, 0, NoFlag); /* - The smallest subnormal value. */ FjcvtzsHelper(0x0000000000000001, 0, NoFlag); /* The same values again, but negated. */ FjcvtzsHelper(0x8000000000000000, 0, NoFlag); FjcvtzsHelper(0x8010000000000000, 0, NoFlag); FjcvtzsHelper(0xbfdfffffffffffff, 0, NoFlag); FjcvtzsHelper(0xbfe0000000000000, 0, NoFlag); FjcvtzsHelper(0xbfe0000000000001, 0, NoFlag); FjcvtzsHelper(0xbfefffffffffffff, 0, NoFlag); FjcvtzsHelper(0xbff0000000000000, 0xffffffff, ZFlag); FjcvtzsHelper(0xbff0000000000001, 0xffffffff, NoFlag); FjcvtzsHelper(0xbff8000000000000, 0xffffffff, NoFlag); FjcvtzsHelper(0xc024000000000000, 0xfffffff6, ZFlag); FjcvtzsHelper(0xffefffffffffffff, 0, NoFlag); FjcvtzsHelper(0xfff0000000000000, 0, NoFlag); FjcvtzsHelper(0xfff923456789abcd, 0, NoFlag); FjcvtzsHelper(0xfff8000000000000, 0, NoFlag); FjcvtzsHelper(0xfff123456789abcd, 0, NoFlag); FjcvtzsHelper(0xfff0000000000001, 0, NoFlag); FjcvtzsHelper(0x800123456789abcd, 0, NoFlag); FjcvtzsHelper(0x800fffffffffffff, 0, NoFlag); FjcvtzsHelper(0x8000000000000001, 0, NoFlag); // Test floating-point numbers of every possible exponent, most of the // expected values are zero but there is a range of exponents where the // results are shifted parts of this mantissa. uint64_t mantissa = 0x0001234567890abc; // Between an exponent of 0 and 52, only some of the top bits of the // mantissa are above the decimal position of doubles so the mantissa is // shifted to the right down to just those top bits. Above 52, all bits // of the mantissa are shifted left above the decimal position until it // reaches 52 + 64 where all the bits are shifted out of the range of 64-bit // integers. int first_exp_boundary = 52; int second_exp_boundary = first_exp_boundary + 64; for (int exponent = 0; exponent < 2048; exponent += 8) { int e = exponent - 1023; uint64_t expected = 0; if (e < 0) { expected = 0; } else if (e <= first_exp_boundary) { expected = (UINT64_C(1) << e) | (mantissa >> (52 - e)); expected &= 0xffffffff; } else if (e < second_exp_boundary) { expected = (mantissa << (e - 52)) & 0xffffffff; } else { expected = 0; } uint64_t value = (static_cast(exponent) << 52) | mantissa; FjcvtzsHelper(value, expected, NoFlag); FjcvtzsHelper(value | kDSignMask, (-expected) & 0xffffffff, NoFlag); } } TEST(fcvtzu) { SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Fmov(s0, 1.0); __ Fmov(s1, 1.1); __ Fmov(s2, 1.5); __ Fmov(s3, -1.5); __ Fmov(s4, kFP32PositiveInfinity); __ Fmov(s5, kFP32NegativeInfinity); __ Fmov(s6, 0x7fffff80); // Largest float < INT32_MAX. __ Fneg(s7, s6); // Smallest float > INT32_MIN. __ Fmov(d8, 1.0); __ Fmov(d9, 1.1); __ Fmov(d10, 1.5); __ Fmov(d11, -1.5); __ Fmov(d12, kFP64PositiveInfinity); __ Fmov(d13, kFP64NegativeInfinity); __ Fmov(d14, kWMaxInt - 1); __ Fmov(d15, kWMinInt + 1); __ Fmov(s17, 1.1); __ Fmov(s18, 1.5); __ Fmov(s19, -1.5); __ Fmov(s20, kFP32PositiveInfinity); __ Fmov(s21, kFP32NegativeInfinity); __ Fmov(s22, 0x7fffff8000000000); // Largest float < INT64_MAX. __ Fneg(s23, s22); // Smallest float > INT64_MIN. __ Fmov(d24, 1.1); __ Fmov(d25, 1.5); __ Fmov(d26, -1.5); __ Fmov(d27, kFP64PositiveInfinity); __ Fmov(d28, kFP64NegativeInfinity); __ Fmov(d29, 0x7ffffffffffffc00); // Largest double < INT64_MAX. __ Fneg(d30, d29); // Smallest double > INT64_MIN. __ Fcvtzu(w0, s0); __ Fcvtzu(w1, s1); __ Fcvtzu(w2, s2); __ Fcvtzu(w3, s3); __ Fcvtzu(w4, s4); __ Fcvtzu(w5, s5); __ Fcvtzu(w6, s6); __ Fcvtzu(w7, s7); __ Fcvtzu(w8, d8); __ Fcvtzu(w9, d9); __ Fcvtzu(w10, d10); __ Fcvtzu(w11, d11); __ Fcvtzu(w12, d12); __ Fcvtzu(w13, d13); __ Fcvtzu(w14, d14); __ Fcvtzu(x17, s17); __ Fcvtzu(x18, s18); __ Fcvtzu(x19, s19); __ Fcvtzu(x20, s20); __ Fcvtzu(x21, s21); __ Fcvtzu(x22, s22); __ Fcvtzu(x23, s23); __ Fcvtzu(x24, d24); __ Fcvtzu(x25, d25); __ Fcvtzu(x26, d26); __ Fcvtzu(x27, d27); __ Fcvtzu(x28, d28); __ Fcvtzu(x29, d29); __ Fcvtzu(x30, d30); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_64(1, x0); ASSERT_EQUAL_64(1, x1); ASSERT_EQUAL_64(1, x2); ASSERT_EQUAL_64(0, x3); ASSERT_EQUAL_64(0xffffffff, x4); ASSERT_EQUAL_64(0, x5); ASSERT_EQUAL_64(0x7fffff80, x6); ASSERT_EQUAL_64(0, x7); ASSERT_EQUAL_64(1, x8); ASSERT_EQUAL_64(1, x9); ASSERT_EQUAL_64(1, x10); ASSERT_EQUAL_64(0, x11); ASSERT_EQUAL_64(0xffffffff, x12); ASSERT_EQUAL_64(0, x13); ASSERT_EQUAL_64(0x7ffffffe, x14); ASSERT_EQUAL_64(1, x17); ASSERT_EQUAL_64(1, x18); ASSERT_EQUAL_64(0, x19); ASSERT_EQUAL_64(0xffffffffffffffff, x20); ASSERT_EQUAL_64(0, x21); ASSERT_EQUAL_64(0x7fffff8000000000, x22); ASSERT_EQUAL_64(0, x23); ASSERT_EQUAL_64(1, x24); ASSERT_EQUAL_64(1, x25); ASSERT_EQUAL_64(0, x26); ASSERT_EQUAL_64(0xffffffffffffffff, x27); ASSERT_EQUAL_64(0, x28); ASSERT_EQUAL_64(0x7ffffffffffffc00, x29); ASSERT_EQUAL_64(0, x30); } } // Test that scvtf and ucvtf can convert the 64-bit input into the expected // value. All possible values of 'fbits' are tested. The expected value is // modified accordingly in each case. // // The expected value is specified as the bit encoding of the expected double // produced by scvtf (expected_scvtf_bits) as well as ucvtf // (expected_ucvtf_bits). // // Where the input value is representable by int32_t or uint32_t, conversions // from W registers will also be tested. static void TestUScvtfHelper(uint64_t in, uint64_t expected_scvtf_bits, uint64_t expected_ucvtf_bits) { uint64_t u64 = in; uint32_t u32 = u64 & 0xffffffff; int64_t s64 = static_cast(in); int32_t s32 = s64 & 0x7fffffff; bool cvtf_s32 = (s64 == s32); bool cvtf_u32 = (u64 == u32); double results_scvtf_x[65]; double results_ucvtf_x[65]; double results_scvtf_w[33]; double results_ucvtf_w[33]; SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Mov(x0, reinterpret_cast(results_scvtf_x)); __ Mov(x1, reinterpret_cast(results_ucvtf_x)); __ Mov(x2, reinterpret_cast(results_scvtf_w)); __ Mov(x3, reinterpret_cast(results_ucvtf_w)); __ Mov(x10, s64); // Corrupt the top word, in case it is accidentally used during W-register // conversions. __ Mov(x11, 0x5555555555555555); __ Bfi(x11, x10, 0, kWRegSize); // Test integer conversions. __ Scvtf(d0, x10); __ Ucvtf(d1, x10); __ Scvtf(d2, w11); __ Ucvtf(d3, w11); __ Str(d0, MemOperand(x0)); __ Str(d1, MemOperand(x1)); __ Str(d2, MemOperand(x2)); __ Str(d3, MemOperand(x3)); // Test all possible values of fbits. for (int fbits = 1; fbits <= 32; fbits++) { __ Scvtf(d0, x10, fbits); __ Ucvtf(d1, x10, fbits); __ Scvtf(d2, w11, fbits); __ Ucvtf(d3, w11, fbits); __ Str(d0, MemOperand(x0, fbits * kDRegSizeInBytes)); __ Str(d1, MemOperand(x1, fbits * kDRegSizeInBytes)); __ Str(d2, MemOperand(x2, fbits * kDRegSizeInBytes)); __ Str(d3, MemOperand(x3, fbits * kDRegSizeInBytes)); } // Conversions from W registers can only handle fbits values <= 32, so just // test conversions from X registers for 32 < fbits <= 64. for (int fbits = 33; fbits <= 64; fbits++) { __ Scvtf(d0, x10, fbits); __ Ucvtf(d1, x10, fbits); __ Str(d0, MemOperand(x0, fbits * kDRegSizeInBytes)); __ Str(d1, MemOperand(x1, fbits * kDRegSizeInBytes)); } END(); if (CAN_RUN()) { RUN(); // Check the results. double expected_scvtf_base = RawbitsToDouble(expected_scvtf_bits); double expected_ucvtf_base = RawbitsToDouble(expected_ucvtf_bits); for (int fbits = 0; fbits <= 32; fbits++) { double expected_scvtf = expected_scvtf_base / std::pow(2, fbits); double expected_ucvtf = expected_ucvtf_base / std::pow(2, fbits); ASSERT_EQUAL_FP64(expected_scvtf, results_scvtf_x[fbits]); ASSERT_EQUAL_FP64(expected_ucvtf, results_ucvtf_x[fbits]); if (cvtf_s32) ASSERT_EQUAL_FP64(expected_scvtf, results_scvtf_w[fbits]); if (cvtf_u32) ASSERT_EQUAL_FP64(expected_ucvtf, results_ucvtf_w[fbits]); } for (int fbits = 33; fbits <= 64; fbits++) { double expected_scvtf = expected_scvtf_base / std::pow(2, fbits); double expected_ucvtf = expected_ucvtf_base / std::pow(2, fbits); ASSERT_EQUAL_FP64(expected_scvtf, results_scvtf_x[fbits]); ASSERT_EQUAL_FP64(expected_ucvtf, results_ucvtf_x[fbits]); } } } TEST(scvtf_ucvtf_double) { // Simple conversions of positive numbers which require no rounding; the // results should not depened on the rounding mode, and ucvtf and scvtf should // produce the same result. TestUScvtfHelper(0x0000000000000000, 0x0000000000000000, 0x0000000000000000); TestUScvtfHelper(0x0000000000000001, 0x3ff0000000000000, 0x3ff0000000000000); TestUScvtfHelper(0x0000000040000000, 0x41d0000000000000, 0x41d0000000000000); TestUScvtfHelper(0x0000000100000000, 0x41f0000000000000, 0x41f0000000000000); TestUScvtfHelper(0x4000000000000000, 0x43d0000000000000, 0x43d0000000000000); // Test mantissa extremities. TestUScvtfHelper(0x4000000000000400, 0x43d0000000000001, 0x43d0000000000001); // The largest int32_t that fits in a double. TestUScvtfHelper(0x000000007fffffff, 0x41dfffffffc00000, 0x41dfffffffc00000); // Values that would be negative if treated as an int32_t. TestUScvtfHelper(0x00000000ffffffff, 0x41efffffffe00000, 0x41efffffffe00000); TestUScvtfHelper(0x0000000080000000, 0x41e0000000000000, 0x41e0000000000000); TestUScvtfHelper(0x0000000080000001, 0x41e0000000200000, 0x41e0000000200000); // The largest int64_t that fits in a double. TestUScvtfHelper(0x7ffffffffffffc00, 0x43dfffffffffffff, 0x43dfffffffffffff); // Check for bit pattern reproduction. TestUScvtfHelper(0x0123456789abcde0, 0x43723456789abcde, 0x43723456789abcde); TestUScvtfHelper(0x0000000012345678, 0x41b2345678000000, 0x41b2345678000000); // Simple conversions of negative int64_t values. These require no rounding, // and the results should not depend on the rounding mode. TestUScvtfHelper(0xffffffffc0000000, 0xc1d0000000000000, 0x43effffffff80000); TestUScvtfHelper(0xffffffff00000000, 0xc1f0000000000000, 0x43efffffffe00000); TestUScvtfHelper(0xc000000000000000, 0xc3d0000000000000, 0x43e8000000000000); // Conversions which require rounding. TestUScvtfHelper(0x1000000000000000, 0x43b0000000000000, 0x43b0000000000000); TestUScvtfHelper(0x1000000000000001, 0x43b0000000000000, 0x43b0000000000000); TestUScvtfHelper(0x1000000000000080, 0x43b0000000000000, 0x43b0000000000000); TestUScvtfHelper(0x1000000000000081, 0x43b0000000000001, 0x43b0000000000001); TestUScvtfHelper(0x1000000000000100, 0x43b0000000000001, 0x43b0000000000001); TestUScvtfHelper(0x1000000000000101, 0x43b0000000000001, 0x43b0000000000001); TestUScvtfHelper(0x1000000000000180, 0x43b0000000000002, 0x43b0000000000002); TestUScvtfHelper(0x1000000000000181, 0x43b0000000000002, 0x43b0000000000002); TestUScvtfHelper(0x1000000000000200, 0x43b0000000000002, 0x43b0000000000002); TestUScvtfHelper(0x1000000000000201, 0x43b0000000000002, 0x43b0000000000002); TestUScvtfHelper(0x1000000000000280, 0x43b0000000000002, 0x43b0000000000002); TestUScvtfHelper(0x1000000000000281, 0x43b0000000000003, 0x43b0000000000003); TestUScvtfHelper(0x1000000000000300, 0x43b0000000000003, 0x43b0000000000003); // Check rounding of negative int64_t values (and large uint64_t values). TestUScvtfHelper(0x8000000000000000, 0xc3e0000000000000, 0x43e0000000000000); TestUScvtfHelper(0x8000000000000001, 0xc3e0000000000000, 0x43e0000000000000); TestUScvtfHelper(0x8000000000000200, 0xc3e0000000000000, 0x43e0000000000000); TestUScvtfHelper(0x8000000000000201, 0xc3dfffffffffffff, 0x43e0000000000000); TestUScvtfHelper(0x8000000000000400, 0xc3dfffffffffffff, 0x43e0000000000000); TestUScvtfHelper(0x8000000000000401, 0xc3dfffffffffffff, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000600, 0xc3dffffffffffffe, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000601, 0xc3dffffffffffffe, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000800, 0xc3dffffffffffffe, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000801, 0xc3dffffffffffffe, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000a00, 0xc3dffffffffffffe, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000a01, 0xc3dffffffffffffd, 0x43e0000000000001); TestUScvtfHelper(0x8000000000000c00, 0xc3dffffffffffffd, 0x43e0000000000002); // Round up to produce a result that's too big for the input to represent. TestUScvtfHelper(0x7ffffffffffffe00, 0x43e0000000000000, 0x43e0000000000000); TestUScvtfHelper(0x7fffffffffffffff, 0x43e0000000000000, 0x43e0000000000000); TestUScvtfHelper(0xfffffffffffffc00, 0xc090000000000000, 0x43f0000000000000); TestUScvtfHelper(0xffffffffffffffff, 0xbff0000000000000, 0x43f0000000000000); } // The same as TestUScvtfHelper, but convert to floats. static void TestUScvtf32Helper(uint64_t in, uint32_t expected_scvtf_bits, uint32_t expected_ucvtf_bits) { uint64_t u64 = in; uint32_t u32 = u64 & 0xffffffff; int64_t s64 = static_cast(in); int32_t s32 = s64 & 0x7fffffff; bool cvtf_s32 = (s64 == s32); bool cvtf_u32 = (u64 == u32); float results_scvtf_x[65]; float results_ucvtf_x[65]; float results_scvtf_w[33]; float results_ucvtf_w[33]; SETUP_WITH_FEATURES(CPUFeatures::kFP); START(); __ Mov(x0, reinterpret_cast(results_scvtf_x)); __ Mov(x1, reinterpret_cast(results_ucvtf_x)); __ Mov(x2, reinterpret_cast(results_scvtf_w)); __ Mov(x3, reinterpret_cast(results_ucvtf_w)); __ Mov(x10, s64); // Corrupt the top word, in case it is accidentally used during W-register // conversions. __ Mov(x11, 0x5555555555555555); __ Bfi(x11, x10, 0, kWRegSize); // Test integer conversions. __ Scvtf(s0, x10); __ Ucvtf(s1, x10); __ Scvtf(s2, w11); __ Ucvtf(s3, w11); __ Str(s0, MemOperand(x0)); __ Str(s1, MemOperand(x1)); __ Str(s2, MemOperand(x2)); __ Str(s3, MemOperand(x3)); // Test all possible values of fbits. for (int fbits = 1; fbits <= 32; fbits++) { __ Scvtf(s0, x10, fbits); __ Ucvtf(s1, x10, fbits); __ Scvtf(s2, w11, fbits); __ Ucvtf(s3, w11, fbits); __ Str(s0, MemOperand(x0, fbits * kSRegSizeInBytes)); __ Str(s1, MemOperand(x1, fbits * kSRegSizeInBytes)); __ Str(s2, MemOperand(x2, fbits * kSRegSizeInBytes)); __ Str(s3, MemOperand(x3, fbits * kSRegSizeInBytes)); } // Conversions from W registers can only handle fbits values <= 32, so just // test conversions from X registers for 32 < fbits <= 64. for (int fbits = 33; fbits <= 64; fbits++) { __ Scvtf(s0, x10, fbits); __ Ucvtf(s1, x10, fbits); __ Str(s0, MemOperand(x0, fbits * kSRegSizeInBytes)); __ Str(s1, MemOperand(x1, fbits * kSRegSizeInBytes)); } END(); if (CAN_RUN()) { RUN(); // Check the results. float expected_scvtf_base = RawbitsToFloat(expected_scvtf_bits); float expected_ucvtf_base = RawbitsToFloat(expected_ucvtf_bits); for (int fbits = 0; fbits <= 32; fbits++) { float expected_scvtf = expected_scvtf_base / std::pow(2.0f, fbits); float expected_ucvtf = expected_ucvtf_base / std::pow(2.0f, fbits); ASSERT_EQUAL_FP32(expected_scvtf, results_scvtf_x[fbits]); ASSERT_EQUAL_FP32(expected_ucvtf, results_ucvtf_x[fbits]); if (cvtf_s32) ASSERT_EQUAL_FP32(expected_scvtf, results_scvtf_w[fbits]); if (cvtf_u32) ASSERT_EQUAL_FP32(expected_ucvtf, results_ucvtf_w[fbits]); } for (int fbits = 33; fbits <= 64; fbits++) { float expected_scvtf = expected_scvtf_base / std::pow(2.0f, fbits); float expected_ucvtf = expected_ucvtf_base / std::pow(2.0f, fbits); ASSERT_EQUAL_FP32(expected_scvtf, results_scvtf_x[fbits]); ASSERT_EQUAL_FP32(expected_ucvtf, results_ucvtf_x[fbits]); } } } TEST(scvtf_ucvtf_float) { // Simple conversions of positive numbers which require no rounding; the // results should not depened on the rounding mode, and ucvtf and scvtf should // produce the same result. TestUScvtf32Helper(0x0000000000000000, 0x00000000, 0x00000000); TestUScvtf32Helper(0x0000000000000001, 0x3f800000, 0x3f800000); TestUScvtf32Helper(0x0000000040000000, 0x4e800000, 0x4e800000); TestUScvtf32Helper(0x0000000100000000, 0x4f800000, 0x4f800000); TestUScvtf32Helper(0x4000000000000000, 0x5e800000, 0x5e800000); // Test mantissa extremities. TestUScvtf32Helper(0x0000000000800001, 0x4b000001, 0x4b000001); TestUScvtf32Helper(0x4000008000000000, 0x5e800001, 0x5e800001); // The largest int32_t that fits in a float. TestUScvtf32Helper(0x000000007fffff80, 0x4effffff, 0x4effffff); // Values that would be negative if treated as an int32_t. TestUScvtf32Helper(0x00000000ffffff00, 0x4f7fffff, 0x4f7fffff); TestUScvtf32Helper(0x0000000080000000, 0x4f000000, 0x4f000000); TestUScvtf32Helper(0x0000000080000100, 0x4f000001, 0x4f000001); // The largest int64_t that fits in a float. TestUScvtf32Helper(0x7fffff8000000000, 0x5effffff, 0x5effffff); // Check for bit pattern reproduction. TestUScvtf32Helper(0x0000000000876543, 0x4b076543, 0x4b076543); // Simple conversions of negative int64_t values. These require no rounding, // and the results should not depend on the rounding mode. TestUScvtf32Helper(0xfffffc0000000000, 0xd4800000, 0x5f7ffffc); TestUScvtf32Helper(0xc000000000000000, 0xde800000, 0x5f400000); // Conversions which require rounding. TestUScvtf32Helper(0x0000800000000000, 0x57000000, 0x57000000); TestUScvtf32Helper(0x0000800000000001, 0x57000000, 0x57000000); TestUScvtf32Helper(0x0000800000800000, 0x57000000, 0x57000000); TestUScvtf32Helper(0x0000800000800001, 0x57000001, 0x57000001); TestUScvtf32Helper(0x0000800001000000, 0x57000001, 0x57000001); TestUScvtf32Helper(0x0000800001000001, 0x57000001, 0x57000001); TestUScvtf32Helper(0x0000800001800000, 0x57000002, 0x57000002); TestUScvtf32Helper(0x0000800001800001, 0x57000002, 0x57000002); TestUScvtf32Helper(0x0000800002000000, 0x57000002, 0x57000002); TestUScvtf32Helper(0x0000800002000001, 0x57000002, 0x57000002); TestUScvtf32Helper(0x0000800002800000, 0x57000002, 0x57000002); TestUScvtf32Helper(0x0000800002800001, 0x57000003, 0x57000003); TestUScvtf32Helper(0x0000800003000000, 0x57000003, 0x57000003); // Check rounding of negative int64_t values (and large uint64_t values). TestUScvtf32Helper(0x8000000000000000, 0xdf000000, 0x5f000000); TestUScvtf32Helper(0x8000000000000001, 0xdf000000, 0x5f000000); TestUScvtf32Helper(0x8000004000000000, 0xdf000000, 0x5f000000); TestUScvtf32Helper(0x8000004000000001, 0xdeffffff, 0x5f000000); TestUScvtf32Helper(0x8000008000000000, 0xdeffffff, 0x5f000000); TestUScvtf32Helper(0x8000008000000001, 0xdeffffff, 0x5f000001); TestUScvtf32Helper(0x800000c000000000, 0xdefffffe, 0x5f000001); TestUScvtf32Helper(0x800000c000000001, 0xdefffffe, 0x5f000001); TestUScvtf32Helper(0x8000010000000000, 0xdefffffe, 0x5f000001); TestUScvtf32Helper(0x8000010000000001, 0xdefffffe, 0x5f000001); TestUScvtf32Helper(0x8000014000000000, 0xdefffffe, 0x5f000001); TestUScvtf32Helper(0x8000014000000001, 0xdefffffd, 0x5f000001); TestUScvtf32Helper(0x8000018000000000, 0xdefffffd, 0x5f000002); // Round up to produce a result that's too big for the input to represent. TestUScvtf32Helper(0x000000007fffffc0, 0x4f000000, 0x4f000000); TestUScvtf32Helper(0x000000007fffffff, 0x4f000000, 0x4f000000); TestUScvtf32Helper(0x00000000ffffff80, 0x4f800000, 0x4f800000); TestUScvtf32Helper(0x00000000ffffffff, 0x4f800000, 0x4f800000); TestUScvtf32Helper(0x7fffffc000000000, 0x5f000000, 0x5f000000); TestUScvtf32Helper(0x7fffffffffffffff, 0x5f000000, 0x5f000000); TestUScvtf32Helper(0xffffff8000000000, 0xd3000000, 0x5f800000); TestUScvtf32Helper(0xffffffffffffffff, 0xbf800000, 0x5f800000); } TEST(process_nan_double) { // Make sure that NaN propagation works correctly. double sn = RawbitsToDouble(0x7ff5555511111111); double qn = RawbitsToDouble(0x7ffaaaaa11111111); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsQuietNaN(qn)); // The input NaNs after passing through ProcessNaN. double sn_proc = RawbitsToDouble(0x7ffd555511111111); double qn_proc = qn; VIXL_ASSERT(IsQuietNaN(sn_proc)); VIXL_ASSERT(IsQuietNaN(qn_proc)); SETUP_WITH_FEATURES(CPUFeatures::kFP); 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(); if (CAN_RUN()) { RUN(); uint64_t qn_raw = DoubleToRawbits(qn); uint64_t sn_raw = DoubleToRawbits(sn); // - Signalling NaN ASSERT_EQUAL_FP64(sn, d1); ASSERT_EQUAL_FP64(RawbitsToDouble(sn_raw & ~kDSignMask), d2); ASSERT_EQUAL_FP64(RawbitsToDouble(sn_raw ^ kDSignMask), d3); // - Quiet NaN ASSERT_EQUAL_FP64(qn, d11); ASSERT_EQUAL_FP64(RawbitsToDouble(qn_raw & ~kDSignMask), d12); ASSERT_EQUAL_FP64(RawbitsToDouble(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); } } TEST(process_nan_float) { // Make sure that NaN propagation works correctly. float sn = RawbitsToFloat(0x7f951111); float qn = RawbitsToFloat(0x7fea1111); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsQuietNaN(qn)); // The input NaNs after passing through ProcessNaN. float sn_proc = RawbitsToFloat(0x7fd51111); float qn_proc = qn; VIXL_ASSERT(IsQuietNaN(sn_proc)); VIXL_ASSERT(IsQuietNaN(qn_proc)); SETUP_WITH_FEATURES(CPUFeatures::kFP); 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(); if (CAN_RUN()) { RUN(); uint32_t qn_raw = FloatToRawbits(qn); uint32_t sn_raw = FloatToRawbits(sn); // - Signalling NaN ASSERT_EQUAL_FP32(sn, s1); ASSERT_EQUAL_FP32(RawbitsToFloat(sn_raw & ~kSSignMask), s2); ASSERT_EQUAL_FP32(RawbitsToFloat(sn_raw ^ kSSignMask), s3); // - Quiet NaN ASSERT_EQUAL_FP32(qn, s11); ASSERT_EQUAL_FP32(RawbitsToFloat(qn_raw & ~kSSignMask), s12); ASSERT_EQUAL_FP32(RawbitsToFloat(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); } } // TODO: TEST(process_nan_half) {} static void ProcessNaNsHelper(double n, double m, double expected) { VIXL_ASSERT(IsNaN(n) || IsNaN(m)); VIXL_ASSERT(IsNaN(expected)); SETUP_WITH_FEATURES(CPUFeatures::kFP); 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(); if (CAN_RUN()) { 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); } } TEST(process_nans_double) { // Make sure that NaN propagation works correctly. double sn = RawbitsToDouble(0x7ff5555511111111); double sm = RawbitsToDouble(0x7ff5555522222222); double qn = RawbitsToDouble(0x7ffaaaaa11111111); double qm = RawbitsToDouble(0x7ffaaaaa22222222); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsSignallingNaN(sm)); VIXL_ASSERT(IsQuietNaN(qn)); VIXL_ASSERT(IsQuietNaN(qm)); // The input NaNs after passing through ProcessNaN. double sn_proc = RawbitsToDouble(0x7ffd555511111111); double sm_proc = RawbitsToDouble(0x7ffd555522222222); double qn_proc = qn; double qm_proc = qm; VIXL_ASSERT(IsQuietNaN(sn_proc)); VIXL_ASSERT(IsQuietNaN(sm_proc)); VIXL_ASSERT(IsQuietNaN(qn_proc)); VIXL_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) { VIXL_ASSERT(IsNaN(n) || IsNaN(m)); VIXL_ASSERT(IsNaN(expected)); SETUP_WITH_FEATURES(CPUFeatures::kFP); 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(); if (CAN_RUN()) { 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); } } TEST(process_nans_float) { // Make sure that NaN propagation works correctly. float sn = RawbitsToFloat(0x7f951111); float sm = RawbitsToFloat(0x7f952222); float qn = RawbitsToFloat(0x7fea1111); float qm = RawbitsToFloat(0x7fea2222); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsSignallingNaN(sm)); VIXL_ASSERT(IsQuietNaN(qn)); VIXL_ASSERT(IsQuietNaN(qm)); // The input NaNs after passing through ProcessNaN. float sn_proc = RawbitsToFloat(0x7fd51111); float sm_proc = RawbitsToFloat(0x7fd52222); float qn_proc = qn; float qm_proc = qm; VIXL_ASSERT(IsQuietNaN(sn_proc)); VIXL_ASSERT(IsQuietNaN(sm_proc)); VIXL_ASSERT(IsQuietNaN(qn_proc)); VIXL_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(Float16 n, Float16 m, Float16 expected) { VIXL_ASSERT(IsNaN(n) || IsNaN(m)); VIXL_ASSERT(IsNaN(expected)); SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kFPHalf); START(); // Execute a number of instructions which all use ProcessNaNs, and check that // they all propagate NaNs correctly. __ Fmov(h0, n); __ Fmov(h1, m); __ Fadd(h2, h0, h1); __ Fsub(h3, h0, h1); __ Fmul(h4, h0, h1); __ Fdiv(h5, h0, h1); __ Fmax(h6, h0, h1); __ Fmin(h7, h0, h1); END(); if (CAN_RUN()) { RUN(); ASSERT_EQUAL_FP16(expected, h2); ASSERT_EQUAL_FP16(expected, h3); ASSERT_EQUAL_FP16(expected, h4); ASSERT_EQUAL_FP16(expected, h5); ASSERT_EQUAL_FP16(expected, h6); ASSERT_EQUAL_FP16(expected, h7); } } TEST(process_nans_half) { // Make sure that NaN propagation works correctly. Float16 sn(RawbitsToFloat16(0x7c11)); Float16 sm(RawbitsToFloat16(0xfc22)); Float16 qn(RawbitsToFloat16(0x7e33)); Float16 qm(RawbitsToFloat16(0xfe44)); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsSignallingNaN(sm)); VIXL_ASSERT(IsQuietNaN(qn)); VIXL_ASSERT(IsQuietNaN(qm)); // The input NaNs after passing through ProcessNaN. Float16 sn_proc(RawbitsToFloat16(0x7e11)); Float16 sm_proc(RawbitsToFloat16(0xfe22)); Float16 qn_proc = qn; Float16 qm_proc = qm; VIXL_ASSERT(IsQuietNaN(sn_proc)); VIXL_ASSERT(IsQuietNaN(sm_proc)); VIXL_ASSERT(IsQuietNaN(qn_proc)); VIXL_ASSERT(IsQuietNaN(qm_proc)); // Quiet NaNs are propagated. ProcessNaNsHelper(qn, Float16(), qn_proc); ProcessNaNsHelper(Float16(), qm, qm_proc); ProcessNaNsHelper(qn, qm, qn_proc); // Signalling NaNs are propagated, and made quiet. ProcessNaNsHelper(sn, Float16(), sn_proc); ProcessNaNsHelper(Float16(), 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) { VIXL_ASSERT(IsNaN(n) || IsNaN(m) || IsNaN(a)); bool test_1op = IsNaN(n); bool test_2op = IsNaN(n) || IsNaN(m); SETUP_WITH_FEATURES(CPUFeatures::kFP); 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(); if (CAN_RUN()) { RUN(); if (test_1op) { uint32_t n_raw = FloatToRawbits(n); ASSERT_EQUAL_FP32(n, s10); ASSERT_EQUAL_FP32(RawbitsToFloat(n_raw & ~kSSignMask), s11); ASSERT_EQUAL_FP32(RawbitsToFloat(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); } } TEST(default_nan_float) { float sn = RawbitsToFloat(0x7f951111); float sm = RawbitsToFloat(0x7f952222); float sa = RawbitsToFloat(0x7f95aaaa); float qn = RawbitsToFloat(0x7fea1111); float qm = RawbitsToFloat(0x7fea2222); float qa = RawbitsToFloat(0x7feaaaaa); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsSignallingNaN(sm)); VIXL_ASSERT(IsSignallingNaN(sa)); VIXL_ASSERT(IsQuietNaN(qn)); VIXL_ASSERT(IsQuietNaN(qm)); VIXL_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) { VIXL_ASSERT(IsNaN(n) || IsNaN(m) || IsNaN(a)); bool test_1op = IsNaN(n); bool test_2op = IsNaN(n) || IsNaN(m); SETUP_WITH_FEATURES(CPUFeatures::kFP); 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(); if (CAN_RUN()) { RUN(); if (test_1op) { uint64_t n_raw = DoubleToRawbits(n); ASSERT_EQUAL_FP64(n, d10); ASSERT_EQUAL_FP64(RawbitsToDouble(n_raw & ~kDSignMask), d11); ASSERT_EQUAL_FP64(RawbitsToDouble(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); } } TEST(default_nan_double) { double sn = RawbitsToDouble(0x7ff5555511111111); double sm = RawbitsToDouble(0x7ff5555522222222); double sa = RawbitsToDouble(0x7ff55555aaaaaaaa); double qn = RawbitsToDouble(0x7ffaaaaa11111111); double qm = RawbitsToDouble(0x7ffaaaaa22222222); double qa = RawbitsToDouble(0x7ffaaaaaaaaaaaaa); VIXL_ASSERT(IsSignallingNaN(sn)); VIXL_ASSERT(IsSignallingNaN(sm)); VIXL_ASSERT(IsSignallingNaN(sa)); VIXL_ASSERT(IsQuietNaN(qn)); VIXL_ASSERT(IsQuietNaN(qm)); VIXL_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); } } // namespace aarch64 } // namespace vixl