mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 22:50:53 +03:00
131 lines
3.8 KiB
C++
131 lines
3.8 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"
|
||
|
||
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);
|
||
const auto r = ap.convertFromString(literal, APFloat::rmNearestTiesToEven);
|
||
if (isOutOfRange) {
|
||
*isOutOfRange = (r & (APFloat::opOverflow | APFloat::opUnderflow)) != 0;
|
||
}
|
||
return ap;
|
||
}
|
||
|
||
} // anonymous namespace
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void CTFloat::initialize() {
|
||
if (apSemantics)
|
||
return;
|
||
|
||
static_assert(sizeof(real_t) >= 8, "real_t < 64 bits?");
|
||
|
||
if (sizeof(real_t) == 8) {
|
||
apSemantics = &(APFloat::IEEEdouble AP_SEMANTICS_PARENS);
|
||
} else {
|
||
#if __aarch64__ || (__ANDROID__ && __LP64__)
|
||
apSemantics = &(APFloat::IEEEquad AP_SEMANTICS_PARENS);
|
||
#elif __i386__ || __x86_64__ || _M_IX86 || _M_X64
|
||
apSemantics = &(APFloat::x87DoubleExtended AP_SEMANTICS_PARENS);
|
||
#elif __ppc__ || __ppc64__
|
||
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;
|
||
|
||
// init value: use a special quiet NaN (with 2nd-most significant mantissa bit
|
||
// set too, like signalling NaNs)
|
||
APInt initMantissa(APFloat::getSizeInBits(*apSemantics), 0);
|
||
initMantissa.setBit(APFloat::semanticsPrecision(*apSemantics) -
|
||
3); // #mantissaBits = precision - 1
|
||
initVal = fromAPFloat(APFloat::getQNaN(*apSemantics, false, &initMantissa));
|
||
|
||
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;
|
||
}
|