diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -73,14 +73,15 @@ } // Decode ARM features from string like +[no]featureA+[no]featureB+... -static bool DecodeARMFeatures(const Driver &D, StringRef text, - StringRef CPU, llvm::ARM::ArchKind ArchKind, - std::vector &Features) { +static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU, + llvm::ARM::ArchKind ArchKind, + std::vector &Features, + unsigned &ArgFPUID) { SmallVector Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features)) + if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUID)) return false; } return true; @@ -102,14 +103,14 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef ArchName, llvm::StringRef CPUName, std::vector &Features, - const llvm::Triple &Triple) { + const llvm::Triple &Triple, unsigned &ArgFPUID) { std::pair Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); if (ArchKind == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && !DecodeARMFeatures( - D, Split.second, CPUName, ArchKind, Features))) + (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPUName, + ArchKind, Features, ArgFPUID))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -117,15 +118,15 @@ static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef CPUName, llvm::StringRef ArchName, std::vector &Features, - const llvm::Triple &Triple) { + const llvm::Triple &Triple, unsigned &ArgFPUID) { std::pair Split = CPUName.split("+"); std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); llvm::ARM::ArchKind ArchKind = arm::getLLVMArchKindForARM(CPU, ArchName, Triple); if (ArchKind == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && !DecodeARMFeatures( - D, Split.second, CPU, ArchKind, Features))) + (Split.second.size() && + !DecodeARMFeatures(D, Split.second, CPU, ArchKind, Features, ArgFPUID))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -347,6 +348,8 @@ const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); StringRef ArchName; StringRef CPUName; + unsigned ArchArgFPUID = llvm::ARM::FK_INVALID; + unsigned CPUArgFPUID = llvm::ARM::FK_INVALID; // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. if (WaCPU) { @@ -364,14 +367,14 @@ D.Diag(clang::diag::warn_drv_unused_argument) << ArchArg->getAsString(Args); ArchName = StringRef(WaArch->getValue()).substr(7); - checkARMArchName(D, WaArch, Args, ArchName, CPUName, - ExtensionFeatures, Triple); + checkARMArchName(D, WaArch, Args, ArchName, CPUName, ExtensionFeatures, + Triple, ArchArgFPUID); // FIXME: Set Arch. D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args); } else if (ArchArg) { ArchName = ArchArg->getValue(); - checkARMArchName(D, ArchArg, Args, ArchName, CPUName, - ExtensionFeatures, Triple); + checkARMArchName(D, ArchArg, Args, ArchName, CPUName, ExtensionFeatures, + Triple, ArchArgFPUID); } // Add CPU features for generic CPUs @@ -390,8 +393,8 @@ } if (CPUArg) - checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, - ExtensionFeatures, Triple); + checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures, + Triple, CPUArgFPUID); // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. unsigned FPUID = llvm::ARM::FK_INVALID; const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); @@ -455,22 +458,29 @@ Features.push_back("+fullfp16"); } - // Setting -msoft-float/-mfloat-abi=soft effectively disables the FPU (GCC - // ignores the -mfpu options in this case). - // Note that the ABI can also be set implicitly by the target selected. + // Setting -msoft-float/-mfloat-abi=soft, -mfpu=none, or adding +nofp to + // -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in + // this case). Note that the ABI can also be set implicitly by the target + // selected. if (ABI == arm::FloatABI::Soft) { llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); // Disable all features relating to hardware FP, not already disabled by the // above call. + Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve", + "-mve.fp", "-fpregs"}); + } else if (FPUID == llvm::ARM::FK_NONE || + ArchArgFPUID == llvm::ARM::FK_NONE || + CPUArgFPUID == llvm::ARM::FK_NONE) { + // -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to + // -mfloat-abi=soft, only that it should not disable MVE-I. They disable the + // FPU, but not the FPU registers, thus MVE-I, which depends only on the + // latter, is still supported. Features.insert(Features.end(), - {"-dotprod", "-fp16fml", "-mve", "-mve.fp", "-fpregs"}); - } else if (FPUID == llvm::ARM::FK_NONE) { - // -mfpu=none is *very* similar to -mfloat-abi=soft, only that it should not - // disable MVE-I. - Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-mve.fp"}); - if (!hasIntegerMVE(Features)) + {"-dotprod", "-fp16fml", "-bf16", "-mve.fp"}); + if (!hasIntegerMVE(Features)) { Features.emplace_back("-fpregs"); + } } // En/disable crc code generation. diff --git a/clang/test/CodeGen/arm-bf16-softfloat.c b/clang/test/CodeGen/arm-bf16-softfloat.c --- a/clang/test/CodeGen/arm-bf16-softfloat.c +++ b/clang/test/CodeGen/arm-bf16-softfloat.c @@ -1,4 +1,9 @@ -// RUN: not %clang -o %t.out -target arm-arm-eabi -march=armv8-a+bf16 -mfloat-abi=soft -c %s 2>&1 | FileCheck %s +// RUN: not %clang -target arm-arm-none-eabi -march=armv8-a+bf16 -mfloat-abi=soft -c %s -o %t 2>&1 | FileCheck %s +// RUN: not %clang -target arm-arm-none-eabi -march=armv8-a+bf16 -mfpu=none -c %s -o %t 2>&1 | FileCheck %s +// RUN: not %clang -target arm-arm-none-eabi -march=armv8-a+bf16+nofp -c %s -o %t 2>&1 | FileCheck %s +// RUN: not %clang -target arm-arm-none-eabi -march=armv8-a+bf16+fp+nofp -c %s -o %t 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8-a+bf16+fp -c %s -o %t +// RUN: %clang -target arm-arm-none-eabi -march=armv8-a+bf16+nofp+fp -c %s -o %t // CHECK: error: __bf16 is not supported on this target extern __bf16 var; diff --git a/clang/test/Driver/arm-nofp-disabled-features.c b/clang/test/Driver/arm-nofp-disabled-features.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/arm-nofp-disabled-features.c @@ -0,0 +1,18 @@ +// RUN: %clang -target arm-arm-none-eabi -mfloat-abi=soft %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MFLOAT-ABI-SOFT +// CHECK-MFLOAT-ABI-SOFT: "-target-feature" "-dotprod" +// CHECK-MFLOAT-ABI-SOFT: "-target-feature" "-fp16fml" +// CHECK-MFLOAT-ABI-SOFT: "-target-feature" "-bf16" +// CHECK-MFLOAT-ABI-SOFT: "-target-feature" "-mve" +// CHECK-MFLOAT-ABI-SOFT: "-target-feature" "-mve.fp" +// CHECK-MFLOAT-ABI-SOFT: "-target-feature" "-fpregs" + +// RUN: %clang -target arm-arm-none-eabi -mfpu=none %s -### 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8-a+nofp %s -### 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -mcpu=cortex-a35+nofp %s -### 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8-a+nofp+nomve %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NOMVE +// RUN: %clang -target arm-arm-none-eabi -mcpu=cortex-a35+nofp+nomve %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NOMVE +// CHECK: "-target-feature" "-dotprod" +// CHECK: "-target-feature" "-fp16fml" +// CHECK: "-target-feature" "-bf16" +// CHECK: "-target-feature" "-mve.fp" +// CHECK-NOMVE: "-target-feature" "-fpregs" diff --git a/llvm/include/llvm/Support/ARMTargetParser.h b/llvm/include/llvm/Support/ARMTargetParser.h --- a/llvm/include/llvm/Support/ARMTargetParser.h +++ b/llvm/include/llvm/Support/ARMTargetParser.h @@ -250,7 +250,8 @@ StringRef getArchExtName(uint64_t ArchExtKind); StringRef getArchExtFeature(StringRef ArchExt); bool appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, - std::vector &Features); + std::vector &Features, + unsigned &ArgFPUKind); StringRef getHWDivName(uint64_t HWDivKind); // Information by Name diff --git a/llvm/lib/Support/ARMTargetParser.cpp b/llvm/lib/Support/ARMTargetParser.cpp --- a/llvm/lib/Support/ARMTargetParser.cpp +++ b/llvm/lib/Support/ARMTargetParser.cpp @@ -490,9 +490,10 @@ return ARM::FK_INVALID; } -bool ARM::appendArchExtFeatures( - StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, - std::vector &Features) { +bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, + StringRef ArchExt, + std::vector &Features, + unsigned &ArgFPUID) { size_t StartingNumFeatures = Features.size(); const bool Negated = stripNegationPrefix(ArchExt); @@ -527,6 +528,7 @@ } else { FPUKind = getDefaultFPU(CPU, AK); } + ArgFPUID = FPUKind; return ARM::getFPUFeatures(FPUKind, Features); } return StartingNumFeatures != Features.size(); diff --git a/llvm/unittests/Support/TargetParserTest.cpp b/llvm/unittests/Support/TargetParserTest.cpp --- a/llvm/unittests/Support/TargetParserTest.cpp +++ b/llvm/unittests/Support/TargetParserTest.cpp @@ -668,9 +668,10 @@ testArchExtDependency(const char *ArchExt, const std::initializer_list &Expected) { std::vector Features; + unsigned FPUID; if (!ARM::appendArchExtFeatures("", ARM::ArchKind::ARMV8_1MMainline, ArchExt, - Features)) + Features, FPUID)) return false; return llvm::all_of(Expected, [&](StringRef Ext) {