[libc][NFC] Move aligned access implementations to separate header
[llvm-project.git] / libc / src / __support / FPUtil / x86_64 / NextAfterLongDouble.h
blob031a083180666f7a0a436f5a7bd1697ee95116ac
1 //===-- nextafter implementation for x86 long double 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 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_NEXT_AFTER_LONG_DOUBLE_H
10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_NEXT_AFTER_LONG_DOUBLE_H
12 #include "src/__support/macros/properties/architectures.h"
14 #if !defined(LIBC_TARGET_ARCH_IS_X86)
15 #error "Invalid include"
16 #endif
18 #include "src/__support/CPP/bit.h"
19 #include "src/__support/FPUtil/FPBits.h"
21 #include <stdint.h>
23 namespace __llvm_libc {
24 namespace fputil {
26 LIBC_INLINE long double nextafter(long double from, long double to) {
27 using FPBits = FPBits<long double>;
28 FPBits from_bits(from);
29 if (from_bits.is_nan())
30 return from;
32 FPBits to_bits(to);
33 if (to_bits.is_nan())
34 return to;
36 if (from == to)
37 return to;
39 // Convert pseudo subnormal number to normal number.
40 if (from_bits.get_implicit_bit() == 1 &&
41 from_bits.get_unbiased_exponent() == 0) {
42 from_bits.set_unbiased_exponent(1);
45 using UIntType = FPBits::UIntType;
46 constexpr UIntType SIGN_VAL = (UIntType(1) << 79);
47 constexpr UIntType MANTISSA_MASK =
48 (UIntType(1) << MantissaWidth<long double>::VALUE) - 1;
49 UIntType int_val = from_bits.uintval();
50 if (from < 0.0l) {
51 if (from > to) {
52 if (int_val == (SIGN_VAL + FPBits::MAX_SUBNORMAL)) {
53 // We deal with normal/subnormal boundary separately to avoid
54 // dealing with the implicit bit.
55 int_val = SIGN_VAL + FPBits::MIN_NORMAL;
56 } else if ((int_val & MANTISSA_MASK) == MANTISSA_MASK) {
57 from_bits.set_mantissa(0);
58 // Incrementing exponent might overflow the value to infinity,
59 // which is what is expected. Since NaNs are handling separately,
60 // it will never overflow "beyond" infinity.
61 from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
62 return from_bits;
63 } else {
64 ++int_val;
66 } else {
67 if (int_val == (SIGN_VAL + FPBits::MIN_NORMAL)) {
68 // We deal with normal/subnormal boundary separately to avoid
69 // dealing with the implicit bit.
70 int_val = SIGN_VAL + FPBits::MAX_SUBNORMAL;
71 } else if ((int_val & MANTISSA_MASK) == 0) {
72 from_bits.set_mantissa(MANTISSA_MASK);
73 // from == 0 is handled separately so decrementing the exponent will not
74 // lead to underflow.
75 from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() - 1);
76 return from_bits;
77 } else {
78 --int_val;
81 } else if (from == 0.0l) {
82 if (from > to)
83 int_val = SIGN_VAL + 1;
84 else
85 int_val = 1;
86 } else {
87 if (from > to) {
88 if (int_val == FPBits::MIN_NORMAL) {
89 int_val = FPBits::MAX_SUBNORMAL;
90 } else if ((int_val & MANTISSA_MASK) == 0) {
91 from_bits.set_mantissa(MANTISSA_MASK);
92 // from == 0 is handled separately so decrementing the exponent will not
93 // lead to underflow.
94 from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() - 1);
95 return from_bits;
96 } else {
97 --int_val;
99 } else {
100 if (int_val == FPBits::MAX_SUBNORMAL) {
101 int_val = FPBits::MIN_NORMAL;
102 } else if ((int_val & MANTISSA_MASK) == MANTISSA_MASK) {
103 from_bits.set_mantissa(0);
104 // Incrementing exponent might overflow the value to infinity,
105 // which is what is expected. Since NaNs are handling separately,
106 // it will never overflow "beyond" infinity.
107 from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
108 return from_bits;
109 } else {
110 ++int_val;
115 return cpp::bit_cast<long double>(int_val);
116 // TODO: Raise floating point exceptions as required by the standard.
119 } // namespace fputil
120 } // namespace __llvm_libc
122 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_NEXT_AFTER_LONG_DOUBLE_H