Skip to content

Commit 3726a93

Browse files
authored
Merge pull request #4840 from kinke/ppc64-d-ieee754-fix-new
ppc64(le): Add an option to use IEEE long double ABI on Linux [2]
2 parents 0d4ba1f + e61fcd7 commit 3726a93

File tree

14 files changed

+659
-197
lines changed

14 files changed

+659
-197
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
- ldc2.conf: `%%ldcversion%%` placeholder added, allowing to refer to version-specific directories.
88

99
#### Platform support
10+
- Supports LLVM 15 - 19.
11+
- Initial compiler and runtime support for ppc64 and ppc64le systems that use IEEE 754R 128-bit floating-point as the default 128-bit floating-point format. (#4833)
1012

1113
#### Bug fixes
1214
- Building multi-file D applications with control-flow protection will no longer cause LDC to throw an internal compiler error. (#4828)

CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,6 @@ if( CMAKE_COMPILER_IS_GNUCXX
275275
AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.6.0" )
276276
append("-mminimal-toc" LDC_CXXFLAGS)
277277
endif()
278-
# Do not use doubledouble on ppc
279-
if( CMAKE_SYSTEM_PROCESSOR MATCHES "ppc|powerpc")
280-
append("-mlong-double-64" LDC_CXXFLAGS)
281-
endif()
282278
if(UNIX)
283279
append("-DLDC_POSIX" LDC_CXXFLAGS)
284280
endif()

driver/main.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,10 @@ void registerPredefinedTargetVersions() {
681681
VersionCondition::addPredefinedGlobalIdent("PPC64");
682682
registerPredefinedFloatABI("PPC_SoftFloat", "PPC_HardFloat");
683683
if (triple.getOS() == llvm::Triple::Linux) {
684-
VersionCondition::addPredefinedGlobalIdent(
685-
triple.getArch() == llvm::Triple::ppc64 ? "ELFv1" : "ELFv2");
684+
const llvm::SmallVector<llvm::StringRef> features{};
685+
const std::string abi = getABI(triple, features);
686+
VersionCondition::addPredefinedGlobalIdent(abi == "elfv1" ? "ELFv1"
687+
: "ELFv2");
686688
}
687689
break;
688690
case llvm::Triple::arm:

gen/abi/ppc64le.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// The ABI implementation used for 64 bit little-endian PowerPC targets.
1111
//
1212
// The PowerOpen 64bit ELF v2 ABI can be found here:
13-
// https://members.openpowerfoundation.org/document/dl/576
13+
// https://files.openpower.foundation/s/cfA2oFPXbbZwEBK/download/64biteflv2abi-v1.5.pdf
1414
//===----------------------------------------------------------------------===//
1515

1616
#include "gen/abi/abi.h"
@@ -51,7 +51,7 @@ struct PPC64LETargetABI : TargetABI {
5151
} else {
5252
compositeToArray64.applyTo(arg);
5353
}
54-
} else if (ty->isintegral()) {
54+
} else if (ty->isintegral() && !ty->isTypeVector()) {
5555
arg.attrs.addAttribute(ty->isunsigned() ? LLAttribute::ZExt
5656
: LLAttribute::SExt);
5757
}

gen/modules.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,23 @@ void addModuleFlags(llvm::Module &m) {
404404
opts::fCFProtection == opts::CFProtectionType::Full) {
405405
m.setModuleFlag(ModuleMinFlag, "cf-protection-branch", ConstantOneMetadata);
406406
}
407+
408+
// Target specific flags
409+
const auto ModuleErrFlag = llvm::Module::Error;
410+
switch (global.params.targetTriple->getArch()) {
411+
case llvm::Triple::ppc64:
412+
case llvm::Triple::ppc64le:
413+
if (target.RealProperties.mant_dig == 113) {
414+
const auto ConstantIEEE128String = llvm::MDString::get(gIR->context(), "ieeequad");
415+
m.setModuleFlag(ModuleErrFlag, "float-abi", ConstantIEEE128String);
416+
} else if (target.RealProperties.mant_dig == 106) {
417+
const auto ConstantIBM128String = llvm::MDString::get(gIR->context(), "doubledouble");
418+
m.setModuleFlag(ModuleErrFlag, "float-abi", ConstantIBM128String);
419+
}
420+
break;
421+
default:
422+
break;
423+
}
407424
}
408425

409426
} // anonymous namespace

gen/target.cpp

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,42 @@
2626
using namespace dmd;
2727
using llvm::APFloat;
2828

29+
enum class RealPrecision : uint8_t { Default, Double, Quad, DoubleDouble };
30+
static llvm::cl::opt<RealPrecision, false> realPrecision{
31+
"real-precision",
32+
llvm::cl::ZeroOrMore,
33+
llvm::cl::Hidden,
34+
llvm::cl::init(RealPrecision::Default),
35+
llvm::cl::desc("Override the precision of the `real` type"),
36+
llvm::cl::values(clEnumValN(RealPrecision::Double, "double",
37+
"Use double precision (64-bit)"),
38+
clEnumValN(RealPrecision::Quad, "quad",
39+
"Use IEEE quad precision (128-bit)"),
40+
clEnumValN(RealPrecision::DoubleDouble, "doubledouble",
41+
"Use IBM double double precision (128-bit)"))};
42+
2943
namespace {
3044
// Returns the LL type to be used for D `real` (C `long double`).
3145
llvm::Type *getRealType(const llvm::Triple &triple) {
3246
using llvm::Triple;
3347

3448
auto &ctx = getGlobalContext();
3549

50+
// if overridden with -real-precision:
51+
if (realPrecision == RealPrecision::Double) {
52+
return LLType::getDoubleTy(ctx);
53+
} else if (realPrecision == RealPrecision::Quad) {
54+
return LLType::getFP128Ty(ctx);
55+
} else if (realPrecision == RealPrecision::DoubleDouble) {
56+
if (triple.getArch() != Triple::ppc64 &&
57+
triple.getArch() != Triple::ppc64le) {
58+
error(Loc(), "'-real-precision=doubledouble' is only supported for "
59+
"PowerPC64 targets");
60+
fatal();
61+
}
62+
return LLType::getPPC_FP128Ty(ctx);
63+
}
64+
3665
// Android: x86 targets follow ARM, with emulated quad precision for x64
3766
if (triple.getEnvironment() == llvm::Triple::Android) {
3867
return triple.isArch64Bit() ? LLType::getFP128Ty(ctx)
@@ -64,9 +93,34 @@ llvm::Type *getRealType(const llvm::Triple &triple) {
6493
case Triple::wasm64:
6594
return LLType::getFP128Ty(ctx);
6695

96+
case Triple::ppc64:
97+
case Triple::ppc64le:
98+
if (triple.isMusl()) { // Musl uses double
99+
return LLType::getDoubleTy(ctx);
100+
}
101+
#if defined(__linux__) && defined(__powerpc64__)
102+
// for a PowerPC64 Linux build:
103+
// default to the C++ host compiler's `long double` ABI when targeting
104+
// PowerPC64 (non-musl) Linux
105+
if (triple.isOSLinux()) {
106+
#if __LDBL_MANT_DIG__ == 113
107+
return LLType::getFP128Ty(ctx);
108+
#elif __LDBL_MANT_DIG__ == 106
109+
return LLType::getPPC_FP128Ty(ctx);
110+
#elif __LDBL_MANT_DIG__ == 53
111+
return LLType::getDoubleTy(ctx);
112+
#else
113+
static_assert(
114+
__LDBL_MANT_DIG__ == 0,
115+
"Unexpected C++ 'long double' precision for a PowerPC64 host!");
116+
#endif
117+
}
118+
#endif
119+
return LLType::getPPC_FP128Ty(ctx);
120+
67121
default:
68122
// 64-bit double precision for all other targets
69-
// FIXME: PowerPC, SystemZ, ...
123+
// FIXME: SystemZ, ...
70124
return LLType::getDoubleTy(ctx);
71125
}
72126
}
@@ -156,6 +210,7 @@ void Target::_init(const Param &params) {
156210
const auto IEEEdouble = &APFloat::IEEEdouble();
157211
const auto x87DoubleExtended = &APFloat::x87DoubleExtended();
158212
const auto IEEEquad = &APFloat::IEEEquad();
213+
const auto PPCDoubleDouble = &APFloat::PPCDoubleDouble();
159214
bool isOutOfRange = false;
160215

161216
RealProperties.nan = CTFloat::nan;
@@ -197,6 +252,18 @@ void Target::_init(const Param &params) {
197252
RealProperties.min_exp = -16381;
198253
RealProperties.max_10_exp = 4932;
199254
RealProperties.min_10_exp = -4931;
255+
} else if (targetRealSemantics == PPCDoubleDouble) {
256+
RealProperties.max =
257+
CTFloat::parse("0x1.fffffffffffff7ffffffffffff8p1023", isOutOfRange);
258+
RealProperties.min_normal = CTFloat::parse("0x1p-969", isOutOfRange);
259+
RealProperties.epsilon =
260+
CTFloat::parse("0x0.000000000000000000000000008p-969", isOutOfRange);
261+
RealProperties.dig = 31;
262+
RealProperties.mant_dig = 106;
263+
RealProperties.max_exp = 1024;
264+
RealProperties.min_exp = -968;
265+
RealProperties.max_10_exp = 308;
266+
RealProperties.min_10_exp = -291;
200267
} else {
201268
// leave initialized with host real_t values
202269
warning(Loc(), "unknown properties for target `real` type, relying on D "
@@ -237,11 +304,29 @@ Type *Target::va_listType(const Loc &loc, Scope *sc) {
237304
const char *TargetCPP::typeMangle(Type *t) {
238305
if (t->ty == TY::Tfloat80) {
239306
const auto &triple = *global.params.targetTriple;
307+
240308
// `long double` on Android/x64 is __float128 and mangled as `g`
241-
bool isAndroidX64 = triple.getEnvironment() == llvm::Triple::Android &&
242-
triple.getArch() == llvm::Triple::x86_64;
243-
return isAndroidX64 ? "g" : "e";
309+
if (triple.getEnvironment() == llvm::Triple::Android &&
310+
triple.getArch() == llvm::Triple::x86_64 &&
311+
target.RealProperties.mant_dig == 113) {
312+
return "g";
313+
};
314+
315+
if (triple.getArch() == llvm::Triple::ppc64 ||
316+
triple.getArch() == llvm::Triple::ppc64le) {
317+
if (target.RealProperties.mant_dig == 113 &&
318+
triple.getEnvironment() == llvm::Triple::GNU) {
319+
return "u9__ieee128";
320+
}
321+
if (target.RealProperties.mant_dig == 106) {
322+
// IBM long double
323+
return "g";
324+
}
325+
}
326+
327+
return "e";
244328
}
329+
245330
return nullptr;
246331
}
247332

gen/toir.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,8 +1858,8 @@ class ToElemVisitor : public Visitor {
18581858

18591859
LLValue *b = DtoRVal(DtoCast(e->loc, u, Type::tbool));
18601860

1861-
LLConstant *zero = DtoConstBool(false);
1862-
b = p->ir->CreateICmpEQ(b, zero);
1861+
LLConstant *one = DtoConstBool(true);
1862+
b = p->ir->CreateXor(b, one);
18631863

18641864
result = zextBool(b, e->type);
18651865
}

runtime/druntime/src/core/atomic.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ version (LDC)
652652
version (D_LP64)
653653
{
654654
version (PPC64)
655-
enum has128BitCAS = false;
655+
enum has128BitCAS = real.mant_dig == 113;
656656
else
657657
enum has128BitCAS = true;
658658
}

runtime/druntime/src/core/stdc/config.d

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,8 @@ package(core) template muslRedirTime64Mangle(string name, string redirectedName)
651651
else
652652
enum muslRedirTime64Mangle = name;
653653
}
654+
655+
version (PPC64)
656+
enum PPCUseIEEE128 = real.mant_dig == 113;
657+
else
658+
enum PPCUseIEEE128 = false;

0 commit comments

Comments
 (0)