Limited support for arbitrary target reals

While parsing of floating-point literals and CTFE still operate with the
host LDC's real type, compile-time reals can in principle be emitted in
arbitrary precision via LLVM software conversion, therefore paving the way
for cross-compilation to all targets.

The representable constants are still limited by the compile-time real_t
precision. E.g., LDC on Windows with its 64-bit reals can't hold and emit
an 80-bit `real.max` when cross-compiling to a non-Windows x86(_64)
target; the compile-time value will silently overflow to infinity and
later be emitted as 80-bit infinity.

LDC on AArch64 with its 128-bit quad-precision reals on the other hand can
hold and emit reals for all targets, making it a universal cross-compiler
with quad-precision compile-time reals in hardware.

We don't use the strange 2x64-bit PPC double-double format (see
`getRealType()` in `ir/irtype.cpp`), but would more or less support it
(the type properties (max, min_normal...) still need to be determined;
LLVM isn't sure about those either...).
This commit is contained in:
Martin 2017-02-10 23:41:24 +01:00
parent c051d8d829
commit 0e71a760ae
7 changed files with 115 additions and 60 deletions

48
gen/ctfloat.cpp Normal file
View file

@ -0,0 +1,48 @@
//===-- 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;
void CTFloat::toAPFloat(const real_t src, APFloat &dst) {
if (sizeof(real_t) == 8) {
dst = APFloat(static_cast<double>(src));
return;
}
assert(sizeof(real_t) > 8 && "real_t < 64 bits?");
union {
real_t fp;
uint64_t bits[(sizeof(real_t) + 7) / 8];
} u;
u.fp = src;
#if LDC_LLVM_VER >= 400
const auto &x87DoubleExtended = APFloat::x87DoubleExtended();
const auto &IEEEquad = APFloat::IEEEquad();
const auto &PPCDoubleDouble = APFloat::PPCDoubleDouble();
#else
const auto &x87DoubleExtended = APFloat::x87DoubleExtended;
const auto &IEEEquad = APFloat::IEEEquad;
const auto &PPCDoubleDouble = APFloat::PPCDoubleDouble;
#endif
#if __i386__ || __x86_64__
dst = APFloat(x87DoubleExtended, APInt(80, 2, u.bits));
#elif __aarch64__
dst = APFloat(IEEEquad, APInt(128, 2, u.bits));
#elif __ppc__ || __ppc64__
dst = APFloat(PPCDoubleDouble, APInt(128, 2, u.bits));
#else
llvm_unreachable("Unknown host real_t type for compile-time reals");
#endif
}