ldc/gen/ctfloat.cpp
Martin Kinkelin e2debcea17
Improve detection of host real_t semantics (#3414)
Supporting more hosts and fixing early stoppers such as issue #3270.
2020-05-04 20:34:31 +02:00

133 lines
3.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- 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;
}