[pkg-d-commits] [ldc] 100/149: Limited support for arbitrary target reals
Matthias Klumpp
mak at moszumanska.debian.org
Sun Apr 23 22:37:02 UTC 2017
This is an automated email from the git hooks/post-receive script.
mak pushed a commit to annotated tag v1.2.0
in repository ldc.
commit 0e71a760aed70e4c81b7320bd021c7d7627b9ac6
Author: Martin <noone at nowhere.com>
Date: Fri Feb 10 23:41:24 2017 +0100
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...).
---
ddmd/root/ctfloat.h | 9 ++++++++
gen/complex.cpp | 2 +-
gen/complex.h | 3 +--
gen/ctfloat.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++
gen/target.cpp | 46 ++++++++++++++++++++++++++---------------
gen/tollvm.cpp | 59 +++++++++++++++++++++--------------------------------
gen/tollvm.h | 2 +-
7 files changed, 112 insertions(+), 57 deletions(-)
diff --git a/ddmd/root/ctfloat.h b/ddmd/root/ctfloat.h
index 719dafe..ba85497 100644
--- a/ddmd/root/ctfloat.h
+++ b/ddmd/root/ctfloat.h
@@ -14,11 +14,17 @@
// Type used by the front-end for compile-time reals
#if IN_LLVM && _MSC_VER
+// Make sure LDC built with MSVC uses double-precision compile-time reals,
+// independent of whether it was built with DMD (80-bit reals) or LDC.
typedef double real_t;
#else
typedef longdouble real_t;
#endif
+#if IN_LLVM
+namespace llvm { class APFloat; }
+#endif
+
// Compile-time floating-point helper
struct CTFloat
{
@@ -42,6 +48,9 @@ struct CTFloat
static real_t ceil(real_t x);
static real_t trunc(real_t x);
static real_t round(real_t x);
+
+ // implemented in gen/ctfloat.cpp
+ static void toAPFloat(real_t src, llvm::APFloat &dst);
#endif
static bool isIdentical(real_t a, real_t b);
diff --git a/gen/complex.cpp b/gen/complex.cpp
index 55f9960..c0b450c 100644
--- a/gen/complex.cpp
+++ b/gen/complex.cpp
@@ -42,7 +42,7 @@ LLType *DtoComplexBaseType(Type *t) {
////////////////////////////////////////////////////////////////////////////////
-LLConstant *DtoConstComplex(Type *_ty, longdouble re, longdouble im) {
+LLConstant *DtoConstComplex(Type *_ty, real_t re, real_t im) {
Type *base = nullptr;
switch (_ty->toBasetype()->ty) {
default:
diff --git a/gen/complex.h b/gen/complex.h
index e3e20c8..14f9715 100644
--- a/gen/complex.h
+++ b/gen/complex.h
@@ -15,7 +15,6 @@
#define LDC_GEN_COMPLEX_H
#include "tokens.h"
-#include "longdouble.h"
#include "dvalue.h"
struct Loc;
@@ -30,7 +29,7 @@ class Value;
llvm::StructType *DtoComplexType(Type *t);
llvm::Type *DtoComplexBaseType(Type *t);
-llvm::Constant *DtoConstComplex(Type *t, longdouble re, longdouble im);
+llvm::Constant *DtoConstComplex(Type *t, real_t re, real_t im);
llvm::Constant *DtoComplexShuffleMask(unsigned a, unsigned b);
diff --git a/gen/ctfloat.cpp b/gen/ctfloat.cpp
new file mode 100644
index 0000000..54b4feb
--- /dev/null
+++ b/gen/ctfloat.cpp
@@ -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
+}
diff --git a/gen/target.cpp b/gen/target.cpp
index c425a6b..04bdcee 100644
--- a/gen/target.cpp
+++ b/gen/target.cpp
@@ -56,29 +56,18 @@ void Target::_init() {
c_long_doublesize = realsize;
classinfosize = 0; // unused
- const auto pTargetRealSemantics = &real->getFltSemantics();
+ const auto targetRealSemantics = &real->getFltSemantics();
#if LDC_LLVM_VER >= 400
- const auto x87DoubleExtended = &APFloat::x87DoubleExtended();
const auto IEEEdouble = &APFloat::IEEEdouble();
- const auto PPCDoubleDouble = &APFloat::PPCDoubleDouble();
+ const auto x87DoubleExtended = &APFloat::x87DoubleExtended();
+ const auto IEEEquad = &APFloat::IEEEquad();
#else
- const auto x87DoubleExtended = &APFloat::x87DoubleExtended;
const auto IEEEdouble = &APFloat::IEEEdouble;
- const auto PPCDoubleDouble = &APFloat::PPCDoubleDouble;
+ const auto x87DoubleExtended = &APFloat::x87DoubleExtended;
+ const auto IEEEquad = &APFloat::IEEEquad;
#endif
- if (pTargetRealSemantics == x87DoubleExtended) {
- real_max = CTFloat::parse("0x1.fffffffffffffffep+16383");
- real_min_normal = CTFloat::parse("0x1p-16382");
- real_epsilon = CTFloat::parse("0x1p-63");
- RealProperties::dig = 18;
- RealProperties::mant_dig = 64;
- RealProperties::max_exp = 16384;
- RealProperties::min_exp = -16381;
- RealProperties::max_10_exp = 4932;
- RealProperties::min_10_exp = -4932;
- } else if (pTargetRealSemantics == IEEEdouble ||
- pTargetRealSemantics == PPCDoubleDouble) {
+ if (targetRealSemantics == IEEEdouble) {
real_max = CTFloat::parse("0x1.fffffffffffffp+1023");
real_min_normal = CTFloat::parse("0x1p-1022");
real_epsilon = CTFloat::parse("0x1p-52");
@@ -88,7 +77,30 @@ void Target::_init() {
RealProperties::min_exp = -1021;
RealProperties::max_10_exp = 308;
RealProperties::min_10_exp = -307;
+ } else if (targetRealSemantics == x87DoubleExtended) {
+ real_max = CTFloat::parse("0x1.fffffffffffffffep+16383");
+ real_min_normal = CTFloat::parse("0x1p-16382");
+ real_epsilon = CTFloat::parse("0x1p-63");
+ RealProperties::dig = 18;
+ RealProperties::mant_dig = 64;
+ RealProperties::max_exp = 16384;
+ RealProperties::min_exp = -16381;
+ RealProperties::max_10_exp = 4932;
+ RealProperties::min_10_exp = -4931;
+ } else if (targetRealSemantics == IEEEquad) {
+ // FIXME: hex constants
+ real_max = CTFloat::parse("1.18973149535723176508575932662800702e+4932");
+ real_min_normal =
+ CTFloat::parse("3.36210314311209350626267781732175260e-4932");
+ real_epsilon = CTFloat::parse("1.92592994438723585305597794258492732e-34");
+ RealProperties::dig = 33;
+ RealProperties::mant_dig = 113;
+ RealProperties::max_exp = 16384;
+ RealProperties::min_exp = -16381;
+ RealProperties::max_10_exp = 4932;
+ RealProperties::min_10_exp = -4931;
} else {
+ // rely on host compiler
real_max = RealProperties::host_max();
real_min_normal = RealProperties::host_min_normal();
real_epsilon = RealProperties::host_epsilon();
diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp
index f41a705..dbbecfd 100644
--- a/gen/tollvm.cpp
+++ b/gen/tollvm.cpp
@@ -411,51 +411,38 @@ llvm::ConstantInt *DtoConstUbyte(unsigned char i) {
return LLConstantInt::get(LLType::getInt8Ty(gIR->context()), i, false);
}
-LLConstant *DtoConstFP(Type *t, longdouble value) {
-#if LDC_LLVM_VER >= 400
- auto &x87DoubleExtended = APFloat::x87DoubleExtended();
- auto &IEEEquad = APFloat::IEEEquad();
- auto &PPCDoubleDouble = APFloat::PPCDoubleDouble();
-#else
- auto &x87DoubleExtended = APFloat::x87DoubleExtended;
- auto &IEEEquad = APFloat::IEEEquad;
- auto &PPCDoubleDouble = APFloat::PPCDoubleDouble;
-#endif
-
+LLConstant *DtoConstFP(Type *t, const real_t value) {
LLType *llty = DtoType(t);
assert(llty->isFloatingPointTy());
- if (llty == LLType::getFloatTy(gIR->context()) ||
- llty == LLType::getDoubleTy(gIR->context())) {
- return LLConstantFP::get(llty, value);
- }
- if (llty == LLType::getX86_FP80Ty(gIR->context())) {
- uint64_t bits[] = {0, 0};
- bits[0] = *reinterpret_cast<uint64_t *>(&value);
- bits[1] =
- *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1);
+ assert(sizeof(real_t) >= 8 && "real_t < 64 bits?");
+
+ if (llty->isFloatTy()) {
+ // let host narrow to single-precision target
return LLConstantFP::get(gIR->context(),
- APFloat(x87DoubleExtended, APInt(80, 2, bits)));
+ APFloat(static_cast<float>(value)));
}
- if (llty == LLType::getFP128Ty(gIR->context())) {
- union {
- longdouble ld;
- uint64_t bits[2];
- } t;
- t.ld = value;
+
+ if (llty->isDoubleTy()) {
+ // let host (potentially) narrow to double-precision target
return LLConstantFP::get(gIR->context(),
- APFloat(IEEEquad, APInt(128, 2, t.bits)));
+ APFloat(static_cast<double>(value)));
}
- if (llty == LLType::getPPC_FP128Ty(gIR->context())) {
- uint64_t bits[] = {0, 0};
- bits[0] = *reinterpret_cast<uint64_t *>(&value);
- bits[1] =
- *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1);
- return LLConstantFP::get(gIR->context(),
- APFloat(PPCDoubleDouble, APInt(128, 2, bits)));
+
+ // host real_t => target real
+
+ // 1) represent host real_t as llvm::APFloat
+ const auto &targetRealSemantics = llty->getFltSemantics();
+ APFloat v(targetRealSemantics, APFloat::uninitialized);
+ CTFloat::toAPFloat(value, v);
+
+ // 2) convert to target real
+ if (&v.getSemantics() != &targetRealSemantics) {
+ bool ignored;
+ v.convert(targetRealSemantics, APFloat::rmNearestTiesToEven, &ignored);
}
- llvm_unreachable("Unknown floating point type encountered");
+ return LLConstantFP::get(gIR->context(), v);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/gen/tollvm.h b/gen/tollvm.h
index 24d037f..ce3c64c 100644
--- a/gen/tollvm.h
+++ b/gen/tollvm.h
@@ -90,7 +90,7 @@ LLConstantInt *DtoConstSize_t(uint64_t);
LLConstantInt *DtoConstUint(unsigned i);
LLConstantInt *DtoConstInt(int i);
LLConstantInt *DtoConstUbyte(unsigned char i);
-LLConstant *DtoConstFP(Type *t, longdouble value);
+LLConstant *DtoConstFP(Type *t, real_t value);
LLConstant *DtoConstString(const char *);
LLConstant *DtoConstBool(bool);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-d/ldc.git
More information about the pkg-d-commits
mailing list