[ARM] Handle conflicts between -mfpu and -mfloat-abi options.
Summary: This patch implements warnings/downgradable errors for
invalid -mfpu, -mfloat-abi option combinations (e.g. -mfpu=none
-mfloat-abi=hard).
Change-Id: I94fa664e1bc0b5855ad835abd7a50a3e0395632d
llvm-svn: 218863
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index 99e34e4..28e92f9 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -581,14 +581,24 @@
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
-// Select the float ABI as determined by -msoft-float, -mhard-float, and
-// -mfloat-abi=.
+// Select the float ABI as determined by -msoft-float, -mhard-float,
+// -mfpu=... and -mfloat-abi=...
StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
- const llvm::Triple &Triple) {
+ const llvm::Triple &Triple,
+ bool *ExplicitNoFloat) {
+
+ // FIXME: -msoft-float and -mhard-float identify the nature of floating point
+ // ops, whereas -mfloat-abi=... identifies the floating point argument passing
+ // convention. But here we are mushing them together into FloatABI = soft/
+ // softfp/hard, which is a bit confusing. For example, this means -msoft-float
+ // and -mfloat-abi=soft are equivalent options to clang. But when we pass
+ // arguments to the backend (AddARMTargetArgs), these two options take their
+ // original interpretations.
StringRef FloatABI;
- if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
- options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ)) {
+ const Arg *A = Args.getLastArg(options::OPT_msoft_float,
+ options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ);
+ if (A) {
if (A->getOption().matches(options::OPT_msoft_float))
FloatABI = "soft";
else if (A->getOption().matches(options::OPT_mhard_float))
@@ -603,6 +613,31 @@
}
}
+ // Some -mfpu=... options are incompatible with some mfloat-abi=... options
+ if (Arg *B = Args.getLastArg(options::OPT_mfpu_EQ)) {
+ StringRef FPU = B->getValue();
+ if (FPU == "none") {
+ // Signal incompatible -mfloat-abi=... options
+ if (FloatABI == "hard")
+ D.Diag(diag::warn_drv_implied_soft_float_conflict)
+ << B->getAsString(Args) << A->getAsString(Args);
+ else if (FloatABI == "softfp")
+ D.Diag(diag::warn_drv_implied_soft_float_assumed)
+ << B->getAsString(Args) << A->getAsString(Args);
+ // Assume soft-float
+ FloatABI = "soft";
+ } else if (FloatABI.empty() || FloatABI == "soft") {
+ // Need -mhard-float for floating point ops
+ FloatABI = "softfp";
+ }
+ }
+
+ // This allows us to differentiate between a user specified soft-float and
+ // an inferred soft-float. The latter may be overridden under other conditions
+ // but the former has higher priority.
+ if (FloatABI == "soft" && ExplicitNoFloat)
+ *ExplicitNoFloat = true;
+
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
switch (Triple.getOS()) {
@@ -681,7 +716,8 @@
const ArgList &Args,
std::vector<const char *> &Features,
bool ForAS) {
- StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple);
+ bool ExplicitNoFloat = false;
+ StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple, &ExplicitNoFloat);
if (!ForAS) {
// FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
// yet (it uses the -mfloat-abi and -msoft-float options), and it is
@@ -716,6 +752,14 @@
Features.push_back("-neon");
// Also need to explicitly disable features which imply NEON.
Features.push_back("-crypto");
+ // Disable remaining floating-point features if soft-float is explicitly
+ // requested.
+ if (ExplicitNoFloat) {
+ Features.push_back("-vfp2");
+ Features.push_back("-vfp3");
+ Features.push_back("-vfp4");
+ Features.push_back("-fp-armv8");
+ }
}
// En/disable crc