diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 9b718c3f81151f..208889ba34a59b 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -357,6 +357,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.cosf libc.src.math.coshf libc.src.math.cospif + libc.src.math.dmull libc.src.math.erff libc.src.math.exp libc.src.math.exp10 @@ -411,6 +412,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.fmodf libc.src.math.fmodl libc.src.math.fmul + libc.src.math.fmull libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -531,6 +533,8 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.f16div libc.src.math.f16divf libc.src.math.f16fmaf + libc.src.math.f16mul + libc.src.math.f16mulf libc.src.math.f16sqrt libc.src.math.f16sqrtf libc.src.math.f16sub diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 4d19a28f4a2b37..cbdee084aa1990 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -382,6 +382,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.cosf libc.src.math.coshf libc.src.math.cospif + libc.src.math.dmull libc.src.math.erff libc.src.math.exp libc.src.math.exp10 @@ -437,6 +438,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.fmodf libc.src.math.fmodl libc.src.math.fmul + libc.src.math.fmull libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -561,6 +563,9 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.f16fma libc.src.math.f16fmaf libc.src.math.f16fmal + libc.src.math.f16mul + libc.src.math.f16mulf + libc.src.math.f16mull libc.src.math.f16sqrt libc.src.math.f16sqrtf libc.src.math.f16sqrtl @@ -622,6 +627,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.f16addf128 libc.src.math.f16divf128 libc.src.math.f16fmaf128 + libc.src.math.f16mulf128 libc.src.math.f16sqrtf128 libc.src.math.f16subf128 ) @@ -634,6 +640,7 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.canonicalizef128 libc.src.math.ceilf128 libc.src.math.copysignf128 + libc.src.math.dmulf128 libc.src.math.fabsf128 libc.src.math.fdimf128 libc.src.math.floorf128 @@ -648,6 +655,7 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.fminimum_numf128 libc.src.math.fminimumf128 libc.src.math.fmodf128 + libc.src.math.fmulf128 libc.src.math.frexpf128 libc.src.math.fromfpf128 libc.src.math.fromfpxf128 diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index 205d14946535e0..5fab9ce4df9490 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -120,7 +120,7 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | dfma | N/A | N/A | | N/A | | 7.12.14.5 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| dmul | N/A | N/A | | N/A | | 7.12.14.3 | F.10.11 | +| dmul | N/A | N/A | |check| | N/A | |check|\* | 7.12.14.3 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | dsub | N/A | N/A | | N/A | | 7.12.14.2 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ @@ -130,6 +130,8 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | f16fma | |check|\* | |check|\* | |check|\* | N/A | |check| | 7.12.14.5 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| f16mul | |check|\* | |check|\* | |check|\* | N/A | |check| | 7.12.14.5 | F.10.11 | ++------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | f16sub | |check|\* | |check|\* | |check|\* | N/A | |check| | 7.12.14.2 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fabs | |check| | |check| | |check| | |check| | |check| | 7.12.7.3 | F.10.4.3 | @@ -166,7 +168,7 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fmod | |check| | |check| | |check| | |check| | |check| | 7.12.10.1 | F.10.7.1 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| fmul | N/A | |check| | | N/A | | 7.12.14.3 | F.10.11 | +| fmul | N/A | |check| | |check| | N/A | |check|\* | 7.12.14.3 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | frexp | |check| | |check| | |check| | |check| | |check| | 7.12.6.7 | F.10.3.7 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/spec/llvm_libc_ext.td b/libc/spec/llvm_libc_ext.td index 86215029831cae..55b354cae74e0b 100644 --- a/libc/spec/llvm_libc_ext.td +++ b/libc/spec/llvm_libc_ext.td @@ -65,6 +65,14 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> { GuardedFunctionSpec<"f16subf", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16subl", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"fmulf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT128">, + + GuardedFunctionSpec<"dmulf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT128">, + + GuardedFunctionSpec<"f16mul", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16mulf", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16mull", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16div", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16divf", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16divl", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index a4c6b40b983880..18592e92d330a8 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -475,8 +475,6 @@ def StdC : StandardSpec<"stdc"> { GuardedFunctionSpec<"fminimum_mag_numf16", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"fminimum_mag_numf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT128">, - FunctionSpec<"fmul", RetValSpec, [ArgSpec, ArgSpec]>, - FunctionSpec<"fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, @@ -733,6 +731,13 @@ def StdC : StandardSpec<"stdc"> { GuardedFunctionSpec<"f16subf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, + FunctionSpec<"fmul", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"fmull", RetValSpec, [ArgSpec, ArgSpec]>, + + FunctionSpec<"dmull", RetValSpec, [ArgSpec, ArgSpec]>, + + GuardedFunctionSpec<"f16mulf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, + GuardedFunctionSpec<"f16divf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, GuardedFunctionSpec<"f16sqrtf128", RetValSpec, [ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt index c73f68723e2321..43096aa529fc37 100644 --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -84,3 +84,20 @@ add_header_library( libc.src.__support.macros.attributes libc.src.__support.macros.optimization ) + +add_header_library( + mul + HDRS + mul.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.CPP.bit + libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.macros.attributes + libc.src.__support.macros.optimization +) diff --git a/libc/src/__support/FPUtil/generic/mul.h b/libc/src/__support/FPUtil/generic/mul.h new file mode 100644 index 00000000000000..636bb84d3a0db5 --- /dev/null +++ b/libc/src/__support/FPUtil/generic/mul.h @@ -0,0 +1,120 @@ +//===-- Division of IEEE 754 floating-point numbers -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_MUL_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_MUL_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { +namespace fputil::generic { + +template +LIBC_INLINE cpp::enable_if_t && + cpp::is_floating_point_v && + sizeof(OutType) <= sizeof(InType), + OutType> +mul(InType x, InType y) { + using OutFPBits = FPBits; + using OutStorageType = typename OutFPBits::StorageType; + using InFPBits = FPBits; + using InStorageType = typename InFPBits::StorageType; + // The product of two p-digit numbers is a 2p-digit number. + using DyadicFloat = DyadicFloat(InFPBits::FRACTION_LEN))>; + using DyadicMantissaType = typename DyadicFloat::MantissaType; + + InFPBits x_bits(x); + InFPBits y_bits(y); + + Sign result_sign = x_bits.sign() == y_bits.sign() ? Sign::POS : Sign::NEG; + + if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() || + x_bits.is_zero() || y_bits.is_zero())) { + if (x_bits.is_nan() || y_bits.is_nan()) { + if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) + raise_except_if_required(FE_INVALID); + + if (x_bits.is_quiet_nan()) { + InStorageType x_payload = static_cast(getpayload(x)); + if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(x_bits.sign(), + static_cast(x_payload)) + .get_val(); + } + + if (y_bits.is_quiet_nan()) { + InStorageType y_payload = static_cast(getpayload(y)); + if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(y_bits.sign(), + static_cast(y_payload)) + .get_val(); + } + + return OutFPBits::quiet_nan().get_val(); + } + + if (x_bits.is_inf()) { + if (y_bits.is_zero()) { + set_errno_if_required(EDOM); + raise_except_if_required(FE_INVALID); + return OutFPBits::quiet_nan().get_val(); + } + + return OutFPBits::inf(result_sign).get_val(); + } + + if (y_bits.is_inf()) { + if (x_bits.is_zero()) { + set_errno_if_required(EDOM); + raise_except_if_required(FE_INVALID); + return OutFPBits::quiet_nan().get_val(); + } + + return OutFPBits::inf(result_sign).get_val(); + } + + // Now either x or y is zero, and the other one is finite. + return OutFPBits::zero(result_sign).get_val(); + } + + DyadicFloat xd(x); + DyadicFloat yd(y); + + // The product is either in the [2, 4) range or the [1, 2) range. We initially + // set the exponent as if the product were in the [2, 4) range. If the product + // is in the [1, 2) range, then it has 1 leading zero bit and the DyadicFloat + // constructor will normalize it and adjust the exponent. + int result_exp = xd.get_unbiased_exponent() + yd.get_unbiased_exponent() + 1 - + DyadicMantissaType::BITS + 1; + + // We use a single DyadicFloat type, which can fit the 2p-digit product, for + // both the normalized inputs and the product. So we need to right-shift the + // normalized input mantissas before multiplying them. + xd.shift_right(DyadicMantissaType::BITS / 2); + yd.shift_right(DyadicMantissaType::BITS / 2); + DyadicMantissaType product = xd.mantissa * yd.mantissa; + + DyadicFloat result(result_sign, result_exp, product); + return result.template as(); +} + +} // namespace fputil::generic +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_MUL_H diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index dc2339896f2bbd..c4e33130e90903 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -86,6 +86,9 @@ add_math_entrypoint_object(cosh) add_math_entrypoint_object(coshf) add_math_entrypoint_object(cospif) +add_math_entrypoint_object(dmull) +add_math_entrypoint_object(dmulf128) + add_math_entrypoint_object(erf) add_math_entrypoint_object(erff) @@ -118,6 +121,11 @@ add_math_entrypoint_object(f16fmaf) add_math_entrypoint_object(f16fmal) add_math_entrypoint_object(f16fmaf128) +add_math_entrypoint_object(f16mul) +add_math_entrypoint_object(f16mulf) +add_math_entrypoint_object(f16mull) +add_math_entrypoint_object(f16mulf128) + add_math_entrypoint_object(f16sqrt) add_math_entrypoint_object(f16sqrtf) add_math_entrypoint_object(f16sqrtl) @@ -210,6 +218,8 @@ add_math_entrypoint_object(fminimum_mag_numf16) add_math_entrypoint_object(fminimum_mag_numf128) add_math_entrypoint_object(fmul) +add_math_entrypoint_object(fmull) +add_math_entrypoint_object(fmulf128) add_math_entrypoint_object(fmod) add_math_entrypoint_object(fmodf) diff --git a/libc/src/math/dmulf128.h b/libc/src/math/dmulf128.h new file mode 100644 index 00000000000000..623f22c910a414 --- /dev/null +++ b/libc/src/math/dmulf128.h @@ -0,0 +1,21 @@ +//===-- Implementation header for dmulf128 ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_DMULF128_H +#define LLVM_LIBC_SRC_MATH_DMULF128_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +double dmulf128(float128 x, float128 y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_DMULF128_H diff --git a/libc/src/math/dmull.h b/libc/src/math/dmull.h new file mode 100644 index 00000000000000..656776a603009b --- /dev/null +++ b/libc/src/math/dmull.h @@ -0,0 +1,20 @@ +//===-- Implementation header for dmull -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_DMULL_H +#define LLVM_LIBC_SRC_MATH_DMULL_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +double dmull(long double x, long double y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_DMULL_H diff --git a/libc/src/math/f16mul.h b/libc/src/math/f16mul.h new file mode 100644 index 00000000000000..89403cf2192714 --- /dev/null +++ b/libc/src/math/f16mul.h @@ -0,0 +1,21 @@ +//===-- Implementation header for f16mul ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16MUL_H +#define LLVM_LIBC_SRC_MATH_F16MUL_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 f16mul(double x, double y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_F16MUL_H diff --git a/libc/src/math/f16mulf.h b/libc/src/math/f16mulf.h new file mode 100644 index 00000000000000..755886d6f14d0e --- /dev/null +++ b/libc/src/math/f16mulf.h @@ -0,0 +1,21 @@ +//===-- Implementation header for f16mulf -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16MULF_H +#define LLVM_LIBC_SRC_MATH_F16MULF_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 f16mulf(float x, float y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_F16MULF_H diff --git a/libc/src/math/f16mulf128.h b/libc/src/math/f16mulf128.h new file mode 100644 index 00000000000000..14371c57ca88c6 --- /dev/null +++ b/libc/src/math/f16mulf128.h @@ -0,0 +1,21 @@ +//===-- Implementation header for f16mulf128 --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16MULF128_H +#define LLVM_LIBC_SRC_MATH_F16MULF128_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 f16mulf128(float128 x, float128 y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_F16MULF128_H diff --git a/libc/src/math/f16mull.h b/libc/src/math/f16mull.h new file mode 100644 index 00000000000000..a3177cadc1306d --- /dev/null +++ b/libc/src/math/f16mull.h @@ -0,0 +1,21 @@ +//===-- Implementation header for f16mull -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16MULL_H +#define LLVM_LIBC_SRC_MATH_F16MULL_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 f16mull(long double x, long double y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_F16MULL_H diff --git a/libc/src/math/fmulf128.h b/libc/src/math/fmulf128.h new file mode 100644 index 00000000000000..94137ae87eb1ee --- /dev/null +++ b/libc/src/math/fmulf128.h @@ -0,0 +1,21 @@ +//===-- Implementation header for fmulf128 ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_FMULF128_H +#define LLVM_LIBC_SRC_MATH_FMULF128_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float fmulf128(float128 x, float128 y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_FMULF128_H diff --git a/libc/src/math/fmull.h b/libc/src/math/fmull.h new file mode 100644 index 00000000000000..46e6c77cc66a24 --- /dev/null +++ b/libc/src/math/fmull.h @@ -0,0 +1,20 @@ +//===-- Implementation header for fmull -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_FMULL_H +#define LLVM_LIBC_SRC_MATH_FMULL_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +float fmull(long double x, long double y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_FMULL_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 415ca3fbce7965..9c86bac4a0cb77 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -2633,11 +2633,32 @@ add_entrypoint_object( HDRS ../fmul.h DEPENDS - libc.src.__support.FPUtil.basic_operations - libc.src.__support.uint128 - libc.src.__support.CPP.bit - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.rounding_mode + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + fmull + SRCS + fmull.cpp + HDRS + ../fmull.h + DEPENDS + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + fmulf128 + SRCS + fmulf128.cpp + HDRS + ../fmulf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.mul COMPILE_OPTIONS -O3 ) @@ -4200,3 +4221,80 @@ add_entrypoint_object( libc.src.__support.macros.optimization libc.src.__support.integer_literals ) + +add_entrypoint_object( + dmull + SRCS + dmull.cpp + HDRS + ../dmull.h + DEPENDS + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + dmulf128 + SRCS + dmulf128.cpp + HDRS + ../dmulf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16mul + SRCS + f16mul.cpp + HDRS + ../f16mul.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16mulf + SRCS + f16mulf.cpp + HDRS + ../f16mulf.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16mull + SRCS + f16mull.cpp + HDRS + ../f16mull.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16mulf128 + SRCS + f16mulf128.cpp + HDRS + ../f16mulf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.mul + COMPILE_OPTIONS + -O3 +) diff --git a/libc/src/math/generic/dmulf128.cpp b/libc/src/math/generic/dmulf128.cpp new file mode 100644 index 00000000000000..7e6ef95362c091 --- /dev/null +++ b/libc/src/math/generic/dmulf128.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of dmulf128 function -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/dmulf128.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(double, dmulf128, (float128 x, float128 y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/dmull.cpp b/libc/src/math/generic/dmull.cpp new file mode 100644 index 00000000000000..428caa84a9977c --- /dev/null +++ b/libc/src/math/generic/dmull.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of dmull function ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/dmull.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(double, dmull, (long double x, long double y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16mul.cpp b/libc/src/math/generic/f16mul.cpp new file mode 100644 index 00000000000000..f7a5225b60f110 --- /dev/null +++ b/libc/src/math/generic/f16mul.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of f16mul function ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16mul.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float16, f16mul, (double x, double y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16mulf.cpp b/libc/src/math/generic/f16mulf.cpp new file mode 100644 index 00000000000000..2c04664f804ea5 --- /dev/null +++ b/libc/src/math/generic/f16mulf.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of f16mulf function --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16mulf.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float16, f16mulf, (float x, float y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16mulf128.cpp b/libc/src/math/generic/f16mulf128.cpp new file mode 100644 index 00000000000000..7e2d6a0d194ae4 --- /dev/null +++ b/libc/src/math/generic/f16mulf128.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of f16mulf128 function -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16mulf128.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float16, f16mulf128, (float128 x, float128 y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16mull.cpp b/libc/src/math/generic/f16mull.cpp new file mode 100644 index 00000000000000..fc66fba4d9f237 --- /dev/null +++ b/libc/src/math/generic/f16mull.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of f16mull function --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16mull.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float16, f16mull, (long double x, long double y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/fmul.cpp b/libc/src/math/generic/fmul.cpp index 16fa11e93df090..64c27d6e2f9564 100644 --- a/libc/src/math/generic/fmul.cpp +++ b/libc/src/math/generic/fmul.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of fmul function------------------------------------===// +//===-- Implementation of fmul function -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,123 +7,14 @@ //===----------------------------------------------------------------------===// #include "src/math/fmul.h" -#include "src/__support/CPP/bit.h" -#include "src/__support/FPUtil/BasicOperations.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/FPUtil/generic/mul.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/__support/uint128.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float, fmul, (double x, double y)) { - auto x_bits = fputil::FPBits(x); - - auto y_bits = fputil::FPBits(y); - - auto output_sign = (x_bits.sign() != y_bits.sign()) ? Sign::NEG : Sign::POS; - - if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() || - x_bits.is_zero() || y_bits.is_zero())) { - if (x_bits.is_nan()) - return static_cast(x); - if (y_bits.is_nan()) - return static_cast(y); - if (x_bits.is_inf()) - return y_bits.is_zero() - ? fputil::FPBits::quiet_nan().get_val() - : fputil::FPBits::inf(output_sign).get_val(); - if (y_bits.is_inf()) - return x_bits.is_zero() - ? fputil::FPBits::quiet_nan().get_val() - : fputil::FPBits::inf(output_sign).get_val(); - // Now either x or y is zero, and the other one is finite. - return fputil::FPBits::zero(output_sign).get_val(); - } - - uint64_t mx, my; - - // Get mantissa and append the hidden bit if needed. - mx = x_bits.get_explicit_mantissa(); - my = y_bits.get_explicit_mantissa(); - - // Get the corresponding biased exponent. - int ex = x_bits.get_explicit_exponent(); - int ey = y_bits.get_explicit_exponent(); - - // Count the number of leading zeros of the explicit mantissas. - int nx = cpp::countl_zero(mx); - int ny = cpp::countl_zero(my); - // Shift the leading 1 bit to the most significant bit. - mx <<= nx; - my <<= ny; - - // Adjust exponent accordingly: If x or y are normal, we will only need to - // shift by (exponent length + sign bit = 11 bits. If x or y are denormal, we - // will need to shift more than 11 bits. - ex -= (nx - 11); - ey -= (ny - 11); - - UInt128 product = static_cast(mx) * static_cast(my); - int32_t dm1; - uint64_t highs, lows; - uint64_t g, hight, lowt; - uint32_t m; - uint32_t b; - int c; - - highs = static_cast(product >> 64); - c = static_cast(highs >= 0x8000000000000000); - lows = static_cast(product); - - lowt = (lows != 0); - - dm1 = ex + ey + c + fputil::FPBits::EXP_BIAS; - - int round_mode = fputil::quick_get_round(); - if (dm1 >= 255) { - if ((round_mode == FE_TOWARDZERO) || - (round_mode == FE_UPWARD && output_sign.is_neg()) || - (round_mode == FE_DOWNWARD && output_sign.is_pos())) { - return fputil::FPBits::max_normal(output_sign).get_val(); - } - return fputil::FPBits::inf().get_val(); - } else if (dm1 <= 0) { - - int m_shift = 40 + c - dm1; - int g_shift = m_shift - 1; - int h_shift = 64 - g_shift; - m = (m_shift >= 64) ? 0 : static_cast(highs >> m_shift); - - g = g_shift >= 64 ? 0 : (highs >> g_shift) & 1; - hight = h_shift >= 64 ? highs : (highs << h_shift) != 0; - - dm1 = 0; - } else { - m = static_cast(highs >> (39 + c)); - g = (highs >> (38 + c)) & 1; - hight = (highs << (26 - c)) != 0; - } - - if (round_mode == FE_TONEAREST) { - b = g && ((hight && lowt) || ((m & 1) != 0)); - } else if ((output_sign.is_neg() && round_mode == FE_DOWNWARD) || - (output_sign.is_pos() && round_mode == FE_UPWARD)) { - b = (g == 0 && (hight && lowt) == 0) ? 0 : 1; - } else { - b = 0; - } - - uint32_t exp16 = (dm1 << 23); - - uint32_t m2 = m & fputil::FPBits::FRACTION_MASK; - - uint32_t result = (exp16 + m2) + b; - - auto result_bits = fputil::FPBits(result); - result_bits.set_sign(output_sign); - return result_bits.get_val(); + return fputil::generic::mul(x, y); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/fmulf128.cpp b/libc/src/math/generic/fmulf128.cpp new file mode 100644 index 00000000000000..c0c55ace641b86 --- /dev/null +++ b/libc/src/math/generic/fmulf128.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of fmulf128 function -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/fmulf128.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float, fmulf128, (float128 x, float128 y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/fmull.cpp b/libc/src/math/generic/fmull.cpp new file mode 100644 index 00000000000000..41ab165e7d09da --- /dev/null +++ b/libc/src/math/generic/fmull.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of fmull function ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/fmull.h" +#include "src/__support/FPUtil/generic/mul.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float, fmull, (long double x, long double y)) { + return fputil::generic::mul(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 64b4d2c58fb6a5..c28385f620cfd1 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1847,10 +1847,28 @@ add_fp_unittest( SRCS fmul_test.cpp HDRS - FMulTest.h + MulTest.h DEPENDS libc.src.math.fmul + libc.src.stdlib.rand + libc.src.stdlib.srand ) + +add_fp_unittest( + fmull_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + fmull_test.cpp + HDRS + MulTest.h + DEPENDS + libc.src.math.fmull + libc.src.stdlib.rand + libc.src.stdlib.srand +) + add_fp_unittest( asinhf_test NEED_MPFR @@ -2237,6 +2255,66 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + dmull_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + dmull_test.cpp + HDRS + MulTest.h + DEPENDS + libc.src.math.dmull + libc.src.stdlib.rand + libc.src.stdlib.srand +) + +add_fp_unittest( + f16mul_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16mul_test.cpp + HDRS + MulTest.h + DEPENDS + libc.src.math.f16mul + libc.src.stdlib.rand + libc.src.stdlib.srand +) + +add_fp_unittest( + f16mulf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16mulf_test.cpp + HDRS + MulTest.h + DEPENDS + libc.src.math.f16mulf + libc.src.stdlib.rand + libc.src.stdlib.srand +) + +add_fp_unittest( + f16mull_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16mull_test.cpp + HDRS + MulTest.h + DEPENDS + libc.src.math.f16mull + libc.src.stdlib.rand + libc.src.stdlib.srand +) + add_subdirectory(generic) add_subdirectory(smoke) diff --git a/libc/test/src/math/FMulTest.h b/libc/test/src/math/FMulTest.h deleted file mode 100644 index 8ca33ea71b7129..00000000000000 --- a/libc/test/src/math/FMulTest.h +++ /dev/null @@ -1,121 +0,0 @@ -//===-- Utility class to test fmul[f|l] -------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H -#define LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H - -#include "src/__support/FPUtil/FPBits.h" -#include "test/UnitTest/FEnvSafeTest.h" -#include "test/UnitTest/FPMatcher.h" -#include "test/UnitTest/Test.h" -#include "utils/MPFRWrapper/MPFRUtils.h" - -namespace mpfr = LIBC_NAMESPACE::testing::mpfr; - -template -class FmulMPFRTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { - - DECLARE_SPECIAL_CONSTANTS(InType) - -public: - typedef OutType (*FMulFunc)(InType, InType); - - void testFMulMPFR(FMulFunc func) { - constexpr int N = 10; - mpfr::BinaryInput INPUTS[N] = { - {3.0, 5.0}, - {0x1.0p1, 0x1.0p-131}, - {0x1.0p2, 0x1.0p-129}, - {1.0, 1.0}, - {-0.0, -0.0}, - {-0.0, 0.0}, - {0.0, -0.0}, - {0x1.0p100, 0x1.0p100}, - {1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150}, - {1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150}}; - - for (int i = 0; i < N; ++i) { - InType x = INPUTS[i].x; - InType y = INPUTS[i].y; - ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i], - func(x, y), 0.5); - } - } - - void testSpecialInputsMPFR(FMulFunc func) { - constexpr int N = 27; - mpfr::BinaryInput INPUTS[N] = {{inf, 0x1.0p-129}, - {0x1.0p-129, inf}, - {inf, 2.0}, - {3.0, inf}, - {0.0, 0.0}, - {neg_inf, aNaN}, - {aNaN, neg_inf}, - {neg_inf, neg_inf}, - {0.0, neg_inf}, - {neg_inf, 0.0}, - {neg_inf, 1.0}, - {1.0, neg_inf}, - {neg_inf, 0x1.0p-129}, - {0x1.0p-129, neg_inf}, - {0.0, 0x1.0p-129}, - {inf, 0.0}, - {0.0, inf}, - {0.0, aNaN}, - {2.0, aNaN}, - {0x1.0p-129, aNaN}, - {inf, aNaN}, - {aNaN, aNaN}, - {0.0, sNaN}, - {2.0, sNaN}, - {0x1.0p-129, sNaN}, - {inf, sNaN}, - {sNaN, sNaN}}; - - for (int i = 0; i < N; ++i) { - InType x = INPUTS[i].x; - InType y = INPUTS[i].y; - ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i], - func(x, y), 0.5); - } - } - - void testNormalRange(FMulFunc func) { - using FPBits = LIBC_NAMESPACE::fputil::FPBits; - using StorageType = typename FPBits::StorageType; - static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval(); - static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval(); - - constexpr StorageType COUNT = 10'001; - constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT; - for (int signs = 0; signs < 4; ++signs) { - for (StorageType v = MIN_NORMAL, w = MAX_NORMAL; - v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) { - InType x = FPBits(v).get_val(), y = FPBits(w).get_val(); - if (signs % 2 == 1) { - x = -x; - } - if (signs >= 2) { - y = -y; - } - - mpfr::BinaryInput input{x, y}; - ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, input, func(x, y), - 0.5); - } - } - } -}; - -#define LIST_FMUL_MPFR_TESTS(OutType, InType, func) \ - using LlvmLibcFmulTest = FmulMPFRTest; \ - TEST_F(LlvmLibcFmulTest, MulMpfr) { testFMulMPFR(&func); } \ - TEST_F(LlvmLibcFmulTest, NanInfMpfr) { testSpecialInputsMPFR(&func); } \ - TEST_F(LlvmLibcFmulTest, NormalRange) { testNormalRange(&func); } - -#endif // LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H diff --git a/libc/test/src/math/MulTest.h b/libc/test/src/math/MulTest.h new file mode 100644 index 00000000000000..cb81a795be36bb --- /dev/null +++ b/libc/test/src/math/MulTest.h @@ -0,0 +1,95 @@ +//===-- Utility class to test different flavors of float mul ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TEST_SRC_MATH_MULTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_MULTEST_H + +#include "src/stdlib/rand.h" +#include "src/stdlib/srand.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template +class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + struct InConstants { + DECLARE_SPECIAL_CONSTANTS(InType) + }; + + using InFPBits = typename InConstants::FPBits; + using InStorageType = typename InConstants::StorageType; + + static constexpr InStorageType IN_MAX_NORMAL_U = + InFPBits::max_normal().uintval(); + static constexpr InStorageType IN_MIN_NORMAL_U = + InFPBits::min_normal().uintval(); + static constexpr InStorageType IN_MAX_SUBNORMAL_U = + InFPBits::max_subnormal().uintval(); + static constexpr InStorageType IN_MIN_SUBNORMAL_U = + InFPBits::min_subnormal().uintval(); + + InStorageType get_random_bit_pattern() { + InStorageType bits{0}; + for (InStorageType i = 0; i < sizeof(InStorageType) / 2; ++i) + bits = (bits << 2) + static_cast(LIBC_NAMESPACE::rand()); + return bits; + } + +public: + using MulFunc = OutType (*)(InType, InType); + + void test_subnormal_range(MulFunc func) { + constexpr InStorageType COUNT = 10'001; + constexpr InStorageType STEP = + (IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) / COUNT; + LIBC_NAMESPACE::srand(1); + for (int signs = 0; signs < 4; signs++) { + for (InStorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + InType x = InFPBits(get_random_bit_pattern()).get_val(); + InType y = InFPBits(v).get_val(); + if ((signs & 1) != 0) + x = -x; + if ((signs & 2) != 0) + y = -y; + mpfr::BinaryInput input{x, y}; + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Mul, input, func(x, y), + 0.5); + } + } + } + + void test_normal_range(MulFunc func) { + constexpr InStorageType COUNT = 10'001; + constexpr InStorageType STEP = (IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT; + LIBC_NAMESPACE::srand(1); + for (int signs = 0; signs < 4; signs++) { + for (InStorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + InType x = InFPBits(get_random_bit_pattern()).get_val(); + InType y = InFPBits(v).get_val(); + if ((signs & 1) != 0) + x = -x; + if ((signs & 2) != 0) + y = -y; + mpfr::BinaryInput input{x, y}; + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Mul, input, func(x, y), + 0.5); + } + } + } +}; + +#define LIST_MUL_TESTS(OutType, InType, func) \ + using LlvmLibcMulTest = MulTest; \ + TEST_F(LlvmLibcMulTest, SubnormalRange) { test_subnormal_range(&func); } \ + TEST_F(LlvmLibcMulTest, NormalRange) { test_normal_range(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_MULTEST_H diff --git a/libc/test/src/math/dmull_test.cpp b/libc/test/src/math/dmull_test.cpp new file mode 100644 index 00000000000000..1b9c9c2c24ed34 --- /dev/null +++ b/libc/test/src/math/dmull_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for dmull -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/dmull.h" + +LIST_MUL_TESTS(double, long double, LIBC_NAMESPACE::dmull) diff --git a/libc/test/src/math/f16mul_test.cpp b/libc/test/src/math/f16mul_test.cpp new file mode 100644 index 00000000000000..49b443870c4833 --- /dev/null +++ b/libc/test/src/math/f16mul_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mul ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mul.h" + +LIST_MUL_TESTS(float16, double, LIBC_NAMESPACE::f16mul) diff --git a/libc/test/src/math/f16mulf_test.cpp b/libc/test/src/math/f16mulf_test.cpp new file mode 100644 index 00000000000000..bf2530863621db --- /dev/null +++ b/libc/test/src/math/f16mulf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mulf ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mulf.h" + +LIST_MUL_TESTS(float16, float, LIBC_NAMESPACE::f16mulf) diff --git a/libc/test/src/math/f16mull_test.cpp b/libc/test/src/math/f16mull_test.cpp new file mode 100644 index 00000000000000..5292ddb87b7f48 --- /dev/null +++ b/libc/test/src/math/f16mull_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mull ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mull.h" + +LIST_MUL_TESTS(float16, long double, LIBC_NAMESPACE::f16mull) diff --git a/libc/test/src/math/fmul_test.cpp b/libc/test/src/math/fmul_test.cpp index 16eaa1a818daf7..3f6df66456bac5 100644 --- a/libc/test/src/math/fmul_test.cpp +++ b/libc/test/src/math/fmul_test.cpp @@ -1,13 +1,13 @@ -//===-- Unittests for fmul-------------------------------------------------===// +//===-- Unittests for fmul ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// -#include "FMulTest.h" +#include "MulTest.h" #include "src/math/fmul.h" -LIST_FMUL_MPFR_TESTS(float, double, LIBC_NAMESPACE::fmul) +LIST_MUL_TESTS(float, double, LIBC_NAMESPACE::fmul) diff --git a/libc/test/src/math/fmull_test.cpp b/libc/test/src/math/fmull_test.cpp new file mode 100644 index 00000000000000..ef694063f20dc2 --- /dev/null +++ b/libc/test/src/math/fmull_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for fmull -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/fmull.h" + +LIST_MUL_TESTS(float, long double, LIBC_NAMESPACE::fmull) diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 76d5919ad91565..c57aa9638ed302 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -2531,10 +2531,27 @@ add_fp_unittest( SRCS fmul_test.cpp HDRS - FMulTest.h + MulTest.h DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations libc.src.math.fmul - libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + fmull_test + SUITE + libc-math-smoke-tests + SRCS + fmull_test.cpp + HDRS + MulTest.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.fmull ) add_fp_unittest( @@ -3981,3 +3998,78 @@ add_fp_unittest( DEPENDS libc.src.math.cbrt ) + +add_fp_unittest( + dmull_test + SUITE + libc-math-smoke-tests + SRCS + dmull_test.cpp + HDRS + MulTest.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.dmull +) + +add_fp_unittest( + f16mul_test + SUITE + libc-math-smoke-tests + SRCS + f16mul_test.cpp + HDRS + MulTest.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16mul +) + +add_fp_unittest( + f16mulf_test + SUITE + libc-math-smoke-tests + SRCS + f16mulf_test.cpp + HDRS + MulTest.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16mulf +) + +add_fp_unittest( + f16mull_test + SUITE + libc-math-smoke-tests + SRCS + f16mull_test.cpp + HDRS + MulTest.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16mull +) + +add_fp_unittest( + f16mulf128_test + SUITE + libc-math-smoke-tests + SRCS + f16mulf128_test.cpp + HDRS + MulTest.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16mulf128 +) diff --git a/libc/test/src/math/smoke/FMulTest.h b/libc/test/src/math/smoke/FMulTest.h deleted file mode 100644 index 33fb82c8d2da13..00000000000000 --- a/libc/test/src/math/smoke/FMulTest.h +++ /dev/null @@ -1,104 +0,0 @@ -//===-- Utility class to test fmul[f|l] ---------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_FMULTEST_H -#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_FMULTEST_H - -#include "test/UnitTest/FEnvSafeTest.h" -#include "test/UnitTest/FPMatcher.h" -#include "test/UnitTest/Test.h" - -template -class FmulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { - - DECLARE_SPECIAL_CONSTANTS(T) - -public: - typedef T (*FMulFunc)(R, R); - - void testMul(FMulFunc func) { - - EXPECT_FP_EQ_ALL_ROUNDING(T(15.0), func(3.0, 5.0)); - EXPECT_FP_EQ_ALL_ROUNDING(T(0x1.0p-130), func(0x1.0p1, 0x1.0p-131)); - EXPECT_FP_EQ_ALL_ROUNDING(T(0x1.0p-127), func(0x1.0p2, 0x1.0p-129)); - EXPECT_FP_EQ_ALL_ROUNDING(T(1.0), func(1.0, 1.0)); - - EXPECT_FP_EQ_ALL_ROUNDING(T(0.0), func(-0.0, -0.0)); - EXPECT_FP_EQ_ALL_ROUNDING(T(-0.0), func(0.0, -0.0)); - EXPECT_FP_EQ_ALL_ROUNDING(T(-0.0), func(-0.0, 0.0)); - - EXPECT_FP_EQ_ROUNDING_NEAREST(inf, func(0x1.0p100, 0x1.0p100)); - EXPECT_FP_EQ_ROUNDING_UPWARD(inf, func(0x1.0p100, 0x1.0p100)); - EXPECT_FP_EQ_ROUNDING_DOWNWARD(max_normal, func(0x1.0p100, 0x1.0p100)); - EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO(max_normal, func(0x1.0p100, 0x1.0p100)); - - EXPECT_FP_EQ_ROUNDING_NEAREST( - 0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - EXPECT_FP_EQ_ROUNDING_DOWNWARD( - 0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO( - 0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - EXPECT_FP_EQ_ROUNDING_UPWARD( - 0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - - EXPECT_FP_EQ_ROUNDING_NEAREST( - 0x1.0p-128f + 0x1.0p-148f, - func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - EXPECT_FP_EQ_ROUNDING_UPWARD( - 0x1.0p-128f + 0x1.0p-148f, - func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - EXPECT_FP_EQ_ROUNDING_DOWNWARD( - 0x1.0p-128f + 0x1.0p-149f, - func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO( - 0x1.0p-128f + 0x1.0p-149f, - func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150)); - } - - void testSpecialInputs(FMulFunc func) { - EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf, 0x1.0p-129)); - EXPECT_FP_EQ_ALL_ROUNDING(inf, func(0x1.0p-129, inf)); - EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf, 2.0)); - EXPECT_FP_EQ_ALL_ROUNDING(inf, func(3.0, inf)); - EXPECT_FP_EQ_ALL_ROUNDING(0.0, func(0.0, 0.0)); - - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(neg_inf, aNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN, neg_inf)); - EXPECT_FP_EQ_ALL_ROUNDING(inf, func(neg_inf, neg_inf)); - - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, neg_inf)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(neg_inf, 0.0)); - - EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(neg_inf, 1.0)); - EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(1.0, neg_inf)); - - EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(neg_inf, 0x1.0p-129)); - EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(0x1.0p-129, neg_inf)); - - EXPECT_FP_EQ_ALL_ROUNDING(0.0, func(0.0, 0x1.0p-129)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(inf, 0.0)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, inf)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, aNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(2.0, aNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0x1.0p-129, aNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(inf, aNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN, aNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, sNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(2.0, sNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0x1.0p-129, sNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(inf, sNaN)); - EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(sNaN, sNaN)); - } -}; - -#define LIST_FMUL_TESTS(T, R, func) \ - using LlvmLibcFmulTest = FmulTest; \ - TEST_F(LlvmLibcFmulTest, Mul) { testMul(&func); } \ - TEST_F(LlvmLibcFmulTest, NaNInf) { testSpecialInputs(&func); } - -#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_FMULTEST_H diff --git a/libc/test/src/math/smoke/MulTest.h b/libc/test/src/math/smoke/MulTest.h new file mode 100644 index 00000000000000..e2298eaeeb2160 --- /dev/null +++ b/libc/test/src/math/smoke/MulTest.h @@ -0,0 +1,171 @@ +//===-- Utility class to test different flavors of float mul ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/BasicOperations.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +template +class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(OutType) + + struct InConstants { + DECLARE_SPECIAL_CONSTANTS(InType) + }; + + using InFPBits = typename InConstants::FPBits; + using InStorageType = typename InConstants::StorageType; + + InConstants in; + +public: + using MulFunc = OutType (*)(InType, InType); + + void test_special_numbers(MulFunc func) { + EXPECT_FP_IS_NAN(func(aNaN, aNaN)); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID); + + InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val(); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, zero))); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_42))); + + if constexpr (sizeof(OutType) < sizeof(InType)) { + InStorageType max_payload = InFPBits::FRACTION_MASK >> 1; + InType qnan_max = InFPBits::quiet_nan(Sign::POS, max_payload).get_val(); + EXPECT_FP_EQ(zero, + LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, zero))); + EXPECT_FP_EQ(zero, + LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_max))); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, qnan_42))); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, qnan_max))); + } + + EXPECT_FP_EQ(inf, func(inf, InType(1.0))); + EXPECT_FP_EQ(neg_inf, func(neg_inf, InType(1.0))); + EXPECT_FP_EQ(neg_inf, func(inf, InType(-1.0))); + EXPECT_FP_EQ(inf, func(neg_inf, InType(-1.0))); + + EXPECT_FP_EQ_ALL_ROUNDING(zero, func(zero, zero)); + EXPECT_FP_EQ_ALL_ROUNDING(zero, func(neg_zero, neg_zero)); + EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(zero, neg_zero)); + EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(neg_zero, zero)); + + EXPECT_FP_EQ_ALL_ROUNDING(OutType(1.0), func(1.0, 1.0)); + EXPECT_FP_EQ_ALL_ROUNDING(OutType(15.0), func(3.0, 5.0)); + EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-13), func(0x1.0p+1, 0x1.0p-14)); + EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-10), func(0x1.0p+2, 0x1.0p-12)); + } + + void test_invalid_operations(MulFunc func) { + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, zero), FE_INVALID); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_zero), FE_INVALID); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, zero), FE_INVALID); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_zero), FE_INVALID); + } + + void test_range_errors(MulFunc func) { + using namespace LIBC_NAMESPACE::fputil::testing; + + if (ForceRoundingMode r(RoundingMode::Nearest); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + + EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, + func(in.neg_min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + + if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal, + func(neg_max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + + EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, + func(in.neg_min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + + if (ForceRoundingMode r(RoundingMode::Downward); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + + EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal, + func(in.neg_min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + + if (ForceRoundingMode r(RoundingMode::Upward); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal, + func(neg_max_normal, max_normal), + FE_OVERFLOW | FE_INEXACT); + + EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal, + func(in.min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, + func(in.neg_min_denormal, in.min_denormal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + } + + void test_inexact_results(MulFunc func) { + InFPBits x_bits = InFPBits::one(); + x_bits.set_mantissa(InFPBits::SIG_MASK); + InType x = x_bits.get_val(); + func(x, x); + EXPECT_FP_EXCEPTION(FE_INEXACT); + } +}; + +#define LIST_MUL_TESTS(OutType, InType, func) \ + using LlvmLibcMulTest = MulTest; \ + TEST_F(LlvmLibcMulTest, SpecialNumbers) { test_special_numbers(&func); } \ + TEST_F(LlvmLibcMulTest, InvalidOperations) { \ + test_invalid_operations(&func); \ + } \ + TEST_F(LlvmLibcMulTest, RangeErrors) { test_range_errors(&func); } \ + TEST_F(LlvmLibcMulTest, InexactResults) { test_inexact_results(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H diff --git a/libc/test/src/math/smoke/dmulf128_test.cpp b/libc/test/src/math/smoke/dmulf128_test.cpp new file mode 100644 index 00000000000000..2ee2d10b9a19bb --- /dev/null +++ b/libc/test/src/math/smoke/dmulf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for dmulf128 --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/dmulf128.h" + +LIST_MUL_TESTS(double, float128, LIBC_NAMESPACE::dmulf128) diff --git a/libc/test/src/math/smoke/dmull_test.cpp b/libc/test/src/math/smoke/dmull_test.cpp new file mode 100644 index 00000000000000..1b9c9c2c24ed34 --- /dev/null +++ b/libc/test/src/math/smoke/dmull_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for dmull -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/dmull.h" + +LIST_MUL_TESTS(double, long double, LIBC_NAMESPACE::dmull) diff --git a/libc/test/src/math/smoke/f16mul_test.cpp b/libc/test/src/math/smoke/f16mul_test.cpp new file mode 100644 index 00000000000000..49b443870c4833 --- /dev/null +++ b/libc/test/src/math/smoke/f16mul_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mul ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mul.h" + +LIST_MUL_TESTS(float16, double, LIBC_NAMESPACE::f16mul) diff --git a/libc/test/src/math/smoke/f16mulf128_test.cpp b/libc/test/src/math/smoke/f16mulf128_test.cpp new file mode 100644 index 00000000000000..46e52cf068a7b7 --- /dev/null +++ b/libc/test/src/math/smoke/f16mulf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mulf128 ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mulf128.h" + +LIST_MUL_TESTS(float16, float128, LIBC_NAMESPACE::f16mulf128) diff --git a/libc/test/src/math/smoke/f16mulf_test.cpp b/libc/test/src/math/smoke/f16mulf_test.cpp new file mode 100644 index 00000000000000..bf2530863621db --- /dev/null +++ b/libc/test/src/math/smoke/f16mulf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mulf ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mulf.h" + +LIST_MUL_TESTS(float16, float, LIBC_NAMESPACE::f16mulf) diff --git a/libc/test/src/math/smoke/f16mull_test.cpp b/libc/test/src/math/smoke/f16mull_test.cpp new file mode 100644 index 00000000000000..5292ddb87b7f48 --- /dev/null +++ b/libc/test/src/math/smoke/f16mull_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16mull ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/f16mull.h" + +LIST_MUL_TESTS(float16, long double, LIBC_NAMESPACE::f16mull) diff --git a/libc/test/src/math/smoke/fmul_test.cpp b/libc/test/src/math/smoke/fmul_test.cpp index 0eb664f7411eec..3f6df66456bac5 100644 --- a/libc/test/src/math/smoke/fmul_test.cpp +++ b/libc/test/src/math/smoke/fmul_test.cpp @@ -1,13 +1,13 @@ -//===-- Unittests for fmul-------------------------------------------------===// +//===-- Unittests for fmul ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// -#include "FMulTest.h" +#include "MulTest.h" #include "src/math/fmul.h" -LIST_FMUL_TESTS(float, double, LIBC_NAMESPACE::fmul) +LIST_MUL_TESTS(float, double, LIBC_NAMESPACE::fmul) diff --git a/libc/test/src/math/smoke/fmulf128_test.cpp b/libc/test/src/math/smoke/fmulf128_test.cpp new file mode 100644 index 00000000000000..37c8d1cf9908d1 --- /dev/null +++ b/libc/test/src/math/smoke/fmulf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for fmulf128 --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/fmulf128.h" + +LIST_MUL_TESTS(float, float128, LIBC_NAMESPACE::fmulf128) diff --git a/libc/test/src/math/smoke/fmull_test.cpp b/libc/test/src/math/smoke/fmull_test.cpp new file mode 100644 index 00000000000000..ef694063f20dc2 --- /dev/null +++ b/libc/test/src/math/smoke/fmull_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for fmull -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MulTest.h" + +#include "src/math/fmull.h" + +LIST_MUL_TESTS(float, long double, LIBC_NAMESPACE::fmull) diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index b67a9da40bd7b0..bb63e0b9f4de01 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -539,7 +539,7 @@ class MPFRNumber { return result; } - MPFRNumber fmul(const MPFRNumber &b) { + MPFRNumber mul(const MPFRNumber &b) { MPFRNumber result(*this); mpfr_mul(result.value, value, b.value, mpfr_rounding); return result; @@ -800,12 +800,12 @@ binary_operation_one_output(Operation op, InputType x, InputType y, return inputX.fmod(inputY); case Operation::Hypot: return inputX.hypot(inputY); + case Operation::Mul: + return inputX.mul(inputY); case Operation::Pow: return inputX.pow(inputY); case Operation::Sub: return inputX.sub(inputY); - case Operation::Fmul: - return inputX.fmul(inputY); default: __builtin_unreachable(); } @@ -1013,15 +1013,18 @@ void explain_binary_operation_one_output_error( template void explain_binary_operation_one_output_error(Operation, const BinaryInput &, float, double, RoundingMode); +template void explain_binary_operation_one_output_error( + Operation, const BinaryInput &, float, double, RoundingMode); template void explain_binary_operation_one_output_error( Operation, const BinaryInput &, double, double, RoundingMode); +template void explain_binary_operation_one_output_error( + Operation, const BinaryInput &, float, double, RoundingMode); +template void explain_binary_operation_one_output_error( + Operation, const BinaryInput &, double, double, RoundingMode); template void explain_binary_operation_one_output_error(Operation, const BinaryInput &, long double, double, RoundingMode); - -template void explain_binary_operation_one_output_error( - Operation, const BinaryInput &, float, double, RoundingMode); #ifdef LIBC_TYPES_HAS_FLOAT16 template void explain_binary_operation_one_output_error( Operation, const BinaryInput &, float16, double, RoundingMode); @@ -1195,6 +1198,12 @@ template bool compare_binary_operation_one_output(Operation, const BinaryInput &, double, double, RoundingMode); template bool +compare_binary_operation_one_output(Operation, const BinaryInput &, + float, double, RoundingMode); +template bool +compare_binary_operation_one_output(Operation, const BinaryInput &, + double, double, RoundingMode); +template bool compare_binary_operation_one_output(Operation, const BinaryInput &, long double, double, RoundingMode); diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h index 28390af9ee6d89..8d51fa4e477267 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -79,9 +79,9 @@ enum class Operation : int { Div, Fmod, Hypot, + Mul, Pow, Sub, - Fmul, EndBinaryOperationsSingleOutput, // Operations which take two floating point numbers of the same type as