Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -180,6 +180,9 @@ "unknown target triple '%0', please use -triple or -arch">; def err_target_unknown_cpu : Error<"unknown target CPU '%0'">; def err_target_unknown_abi : Error<"unknown target ABI '%0'">; +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_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: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -982,6 +982,11 @@ return getTargetOpts().SupportedOpenCLOptions; } + /// \brief Check the target is valid after it is fully initialized. + virtual bool validateTarget(DiagnosticsEngine &Diags) const { + return true; + } + protected: virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return PointerWidth; Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -7074,34 +7074,38 @@ return IsNan2008; } + bool processorSupportsGPR64() const { + return llvm::StringSwitch(CPU) + .Case("mips3", true) + .Case("mips4", true) + .Case("mips5", true) + .Case("mips64", true) + .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) + .Case("mips64r6", true) + .Case("octeon", true) + .Default(false); + return false; + } + StringRef getABI() const override { return ABI; } bool setABI(const std::string &Name) override { - // FIXME: The Arch component on the triple actually has no bearing on - // whether the ABI is valid or not. It's features of the CPU that - // matters and the size of the GPR's in particular. - // However, we can't allow O32 on 64-bit processors just yet because - // the backend still checks the Arch component instead of the ABI in - // a few places. - if (getTriple().getArch() == llvm::Triple::mips || - getTriple().getArch() == llvm::Triple::mipsel) { - if (Name == "o32") { - setO32ABITypes(); - ABI = Name; - return true; - } + if (Name == "o32") { + setO32ABITypes(); + ABI = Name; + return true; } - if (getTriple().getArch() == llvm::Triple::mips64 || - getTriple().getArch() == llvm::Triple::mips64el) { - if (Name == "n32") { - setN32ABITypes(); - ABI = Name; - return true; - } - if (Name == "n64") { - setN64ABITypes(); - ABI = Name; - return true; - } + + if (Name == "n32") { + setN32ABITypes(); + ABI = Name; + return true; + } + if (Name == "n64") { + setN64ABITypes(); + ABI = Name; + return true; } return false; } @@ -7151,26 +7155,25 @@ } bool setCPU(const std::string &Name) override { - bool GPR64Required = ABI == "n32" || ABI == "n64"; CPU = Name; return llvm::StringSwitch(Name) - .Case("mips1", !GPR64Required) - .Case("mips2", !GPR64Required) + .Case("mips1", true) + .Case("mips2", true) .Case("mips3", true) .Case("mips4", true) .Case("mips5", true) - .Case("mips32", !GPR64Required) - .Case("mips32r2", !GPR64Required) - .Case("mips32r3", !GPR64Required) - .Case("mips32r5", !GPR64Required) - .Case("mips32r6", !GPR64Required) + .Case("mips32", true) + .Case("mips32r2", true) + .Case("mips32r3", true) + .Case("mips32r5", true) + .Case("mips32r6", true) .Case("mips64", true) .Case("mips64r2", true) .Case("mips64r3", true) .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) - .Case("p5600", !GPR64Required) + .Case("p5600", true) .Default(false); } const std::string& getCPU() const { return CPU; } @@ -7499,6 +7502,45 @@ bool hasInt128Type() const override { return ABI == "n32" || ABI == "n64"; } + + bool validateTarget(DiagnosticsEngine &Diags) const override { + // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle + // this yet. It's better to fail here than on the backend assertion. + if (processorSupportsGPR64() && ABI == "o32") { + Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; + return false; + } + + // 64-bit ABI's require 64-bit CPU's. + if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; + return false; + } + + // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend + // can't handle this yet. It's better to fail here than on the + // backend assertion. + if ((getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el) && + ABI == "o32") { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << ABI << getTriple().str(); + return false; + } + + // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend + // can't handle this yet. It's better to fail here than on the + // backend assertion. + if ((getTriple().getArch() == llvm::Triple::mips || + getTriple().getArch() == llvm::Triple::mipsel) && + (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << ABI << getTriple().str(); + return false; + } + + return true; + } }; const Builtin::Info MipsTargetInfo::BuiltinInfo[] = { @@ -8435,5 +8477,8 @@ Target->setSupportedOpenCLOpts(); + if (!Target->validateTarget(Diags)) + return nullptr; + return Target.release(); } Index: test/Driver/mips-abi.c =================================================================== --- test/Driver/mips-abi.c +++ test/Driver/mips-abi.c @@ -1,9 +1,18 @@ // Check passing Mips ABI options to the backend. // // RUN: %clang -target mips-linux-gnu -### -c %s 2>&1 \ -// RUN: | FileCheck -check-prefix=MIPS-DEF %s -// MIPS-DEF: "-target-cpu" "mips32r2" -// MIPS-DEF: "-target-abi" "o32" +// RUN: | FileCheck -check-prefix=MIPS32R2-O32 %s +// RUN: %clang -target mips64-linux-gnu -mips32r2 -mabi=32 -### -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=MIPS32R2-O32 %s +// MIPS32R2-O32: "-target-cpu" "mips32r2" +// MIPS32R2-O32: "-target-abi" "o32" +// +// FIXME: This is a valid combination of options but we reject it at the moment +// because the backend can't handle it. +// RUN: not %clang -target mips-linux-gnu -c %s \ +// RUN: -march=mips64r2 -mabi=32 2>&1 \ +// RUN: | FileCheck -check-prefix=MIPS64R2-O32 %s +// MIPS64R2-O32: error: ABI 'o32' is not supported on CPU 'mips64r2' // // RUN: %clang -target mips64-linux-gnu -### -c %s 2>&1 \ // RUN: | FileCheck -check-prefix=MIPS64R2-N64 %s @@ -11,6 +20,8 @@ // RUN: | FileCheck -check-prefix=MIPS64R2-N64 %s // RUN: %clang -target mips-mti-linux-gnu -mips64r2 -### -c %s 2>&1 \ // RUN: | FileCheck -check-prefix=MIPS64R2-N64 %s +// RUN: %clang -target mips-linux-gnu -mips64r2 -mabi=64 -### -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=MIPS64R2-N64 %s // MIPS64R2-N64: "-target-cpu" "mips64r2" // MIPS64R2-N64: "-target-abi" "n64" // @@ -114,7 +125,7 @@ // RUN: not %clang -target mips-linux-gnu -c %s \ // RUN: -march=p5600 -mabi=64 2>&1 \ // RUN: | FileCheck -check-prefix=MIPS-ARCH-P5600-N64 %s -// MIPS-ARCH-P5600-N64: error: unknown target ABI 'n64' +// MIPS-ARCH-P5600-N64: error: ABI 'n64' is not supported on CPU 'p5600' // // RUN: %clang -target mips-linux-gnu -### -c %s \ // RUN: -march=mips64 2>&1 \ @@ -143,7 +154,7 @@ // RUN: not %clang -target mips64-linux-gnu -c %s \ // RUN: -march=mips32 2>&1 \ // RUN: | FileCheck -check-prefix=MIPS-ARCH-6432 %s -// MIPS-ARCH-6432: error: unknown target CPU 'mips32' +// MIPS-ARCH-6432: error: ABI 'n64' is not supported on CPU 'mips32' // // RUN: not %clang -target mips-linux-gnu -c %s \ // RUN: -march=unknown 2>&1 \