Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -685,6 +685,10 @@ return std::string(1, *Constraint); } + virtual bool isSoftFloatABI() const { + return false; + } + /// \brief Returns a string of target-specific clobbers, in LLVM format. virtual const char *getClobbers() const = 0; Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -770,6 +770,7 @@ std::string CPU; // Target cpu features. + bool IsSoftFloat; bool HasVSX; bool HasP8Vector; bool HasP8Crypto; @@ -784,7 +785,7 @@ public: PPCTargetInfo(const llvm::Triple &Triple) - : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), + : TargetInfo(Triple), IsSoftFloat(false), HasVSX(false), HasP8Vector(false), HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), HasBPERMD(false), HasExtDiv(false) { BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); @@ -873,7 +874,7 @@ return CPUKnown; } - + bool isSoftFloatABI() const override {return IsSoftFloat;} StringRef getABI() const override { return ABI; } void getTargetBuiltins(const Builtin::Info *&Records, @@ -1068,6 +1069,11 @@ // all. } + auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); + if (Feature != Features.end()) { + IsSoftFloat = true; + } + return true; } Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -3422,6 +3422,8 @@ bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64; bool isInt = Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType(); + bool isF64 = Ty->isFloatingType() && getContext().getTypeSize(Ty) == 64; + bool isSF = getTarget().isSoftFloatABI(); // All aggregates are passed indirectly? That doesn't seem consistent // with the argument-lowering code. @@ -3431,7 +3433,7 @@ // The calling convention either uses 1-2 GPRs or 1 FPR. Address NumRegsAddr = Address::invalid(); - if (isInt) { + if (isInt || isSF) { NumRegsAddr = Builder.CreateStructGEP(VAList, 0, CharUnits::Zero(), "gpr"); } else { NumRegsAddr = Builder.CreateStructGEP(VAList, 1, CharUnits::One(), "fpr"); @@ -3440,7 +3442,7 @@ llvm::Value *NumRegs = Builder.CreateLoad(NumRegsAddr, "numUsedRegs"); // "Align" the register count when TY is i64. - if (isI64) { + if (isI64 || (isF64 && isSF)) { NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(1)); NumRegs = Builder.CreateAnd(NumRegs, Builder.getInt8((uint8_t) ~1U)); } @@ -3469,14 +3471,14 @@ assert(RegAddr.getElementType() == CGF.Int8Ty); // Floating-point registers start after the general-purpose registers. - if (!isInt) { + if (!(isInt || isSF)) { 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 || isSF) ? 4 : 8); llvm::Value *RegOffset = Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity())); RegAddr = Address(Builder.CreateInBoundsGEP(CGF.Int8Ty, @@ -3485,7 +3487,7 @@ 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 && isSF)) ? 2 : 1)); Builder.CreateStore(NumRegs, NumRegsAddr); CGF.EmitBranch(Cont); Index: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ lib/Driver/Tools.h @@ -728,6 +728,10 @@ FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); } + +namespace ppc { + StringRef getPPCFloatABI(const llvm::opt::ArgList &Args); +} namespace XCore { // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and // Compile. Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -1344,15 +1344,44 @@ // TODO: Change the LLVM backend option maybe? if (Name == "mfcrf") Name = "mfocrf"; - + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } + StringRef FloatABI = ppc::getPPCFloatABI(Args); + if (FloatABI == "soft") + Features.push_back("+soft-float"); + // Altivec is a bit weird, allow overriding of the Altivec feature here. AddTargetFeature(Args, Features, options::OPT_faltivec, options::OPT_fno_altivec, "altivec"); } +StringRef ppc::getPPCFloatABI(const ArgList &Args) { + StringRef FloatABI; + 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)) + FloatABI = "soft"; + else if (A->getOption().matches(options::OPT_mhard_float)) + FloatABI = "hard"; + else { + FloatABI = A->getValue(); + if (FloatABI != "soft" && FloatABI != "hard") { + FloatABI = "hard"; + } + } + } + + // If unspecified, choose the default based on the platform. + if (FloatABI.empty()) { + FloatABI = "hard"; + } + + return FloatABI; +} + void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Select the ABI to use. @@ -1389,6 +1418,21 @@ if (StringRef(A->getValue()) != "altivec") ABIName = A->getValue(); + StringRef FloatABI = ppc::getPPCFloatABI(Args); + + if (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 == "hard" && "Invalid float abi!"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); + } + if (ABIName) { CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); Index: test/CodeGen/ppc-sfvarargs.c =================================================================== --- test/CodeGen/ppc-sfvarargs.c +++ 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: test/Driver/ppc-features.cpp =================================================================== --- test/Driver/ppc-features.cpp +++ test/Driver/ppc-features.cpp @@ -12,6 +12,10 @@ // 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 soft float option only 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: invalid argument '-faltivec' only allowed with 'ppc/ppc64/ppc64le' // Check that -fno-altivec and -mno-altivec correctly disable the altivec