unplugged-system/frameworks/libs/binary_translation/intrinsics/intrinsics_float_test.cc

501 lines
23 KiB
C++

/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gtest/gtest.h"
#include <cmath>
#include <utility> // std::forward
#include "berberis/base/bit_util.h"
#include "berberis/intrinsics/intrinsics_float.h"
namespace berberis {
namespace intrinsics {
// On i386 we have problems with returning NaN floats and doubles from function.
// This is ABI issue (passing certain values through 8087 stack corrupts them) and couldn't be
// fixed - but could be hidden by optimized build
//
// This wrapper makes sure function in question is actually called using 8087 stack on IA32 and
// using proper calling conventions on other platforms.
//
// Note: if function is made static or put in the anonymous namespace then clang may change the
// calling convention! Keep it exportable to prevent that.
template <typename FuncType>
class NonInlineWrapper;
template <typename ResultType, typename... ArgsTypes>
class NonInlineWrapper<ResultType(ArgsTypes...)> {
public:
template <ResultType (*function)(ArgsTypes...)>
static ResultType __attribute__((noinline)) Call(ArgsTypes&&... args) {
return function(std::forward<ArgsTypes>(args)...);
}
};
namespace {
// We couldn't use float consts here because of bit_cast.
constexpr uint32_t kBadNegativeNan32 = 0xff811dea;
constexpr uint32_t kBadPositiveNan32 = 0x7f811dea;
constexpr uint64_t kBadNegativeNan64 = 0xfff0deadbeaf0000;
constexpr uint64_t kBadPositiveNan64 = 0x7ff0deadbeaf0000;
// We don't use std::limits because we want to be sure definitions match ARM.
constexpr uint32_t kPlusZero32 = 0x00000000;
constexpr uint32_t kPlusOne32 = 0x3f800000;
constexpr uint32_t kMinusZero32 = 0x80000000;
constexpr uint32_t kMinusOne32 = 0xbf800000;
constexpr uint32_t kPlusInfinity32 = 0x7f800000;
constexpr uint32_t kMinusInfinity32 = 0xff800000;
// Default NaN created as result of math operations (when NaN wasn't an input).
#if defined(__i386__) || defined(__x86_64__)
constexpr uint32_t kDefaultNan32 = 0xffc00000;
#else
constexpr uint32_t kDefaultNan32 = 0x7fc00000;
#endif
constexpr uint64_t kPlusZero64 = 0x0000000000000000;
// constexpr uint64_t kPlusOne64 = 0x3ff0000000000000;
constexpr uint64_t kMinusZero64 = 0x8000000000000000;
// constexpr uint64_t kMinusOne64 = 0xbff0000000000000;
constexpr uint64_t kPlusInfinity64 = 0x7ff0000000000000;
constexpr uint64_t kMinusInfinity64 = 0xfff0000000000000;
#if defined(__i386__) || defined(__x86_64__)
constexpr uint64_t kDefaultNan64 = 0xfff8000000000000;
#else
constexpr uint64_t kDefaultNan64 = 0x7ff8000000000000;
#endif
#ifdef __i386__
// Please note: tests below are NOT GUARANTEED to succeed on ALL IA32 platforms.
//
// They are only relevant for platforms where 8087 stack is used to pass float/double results.
//
// If they fail in your platforms then you don't need complex dance in intrinsics_float_x86.h
TEST(FPU, float_std_fabs) {
uint32_t fabs_result = bit_cast<uint32_t, float>(NonInlineWrapper<float(float)>::Call<std::fabs>(
bit_cast<float, uint32_t>(kBadNegativeNan32)));
EXPECT_NE(fabs_result, kBadPositiveNan32);
}
TEST(FPU, float_fabsf) {
uint32_t fabsf_result = bit_cast<uint32_t, float>(
NonInlineWrapper<float(float)>::Call<::fabsf>(bit_cast<float, uint32_t>(kBadNegativeNan32)));
EXPECT_NE(fabsf_result, kBadPositiveNan32);
}
TEST(FPU, double_std_fabs) {
uint64_t fabs_result =
bit_cast<uint64_t, double>(NonInlineWrapper<double(double)>::Call<std::fabs>(
bit_cast<double, uint64_t>(kBadNegativeNan64)));
EXPECT_NE(fabs_result, kBadPositiveNan64);
}
TEST(FPU, double_fabs) {
uint64_t fabs_result = bit_cast<uint64_t, double>(NonInlineWrapper<double(double)>::Call<::fabs>(
bit_cast<double, uint64_t>(kBadNegativeNan64)));
EXPECT_NE(fabs_result, kBadPositiveNan64);
}
#endif
TEST(FPU, Float32_fabs) {
uint32_t fabs_result =
bit_cast<uint32_t, Float32>(NonInlineWrapper<Float32(const Float32&)>::Call<Absolute>(
bit_cast<Float32, uint32_t>(kBadNegativeNan32)));
EXPECT_EQ(fabs_result, kBadPositiveNan32);
}
TEST(FPU, Float64_fabs) {
uint64_t fabs_result =
bit_cast<uint64_t, Float64>(NonInlineWrapper<Float64(const Float64&)>::Call<Absolute>(
bit_cast<Float64, uint64_t>(kBadNegativeNan64)));
EXPECT_EQ(fabs_result, kBadPositiveNan64);
}
TEST(FPU, Float32_fneg) {
uint32_t fabs_result =
bit_cast<uint32_t, Float32>(NonInlineWrapper<Float32(const Float32&)>::Call<Negative>(
bit_cast<Float32, uint32_t>(kBadNegativeNan32)));
EXPECT_EQ(fabs_result, kBadPositiveNan32);
}
TEST(FPU, Float64_fneg) {
uint64_t fabs_result =
bit_cast<uint64_t, Float64>(NonInlineWrapper<Float64(const Float64&)>::Call<Negative>(
bit_cast<Float64, uint64_t>(kBadNegativeNan64)));
EXPECT_EQ(fabs_result, kBadPositiveNan64);
}
TEST(FPU, Float32_InfPlusMinusInf) {
// +inf + +inf => +inf
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) +
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kPlusInfinity32);
// -inf + -inf => -inf
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) +
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kMinusInfinity32);
// +inf + -inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) +
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// -inf + +inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) +
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
}
TEST(FPU, Float64_InfPlusMinusInf) {
// +inf + +inf => +inf
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) +
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kPlusInfinity64);
// -inf + -inf => -inf
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) +
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kMinusInfinity64);
// +inf + -inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) +
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// -inf + +inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) +
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
}
TEST(FPU, Float32_ZeroPlusMinusZero) {
// +0.f + +0.f => +0.f
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) +
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kPlusZero32);
// +0.f + -0.f => +0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) +
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kPlusZero32);
// -0.f + +0.f => +0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) +
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kPlusZero32);
// -0.f + -0.f => -0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) +
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kMinusZero32);
}
TEST(FPU, Float64_ZeroPlusMinusZero) {
// +0.f + +0.f => +0.f
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) +
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kPlusZero64);
// +0.f + -0.f => +0.f
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) +
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kPlusZero64);
// -0.f + +0.f => +0.f
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) +
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kPlusZero64);
// -0.f + -0.f => -0.f
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) +
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kMinusZero64);
}
TEST(FPU, Float32_InfMinusInf) {
// +inf - -inf => +inf
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) -
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kPlusInfinity32);
// -inf - +inf => -inf
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) -
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kMinusInfinity32);
// +inf - +inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) -
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// -inf - -inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) -
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
}
TEST(FPU, Float64_InfMinusInf) {
// +inf - -inf => +inf
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) -
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kPlusInfinity64);
// -inf - +inf => -inf
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) -
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kMinusInfinity64);
// +inf - +inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) -
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// -inf - -inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) -
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
}
TEST(FPU, Float32_ZeroMinusZero) {
// +0.f - +0.f => +0.f
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) -
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kPlusZero32);
// +0.f - -0.f => +0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) -
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kPlusZero32);
// -0.f - +0.f => -0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) -
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kMinusZero32);
// -0.f - +0.f => +0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) -
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kPlusZero32);
}
TEST(FPU, Float64_ZeroMinusZero) {
// +0.0 - +0.0 => +0.0
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) -
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kPlusZero64);
// +0.0 - -0.0 => +0.0
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) -
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kPlusZero64);
// -0.0 - +0.0 => -0.0
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) -
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kMinusZero64);
// -0.0 - +0.0 => +0.0
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) -
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kPlusZero64);
}
TEST(FPU, Float32_InfMultiplyByZero) {
// +inf * +0.f => dNaN
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) *
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kDefaultNan32);
// +0.f * +inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) *
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// +inf * -0.f => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) *
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kDefaultNan32);
// -0.f * +inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) *
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// -inf * +0.f => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) *
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kDefaultNan32);
// +0.f * -inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) *
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// -inf * -0.f => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) *
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kDefaultNan32);
// -0.f * -inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) *
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
}
TEST(FPU, Float64_InfMultiplyByZero) {
// +inf * +0.0 => dNaN
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) *
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kDefaultNan64);
// +0.0 * +inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) *
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// +inf * -0.0 => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) *
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kDefaultNan64);
// -0.0 * +inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) *
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// -inf * +0.0 => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) *
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kDefaultNan64);
// +0.0 * -inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) *
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// -inf * -0.0 => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) *
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kDefaultNan64);
// -0.0 * -inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) *
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
}
TEST(FPU, Float32_ZeroMultiplyByZero) {
// +0.f * +0.f => +0.f
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) *
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kPlusZero32);
// +0.f * -0.f => -0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) *
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kMinusZero32);
// -0.f * +0.f => -0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) *
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kMinusZero32);
// -0.f * -0.f => +0.f
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) *
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kPlusZero32);
}
TEST(FPU, Float64_ZeroMultiplyByZero) {
// +0.0 * +0.0 => +0.0
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) *
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kPlusZero64);
// +0.0 * -0.0 => -0.0
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) *
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kMinusZero64);
// -0.0 * +0.0 => -0.0
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) *
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kMinusZero64);
// -0.0 * -0.0 => +0.0
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) *
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kPlusZero64);
}
TEST(FPU, Float32_InfDivideByInf) {
// +inf / +inf => dNaN
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) /
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// +inf / -inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusInfinity32) /
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// -inf / +inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) /
bit_cast<Float32, uint32_t>(kPlusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
// -inf / -inf => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusInfinity32) /
bit_cast<Float32, uint32_t>(kMinusInfinity32));
EXPECT_EQ(result, kDefaultNan32);
}
TEST(FPU, Float64_InfDivideByInf) {
// +inf / +inf => dNaN
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) /
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// +inf / -inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusInfinity64) /
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// -inf / +inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) /
bit_cast<Float64, uint64_t>(kPlusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
// -inf / -inf => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusInfinity64) /
bit_cast<Float64, uint64_t>(kMinusInfinity64));
EXPECT_EQ(result, kDefaultNan64);
}
TEST(FPU, Float32_ZeroDivideByZero) {
// +0.f - +0.f => dNaN
uint32_t result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) /
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kDefaultNan32);
// +0.f - -0.f => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kPlusZero32) /
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kDefaultNan32);
// -0.f - +0.f => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) /
bit_cast<Float32, uint32_t>(kPlusZero32));
EXPECT_EQ(result, kDefaultNan32);
// -0.f - +0.f => dNaN
result = bit_cast<uint32_t, Float32>(bit_cast<Float32, uint32_t>(kMinusZero32) /
bit_cast<Float32, uint32_t>(kMinusZero32));
EXPECT_EQ(result, kDefaultNan32);
}
TEST(FPU, Float64_ZeroDivideByZero) {
// +0.0 - +0.0 => dNaN
uint64_t result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) /
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kDefaultNan64);
// +0.0 - -0.0 => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kPlusZero64) /
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kDefaultNan64);
// -0.0 - +0.0 => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) /
bit_cast<Float64, uint64_t>(kPlusZero64));
EXPECT_EQ(result, kDefaultNan64);
// -0.0 - +0.0 => dNaN
result = bit_cast<uint64_t, Float64>(bit_cast<Float64, uint64_t>(kMinusZero64) /
bit_cast<Float64, uint64_t>(kMinusZero64));
EXPECT_EQ(result, kDefaultNan64);
}
TEST(FPU, Float32_Sqrt) {
// +0.0 => +0.0
uint32_t result = bit_cast<uint32_t, Float32>(Sqrt(bit_cast<Float32, uint32_t>(kPlusZero32)));
EXPECT_EQ(result, kPlusZero32);
// -0.0 => -0.0
result = bit_cast<uint32_t, Float32>(Sqrt(bit_cast<Float32, uint32_t>(kMinusZero32)));
EXPECT_EQ(result, kMinusZero32);
// +1.0 => +1.0
result = bit_cast<uint32_t, Float32>(Sqrt(bit_cast<Float32, uint32_t>(kPlusOne32)));
EXPECT_EQ(result, kPlusOne32);
// -1.0 => dNaN
result = bit_cast<uint32_t, Float32>(Sqrt(bit_cast<Float32, uint32_t>(kMinusOne32)));
EXPECT_EQ(result, kDefaultNan32);
}
} // namespace
} // namespace intrinsics
} // namespace berberis