ldc/gen/ctfloat.cpp
2017-07-16 02:18:00 +02:00

102 lines
2.8 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 "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::_init() {
static_assert(sizeof(real_t) >= 8, "real_t < 64 bits?");
if (sizeof(real_t) == 8) {
apSemantics = &(APFloat::IEEEdouble AP_SEMANTICS_PARENS);
return;
}
#if __i386__ || __x86_64__
apSemantics = &(APFloat::x87DoubleExtended AP_SEMANTICS_PARENS);
#elif __aarch64__
apSemantics = &(APFloat::IEEEquad 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
}
////////////////////////////////////////////////////////////////////////////////
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::parse(const char *literal, bool *isOutOfRange) {
const APFloat ap = parseLiteral(*apSemantics, literal, isOutOfRange);
const APInt bits = ap.bitcastToAPInt();
CTFloatUnion u;
memcpy(u.bits, bits.getRawData(), bits.getBitWidth() / 8);
return u.fp;
}
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;
}