diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index c67b437ddff8..c54bafc07fe8 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -115,6 +115,9 @@ def err_target_unknown_triple : Error< def err_target_unknown_cpu : Error<"unknown target CPU '%0'">; def err_target_unknown_abi : Error<"unknown target ABI '%0'">; def err_target_unknown_cxxabi : Error<"unknown C++ ABI '%0'">; +def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">; +def err_target_unsupported_fpmath : Error< + "the '%0' unit is not supported with this instruction set">; // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 821a469d617c..ec7cdec7ad43 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -653,6 +653,13 @@ public: return false; } + /// \brief Use the specified unit for FP math. + /// + /// \return False on error (invalid unit name). + virtual bool setFPMath(StringRef Name) { + return false; + } + /// \brief Use this specified C++ ABI. /// /// \return False on error (invalid C++ ABI name). @@ -685,7 +692,11 @@ public: /// /// The target may modify the features list, to change which options are /// passed onwards to the backend. - virtual void HandleTargetFeatures(std::vector &Features) { + /// + /// \return False on error. + virtual bool HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { + return true; } /// \brief Determine whether the given target has the given feature. diff --git a/clang/include/clang/Basic/TargetOptions.h b/clang/include/clang/Basic/TargetOptions.h index c2183fd29d56..9909182ab6dd 100644 --- a/clang/include/clang/Basic/TargetOptions.h +++ b/clang/include/clang/Basic/TargetOptions.h @@ -32,6 +32,9 @@ public: /// If given, the name of the target CPU to generate code for. std::string CPU; + /// If given, the unit to use for floating point math. + std::string FPMath; + /// If given, the name of the target ABI to use. std::string ABI; diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 2774dc69f2ea..b74f4453e654 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -23,6 +23,8 @@ def target_abi : Separate<["-"], "target-abi">, HelpText<"Target a particular ABI type">; def target_cpu : Separate<["-"], "target-cpu">, HelpText<"Target a specific cpu type">; +def mfpmath : Separate<["-"], "mfpmath">, + HelpText<"Which unit to use for fp math">; def target_feature : Separate<["-"], "target-feature">, HelpText<"Target specific attributes">; def target_linker_version : Separate<["-"], "target-linker-version">, diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 8674b2a4a405..fd3cfa6eff30 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -1709,6 +1709,12 @@ class X86TargetInfo : public TargetInfo { //@} } CPU; + enum FPMathKind { + FP_Default, + FP_SSE, + FP_387 + } FPMath; + public: X86TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow), @@ -1716,7 +1722,7 @@ public: HasRDRND(false), HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false), HasPRFCHW(false), HasRDSEED(false), HasFMA(false), HasF16C(false), HasAVX512CD(false), HasAVX512ER(false), - HasAVX512PF(false), CPU(CK_Generic) { + HasAVX512PF(false), CPU(CK_Generic), FPMath(FP_Default) { BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } @@ -1763,7 +1769,8 @@ public: bool Enabled) const; virtual void getDefaultFeatures(llvm::StringMap &Features) const; virtual bool hasFeature(StringRef Feature) const; - virtual void HandleTargetFeatures(std::vector &Features); + virtual bool HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags); virtual const char* getABI() const { if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) return "avx"; @@ -1895,6 +1902,8 @@ public: llvm_unreachable("Unhandled CPU kind"); } + virtual bool setFPMath(StringRef Name); + virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { // We accept all non-ARM calling conventions return (CC == CC_X86ThisCall || @@ -1910,6 +1919,18 @@ public: } }; +bool X86TargetInfo::setFPMath(StringRef Name) { + if (Name == "387") { + FPMath = FP_387; + return true; + } + if (Name == "sse") { + FPMath = FP_SSE; + return true; + } + return false; +} + void X86TargetInfo::getDefaultFeatures(llvm::StringMap &Features) const { // FIXME: This *really* should not be here. @@ -2246,7 +2267,8 @@ void X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, /// HandleTargetOptions - Perform initialization based on the user /// configured set of features. -void X86TargetInfo::HandleTargetFeatures(std::vector &Features) { +bool X86TargetInfo::HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { // Remember the maximum enabled sselevel. for (unsigned i = 0, e = Features.size(); i !=e; ++i) { // Ignore disabled features. @@ -2360,12 +2382,23 @@ void X86TargetInfo::HandleTargetFeatures(std::vector &Features) { XOPLevel = std::max(XOPLevel, XLevel); } + // LLVM doesn't have a separate switch for fpmath, so only accept it if it + // matches the selected sse level. + if (FPMath == FP_SSE && SSELevel < SSE1) { + Diags.Report(diag::err_target_unsupported_fpmath) << "sse"; + return false; + } else if (FPMath == FP_387 && SSELevel >= SSE1) { + Diags.Report(diag::err_target_unsupported_fpmath) << "387"; + return false; + } + // Don't tell the backend if we're turning off mmx; it will end up disabling // SSE, which we don't want. std::vector::iterator it; it = std::find(Features.begin(), Features.end(), "-mmx"); if (it != Features.end()) Features.erase(it); + return true; } /// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro @@ -3280,12 +3313,14 @@ public: return Feature == "aarch64" || (Feature == "neon" && FPU == NeonMode); } - virtual void HandleTargetFeatures(std::vector &Features) { + virtual bool HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { FPU = FPUMode; for (unsigned i = 0, e = Features.size(); i != e; ++i) { if (Features[i] == "+neon") FPU = NeonMode; } + return true; } virtual void getGCCRegNames(const char *const *&Names, @@ -3421,6 +3456,12 @@ class ARMTargetInfo : public TargetInfo { std::string ABI, CPU; + enum { + FP_Default, + FP_VFP, + FP_Neon + } FPMath; + unsigned FPU : 4; unsigned IsAAPCS : 1; @@ -3465,7 +3506,7 @@ class ARMTargetInfo : public TargetInfo { public: ARMTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple), ABI("aapcs-linux"), CPU("arm1136j-s"), - IsAAPCS(true) { + FPMath(FP_Default), IsAAPCS(true) { BigEndian = false; SizeType = UnsignedInt; PtrDiffType = SignedInt; @@ -3571,7 +3612,8 @@ public: } } - virtual void HandleTargetFeatures(std::vector &Features) { + virtual bool HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { FPU = 0; SoftFloat = SoftFloatABI = false; for (unsigned i = 0, e = Features.size(); i != e; ++i) { @@ -3589,6 +3631,16 @@ public: FPU |= NeonFPU; } + if (!(FPU & NeonFPU) && FPMath == FP_Neon) { + Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; + return false; + } + + if (FPMath == FP_Neon) + Features.push_back("+neonfp"); + else if (FPMath == FP_VFP) + Features.push_back("-neonfp"); + // Remove front-end specific options which the backend handles differently. std::vector::iterator it; it = std::find(Features.begin(), Features.end(), "+soft-float"); @@ -3597,6 +3649,7 @@ public: it = std::find(Features.begin(), Features.end(), "+soft-float-abi"); if (it != Features.end()) Features.erase(it); + return true; } virtual bool hasFeature(StringRef Feature) const { @@ -3649,6 +3702,7 @@ public: CPU = Name; return true; } + virtual bool setFPMath(StringRef Name); virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. @@ -3820,6 +3874,18 @@ public: } }; +bool ARMTargetInfo::setFPMath(StringRef Name) { + if (Name == "neon") { + FPMath = FP_Neon; + return true; + } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || + Name == "vfp4") { + FPMath = FP_VFP; + return true; + } + return false; +} + const char * const ARMTargetInfo::GCCRegNames[] = { // Integer registers "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -4070,11 +4136,13 @@ class SparcTargetInfo : public TargetInfo { public: SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {} - virtual void HandleTargetFeatures(std::vector &Features) { + virtual bool HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { SoftFloat = false; for (unsigned i = 0, e = Features.size(); i != e; ++i) if (Features[i] == "+soft-float") SoftFloat = true; + return true; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -4642,7 +4710,8 @@ public: return ""; } - virtual void HandleTargetFeatures(std::vector &Features) { + virtual bool HandleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { IsMips16 = false; IsMicromips = false; IsSingleFloat = false; @@ -4672,6 +4741,8 @@ public: std::find(Features.begin(), Features.end(), "+soft-float"); if (it != Features.end()) Features.erase(it); + + return true; } virtual int getEHDataRegisterNumber(unsigned RegNo) const { @@ -5488,6 +5559,12 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, return 0; } + // Set the fp math unit. + if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) { + Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath; + return 0; + } + // Compute the default target features, we need the target to handle this // because features may have dependencies on one another. llvm::StringMap Features; @@ -5510,7 +5587,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, for (llvm::StringMap::const_iterator it = Features.begin(), ie = Features.end(); it != ie; ++it) Opts->Features.push_back((it->second ? "+" : "-") + it->first().str()); - Target->HandleTargetFeatures(Opts->Features); + if (!Target->HandleTargetFeatures(Opts->Features, Diags)) + return 0; return Target.take(); } diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 746300000f2f..25be6b48b660 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -602,30 +602,6 @@ static void getFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args, D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } -// Handle -mfpmath=. -static void getFPMathFeatures(const Driver &D, const Arg *A, - const ArgList &Args, - std::vector &Features, - StringRef CPU) { - StringRef FPMath = A->getValue(); - - // Set the target features based on the FPMath. - if (FPMath == "neon") { - Features.push_back("+neonfp"); - - if (CPU != "cortex-a5" && CPU != "cortex-a7" && - CPU != "cortex-a8" && CPU != "cortex-a9" && - CPU != "cortex-a9-mp" && CPU != "cortex-a15") - D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU; - - } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" || - FPMath == "vfp4") { - Features.push_back("-neonfp"); - // FIXME: Add warnings when disabling a feature not present for a given CPU. - } else - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); -} - // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. static StringRef getARMFloatABI(const Driver &D, @@ -725,10 +701,6 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) getFPUFeatures(D, A, Args, Features); - // Honor -mfpmath=. - if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) - getFPMathFeatures(D, A, Args, Features, getARMTargetCPU(Args, Triple)); - // Setting -msoft-float effectively disables NEON because of the GCC // implementation, although the same isn't true of VFP or VFP3. if (FloatABI == "soft") @@ -2409,6 +2381,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(CPU)); } + if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { + CmdArgs.push_back("-mfpmath"); + CmdArgs.push_back(A->getValue()); + } + // Add the target features getTargetFeatures(D, ETriple, Args, CmdArgs); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 9e6061900804..b637938735c1 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1541,6 +1541,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { Opts.ABI = Args.getLastArgValue(OPT_target_abi); Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); + Opts.FPMath = Args.getLastArgValue(OPT_mfpmath); Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); diff --git a/clang/test/Driver/arm-mfpmath.c b/clang/test/Driver/arm-mfpmath.c deleted file mode 100644 index 0421046c5bc8..000000000000 --- a/clang/test/Driver/arm-mfpmath.c +++ /dev/null @@ -1,29 +0,0 @@ -// Test different values of -mfpmath. - -// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-VFP %s -// CHECK-VFP: "-target-feature" "-neonfp" - -// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp2 %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-VFP2 %s -// CHECK-VFP2: "-target-feature" "-neonfp" - -// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp3 %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-VFP3 %s -// CHECK-VFP3: "-target-feature" "-neonfp" - -// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp4 %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-VFP4 %s -// CHECK-VFP4: "-target-feature" "-neonfp" - -// RUN: %clang -target arm-apple-darwin10 -mfpmath=neon %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-NEON %s -// CHECK-NEON: "-target-feature" "+neonfp" - -// RUN: %clang -target arm-apple-darwin10 -mfpmath=foo %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-ERROR %s -// CHECK-ERROR: clang compiler does not support '-mfpmath=foo' - -// RUN: %clang -target arm-apple-darwin10 -mcpu=arm1136j-s -mfpmath=neon %s -### -c -o %t.o 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-MCPU-ERROR %s -// CHECK-MCPU-ERROR: error: invalid feature '-mfpmath=neon' for CPU 'arm1136j-s' diff --git a/clang/test/Frontend/mfpmath.c b/clang/test/Frontend/mfpmath.c new file mode 100644 index 000000000000..f650e485cb99 --- /dev/null +++ b/clang/test/Frontend/mfpmath.c @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse %s + +// RUN: %clang_cc1 -triple i686-pc-linux -target-feature -sse -mfpmath 387 %s + +// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse %s + +// RUN: %clang_cc1 -triple i686-pc-linux -target-feature +sse -mfpmath sse %s + +// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \ +// RUN: -mfpmath xyz %s 2>&1 | FileCheck --check-prefix=CHECK-XYZ %s +// CHECK-XYZ: error: unknown FP unit 'xyz' + +// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature +sse \ +// RUN: -mfpmath 387 %s 2>&1 | FileCheck --check-prefix=CHECK-NO-387 %s +// CHECK-NO-387: error: the '387' unit is not supported with this instruction set + +// RUN: not %clang_cc1 -triple i686-pc-linux -target-feature -sse \ +// RUN: -mfpmath sse %s 2>&1 | FileCheck --check-prefix=CHECK-NO-SSE %s +// CHECK-NO-SSE: error: the 'sse' unit is not supported with this instruction set + + +// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp %s + +// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp2 %s + +// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp3 %s + +// RUN: %clang_cc1 -triple arm-apple-darwin10 -mfpmath vfp4 %s + +// RUN: %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \ +// RUN: -mfpmath neon %s + +// RUN: not %clang_cc1 -triple arm-apple-darwin10 -mfpmath foo %s 2>&1 \ +// RUN: FileCheck --check-prefix=CHECK-FOO %s +// CHECK-FOO: unknown FP unit 'foo' + +// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu arm1136j-s \ +// RUN: -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s + +// RUN: not %clang_cc1 -triple arm-apple-darwin10 -target-cpu cortex-a9 \ +// RUN: -target-feature -neon -mfpmath neon %s 2>&1 | FileCheck --check-prefix=CHECK-NO-NEON %s + +// CHECK-NO-NEON: error: the 'neon' unit is not supported with this instruction set