-
-
Notifications
You must be signed in to change notification settings - Fork 273
ppc64(le): Add an option to use IEEE long double ABI on Linux #4833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
05ccbb7
7802f8d
d892d68
84c6a2b
eb7c41c
b0ab201
a698caf
4e7800d
26034e5
f6d20f4
5180b4d
4151349
ae4c0d8
5195def
96c455c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,24 +10,84 @@ | |
| // The ABI implementation used for 64 bit little-endian PowerPC targets. | ||
| // | ||
| // The PowerOpen 64bit ELF v2 ABI can be found here: | ||
| // https://members.openpowerfoundation.org/document/dl/576 | ||
| // https://files.openpower.foundation/s/cfA2oFPXbbZwEBK/download/64biteflv2abi-v1.5.pdf | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include <llvm/IR/IntrinsicsPowerPC.h> | ||
|
|
||
| #include "gen/abi/abi.h" | ||
| #include "gen/abi/generic.h" | ||
| #include "gen/dvalue.h" | ||
| #include "gen/funcgenstate.h" | ||
| #include "gen/irstate.h" | ||
| #include "gen/llvmhelpers.h" | ||
| #include "gen/tollvm.h" | ||
| #include "target.h" | ||
|
|
||
| using namespace dmd; | ||
|
|
||
| struct LongDoubleRewrite : ABIRewrite { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need this rewrite. The D |
||
| inline bool shouldRewrite(Type *ty) { | ||
| const auto baseTy = ty->toBasetype()->ty; | ||
| return baseTy == TY::Tfloat80 || baseTy == TY::Tcomplex80 || | ||
| baseTy == TY::Timaginary80; | ||
| } | ||
|
|
||
| LLValue *put(DValue *dv, bool, bool) override { | ||
| if (shouldRewrite(dv->type)) { | ||
| auto *dconst = llvm::dyn_cast<llvm::ConstantFP>(DtoRVal(dv)); | ||
| if (dconst) { | ||
| // try to CTFE the conversion | ||
| // (ppc_convert_f128_to_ppcf128 intrinsics do not perform the conversion | ||
| // during the compile time) | ||
| bool ignored; | ||
| auto apfloat = dconst->getValue(); | ||
| apfloat.convert(llvm::APFloat::PPCDoubleDouble(), | ||
| llvm::APFloat::rmNearestTiesToEven, &ignored); | ||
| return llvm::ConstantFP::get(gIR->context(), apfloat); | ||
| } | ||
| const auto convertFunc = llvm::Intrinsic::getDeclaration( | ||
| &gIR->module, llvm::Intrinsic::ppc_convert_f128_to_ppcf128); | ||
| const auto ret = gIR->funcGen().callOrInvoke( | ||
| convertFunc, convertFunc->getFunctionType(), {DtoRVal(dv)}); | ||
| return ret; | ||
| } | ||
| return DtoRVal(dv); | ||
| } | ||
|
|
||
| LLValue *getLVal(Type *dty, LLValue *v) override { | ||
| // inverse operation of method "put" | ||
| auto dstType = DtoType(dty); | ||
| if (shouldRewrite(dty) && dstType->isFP128Ty()) { | ||
| const auto convertFunc = llvm::Intrinsic::getDeclaration( | ||
| &gIR->module, llvm::Intrinsic::ppc_convert_ppcf128_to_f128); | ||
| const auto retType = LLType::getFP128Ty(gIR->context()); | ||
| const auto buffer = DtoRawAlloca(retType, 16); | ||
| const auto ret = gIR->funcGen().callOrInvoke( | ||
| convertFunc, convertFunc->getFunctionType(), {v}); | ||
| DtoStore(ret, buffer); | ||
| return buffer; | ||
| } | ||
| // dual-ABI situation: if the destination type is already correct, we just store it | ||
| const auto buffer = DtoRawAlloca(dstType, 16); | ||
| DtoStore(v, buffer); | ||
| return buffer; | ||
| } | ||
|
|
||
| LLType *type(Type *ty) override { | ||
| return LLType::getPPC_FP128Ty(gIR->context()); | ||
| } | ||
| }; | ||
|
|
||
| struct PPC64LETargetABI : TargetABI { | ||
| HFVAToArray hfvaToArray; | ||
| CompositeToArray64 compositeToArray64; | ||
| IntegerRewrite integerRewrite; | ||
| LongDoubleRewrite longDoubleRewrite; | ||
| bool useIEEE128; | ||
|
|
||
| explicit PPC64LETargetABI() : hfvaToArray(8) {} | ||
| explicit PPC64LETargetABI() | ||
| : hfvaToArray(8), useIEEE128(target.RealProperties.mant_dig == 113) {} | ||
|
|
||
| bool passByVal(TypeFunction *, Type *t) override { | ||
| t = t->toBasetype(); | ||
|
|
@@ -51,9 +111,11 @@ struct PPC64LETargetABI : TargetABI { | |
| } else { | ||
| compositeToArray64.applyTo(arg); | ||
| } | ||
| } else if (ty->isintegral()) { | ||
| } else if (ty->isintegral() && !ty->isTypeVector()) { | ||
| arg.attrs.addAttribute(ty->isunsigned() ? LLAttribute::ZExt | ||
| : LLAttribute::SExt); | ||
| } else if (!useIEEE128 && longDoubleRewrite.shouldRewrite(arg.type)) { | ||
| longDoubleRewrite.applyTo(arg); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,13 @@ default: | |
| rpath = "@SHARED_LIBS_RPATH@"; | ||
| }; | ||
|
|
||
| "^powerpc64le-.*linux-gnu$": | ||
| { | ||
| // default to IEEE quad precision | ||
| // if your platform does not support this, feel free to remove it. | ||
| switches = ["--real-precision=quad"] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Arrays are not cumulative in ldc2.conf so what you did removed |
||
| }; | ||
|
|
||
| "^wasm(32|64)-": | ||
| { | ||
| switches = [ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, you check the default behavior of the C++ compiler, so we shouldn't need any explicit C++ flags. [Unless you wanna override the LLVM flags.] The D host compiler might need a flag though, to make sure it's
realmatches the C++long double, at least for the IEEE-quad case, which needs explicit opting it in with (new) LDC compilers.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I admit that might be a mistake. I will fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's a bit more complicated than that - host druntime and Phobos need to be (pre)compiled with the same ABI setting, matching the C++/LLVM one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one might need to be documented. According to my testing, changing the host
druntimefiles inincludedirectory is enough to get new LDC bootstrapped (using GDC/GDMD).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. But as adding some D flag wouldn't be sufficient then anyway, we probably don't need to try to add some here in CMake anymore. Host C++ and D compilers need to target the same ABI when building LDC; if the D one needs tweaking via extra flag, host druntime and Phobos need to be built accordingly and selected too, as in a cross-compile scenario.
[You were probably lucky that a few binding adaptations in the source files were enough to fix up host druntime, without having to rebuild the library.]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. CMake files fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You now affect the new druntime and Phobos builds for the just-built LDC, compiling them with the same ABI setting as the compiler itself. It doesn't affect (and cannot) host druntime and Phobos (from GDC in your case), which need to be precompiled with the same ABI setting (as they are linked into the LDC executable).
Now suppose LDC was built on a PPC system with (default) IEEE quad ABI. New druntime and Phobos would be compiled with
-real-precision=quad. But when the user runs it withldc2 hello.d, he'd get a hello object file compiled with default doubledouble ABI, linked with druntime and Phobos using the IEEE ABI. As the Drealmangling isn't affected by its precision, the user wouldn't get undefined symbols, but most likely just corrupt floating-point values at runtime.So a distro package maintainer would in that case need to make sure the compiler defaults to the same ABI as the bundled precompiled druntime and Phobos. E.g., by adding a PPC section in
ldc2.conf, adding-real-precision=quadas default switch.So as said, I think it'd be best to just remove all of this CMake flag fiddling for PPC - it's not enough, the user/package maintainer has to get involved and provide explicit flags in case the default host compiler ABIs diverge, and/or a non-default ABI is desired. As long as using GDC as host compiler, the compilers most likely default to the same ABI. [And there's probably a long way to go until LDC can build itself on such platforms, that requires full C ABI compatibility (ABI rewrites to help LLVM do the right thing) and full C-style variadic arguments support.]
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What we could also do: for a native ppc compiler build, default to the
realprecision of the host. So a native IEEE-quad build would default to-real-precision=quad(incl. druntime and Phobos automatically precompiled with that ABI setting).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I have now put these inside
ldc2*.conffiles.