1*71db0c75SAndroid Build Coastguard Worker //===-- Implementation of fmul function -----------------------------------===// 2*71db0c75SAndroid Build Coastguard Worker // 3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*71db0c75SAndroid Build Coastguard Worker // 7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*71db0c75SAndroid Build Coastguard Worker #include "src/math/fmul.h" 9*71db0c75SAndroid Build Coastguard Worker #include "hdr/errno_macros.h" 10*71db0c75SAndroid Build Coastguard Worker #include "hdr/fenv_macros.h" 11*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/double_double.h" 12*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/generic/mul.h" 13*71db0c75SAndroid Build Coastguard Worker #include "src/__support/common.h" 14*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/config.h" 15*71db0c75SAndroid Build Coastguard Worker 16*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL { 17*71db0c75SAndroid Build Coastguard Worker 18*71db0c75SAndroid Build Coastguard Worker LLVM_LIBC_FUNCTION(float, fmul, (double x, double y)) { 19*71db0c75SAndroid Build Coastguard Worker 20*71db0c75SAndroid Build Coastguard Worker // Without FMA instructions, fputil::exact_mult is not 21*71db0c75SAndroid Build Coastguard Worker // correctly rounded for all rounding modes, so we fall 22*71db0c75SAndroid Build Coastguard Worker // back to the generic `fmul` implementation 23*71db0c75SAndroid Build Coastguard Worker 24*71db0c75SAndroid Build Coastguard Worker #ifndef LIBC_TARGET_CPU_HAS_FMA 25*71db0c75SAndroid Build Coastguard Worker return fputil::generic::mul<float>(x, y); 26*71db0c75SAndroid Build Coastguard Worker #else 27*71db0c75SAndroid Build Coastguard Worker fputil::DoubleDouble prod = fputil::exact_mult(x, y); 28*71db0c75SAndroid Build Coastguard Worker using DoubleBits = fputil::FPBits<double>; 29*71db0c75SAndroid Build Coastguard Worker using DoubleStorageType = typename DoubleBits::StorageType; 30*71db0c75SAndroid Build Coastguard Worker using FloatBits = fputil::FPBits<float>; 31*71db0c75SAndroid Build Coastguard Worker using FloatStorageType = typename FloatBits::StorageType; 32*71db0c75SAndroid Build Coastguard Worker DoubleBits x_bits(x); 33*71db0c75SAndroid Build Coastguard Worker DoubleBits y_bits(y); 34*71db0c75SAndroid Build Coastguard Worker 35*71db0c75SAndroid Build Coastguard Worker Sign result_sign = x_bits.sign() == y_bits.sign() ? Sign::POS : Sign::NEG; 36*71db0c75SAndroid Build Coastguard Worker double result = prod.hi; 37*71db0c75SAndroid Build Coastguard Worker DoubleBits hi_bits(prod.hi), lo_bits(prod.lo); 38*71db0c75SAndroid Build Coastguard Worker // Check for cases where we need to propagate the sticky bits: 39*71db0c75SAndroid Build Coastguard Worker constexpr uint64_t STICKY_MASK = 0xFFF'FFF; // Lower (52 - 23 - 1 = 28 bits) 40*71db0c75SAndroid Build Coastguard Worker uint64_t sticky_bits = (hi_bits.uintval() & STICKY_MASK); 41*71db0c75SAndroid Build Coastguard Worker if (LIBC_UNLIKELY(sticky_bits == 0)) { 42*71db0c75SAndroid Build Coastguard Worker // Might need to propagate sticky bits: 43*71db0c75SAndroid Build Coastguard Worker if (!(lo_bits.is_inf_or_nan() || lo_bits.is_zero())) { 44*71db0c75SAndroid Build Coastguard Worker // Now prod.lo is nonzero and finite, we need to propagate sticky bits. 45*71db0c75SAndroid Build Coastguard Worker if (lo_bits.sign() != hi_bits.sign()) 46*71db0c75SAndroid Build Coastguard Worker result = DoubleBits(hi_bits.uintval() - 1).get_val(); 47*71db0c75SAndroid Build Coastguard Worker else 48*71db0c75SAndroid Build Coastguard Worker result = DoubleBits(hi_bits.uintval() | 1).get_val(); 49*71db0c75SAndroid Build Coastguard Worker } 50*71db0c75SAndroid Build Coastguard Worker } 51*71db0c75SAndroid Build Coastguard Worker 52*71db0c75SAndroid Build Coastguard Worker float result_f = static_cast<float>(result); 53*71db0c75SAndroid Build Coastguard Worker FloatBits rf_bits(result_f); 54*71db0c75SAndroid Build Coastguard Worker uint32_t rf_exp = rf_bits.get_biased_exponent(); 55*71db0c75SAndroid Build Coastguard Worker if (LIBC_LIKELY(rf_exp > 0 && rf_exp < 2 * FloatBits::EXP_BIAS + 1)) { 56*71db0c75SAndroid Build Coastguard Worker return result_f; 57*71db0c75SAndroid Build Coastguard Worker } 58*71db0c75SAndroid Build Coastguard Worker 59*71db0c75SAndroid Build Coastguard Worker // Now result_f is either inf/nan/zero/denormal. 60*71db0c75SAndroid Build Coastguard Worker if (x_bits.is_nan() || y_bits.is_nan()) { 61*71db0c75SAndroid Build Coastguard Worker if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) 62*71db0c75SAndroid Build Coastguard Worker fputil::raise_except_if_required(FE_INVALID); 63*71db0c75SAndroid Build Coastguard Worker 64*71db0c75SAndroid Build Coastguard Worker if (x_bits.is_quiet_nan()) { 65*71db0c75SAndroid Build Coastguard Worker DoubleStorageType x_payload = x_bits.get_mantissa(); 66*71db0c75SAndroid Build Coastguard Worker x_payload >>= DoubleBits::FRACTION_LEN - FloatBits::FRACTION_LEN; 67*71db0c75SAndroid Build Coastguard Worker return FloatBits::quiet_nan(x_bits.sign(), 68*71db0c75SAndroid Build Coastguard Worker static_cast<FloatStorageType>(x_payload)) 69*71db0c75SAndroid Build Coastguard Worker .get_val(); 70*71db0c75SAndroid Build Coastguard Worker } 71*71db0c75SAndroid Build Coastguard Worker 72*71db0c75SAndroid Build Coastguard Worker if (y_bits.is_quiet_nan()) { 73*71db0c75SAndroid Build Coastguard Worker DoubleStorageType y_payload = y_bits.get_mantissa(); 74*71db0c75SAndroid Build Coastguard Worker y_payload >>= DoubleBits::FRACTION_LEN - FloatBits::FRACTION_LEN; 75*71db0c75SAndroid Build Coastguard Worker return FloatBits::quiet_nan(y_bits.sign(), 76*71db0c75SAndroid Build Coastguard Worker static_cast<FloatStorageType>(y_payload)) 77*71db0c75SAndroid Build Coastguard Worker .get_val(); 78*71db0c75SAndroid Build Coastguard Worker } 79*71db0c75SAndroid Build Coastguard Worker 80*71db0c75SAndroid Build Coastguard Worker return FloatBits::quiet_nan().get_val(); 81*71db0c75SAndroid Build Coastguard Worker } 82*71db0c75SAndroid Build Coastguard Worker 83*71db0c75SAndroid Build Coastguard Worker if (x_bits.is_inf()) { 84*71db0c75SAndroid Build Coastguard Worker if (y_bits.is_zero()) { 85*71db0c75SAndroid Build Coastguard Worker fputil::set_errno_if_required(EDOM); 86*71db0c75SAndroid Build Coastguard Worker fputil::raise_except_if_required(FE_INVALID); 87*71db0c75SAndroid Build Coastguard Worker 88*71db0c75SAndroid Build Coastguard Worker return FloatBits::quiet_nan().get_val(); 89*71db0c75SAndroid Build Coastguard Worker } 90*71db0c75SAndroid Build Coastguard Worker 91*71db0c75SAndroid Build Coastguard Worker return FloatBits::inf(result_sign).get_val(); 92*71db0c75SAndroid Build Coastguard Worker } 93*71db0c75SAndroid Build Coastguard Worker 94*71db0c75SAndroid Build Coastguard Worker if (y_bits.is_inf()) { 95*71db0c75SAndroid Build Coastguard Worker if (x_bits.is_zero()) { 96*71db0c75SAndroid Build Coastguard Worker fputil::set_errno_if_required(EDOM); 97*71db0c75SAndroid Build Coastguard Worker fputil::raise_except_if_required(FE_INVALID); 98*71db0c75SAndroid Build Coastguard Worker return FloatBits::quiet_nan().get_val(); 99*71db0c75SAndroid Build Coastguard Worker } 100*71db0c75SAndroid Build Coastguard Worker 101*71db0c75SAndroid Build Coastguard Worker return FloatBits::inf(result_sign).get_val(); 102*71db0c75SAndroid Build Coastguard Worker } 103*71db0c75SAndroid Build Coastguard Worker 104*71db0c75SAndroid Build Coastguard Worker // Now either x or y is zero, and the other one is finite. 105*71db0c75SAndroid Build Coastguard Worker if (rf_bits.is_inf()) { 106*71db0c75SAndroid Build Coastguard Worker fputil::set_errno_if_required(ERANGE); 107*71db0c75SAndroid Build Coastguard Worker return FloatBits::inf(result_sign).get_val(); 108*71db0c75SAndroid Build Coastguard Worker } 109*71db0c75SAndroid Build Coastguard Worker 110*71db0c75SAndroid Build Coastguard Worker if (x_bits.is_zero() || y_bits.is_zero()) 111*71db0c75SAndroid Build Coastguard Worker return FloatBits::zero(result_sign).get_val(); 112*71db0c75SAndroid Build Coastguard Worker 113*71db0c75SAndroid Build Coastguard Worker fputil::set_errno_if_required(ERANGE); 114*71db0c75SAndroid Build Coastguard Worker fputil::raise_except_if_required(FE_UNDERFLOW); 115*71db0c75SAndroid Build Coastguard Worker return result_f; 116*71db0c75SAndroid Build Coastguard Worker 117*71db0c75SAndroid Build Coastguard Worker #endif 118*71db0c75SAndroid Build Coastguard Worker } 119*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL 120