1 //===-- Division of IEEE 754 floating-point numbers -------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H 10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H 11 12 #include "hdr/errno_macros.h" 13 #include "hdr/fenv_macros.h" 14 #include "src/__support/CPP/bit.h" 15 #include "src/__support/CPP/type_traits.h" 16 #include "src/__support/FPUtil/BasicOperations.h" 17 #include "src/__support/FPUtil/FEnvImpl.h" 18 #include "src/__support/FPUtil/FPBits.h" 19 #include "src/__support/FPUtil/dyadic_float.h" 20 #include "src/__support/macros/attributes.h" 21 #include "src/__support/macros/config.h" 22 #include "src/__support/macros/optimization.h" 23 24 namespace LIBC_NAMESPACE_DECL { 25 namespace fputil::generic { 26 27 template <typename OutType, typename InType> 28 LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<OutType> && 29 cpp::is_floating_point_v<InType> && 30 sizeof(OutType) <= sizeof(InType), 31 OutType> 32 div(InType x, InType y) { 33 using OutFPBits = FPBits<OutType>; 34 using OutStorageType = typename OutFPBits::StorageType; 35 using InFPBits = FPBits<InType>; 36 using InStorageType = typename InFPBits::StorageType; 37 using DyadicFloat = 38 DyadicFloat<cpp::bit_ceil(static_cast<size_t>(InFPBits::SIG_LEN + 1))>; 39 40 InFPBits x_bits(x); 41 InFPBits y_bits(y); 42 43 Sign result_sign = x_bits.sign() == y_bits.sign() ? Sign::POS : Sign::NEG; 44 45 if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() || 46 x_bits.is_zero() || y_bits.is_zero())) { 47 if (x_bits.is_nan() || y_bits.is_nan()) { 48 if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) 49 raise_except_if_required(FE_INVALID); 50 51 if (x_bits.is_quiet_nan()) { 52 InStorageType x_payload = x_bits.get_mantissa(); 53 x_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN; 54 return OutFPBits::quiet_nan(x_bits.sign(), 55 static_cast<OutStorageType>(x_payload)) 56 .get_val(); 57 } 58 59 if (y_bits.is_quiet_nan()) { 60 InStorageType y_payload = y_bits.get_mantissa(); 61 y_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN; 62 return OutFPBits::quiet_nan(y_bits.sign(), 63 static_cast<OutStorageType>(y_payload)) 64 .get_val(); 65 } 66 67 return OutFPBits::quiet_nan().get_val(); 68 } 69 70 if (x_bits.is_inf()) { 71 if (y_bits.is_inf()) { 72 set_errno_if_required(EDOM); 73 raise_except_if_required(FE_INVALID); 74 return OutFPBits::quiet_nan().get_val(); 75 } 76 77 return OutFPBits::inf(result_sign).get_val(); 78 } 79 80 if (y_bits.is_inf()) 81 return OutFPBits::inf(result_sign).get_val(); 82 83 if (y_bits.is_zero()) { 84 if (x_bits.is_zero()) { 85 raise_except_if_required(FE_INVALID); 86 return OutFPBits::quiet_nan().get_val(); 87 } 88 89 raise_except_if_required(FE_DIVBYZERO); 90 return OutFPBits::inf(result_sign).get_val(); 91 } 92 93 if (x_bits.is_zero()) 94 return OutFPBits::zero(result_sign).get_val(); 95 } 96 97 DyadicFloat xd(x); 98 DyadicFloat yd(y); 99 100 // Number of iterations = full output precision + 1 rounding bit + 1 potential 101 // leading 0. 102 constexpr int NUM_ITERS = OutFPBits::FRACTION_LEN + 3; 103 int result_exp = xd.exponent - yd.exponent - (NUM_ITERS - 1); 104 105 InStorageType q = 0; 106 InStorageType r = static_cast<InStorageType>(xd.mantissa >> 2); 107 InStorageType yd_mant_in = static_cast<InStorageType>(yd.mantissa >> 1); 108 109 for (int i = 0; i < NUM_ITERS; ++i) { 110 q <<= 1; 111 r <<= 1; 112 if (r >= yd_mant_in) { 113 q += 1; 114 r -= yd_mant_in; 115 } 116 } 117 118 DyadicFloat result(result_sign, result_exp, q); 119 result.mantissa |= static_cast<unsigned int>(r != 0); 120 return result.template as<OutType, /*ShouldSignalExceptions=*/true>(); 121 } 122 123 } // namespace fputil::generic 124 } // namespace LIBC_NAMESPACE_DECL 125 126 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H 127