1//===-- Definition of bfloat16 data type. -----------------------*- 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_BFLOAT16_H
10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BFLOAT16_H
11
12#include "hdr/stdint_proxy.h"
13#include "src/__support/CPP/bit.h"
14#include "src/__support/CPP/type_traits.h"
15#include "src/__support/FPUtil/cast.h"
16#include "src/__support/FPUtil/comparison_operations.h"
17#include "src/__support/FPUtil/dyadic_float.h"
18#include "src/__support/FPUtil/generic/add_sub.h"
19#include "src/__support/FPUtil/generic/div.h"
20#include "src/__support/FPUtil/generic/mul.h"
21#include "src/__support/macros/config.h"
22#include "src/__support/macros/properties/types.h"
23
24namespace LIBC_NAMESPACE_DECL {
25namespace fputil {
26
27struct BFloat16 {
28 uint16_t bits;
29
30 LIBC_INLINE BFloat16() = default;
31
32 template <typename T>
33 LIBC_INLINE constexpr explicit BFloat16(T value)
34 : bits(static_cast<uint16_t>(0U)) {
35 if constexpr (cpp::is_floating_point_v<T>) {
36 bits = fputil::cast<bfloat16>(value).bits;
37 } else if constexpr (cpp::is_integral_v<T>) {
38 Sign sign = Sign::POS;
39
40 if constexpr (cpp::is_signed_v<T>) {
41 if (value < 0) {
42 sign = Sign::NEG;
43 value = -value;
44 }
45 }
46
47 fputil::DyadicFloat<cpp::numeric_limits<cpp::make_unsigned_t<T>>::digits>
48 xd(sign, 0, value);
49 bits = xd.template as<bfloat16, /*ShouldSignalExceptions=*/true>().bits;
50
51 } else if constexpr (cpp::is_convertible_v<T, BFloat16>) {
52 bits = value.operator BFloat16().bits;
53 } else {
54 bits = fputil::cast<bfloat16>(x: static_cast<float>(value)).bits;
55 }
56 }
57
58 template <cpp::enable_if_t<fputil::get_fp_type<float>() ==
59 fputil::FPType::IEEE754_Binary32,
60 int> = 0>
61 LIBC_INLINE constexpr operator float() const {
62 uint32_t x_bits = static_cast<uint32_t>(bits) << 16U;
63 return cpp::bit_cast<float>(from: x_bits);
64 }
65
66 template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
67 LIBC_INLINE constexpr explicit operator T() const {
68 return static_cast<T>(static_cast<float>(*this));
69 }
70
71 LIBC_INLINE constexpr bool operator==(BFloat16 other) const {
72 return fputil::equals(x: *this, y: other);
73 }
74
75 LIBC_INLINE constexpr bool operator!=(BFloat16 other) const {
76 return !fputil::equals(x: *this, y: other);
77 }
78
79 LIBC_INLINE constexpr bool operator<(BFloat16 other) const {
80 return fputil::less_than(x: *this, y: other);
81 }
82
83 LIBC_INLINE constexpr bool operator<=(BFloat16 other) const {
84 return fputil::less_than_or_equals(x: *this, y: other);
85 }
86
87 LIBC_INLINE constexpr bool operator>(BFloat16 other) const {
88 return fputil::greater_than(x: *this, y: other);
89 }
90
91 LIBC_INLINE constexpr bool operator>=(BFloat16 other) const {
92 return fputil::greater_than_or_equals(x: *this, y: other);
93 }
94
95 LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR BFloat16 operator-() const {
96 fputil::FPBits<bfloat16> result(*this);
97 result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS);
98 return result.get_val();
99 }
100
101 LIBC_INLINE constexpr BFloat16 operator+(BFloat16 other) const {
102 return fputil::generic::add<BFloat16>(x: *this, y: other);
103 }
104
105 LIBC_INLINE constexpr BFloat16 operator-(BFloat16 other) const {
106 return fputil::generic::sub<BFloat16>(x: *this, y: other);
107 }
108
109 LIBC_INLINE constexpr BFloat16 operator*(BFloat16 other) const {
110 return fputil::generic::mul<bfloat16>(x: *this, y: other);
111 }
112
113 LIBC_INLINE constexpr BFloat16 operator/(BFloat16 other) const {
114 return fputil::generic::div<bfloat16>(x: *this, y: other);
115 }
116
117 LIBC_INLINE constexpr BFloat16 &operator*=(BFloat16 other) {
118 *this = *this * other;
119 return *this;
120 }
121 LIBC_INLINE constexpr BFloat16 &operator+=(BFloat16 other) {
122 *this = *this + other;
123 return *this;
124 }
125 LIBC_INLINE constexpr BFloat16 &operator-=(BFloat16 other) {
126 *this = *this - other;
127 return *this;
128 }
129 LIBC_INLINE constexpr BFloat16 &operator/=(BFloat16 other) {
130 *this = *this / other;
131 return *this;
132 }
133}; // struct BFloat16
134
135} // namespace fputil
136} // namespace LIBC_NAMESPACE_DECL
137
138#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_BFLOAT16_H
139