Skip to content

Commit 44fb424

Browse files
committed
fixup! [libc][math][c23] Add f16divf C23 math function
1 parent 4ff508d commit 44fb424

File tree

3 files changed

+29
-117
lines changed

3 files changed

+29
-117
lines changed

libc/src/__support/FPUtil/dyadic_float.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ template <size_t Bits> struct DyadicFloat {
107107
T d_hi =
108108
FPBits<T>::create_value(sign, 2 * FPBits<T>::EXP_BIAS, IMPLICIT_MASK)
109109
.get_val();
110-
return T(2) * d_hi;
110+
// volatile prevents constant propagation that would result in infinity
111+
// always being returned no matter the current rounding mode.
112+
volatile T two(2.0);
113+
return two * d_hi;
111114
}
112115

113116
bool denorm = false;
@@ -179,10 +182,18 @@ template <size_t Bits> struct DyadicFloat {
179182
output_bits_t clear_exp = static_cast<output_bits_t>(
180183
output_bits_t(exp_hi) << FPBits<T>::SIG_LEN);
181184
output_bits_t r_bits = FPBits<T>(r).uintval() - clear_exp;
185+
182186
if (!(r_bits & FPBits<T>::EXP_MASK)) {
183187
// Output is denormal after rounding, clear the implicit bit for 80-bit
184188
// long double.
185189
r_bits -= IMPLICIT_MASK;
190+
191+
// TODO: IEEE Std 754-2019 lets implementers choose whether to check for
192+
// "tininess" before or after rounding for base-2 formats, as long as
193+
// the same choice is made for all operations. Our choice to check after
194+
// rounding might not be the same as the hardware's.
195+
if (round_and_sticky)
196+
raise_except_if_required(FE_UNDERFLOW);
186197
}
187198

188199
return FPBits<T>(r_bits).get_val();

libc/src/__support/FPUtil/generic/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,13 @@ add_header_library(
5151
HDRS
5252
div.h
5353
DEPENDS
54-
libc.hdr.errno_macros
5554
libc.hdr.fenv_macros
5655
libc.src.__support.CPP.bit
5756
libc.src.__support.CPP.type_traits
5857
libc.src.__support.FPUtil.basic_operations
5958
libc.src.__support.FPUtil.fenv_impl
6059
libc.src.__support.FPUtil.fp_bits
6160
libc.src.__support.FPUtil.dyadic_float
62-
libc.src.__support.FPUtil.rounding_mode
6361
libc.src.__support.macros.attributes
6462
libc.src.__support.macros.optimization
6563
)

libc/src/__support/FPUtil/generic/div.h

Lines changed: 17 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@
99
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H
1010
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H
1111

12-
#include "hdr/errno_macros.h"
1312
#include "hdr/fenv_macros.h"
1413
#include "src/__support/CPP/bit.h"
1514
#include "src/__support/CPP/type_traits.h"
1615
#include "src/__support/FPUtil/BasicOperations.h"
1716
#include "src/__support/FPUtil/FEnvImpl.h"
1817
#include "src/__support/FPUtil/FPBits.h"
1918
#include "src/__support/FPUtil/dyadic_float.h"
20-
#include "src/__support/FPUtil/rounding_mode.h"
2119
#include "src/__support/macros/attributes.h"
2220
#include "src/__support/macros/optimization.h"
2321

@@ -35,14 +33,6 @@ div(InType x, InType y) {
3533
using InStorageType = typename InFPBits::StorageType;
3634
using DyadicFloat =
3735
DyadicFloat<cpp::bit_ceil(static_cast<size_t>(InFPBits::FRACTION_LEN))>;
38-
using DyadicMantissaType = typename DyadicFloat::MantissaType;
39-
40-
// +1 for the implicit bit.
41-
constexpr int DYADIC_EXTRA_MANTISSA_LEN =
42-
DyadicMantissaType::BITS - (InFPBits::FRACTION_LEN + 1);
43-
// +1 for the extra fractional bit in q.
44-
constexpr int Q_EXTRA_FRACTION_LEN =
45-
InFPBits::FRACTION_LEN + 1 - OutFPBits::FRACTION_LEN;
4636

4737
InFPBits x_bits(x);
4838
InFPBits y_bits(y);
@@ -104,120 +94,33 @@ div(InType x, InType y) {
10494
DyadicFloat xd(x);
10595
DyadicFloat yd(y);
10696

107-
bool would_q_be_subnormal = xd.mantissa < yd.mantissa;
108-
int q_exponent = xd.get_unbiased_exponent() - yd.get_unbiased_exponent() -
109-
would_q_be_subnormal;
110-
111-
if (q_exponent + OutFPBits::EXP_BIAS >= OutFPBits::MAX_BIASED_EXPONENT) {
112-
set_errno_if_required(ERANGE);
113-
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
97+
// Number of iterations = full output precision + 1 rounding bit + 1 potential
98+
// leading 0.
99+
constexpr size_t NUM_ITERS = OutFPBits::FRACTION_LEN + 3;
100+
int result_exp = xd.exponent - yd.exponent - (NUM_ITERS - 1);
114101

115-
switch (get_round()) {
116-
case FE_TONEAREST:
117-
return OutFPBits::inf(result_sign).get_val();
118-
case FE_DOWNWARD:
119-
if (result_sign.is_pos())
120-
return OutFPBits::max_normal(result_sign).get_val();
121-
return OutFPBits::inf(result_sign).get_val();
122-
case FE_UPWARD:
123-
if (result_sign.is_pos())
124-
return OutFPBits::inf(result_sign).get_val();
125-
return OutFPBits::max_normal(result_sign).get_val();
126-
default:
127-
return OutFPBits::max_normal(result_sign).get_val();
128-
}
129-
}
102+
InStorageType q = 0;
103+
InStorageType r = static_cast<InStorageType>(xd.mantissa >> 2);
104+
InStorageType yd_mant_in = static_cast<InStorageType>(yd.mantissa >> 1);
130105

131-
if (q_exponent < -OutFPBits::EXP_BIAS - OutFPBits::FRACTION_LEN) {
132-
set_errno_if_required(ERANGE);
133-
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
134-
135-
switch (quick_get_round()) {
136-
case FE_DOWNWARD:
137-
if (result_sign.is_pos())
138-
return OutFPBits::zero(result_sign).get_val();
139-
return OutFPBits::min_subnormal(result_sign).get_val();
140-
case FE_UPWARD:
141-
if (result_sign.is_pos())
142-
return OutFPBits::min_subnormal(result_sign).get_val();
143-
return OutFPBits::zero(result_sign).get_val();
144-
default:
145-
return OutFPBits::zero(result_sign).get_val();
146-
}
147-
}
148-
149-
InStorageType q = 1;
150-
InStorageType xd_mant_in = static_cast<InStorageType>(
151-
xd.mantissa >> (DYADIC_EXTRA_MANTISSA_LEN - would_q_be_subnormal));
152-
InStorageType yd_mant_in =
153-
static_cast<InStorageType>(yd.mantissa >> DYADIC_EXTRA_MANTISSA_LEN);
154-
InStorageType r = xd_mant_in - yd_mant_in;
155-
156-
for (size_t i = 0; i < InFPBits::FRACTION_LEN + 1; i++) {
106+
for (size_t i = 0; i < NUM_ITERS; ++i) {
157107
q <<= 1;
158-
InStorageType t = r << 1;
159-
if (t < yd_mant_in) {
160-
r = t;
161-
} else {
108+
r <<= 1;
109+
if (r >= yd_mant_in) {
162110
q += 1;
163-
r = t - yd_mant_in;
111+
r -= yd_mant_in;
164112
}
165113
}
166114

167-
bool round;
168-
bool sticky;
169-
OutStorageType result;
170-
171-
if (q_exponent > -OutFPBits::EXP_BIAS) {
172-
// Result is normal.
173-
174-
InStorageType round_mask = InStorageType(1) << (Q_EXTRA_FRACTION_LEN - 1);
175-
round = (q & round_mask) != 0;
176-
InStorageType sticky_mask = round_mask - 1;
177-
sticky = (q & sticky_mask) != 0;
178-
179-
result = OutFPBits::create_value(
180-
result_sign,
181-
static_cast<OutStorageType>(q_exponent + OutFPBits::EXP_BIAS),
182-
static_cast<OutStorageType>(q >> Q_EXTRA_FRACTION_LEN))
183-
.uintval();
184-
185-
} else {
186-
// Result is subnormal.
115+
DyadicFloat result(result_sign, result_exp, q);
116+
result.mantissa += r != 0;
187117

188-
// +1 because the leading bit is now part of the fraction.
189-
int extra_fraction_len =
190-
Q_EXTRA_FRACTION_LEN + 1 - q_exponent - OutFPBits::EXP_BIAS;
118+
OutType output = static_cast<OutType>(result);
191119

192-
InStorageType round_mask = InStorageType(1) << (extra_fraction_len - 1);
193-
round = (q & round_mask) != 0;
194-
InStorageType sticky_mask = round_mask - 1;
195-
sticky = (q & sticky_mask) != 0;
196-
197-
result = OutFPBits::create_value(
198-
result_sign, 0,
199-
static_cast<OutStorageType>(q >> extra_fraction_len))
200-
.uintval();
201-
}
202-
203-
if (round || sticky)
204-
raise_except_if_required(FE_INEXACT);
205-
206-
bool lsb = (result & 1) != 0;
207-
208-
switch (quick_get_round()) {
209-
case FE_TONEAREST:
210-
if (round && (lsb || sticky))
211-
++result;
212-
break;
213-
case FE_UPWARD:
214-
++result;
215-
break;
216-
default:
217-
break;
218-
}
120+
if (test_except(FE_OVERFLOW | FE_UNDERFLOW) != 0)
121+
set_errno_if_required(ERANGE);
219122

220-
return cpp::bit_cast<OutType>(result);
123+
return output;
221124
}
222125

223126
} // namespace LIBC_NAMESPACE::fputil::generic

0 commit comments

Comments
 (0)