| // 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 <cfloat> |
| #include <cmath> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <cstring> |
| #include <sys/mman.h> |
| |
| #include "test-runner.h" |
| #include "test-utils.h" |
| |
| #include "aarch64/cpu-aarch64.h" |
| #include "aarch64/disasm-aarch64.h" |
| #include "aarch64/macro-assembler-aarch64.h" |
| #include "aarch64/simulator-aarch64.h" |
| #include "aarch64/test-utils-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<uintptr_t>(src); |
| uintptr_t dst_base = reinterpret_cast<uintptr_t>(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<uintptr_t>(src); |
| uintptr_t dst_base = reinterpret_cast<uintptr_t>(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<uintptr_t>(src); |
| uintptr_t dst_base = reinterpret_cast<uintptr_t>(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<uintptr_t>(src); |
| uintptr_t dst_base = reinterpret_cast<uintptr_t>(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<uintptr_t>(src); |
| uintptr_t dst_base = reinterpret_cast<uintptr_t>(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<uintptr_t>(src); |
| uintptr_t dst_base = reinterpret_cast<uintptr_t>(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 <typename T> |
| 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 sig1 = RawbitsToDouble(0x7ff5555511111111); |
| double sig2 = RawbitsToDouble(0x7ff5555522222222); |
| double siga = RawbitsToDouble(0x7ff55555aaaaaaaa); |
| double qui1 = RawbitsToDouble(0x7ffaaaaa11111111); |
| double qui2 = RawbitsToDouble(0x7ffaaaaa22222222); |
| double quia = RawbitsToDouble(0x7ffaaaaaaaaaaaaa); |
| VIXL_ASSERT(IsSignallingNaN(sig1)); |
| VIXL_ASSERT(IsSignallingNaN(sig2)); |
| VIXL_ASSERT(IsSignallingNaN(siga)); |
| VIXL_ASSERT(IsQuietNaN(qui1)); |
| VIXL_ASSERT(IsQuietNaN(qui2)); |
| VIXL_ASSERT(IsQuietNaN(quia)); |
| |
| // The input NaNs after passing through ProcessNaN. |
| double sig1_proc = RawbitsToDouble(0x7ffd555511111111); |
| double sig2_proc = RawbitsToDouble(0x7ffd555522222222); |
| double siga_proc = RawbitsToDouble(0x7ffd5555aaaaaaaa); |
| double qui1_proc = qui1; |
| double qui2_proc = qui2; |
| double quia_proc = quia; |
| VIXL_ASSERT(IsQuietNaN(sig1_proc)); |
| VIXL_ASSERT(IsQuietNaN(sig2_proc)); |
| VIXL_ASSERT(IsQuietNaN(siga_proc)); |
| VIXL_ASSERT(IsQuietNaN(qui1_proc)); |
| VIXL_ASSERT(IsQuietNaN(qui2_proc)); |
| VIXL_ASSERT(IsQuietNaN(quia_proc)); |
| |
| // Negated NaNs as it would be done on ARMv8 hardware. |
| double sig1_proc_neg = RawbitsToDouble(0xfffd555511111111); |
| double siga_proc_neg = RawbitsToDouble(0xfffd5555aaaaaaaa); |
| double qui1_proc_neg = RawbitsToDouble(0xfffaaaaa11111111); |
| double quia_proc_neg = RawbitsToDouble(0xfffaaaaaaaaaaaaa); |
| VIXL_ASSERT(IsQuietNaN(sig1_proc_neg)); |
| VIXL_ASSERT(IsQuietNaN(siga_proc_neg)); |
| VIXL_ASSERT(IsQuietNaN(qui1_proc_neg)); |
| VIXL_ASSERT(IsQuietNaN(quia_proc_neg)); |
| |
| // Quiet NaNs are propagated. |
| FmaddFmsubHelper(qui1, |
| 0, |
| 0, |
| qui1_proc, |
| qui1_proc_neg, |
| qui1_proc_neg, |
| qui1_proc); |
| FmaddFmsubHelper(0, qui2, 0, qui2_proc, qui2_proc, qui2_proc, qui2_proc); |
| FmaddFmsubHelper(0, |
| 0, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| FmaddFmsubHelper(qui1, |
| qui2, |
| 0, |
| qui1_proc, |
| qui1_proc_neg, |
| qui1_proc_neg, |
| qui1_proc); |
| FmaddFmsubHelper(0, |
| qui2, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| FmaddFmsubHelper(qui1, |
| 0, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| FmaddFmsubHelper(qui1, |
| qui2, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| |
| // Signalling NaNs are propagated, and made quiet. |
| FmaddFmsubHelper(sig1, |
| 0, |
| 0, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(0, sig2, 0, sig2_proc, sig2_proc, sig2_proc, sig2_proc); |
| FmaddFmsubHelper(0, |
| 0, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| 0, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(0, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| 0, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| |
| // Signalling NaNs take precedence over quiet NaNs. |
| FmaddFmsubHelper(sig1, |
| qui2, |
| quia, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(qui1, |
| sig2, |
| quia, |
| sig2_proc, |
| sig2_proc, |
| sig2_proc, |
| sig2_proc); |
| FmaddFmsubHelper(qui1, |
| qui2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| quia, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(qui1, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| qui2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| |
| // A NaN generated by the intermediate op1 * op2 overrides a quiet NaN in a. |
| FmaddFmsubHelper(0, |
| kFP64PositiveInfinity, |
| quia, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN); |
| FmaddFmsubHelper(kFP64PositiveInfinity, |
| 0, |
| quia, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN); |
| FmaddFmsubHelper(0, |
| kFP64NegativeInfinity, |
| quia, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN); |
| FmaddFmsubHelper(kFP64NegativeInfinity, |
| 0, |
| quia, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN, |
| kFP64DefaultNaN); |
| } |
| |
| |
| TEST(fmadd_fmsub_float_nans) { |
| // Make sure that NaN propagation works correctly. |
| float sig1 = RawbitsToFloat(0x7f951111); |
| float sig2 = RawbitsToFloat(0x7f952222); |
| float siga = RawbitsToFloat(0x7f95aaaa); |
| float qui1 = RawbitsToFloat(0x7fea1111); |
| float qui2 = RawbitsToFloat(0x7fea2222); |
| float quia = RawbitsToFloat(0x7feaaaaa); |
| VIXL_ASSERT(IsSignallingNaN(sig1)); |
| VIXL_ASSERT(IsSignallingNaN(sig2)); |
| VIXL_ASSERT(IsSignallingNaN(siga)); |
| VIXL_ASSERT(IsQuietNaN(qui1)); |
| VIXL_ASSERT(IsQuietNaN(qui2)); |
| VIXL_ASSERT(IsQuietNaN(quia)); |
| |
| // The input NaNs after passing through ProcessNaN. |
| float sig1_proc = RawbitsToFloat(0x7fd51111); |
| float sig2_proc = RawbitsToFloat(0x7fd52222); |
| float siga_proc = RawbitsToFloat(0x7fd5aaaa); |
| float qui1_proc = qui1; |
| float qui2_proc = qui2; |
| float quia_proc = quia; |
| VIXL_ASSERT(IsQuietNaN(sig1_proc)); |
| VIXL_ASSERT(IsQuietNaN(sig2_proc)); |
| VIXL_ASSERT(IsQuietNaN(siga_proc)); |
| VIXL_ASSERT(IsQuietNaN(qui1_proc)); |
| VIXL_ASSERT(IsQuietNaN(qui2_proc)); |
| VIXL_ASSERT(IsQuietNaN(quia_proc)); |
| |
| // Negated NaNs as it would be done on ARMv8 hardware. |
| float sig1_proc_neg = RawbitsToFloat(0xffd51111); |
| float siga_proc_neg = RawbitsToFloat(0xffd5aaaa); |
| float qui1_proc_neg = RawbitsToFloat(0xffea1111); |
| float quia_proc_neg = RawbitsToFloat(0xffeaaaaa); |
| VIXL_ASSERT(IsQuietNaN(sig1_proc_neg)); |
| VIXL_ASSERT(IsQuietNaN(siga_proc_neg)); |
| VIXL_ASSERT(IsQuietNaN(qui1_proc_neg)); |
| VIXL_ASSERT(IsQuietNaN(quia_proc_neg)); |
| |
| // Quiet NaNs are propagated. |
| FmaddFmsubHelper(qui1, |
| 0, |
| 0, |
| qui1_proc, |
| qui1_proc_neg, |
| qui1_proc_neg, |
| qui1_proc); |
| FmaddFmsubHelper(0, qui2, 0, qui2_proc, qui2_proc, qui2_proc, qui2_proc); |
| FmaddFmsubHelper(0, |
| 0, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| FmaddFmsubHelper(qui1, |
| qui2, |
| 0, |
| qui1_proc, |
| qui1_proc_neg, |
| qui1_proc_neg, |
| qui1_proc); |
| FmaddFmsubHelper(0, |
| qui2, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| FmaddFmsubHelper(qui1, |
| 0, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| FmaddFmsubHelper(qui1, |
| qui2, |
| quia, |
| quia_proc, |
| quia_proc, |
| quia_proc_neg, |
| quia_proc_neg); |
| |
| // Signalling NaNs are propagated, and made quiet. |
| FmaddFmsubHelper(sig1, |
| 0, |
| 0, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(0, sig2, 0, sig2_proc, sig2_proc, sig2_proc, sig2_proc); |
| FmaddFmsubHelper(0, |
| 0, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| 0, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(0, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| 0, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| |
| // Signalling NaNs take precedence over quiet NaNs. |
| FmaddFmsubHelper(sig1, |
| qui2, |
| quia, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(qui1, |
| sig2, |
| quia, |
| sig2_proc, |
| sig2_proc, |
| sig2_proc, |
| sig2_proc); |
| FmaddFmsubHelper(qui1, |
| qui2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| quia, |
| sig1_proc, |
| sig1_proc_neg, |
| sig1_proc_neg, |
| sig1_proc); |
| FmaddFmsubHelper(qui1, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| qui2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| FmaddFmsubHelper(sig1, |
| sig2, |
| siga, |
| siga_proc, |
| siga_proc, |
| siga_proc_neg, |
| siga_proc_neg); |
| |
| // A NaN generated by the intermediate op1 * op2 overrides a quiet NaN in a. |
| FmaddFmsubHelper(0, |
| kFP32PositiveInfinity, |
| quia, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN); |
| FmaddFmsubHelper(kFP32PositiveInfinity, |
| 0, |
| quia, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN); |
| FmaddFmsubHelper(0, |
| kFP32NegativeInfinity, |
| quia, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN, |
| kFP32DefaultNaN); |
| FmaddFmsubHelper(kFP32NegativeInfinity, |
| 0, |
| quia, |
| 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); |
| } |
| } |
| |
| typedef void (MacroAssembler::*FcvtFn2)(const Register& rd, |
| const VRegister& vn); |
| typedef void (MacroAssembler::*FcvtFn3)(const Register& rd, |
| const VRegister& vn, |
| int fbits); |
| |
| static void GenFcvt(MacroAssembler* m, |
| FcvtFn2 fn, |
| const Register& rd, |
| const VRegister& vn) { |
| (m->*fn)(rd, vn); |
| } |
| static void GenFcvt(MacroAssembler* m, |
| FcvtFn3 fn, |
| const Register& rd, |
| const VRegister& vn) { |
| (m->*fn)(rd, vn, 0); |
| } |
| |
| template <typename F = FcvtFn2, typename T, size_t N> |
| static void FcvtHelper(F fn, |
| const T (&inputs)[N], |
| const uint64_t (&expected)[N], |
| int dstsize) { |
| VIXL_STATIC_ASSERT(N < 16); // Use no more than 16 registers. |
| |
| SETUP_WITH_FEATURES(CPUFeatures::kFP); |
| START(); |
| |
| for (unsigned i = 0; i < N; i++) { |
| Register wi = WRegister(i); |
| Register xi = XRegister(i); |
| VRegister si = SRegister(i); |
| VRegister di = DRegister(i); |
| |
| if (std::is_same<float, T>::value) { |
| __ Fmov(si, inputs[i]); |
| if (dstsize == kWRegSize) { |
| GenFcvt(&masm, fn, wi, si); |
| } else { |
| VIXL_ASSERT(dstsize == kXRegSize); |
| GenFcvt(&masm, fn, xi, si); |
| } |
| } else { |
| __ Fmov(di, inputs[i]); |
| if (dstsize == kWRegSize) { |
| GenFcvt(&masm, fn, wi, di); |
| } else { |
| VIXL_ASSERT(dstsize == kXRegSize); |
| GenFcvt(&masm, fn, xi, di); |
| } |
| } |
| } |
| |
| END(); |
| if (CAN_RUN()) { |
| RUN(); |
| |
| for (unsigned i = 0; i < N; i++) { |
| ASSERT_EQUAL_64(expected[i], XRegister(i)); |
| } |
| } |
| } |
| |
| // Largest float/double < INT32_MAX. |
| static const float kLargestF32ltI32Max = RawbitsToFloat(0x4effffff); |
| static const double kLargestF64ltI32Max = kWMaxInt - 1; |
| |
| // Smallest float/double > INT32_MIN. |
| static const float kSmallestF32gtI32Min = RawbitsToFloat(0xceffffff); |
| static const double kSmallestF64gtI32Min = kWMinInt + 1; |
| |
| // Largest float/double < INT64_MAX. |
| static const float kLargestF32ltI64Max = RawbitsToFloat(0x5effffff); |
| static const double kLargestF64ltI64Max = RawbitsToDouble(0x43dfffffffffffff); |
| |
| // Smallest float/double > INT64_MIN. |
| static const float kSmallestF32gtI64Min = RawbitsToFloat(0xdeffffff); |
| static const double kSmallestF64gtI64Min = RawbitsToDouble(0xc3dfffffffffffff); |
| |
| // Largest float/double < UINT32_MAX. |
| static const float kLargestF32ltU32Max = 0xffffff00; |
| static const double kLargestF64ltU32Max = 0xfffffffe; |
| |
| // Largest float/double < UINT64_MAX. |
| static const float kLargestF32ltU64Max = 0xffffff0000000000; |
| static const double kLargestF64ltU64Max = 0xfffffffffffff800; |
| |
| TEST(fcvt_infinity) { |
| float inputs_s[] = {kFP32PositiveInfinity, kFP32NegativeInfinity}; |
| double inputs_d[] = {kFP64PositiveInfinity, kFP64NegativeInfinity}; |
| uint64_t expected_w[] = {0x7fffffff, 0x80000000}; |
| uint64_t expected_x[] = {0x7fffffffffffffff, 0x8000000000000000}; |
| |
| // Test all combinations of fcvt, input size and output size. |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_s, expected_w, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_s, expected_w, kWRegSize); |
| |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_d, expected_w, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_d, expected_w, kWRegSize); |
| |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_s, expected_x, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_s, expected_x, kXRegSize); |
| |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_d, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_d, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_d, expected_x, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvt_ws_minmax) { |
| float inputs[] = {kLargestF32ltI32Max, kSmallestF32gtI32Min}; |
| uint64_t expected[] = {0x7fffff80, 0x80000080}; |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs, expected, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs, expected, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs, expected, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs, expected, kWRegSize); |
| |
| float inputs_u[] = {kLargestF32ltU32Max}; |
| uint64_t expected_u[] = {0xffffff00}; |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_u, expected_u, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_u, expected_u, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_u, expected_u, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_u, expected_u, kWRegSize); |
| } |
| |
| TEST(fcvt_wd_minmax) { |
| double inputs[] = {kLargestF64ltI32Max, kSmallestF64gtI32Min}; |
| uint64_t expected[] = {0x7ffffffe, 0x80000001}; |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs, expected, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs, expected, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs, expected, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs, expected, kWRegSize); |
| |
| double inputs_u[] = {kLargestF64ltU32Max}; |
| uint64_t expected_u[] = {0xfffffffe}; |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_u, expected_u, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_u, expected_u, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_u, expected_u, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_u, expected_u, kWRegSize); |
| } |
| |
| TEST(fcvt_xs_minmax) { |
| float inputs[] = {kLargestF32ltI64Max, kSmallestF32gtI64Min}; |
| uint64_t expected[] = {0x7fffff8000000000, 0x8000008000000000}; |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs, expected, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs, expected, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs, expected, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs, expected, kXRegSize); |
| |
| float inputs_u[] = {kLargestF32ltU64Max}; |
| uint64_t expected_u[] = {0xffffff0000000000}; |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_u, expected_u, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_u, expected_u, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_u, expected_u, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_u, expected_u, kXRegSize); |
| } |
| |
| TEST(fcvt_xd_minmax) { |
| double inputs[] = {kLargestF64ltI64Max, kSmallestF64gtI64Min}; |
| uint64_t expected[] = {0x7ffffffffffffc00, 0x8000000000000400}; |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs, expected, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs, expected, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs, expected, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs, expected, kXRegSize); |
| |
| double inputs_u[] = {kLargestF64ltU64Max}; |
| uint64_t expected_u[] = {0xfffffffffffff800}; |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_u, expected_u, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_u, expected_u, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_u, expected_u, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_u, expected_u, kXRegSize); |
| } |
| |
| TEST(fcvtas) { |
| float inputs_s[] = {1.0, 1.1, 2.5, -2.5}; |
| double inputs_d[] = {1.0, 1.1, 2.5, -2.5}; |
| uint64_t expected_w[] = {1, 1, 3, 0xfffffffd}; |
| uint64_t expected_x[] = {1, 1, 3, 0xfffffffffffffffd}; |
| |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtas, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtau) { |
| float inputs_s[] = {1.0, 1.1, 2.5, -2.5, 0x100000000}; |
| double inputs_d[] = {1.0, 1.1, 2.5, -2.5, 0x100000000}; |
| uint64_t expected_w[] = {1, 1, 3, 0, 0xffffffff}; |
| uint64_t expected_x[] = {1, 1, 3, 0, 0x100000000}; |
| |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtau, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtms) { |
| float inputs_s[] = {1.0, 1.1, 1.5, -1.5}; |
| double inputs_d[] = {1.0, 1.1, 1.5, -1.5}; |
| uint64_t expected_w[] = {1, 1, 1, 0xfffffffe}; |
| uint64_t expected_x[] = {1, 1, 1, 0xfffffffffffffffe}; |
| |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtms, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtmu) { |
| float inputs_s[] = {1.0, 1.1, 1.5, -1.5}; |
| double inputs_d[] = {1.0, 1.1, 1.5, -1.5}; |
| uint64_t expected_w[] = {1, 1, 1, 0}; |
| uint64_t expected_x[] = {1, 1, 1, 0}; |
| |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtmu, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtns) { |
| float inputs_s[] = {1.0, 1.1, 1.5, -1.5}; |
| double inputs_d[] = {1.0, 1.1, 1.5, -1.5}; |
| uint64_t expected_w[] = {1, 1, 2, 0xfffffffe}; |
| uint64_t expected_x[] = {1, 1, 2, 0xfffffffffffffffe}; |
| |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtns, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtnu) { |
| float inputs_s[] = {1.0, 1.1, 1.5, -1.5, 0x100000000}; |
| double inputs_d[] = {1.0, 1.1, 1.5, -1.5, 0x100000000}; |
| uint64_t expected_w[] = {1, 1, 2, 0, 0xffffffff}; |
| uint64_t expected_x[] = {1, 1, 2, 0, 0x100000000}; |
| |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_s, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_d, expected_w, kWRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_s, expected_x, kXRegSize); |
| FcvtHelper(&MacroAssembler::Fcvtnu, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtzs) { |
| float inputs_s[] = {1.0, 1.1, 1.5, -1.5}; |
| double inputs_d[] = {1.0, 1.1, 1.5, -1.5}; |
| uint64_t expected_w[] = {1, 1, 1, 0xffffffff}; |
| uint64_t expected_x[] = {1, 1, 1, 0xffffffffffffffff}; |
| |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_s, expected_w, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_d, expected_w, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_s, expected_x, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzs, inputs_d, expected_x, kXRegSize); |
| } |
| |
| TEST(fcvtzu) { |
| float inputs_s[] = {1.0, 1.1, 1.5, -1.5}; |
| double inputs_d[] = {1.0, 1.1, 1.5, -1.5}; |
| uint64_t expected_w[] = {1, 1, 1, 0}; |
| uint64_t expected_x[] = {1, 1, 1, 0}; |
| |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_s, expected_w, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_d, expected_w, kWRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_s, expected_x, kXRegSize); |
| FcvtHelper<FcvtFn3>(&MacroAssembler::Fcvtzu, inputs_d, expected_x, kXRegSize); |
| } |
| |
| 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<uint64_t>(exponent) << 52) | mantissa; |
| FjcvtzsHelper(value, expected, NoFlag); |
| FjcvtzsHelper(value | kDSignMask, (-expected) & 0xffffffff, NoFlag); |
| } |
| } |
| |
| // 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<int64_t>(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<uintptr_t>(results_scvtf_x)); |
| __ Mov(x1, reinterpret_cast<uintptr_t>(results_ucvtf_x)); |
| __ Mov(x2, reinterpret_cast<uintptr_t>(results_scvtf_w)); |
| __ Mov(x3, reinterpret_cast<uintptr_t>(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 depend 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<int64_t>(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<uintptr_t>(results_scvtf_x)); |
| __ Mov(x1, reinterpret_cast<uintptr_t>(results_ucvtf_x)); |
| __ Mov(x2, reinterpret_cast<uintptr_t>(results_scvtf_w)); |
| __ Mov(x3, reinterpret_cast<uintptr_t>(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 depend 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 |