[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