Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -199,6 +199,9 @@ def err_target_unsupported_abi : Error<"ABI '%0' is not supported on CPU '%1'">; def err_target_unsupported_abi_for_triple : Error< "ABI '%0' is not supported for '%1'">; +def err_unsupported_abi_for_opt : Error<"'%0' can only be used with the '%1' ABI">; +def err_mips_fp64_req : Error< + "'%0' can only be used if the target supports the mfhc1 and mthc1 instructions">; 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">; Index: lib/Basic/Targets/Mips.h =================================================================== --- lib/Basic/Targets/Mips.h +++ lib/Basic/Targets/Mips.h @@ -57,7 +57,7 @@ bool UseIndirectJumpHazard; protected: - bool HasFP64; + enum FPModeEnum { FPXX, FP32, FP64 } FPMode; std::string ABI; public: @@ -66,7 +66,7 @@ IsNan2008(false), IsAbs2008(false), IsSingleFloat(false), IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat), DspRev(NoDSP), HasMSA(false), DisableMadd4(false), - UseIndirectJumpHazard(false), HasFP64(false) { + UseIndirectJumpHazard(false), FPMode(FPXX) { TheCXXABI.set(TargetCXXABI::GenericMIPS); setABI(getTriple().isMIPS32() ? "o32" : "n64"); @@ -181,6 +181,8 @@ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } + unsigned getISARev() const; + void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; @@ -305,7 +307,7 @@ IsSingleFloat = false; FloatABI = HardFloat; DspRev = NoDSP; - HasFP64 = isFP64Default(); + FPMode = isFP64Default() ? FP64 : FPXX; for (const auto &Feature : Features) { if (Feature == "+single-float") @@ -325,9 +327,11 @@ else if (Feature == "+nomadd4") DisableMadd4 = true; else if (Feature == "+fp64") - HasFP64 = true; + FPMode = FP64; else if (Feature == "-fp64") - HasFP64 = false; + FPMode = FP32; + else if (Feature == "+fpxx") + FPMode = FPXX; else if (Feature == "+nan2008") IsNan2008 = true; else if (Feature == "-nan2008") Index: lib/Basic/Targets/Mips.cpp =================================================================== --- lib/Basic/Targets/Mips.cpp +++ lib/Basic/Targets/Mips.cpp @@ -59,6 +59,16 @@ Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); } +unsigned MipsTargetInfo::getISARev() const { + return llvm::StringSwitch(getCPU()) + .Cases("mips32", "mips64", 1) + .Cases("mips32r2", "mips64r2", 2) + .Cases("mips32r3", "mips64r3", 3) + .Cases("mips32r5", "mips64r5", 5) + .Cases("mips32r6", "mips64r6", 6) + .Default(0); +} + void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { if (BigEndian) { @@ -84,13 +94,8 @@ Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); } - const std::string ISARev = llvm::StringSwitch(getCPU()) - .Cases("mips32", "mips64", "1") - .Cases("mips32r2", "mips64r2", "2") - .Cases("mips32r3", "mips64r3", "3") - .Cases("mips32r5", "mips64r5", "5") - .Cases("mips32r6", "mips64r6", "6") - .Default(""); + const std::string ISARev = std::to_string(getISARev()); + if (!ISARev.empty()) Builder.defineMacro("__mips_isa_rev", ISARev); @@ -129,9 +134,22 @@ if (IsSingleFloat) Builder.defineMacro("__mips_single_float", Twine(1)); - Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); - Builder.defineMacro("_MIPS_FPSET", - Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); + switch (FPMode) { + case FPXX: + Builder.defineMacro("__mips_fpr", Twine(0)); + break; + case FP32: + Builder.defineMacro("__mips_fpr", Twine(32)); + break; + case FP64: + Builder.defineMacro("__mips_fpr", Twine(64)); + break; +} + + if (FPMode == FP64 || IsSingleFloat) + Builder.defineMacro("_MIPS_FPSET", Twine(32)); + else + Builder.defineMacro("_MIPS_FPSET", Twine(16)); if (IsMips16) Builder.defineMacro("__mips16", Twine(1)); @@ -189,7 +207,7 @@ bool MipsTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("mips", true) - .Case("fp64", HasFP64) + .Case("fp64", FPMode == FP64) .Default(false); } @@ -235,5 +253,30 @@ return false; } + // -fpxx is valid only for the o32 ABI + if (FPMode == FPXX && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_unsupported_abi_for_opt) << "-mfpxx" << "o32"; + return false; + } + + // -mfp32 and n32/n64 ABIs are incompatible + if (FPMode != FP64 && FPMode != FPXX && !IsSingleFloat && + (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfpxx" << CPU; + return false; + } + // Mips revision 6 and -mfp32 are incompatible + if (FPMode != FP64 && FPMode != FPXX && (CPU == "mips32r6" || + CPU == "mips64r6")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfp32" << CPU; + return false; + } + // Option -mfp64 permitted on Mips32 iff revision 2 or higher is present + if (FPMode == FP64 && (CPU == "mips1" || CPU == "mips2" || + getISARev() < 2) && ABI == "o32") { + Diags.Report(diag::err_mips_fp64_req) << "-mfp64"; + return false; + } + return true; } Index: test/Preprocessor/init.c =================================================================== --- test/Preprocessor/init.c +++ test/Preprocessor/init.c @@ -3442,7 +3442,7 @@ // MIPS32BE:#define __mips 32 // MIPS32BE:#define __mips__ 1 // MIPS32BE:#define __mips_abicalls 1 -// MIPS32BE:#define __mips_fpr 32 +// MIPS32BE:#define __mips_fpr 0 // MIPS32BE:#define __mips_hard_float 1 // MIPS32BE:#define __mips_o32 1 // MIPS32BE:#define _mips 1 @@ -3649,7 +3649,7 @@ // MIPS32EL:#define __mips 32 // MIPS32EL:#define __mips__ 1 // MIPS32EL:#define __mips_abicalls 1 -// MIPS32EL:#define __mips_fpr 32 +// MIPS32EL:#define __mips_fpr 0 // MIPS32EL:#define __mips_hard_float 1 // MIPS32EL:#define __mips_o32 1 // MIPS32EL:#define _mips 1 @@ -4900,6 +4900,41 @@ // RUN: | FileCheck -match-full-lines -check-prefix NOMIPS-ABS2008 %s // NOMIPS-ABS2008-NOT:#define __mips_abs2008 1 // +// RUN: %clang_cc1 \ +// RUN: -E -dM -triple=mips-none-none < /dev/null \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS32-NOFP %s +// MIPS32-NOFP:#define __mips_fpr 0 +// +// RUN: %clang_cc1 -target-feature +fpxx \ +// RUN: -E -dM -triple=mips-none-none < /dev/null \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS32-MFPXX %s +// MIPS32-MFPXX:#define __mips_fpr 0 +// +// RUN: %clang_cc1 -target-cpu mips32r6 -target-feature +fpxx \ +// RUN: -E -dM -triple=mips-none-none < /dev/null \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS32R6-MFPXX %s +// MIPS32R6-MFPXX:#define __mips_fpr 0 +// +// RUN: %clang_cc1 \ +// RUN: -E -dM -triple=mips64-none-none < /dev/null \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS64-NOFP %s +// MIPS64-NOFP:#define __mips_fpr 64 +// +// RUN: not %clang_cc1 -target-feature -fp64 \ +// RUN: -E -dM -triple=mips64-none-none < /dev/null 2>&1 \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS64-MFP32 %s +// MIPS64-MFP32:error: option '-mfpxx' cannot be specified with 'mips64r2' +// +// RUN: not %clang_cc1 -target-feature +fpxx \ +// RUN: -E -dM -triple=mips64-none-none < /dev/null 2>&1 \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS64-MFPXX %s +// MIPS64-MFPXX:error: '-mfpxx' can only be used with the 'o32' ABI +// +// RUN: not %clang_cc1 -target-cpu mips64r6 -target-feature +fpxx \ +// RUN: -E -dM -triple=mips64-none-none < /dev/null 2>&1 \ +// RUN: | FileCheck -match-full-lines -check-prefix MIPS64R6-MFPXX %s +// MIPS64R6-MFPXX:error: '-mfpxx' can only be used with the 'o32' ABI +// // RUN: %clang_cc1 -target-feature -fp64 \ // RUN: -E -dM -triple=mips-none-none < /dev/null \ // RUN: | FileCheck -match-full-lines -check-prefix MIPS32-MFP32 %s @@ -4916,7 +4951,7 @@ // RUN: -E -dM -triple=mips-none-none < /dev/null \ // RUN: | FileCheck -match-full-lines -check-prefix MIPS32-MFP32SF %s // MIPS32-MFP32SF:#define _MIPS_FPSET 32 -// MIPS32-MFP32SF:#define __mips_fpr 32 +// MIPS32-MFP32SF:#define __mips_fpr 0 // // RUN: %clang_cc1 -target-feature +fp64 \ // RUN: -E -dM -triple=mips64-none-none < /dev/null \