diff --git a/gen/abi-aarch64.cpp b/gen/abi-aarch64.cpp index 4f81c8cdcb..95c52d0330 100644 --- a/gen/abi-aarch64.cpp +++ b/gen/abi-aarch64.cpp @@ -16,32 +16,6 @@ #include "gen/abi-generic.h" #include "gen/abi-aarch64.h" -namespace { - struct CompositeToArray64 : ABIRewrite { - LLValue *get(Type *dty, LLValue *v) override { - Logger::println("rewriting i64 array -> as %s", dty->toChars()); - LLValue *lval = DtoRawAlloca(v->getType(), 0); - DtoStore(v, lval); - - LLType *pTy = getPtrToType(DtoType(dty)); - return DtoLoad(DtoBitCast(lval, pTy), "get-result"); - } - - LLValue *put(DValue *dv) override { - Type *dty = dv->getType(); - Logger::println("rewriting %s -> as i64 array", dty->toChars()); - LLType *t = type(dty, nullptr); - return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t))); - } - - LLType *type(Type *t, LLType *) override { - // An i64 array that will hold Type 't' - size_t sz = (t->size() + 7) / 8; - return LLArrayType::get(LLIntegerType::get(gIR->context(), 64), sz); - } - }; -} - struct AArch64TargetABI : TargetABI { HFAToArray hfaToArray; CompositeToArray64 compositeToArray64; diff --git a/gen/abi-generic.h b/gen/abi-generic.h index 17bacdbd37..10231d2b65 100644 --- a/gen/abi-generic.h +++ b/gen/abi-generic.h @@ -241,6 +241,10 @@ struct ExplicitByvalRewrite : ABIRewrite { * float type. */ struct HFAToArray : ABIRewrite { + const int maxFloats = 4; + + HFAToArray(const int max = 4) : maxFloats(max) {} + LLValue *get(Type *dty, LLValue *v) override { Logger::println("rewriting array -> as HFA %s", dty->toChars()); LLValue *lval = DtoRawAlloca(v->getType(), 0); @@ -260,10 +264,37 @@ struct HFAToArray : ABIRewrite { LLType *type(Type *dty, LLType *) override { assert(dty->ty == Tstruct); LLType *floatArrayType = nullptr; - if (TargetABI::isHFA((TypeStruct *)dty, &floatArrayType)) + if (TargetABI::isHFA((TypeStruct *)dty, &floatArrayType, maxFloats)) return floatArrayType; llvm_unreachable("Type dty should be an HFA"); } }; +/** +* Rewrite a composite as array of i64. +*/ +struct CompositeToArray64 : ABIRewrite { + LLValue *get(Type *dty, LLValue *v) override { + Logger::println("rewriting i64 array -> as %s", dty->toChars()); + LLValue *lval = DtoRawAlloca(v->getType(), 0); + DtoStore(v, lval); + + LLType *pTy = getPtrToType(DtoType(dty)); + return DtoLoad(DtoBitCast(lval, pTy), "get-result"); + } + + LLValue *put(DValue *dv) override { + Type *dty = dv->getType(); + Logger::println("rewriting %s -> as i64 array", dty->toChars()); + LLType *t = type(dty, nullptr); + return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t))); + } + + LLType *type(Type *t, LLType *) override { + // An i64 array that will hold Type 't' + size_t sz = (t->size() + 7) / 8; + return LLArrayType::get(LLIntegerType::get(gIR->context(), 64), sz); + } +}; + #endif diff --git a/gen/abi-ppc64.cpp b/gen/abi-ppc.cpp similarity index 83% rename from gen/abi-ppc64.cpp rename to gen/abi-ppc.cpp index 06fc1cce70..b3748cf703 100644 --- a/gen/abi-ppc64.cpp +++ b/gen/abi-ppc.cpp @@ -7,25 +7,32 @@ // //===----------------------------------------------------------------------===// // +// The ABI implementation used for 32/64 bit big-endian PowerPC targets. +// +// The System V Application Binary Interface PowerPC Processor Supplement can be +// found here: +// http://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf +// // The PowerOpen 64bit ABI can be found here: // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html +// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf // //===----------------------------------------------------------------------===// #include "gen/abi.h" #include "gen/abi-generic.h" -#include "gen/abi-ppc64.h" +#include "gen/abi-ppc.h" #include "gen/dvalue.h" #include "gen/irstate.h" #include "gen/llvmhelpers.h" #include "gen/tollvm.h" -struct PPC64TargetABI : TargetABI { +struct PPCTargetABI : TargetABI { ExplicitByvalRewrite byvalRewrite; IntegerRewrite integerRewrite; const bool Is64Bit; - explicit PPC64TargetABI(const bool Is64Bit) : Is64Bit(Is64Bit) {} + explicit PPCTargetABI(const bool Is64Bit) : Is64Bit(Is64Bit) {} bool returnInArg(TypeFunction *tf) override { if (tf->isref) { @@ -81,6 +88,6 @@ struct PPC64TargetABI : TargetABI { }; // The public getter for abi.cpp -TargetABI *getPPC64TargetABI(bool Is64Bit) { - return new PPC64TargetABI(Is64Bit); +TargetABI *getPPCTargetABI(bool Is64Bit) { + return new PPCTargetABI(Is64Bit); } diff --git a/gen/abi-ppc64.h b/gen/abi-ppc.h similarity index 72% rename from gen/abi-ppc64.h rename to gen/abi-ppc.h index f2f602866d..d7dcdb326f 100644 --- a/gen/abi-ppc64.h +++ b/gen/abi-ppc.h @@ -7,15 +7,15 @@ // //===----------------------------------------------------------------------===// // -// The ABI implementation used for 64 bit PowerPC targets. +// The ABI implementation used for 32/64 bit big-endian PowerPC targets. // //===----------------------------------------------------------------------===// -#ifndef LDC_GEN_ABI_PPC64_H -#define LDC_GEN_ABI_PPC64_H +#ifndef LDC_GEN_ABI_PPC_H +#define LDC_GEN_ABI_PPC_H struct TargetABI; -TargetABI *getPPC64TargetABI(bool Is64Bit); +TargetABI *getPPCTargetABI(bool Is64Bit); #endif diff --git a/gen/abi-ppc64le.cpp b/gen/abi-ppc64le.cpp new file mode 100644 index 0000000000..bc268d4921 --- /dev/null +++ b/gen/abi-ppc64le.cpp @@ -0,0 +1,107 @@ +//===-- abi-ppc64.cpp -----------------------------------------------------===// +// +// LDC - the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// 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 +//===----------------------------------------------------------------------===// + +#include "gen/abi.h" +#include "gen/abi-generic.h" +#include "gen/abi-ppc64le.h" +#include "gen/dvalue.h" +#include "gen/irstate.h" +#include "gen/llvmhelpers.h" +#include "gen/tollvm.h" + +struct PPC64LETargetABI : TargetABI { + HFAToArray hfaToArray; + CompositeToArray64 compositeToArray64; + IntegerRewrite integerRewrite; + + explicit PPC64LETargetABI() : hfaToArray(8) {} + + bool returnInArg(TypeFunction *tf) override { + if (tf->isref) { + return false; + } + + Type *rt = tf->next->toBasetype(); + + // FIXME: The return value of this function translates + // to RETstack or RETregs in function retStyle(), which + // directly influences if NRVO is possible or not + // (false -> RETregs -> nrvo_can = false). Depending on + // NRVO, the postblit constructor is called or not. + // Thus using the rules of the C ABI here (as mandated by + // the D specification) leads to crashes. + if (tf->linkage == LINKd) + return rt->ty == Tsarray || rt->ty == Tstruct; + + return rt->ty == Tsarray || (rt->ty == Tstruct && rt->size() > 16 && + !isHFA((TypeStruct *)rt, nullptr, 8)); + } + + bool passByVal(Type *t) override { + t = t->toBasetype(); + return t->ty == Tsarray || (t->ty == Tstruct && t->size() > 16 && + !isHFA((TypeStruct *)t, nullptr, 8)); + } + + void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override { + // RETURN VALUE + Type *retTy = fty.ret->type->toBasetype(); + if (!fty.ret->byref) { + if (retTy->ty == Tstruct || retTy->ty == Tsarray) { + if (retTy->ty == Tstruct && + isHFA((TypeStruct *)retTy, &fty.ret->ltype, 8)) { + fty.ret->rewrite = &hfaToArray; + fty.ret->ltype = hfaToArray.type(fty.ret->type, fty.ret->ltype); + } else if (canRewriteAsInt(retTy, true)) { + fty.ret->rewrite = &integerRewrite; + fty.ret->ltype = integerRewrite.type(fty.ret->type, fty.ret->ltype); + } else { + fty.ret->rewrite = &compositeToArray64; + fty.ret->ltype = + compositeToArray64.type(fty.ret->type, fty.ret->ltype); + } + } else if (retTy->isintegral()) + fty.ret->attrs.add(retTy->isunsigned() ? LLAttribute::ZExt + : LLAttribute::SExt); + } + + // EXPLICIT PARAMETERS + for (auto arg : fty.args) { + if (!arg->byref) { + rewriteArgument(fty, *arg); + } + } + } + + void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override { + Type *ty = arg.type->toBasetype(); + if (ty->ty == Tstruct || ty->ty == Tsarray) { + if (ty->ty == Tstruct && isHFA((TypeStruct *)ty, &arg.ltype, 8)) { + arg.rewrite = &hfaToArray; + arg.ltype = hfaToArray.type(arg.type, arg.ltype); + } else if (canRewriteAsInt(ty, true)) { + arg.rewrite = &integerRewrite; + arg.ltype = integerRewrite.type(arg.type, arg.ltype); + } else { + arg.rewrite = &compositeToArray64; + arg.ltype = compositeToArray64.type(arg.type, arg.ltype); + } + } else if (ty->isintegral()) + arg.attrs.add(ty->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt); + } +}; + +// The public getter for abi.cpp +TargetABI *getPPC64LETargetABI() { return new PPC64LETargetABI(); } diff --git a/gen/abi-ppc64le.h b/gen/abi-ppc64le.h new file mode 100644 index 0000000000..39892b550e --- /dev/null +++ b/gen/abi-ppc64le.h @@ -0,0 +1,21 @@ +//===-- gen/abi-ppc-64.h - PPC64 ABI description ----------------*- C++ -*-===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// The ABI implementation used for 64 bit little-endian PowerPC targets. +// +//===----------------------------------------------------------------------===// + +#ifndef LDC_GEN_ABI_PPC64LE_H +#define LDC_GEN_ABI_PPC64LE_H + +struct TargetABI; + +TargetABI *getPPC64LETargetABI(); + +#endif diff --git a/gen/abi.cpp b/gen/abi.cpp index 14589d609c..bf9c322853 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -14,7 +14,8 @@ #include "gen/abi-aarch64.h" #include "gen/abi-arm.h" #include "gen/abi-mips64.h" -#include "gen/abi-ppc64.h" +#include "gen/abi-ppc.h" +#include "gen/abi-ppc64le.h" #include "gen/abi-win64.h" #include "gen/abi-x86-64.h" #include "gen/abi-x86.h" @@ -166,8 +167,8 @@ bool isNestedHFA(const TypeStruct *t, d_uns64 &floatSize, int &num, else if (sz != floatSize) // different float size, reject return false; - if (n > 4) - return false; // too many floats for HFA, reject + //if (n > 4) + // return false; // too many floats for HFA, reject } else { return false; // reject all other types } @@ -181,29 +182,31 @@ bool isNestedHFA(const TypeStruct *t, d_uns64 &floatSize, int &num, } } -bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType) { +bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType, const int maxFloats) { d_uns64 floatSize = 0; int num = 0; if (isNestedHFA(t, floatSize, num, 1)) { - if (rewriteType) { - llvm::Type *floatType = nullptr; - switch (floatSize) { - case 4: - floatType = llvm::Type::getFloatTy(gIR->context()); - break; - case 8: - floatType = llvm::Type::getDoubleTy(gIR->context()); - break; - case 16: - floatType = llvm::Type::getFP128Ty(gIR->context()); - break; - default: - llvm_unreachable("Unexpected size for float type"); + if (num <= maxFloats) { + if (rewriteType) { + llvm::Type *floatType = nullptr; + switch (floatSize) { + case 4: + floatType = llvm::Type::getFloatTy(gIR->context()); + break; + case 8: + floatType = llvm::Type::getDoubleTy(gIR->context()); + break; + case 16: + floatType = llvm::Type::getFP128Ty(gIR->context()); + break; + default: + llvm_unreachable("Unexpected size for float type"); + } + *rewriteType = LLArrayType::get(floatType, num); } - *rewriteType = LLArrayType::get(floatType, num); + return true; } - return true; } return false; } @@ -336,9 +339,11 @@ TargetABI *TargetABI::getTarget() { case llvm::Triple::mips64: case llvm::Triple::mips64el: return getMIPS64TargetABI(global.params.is64bit); + case llvm::Triple::ppc: case llvm::Triple::ppc64: + return getPPCTargetABI(global.params.targetTriple.isArch64Bit()); case llvm::Triple::ppc64le: - return getPPC64TargetABI(global.params.targetTriple.isArch64Bit()); + return getPPC64LETargetABI(); #if LDC_LLVM_VER == 305 case llvm::Triple::arm64: case llvm::Triple::arm64_be: diff --git a/gen/abi.h b/gen/abi.h index 720e2855c4..122bc0fd15 100644 --- a/gen/abi.h +++ b/gen/abi.h @@ -154,7 +154,7 @@ struct TargetABI { /// Check if struct 't' is a Homogeneous Floating-point Aggregate (HFA) /// consisting of up to 4 of same floating point type. If so, optionally /// produce the rewriteType: an array of that floating point type - static bool isHFA(TypeStruct *t, llvm::Type **rewriteType = nullptr); + static bool isHFA(TypeStruct *t, llvm::Type **rewriteType = nullptr, const int maxFloats = 4); protected: