[Power PC] add soft float support for ppc32

This patch enables soft float support for ppc32 architecture and fixes
the ABI for variadic functions. This is the first in a set of patches
for soft float support in LLVM.

Patch by Strahinja Petrovic.

Differential Revision: http://reviews.llvm.org/D13351

llvm-svn: 255515
This commit is contained in:
Petar Jovanovic 2015-12-14 17:51:50 +00:00
parent 67390c6cd3
commit 88a328fbbe
5 changed files with 144 additions and 11 deletions

View File

@ -3413,8 +3413,10 @@ Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
namespace {
/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
bool IsSoftFloatABI;
public:
PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI)
: DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {}
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
@ -3422,8 +3424,8 @@ public:
class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
PPC32TargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT)) {}
PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI)
: TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI)) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
@ -3455,6 +3457,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64;
bool isInt =
Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType();
bool isF64 = Ty->isFloatingType() && getContext().getTypeSize(Ty) == 64;
// All aggregates are passed indirectly? That doesn't seem consistent
// with the argument-lowering code.
@ -3464,7 +3467,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
// The calling convention either uses 1-2 GPRs or 1 FPR.
Address NumRegsAddr = Address::invalid();
if (isInt) {
if (isInt || IsSoftFloatABI) {
NumRegsAddr = Builder.CreateStructGEP(VAList, 0, CharUnits::Zero(), "gpr");
} else {
NumRegsAddr = Builder.CreateStructGEP(VAList, 1, CharUnits::One(), "fpr");
@ -3473,7 +3476,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
llvm::Value *NumRegs = Builder.CreateLoad(NumRegsAddr, "numUsedRegs");
// "Align" the register count when TY is i64.
if (isI64) {
if (isI64 || (isF64 && IsSoftFloatABI)) {
NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(1));
NumRegs = Builder.CreateAnd(NumRegs, Builder.getInt8((uint8_t) ~1U));
}
@ -3502,14 +3505,14 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
assert(RegAddr.getElementType() == CGF.Int8Ty);
// Floating-point registers start after the general-purpose registers.
if (!isInt) {
if (!(isInt || IsSoftFloatABI)) {
RegAddr = Builder.CreateConstInBoundsByteGEP(RegAddr,
CharUnits::fromQuantity(32));
}
// Get the address of the saved value by scaling the number of
// registers we've used by the number of
CharUnits RegSize = CharUnits::fromQuantity(isInt ? 4 : 8);
CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8);
llvm::Value *RegOffset =
Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity()));
RegAddr = Address(Builder.CreateInBoundsGEP(CGF.Int8Ty,
@ -3518,7 +3521,9 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
RegAddr = Builder.CreateElementBitCast(RegAddr, DirectTy);
// Increase the used-register count.
NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(isI64 ? 2 : 1));
NumRegs =
Builder.CreateAdd(NumRegs,
Builder.getInt8((isI64 || (isF64 && IsSoftFloatABI)) ? 2 : 1));
Builder.CreateStore(NumRegs, NumRegsAddr);
CGF.EmitBranch(Cont);
@ -7471,7 +7476,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
}
case llvm::Triple::ppc:
return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
return *(TheTargetCodeGenInfo =
new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft"));
case llvm::Triple::ppc64:
if (Triple.isOSBinFormatELF()) {
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;

View File

@ -1407,7 +1407,8 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
return "";
}
static void getPPCTargetFeatures(const ArgList &Args,
static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<const char *> &Features) {
for (const Arg *A : Args.filtered(options::OPT_m_ppc_Features_Group)) {
StringRef Name = A->getOption().getName();
@ -1431,11 +1432,51 @@ static void getPPCTargetFeatures(const ArgList &Args,
Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
if (FloatABI == ppc::FloatABI::Soft &&
!(Triple.getArch() == llvm::Triple::ppc64 ||
Triple.getArch() == llvm::Triple::ppc64le))
Features.push_back("+soft-float");
else if (FloatABI == ppc::FloatABI::Soft &&
(Triple.getArch() == llvm::Triple::ppc64 ||
Triple.getArch() == llvm::Triple::ppc64le))
D.Diag(diag::err_drv_invalid_mfloat_abi)
<< "soft float is not supported for ppc64";
// Altivec is a bit weird, allow overriding of the Altivec feature here.
AddTargetFeature(Args, Features, options::OPT_faltivec,
options::OPT_fno_altivec, "altivec");
}
ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) {
ppc::FloatABI ABI = ppc::FloatABI::Invalid;
if (Arg *A =
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
options::OPT_mfloat_abi_EQ)) {
if (A->getOption().matches(options::OPT_msoft_float))
ABI = ppc::FloatABI::Soft;
else if (A->getOption().matches(options::OPT_mhard_float))
ABI = ppc::FloatABI::Hard;
else {
ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue())
.Case("soft", ppc::FloatABI::Soft)
.Case("hard", ppc::FloatABI::Hard)
.Default(ppc::FloatABI::Invalid);
if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
ABI = ppc::FloatABI::Hard;
}
}
}
// If unspecified, choose the default based on the platform.
if (ABI == ppc::FloatABI::Invalid) {
ABI = ppc::FloatABI::Hard;
}
return ABI;
}
void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Select the ABI to use.
@ -1472,6 +1513,21 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
if (StringRef(A->getValue()) != "altivec")
ABIName = A->getValue();
ppc::FloatABI FloatABI =
ppc::getPPCFloatABI(getToolChain().getDriver(), Args);
if (FloatABI == ppc::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
} else {
// Floating point operations and argument passing are hard.
assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
if (ABIName) {
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
@ -2248,7 +2304,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
getPPCTargetFeatures(Args, Features);
getPPCTargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::systemz:
getSystemZTargetFeatures(Args, Features);

View File

@ -742,6 +742,16 @@ enum class FloatABI {
FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args);
} // end namespace arm
namespace ppc {
enum class FloatABI {
Invalid,
Soft,
Hard,
};
FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
} // end namespace ppc
namespace XCore {
// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and
// Compile.

View File

@ -0,0 +1,17 @@
// RUN: %clang -O0 --target=powerpc-unknown-linux-gnu -EB -msoft-float -S -emit-llvm %s -o - | FileCheck %s
#include <stdarg.h>
void test(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
va_arg(ap, double);
va_end(ap);
}
void foo() {
double a;
test("test",a);
}
// CHECK: %{{[0-9]+}} = add i8 %numUsedRegs, 1
// CHECK: %{{[0-9]+}} = and i8 %{{[0-9]+}}, -2
// CHECK: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, 4

View File

@ -12,6 +12,50 @@
// RUN: not %clang -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
// RUN: not %clang -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
// check -msoft-float option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT %s
// CHECK-SOFTFLOAT: "-target-feature" "+soft-float"
// check -mfloat-abi=soft option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT %s
// CHECK-FLOATABISOFT: "-target-feature" "+soft-float"
// check -mhard-float option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -mhard-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-HARDFLOAT %s
// CHECK-HARDFLOAT-NOT: "-target-feature" "+soft-float"
// check -mfloat-abi=hard option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -mfloat-abi=hard -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABIHARD %s
// CHECK-FLOATABIHARD-NOT: "-target-feature" "+soft-float"
// check combine -mhard-float -msoft-float option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -mhard-float -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-HARDSOFT %s
// CHECK-HARDSOFT: "-target-feature" "+soft-float"
// check combine -msoft-float -mhard-float option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -msoft-float -mhard-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTHARD %s
// CHECK-SOFTHARD-NOT: "-target-feature" "+soft-float"
// check -mfloat-abi=x option
// RUN: %clang -target powerpc-unknown-linux-gnu %s -mfloat-abi=x -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-ERRMSG %s
// CHECK-ERRMSG: clang: error: invalid float ABI '-mfloat-abi=x'
// check -msoft-float option for ppc64
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT64 %s
// CHECK-SOFTFLOAT64: clang: error: invalid float ABI 'soft float is not supported for ppc64'
// check -mfloat-abi=soft option for ppc64
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT64 %s
// CHECK-FLOATABISOFT64: clang: error: invalid float ABI 'soft float is not supported for ppc64'
// check -msoft-float option for ppc64
// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT64le %s
// CHECK-SOFTFLOAT64le: clang: error: invalid float ABI 'soft float is not supported for ppc64'
// check -mfloat-abi=soft option for ppc64
// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT64le %s
// CHECK-FLOATABISOFT64le: clang: error: invalid float ABI 'soft float is not supported for ppc64'
// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64/ppc64le'
// Check that -fno-altivec and -mno-altivec correctly disable the altivec