mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 22:50:53 +03:00
133 lines
3.7 KiB
C++
133 lines
3.7 KiB
C++
//===-- ctfloat.cpp -------------------------------------------------------===//
|
||
//
|
||
// LDC – the LLVM D compiler
|
||
//
|
||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||
// file for details.
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#include "dmd/root/ctfloat.h"
|
||
#include "gen/llvm.h"
|
||
#include "llvm/Support/Error.h"
|
||
|
||
using llvm::APFloat;
|
||
|
||
#if LDC_LLVM_VER >= 400
|
||
#define AP_SEMANTICS_PARENS ()
|
||
#else
|
||
#define AP_SEMANTICS_PARENS
|
||
#endif
|
||
|
||
namespace {
|
||
|
||
const llvm::fltSemantics *apSemantics = nullptr;
|
||
|
||
constexpr unsigned numUint64Parts = (sizeof(real_t) + 7) / 8;
|
||
union CTFloatUnion {
|
||
real_t fp;
|
||
uint64_t bits[numUint64Parts];
|
||
};
|
||
|
||
APFloat parseLiteral(const llvm::fltSemantics &semantics, const char *literal,
|
||
bool *isOutOfRange = nullptr) {
|
||
APFloat ap(semantics, APFloat::uninitialized);
|
||
auto r =
|
||
#if LDC_LLVM_VER >= 1000
|
||
llvm::cantFail
|
||
#endif
|
||
(ap.convertFromString(literal, APFloat::rmNearestTiesToEven));
|
||
if (isOutOfRange) {
|
||
*isOutOfRange = (r & (APFloat::opOverflow | APFloat::opUnderflow)) != 0;
|
||
}
|
||
return ap;
|
||
}
|
||
|
||
} // anonymous namespace
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void CTFloat::initialize() {
|
||
if (apSemantics)
|
||
return;
|
||
|
||
#ifdef _MSC_VER
|
||
// MSVC hosts use dmd.root.longdouble (80-bit x87)
|
||
apSemantics = &(APFloat::x87DoubleExtended AP_SEMANTICS_PARENS);
|
||
#else
|
||
static_assert(std::numeric_limits<real_t>::is_specialized,
|
||
"real_t is not an arithmetic type");
|
||
constexpr int digits = std::numeric_limits<real_t>::digits;
|
||
if (digits == 53) {
|
||
apSemantics = &(APFloat::IEEEdouble AP_SEMANTICS_PARENS);
|
||
} else if (digits == 64) {
|
||
apSemantics = &(APFloat::x87DoubleExtended AP_SEMANTICS_PARENS);
|
||
} else if (digits == 113) {
|
||
apSemantics = &(APFloat::IEEEquad AP_SEMANTICS_PARENS);
|
||
} else if (digits == 106) {
|
||
apSemantics = &(APFloat::PPCDoubleDouble AP_SEMANTICS_PARENS);
|
||
} else {
|
||
llvm_unreachable("Unknown host real_t type for compile-time reals");
|
||
}
|
||
#endif
|
||
|
||
zero = 0;
|
||
one = 1;
|
||
minusone = -1;
|
||
half = 0.5;
|
||
|
||
nan = fromAPFloat(APFloat::getQNaN(*apSemantics));
|
||
infinity = fromAPFloat(APFloat::getInf(*apSemantics));
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void CTFloat::toAPFloat(const real_t src, APFloat &dst) {
|
||
if (sizeof(real_t) == 8) {
|
||
dst = APFloat(static_cast<double>(src));
|
||
return;
|
||
}
|
||
|
||
CTFloatUnion u;
|
||
u.fp = src;
|
||
|
||
const unsigned sizeInBits = APFloat::getSizeInBits(*apSemantics);
|
||
const APInt bits = APInt(sizeInBits, numUint64Parts, u.bits);
|
||
|
||
dst = APFloat(*apSemantics, bits);
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
real_t CTFloat::fromAPFloat(const APFloat &src_) {
|
||
APFloat src = src_;
|
||
if (&src.getSemantics() != apSemantics) {
|
||
bool ignored;
|
||
src.convert(*apSemantics, APFloat::rmNearestTiesToEven, &ignored);
|
||
}
|
||
|
||
const APInt bits = src.bitcastToAPInt();
|
||
|
||
CTFloatUnion u;
|
||
memcpy(u.bits, bits.getRawData(), bits.getBitWidth() / 8);
|
||
return u.fp;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
real_t CTFloat::parse(const char *literal, bool *isOutOfRange) {
|
||
const APFloat ap = parseLiteral(*apSemantics, literal, isOutOfRange);
|
||
return fromAPFloat(ap);
|
||
}
|
||
|
||
bool CTFloat::isFloat32LiteralOutOfRange(const char *literal) {
|
||
bool isOutOfRange;
|
||
parseLiteral(APFloat::IEEEsingle AP_SEMANTICS_PARENS, literal, &isOutOfRange);
|
||
return isOutOfRange;
|
||
}
|
||
|
||
bool CTFloat::isFloat64LiteralOutOfRange(const char *literal) {
|
||
bool isOutOfRange;
|
||
parseLiteral(APFloat::IEEEdouble AP_SEMANTICS_PARENS, literal, &isOutOfRange);
|
||
return isOutOfRange;
|
||
}
|