xref: /aosp_15_r20/external/llvm-libc/src/math/generic/fmul.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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