Index: cfe/trunk/lib/CodeGen/TargetInfo.cpp =================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp @@ -3413,8 +3413,10 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ } 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; Index: cfe/trunk/lib/Driver/Tools.h =================================================================== --- cfe/trunk/lib/Driver/Tools.h +++ cfe/trunk/lib/Driver/Tools.h @@ -742,6 +742,16 @@ 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. Index: cfe/trunk/lib/Driver/Tools.cpp =================================================================== --- cfe/trunk/lib/Driver/Tools.cpp +++ cfe/trunk/lib/Driver/Tools.cpp @@ -1407,7 +1407,8 @@ return ""; } -static void getPPCTargetFeatures(const ArgList &Args, +static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, std::vector &Features) { for (const Arg *A : Args.filtered(options::OPT_m_ppc_Features_Group)) { StringRef Name = A->getOption().getName(); @@ -1431,11 +1432,51 @@ 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(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 @@ 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 @@ 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); Index: cfe/trunk/test/CodeGen/ppc-sfvarargs.c =================================================================== --- cfe/trunk/test/CodeGen/ppc-sfvarargs.c +++ cfe/trunk/test/CodeGen/ppc-sfvarargs.c @@ -0,0 +1,17 @@ +// RUN: %clang -O0 --target=powerpc-unknown-linux-gnu -EB -msoft-float -S -emit-llvm %s -o - | FileCheck %s + +#include +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 \ No newline at end of file Index: cfe/trunk/test/Driver/ppc-features.cpp =================================================================== --- cfe/trunk/test/Driver/ppc-features.cpp +++ cfe/trunk/test/Driver/ppc-features.cpp @@ -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