blob: 8aaf9f78e8d3200d6e71a7de18b7ce265a10f170 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Shared integer-to-floating-point conversions, rounded to nearest with ties
/// to even. These mirror compiler-rt's __float<i><f> / __floatun<i><f>
/// builtins via an LLVM-libc DyadicFloat, so they can be reused by
/// compiler-rt's builtins.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_FLOATINT_HELPER_H
#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_FLOATINT_HELPER_H
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/sign.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
namespace builtins {
// TODO: use constructors after adding Float128/64/32/16 classes.
// Convert the integer I to the floating-point type F, rounding to nearest
// (ties to even) per the current rounding mode. Handles signed and unsigned
// I alike; mirrors compiler-rt's __float<i><f> / __floatun<i><f>.
template <typename F, typename I> LIBC_INLINE constexpr F floatint(I x) {
using UI = cpp::make_unsigned_t<I>;
Sign sign = Sign::POS;
UI mag = static_cast<UI>(x);
if constexpr (cpp::is_signed_v<I>) {
if (x < 0) {
sign = Sign::NEG;
mag = static_cast<UI>(-mag); // modular negation; correct for I's min too
}
}
// A mantissa wide enough for I and for F's fraction, rounded up to a whole
// number of 64-bit words (UInt's width requirement). With exponent 0 the
// dyadic value is exactly `mag`, which as<F>() then rounds to F.
constexpr size_t NEED = (sizeof(I) > sizeof(F) ? sizeof(I) : sizeof(F)) * 8;
constexpr size_t BITS = ((NEED + 63) / 64) * 64;
return static_cast<F>(fputil::DyadicFloat<BITS>(sign, 0, mag));
}
} // namespace builtins
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_FLOATINT_HELPER_H