diff options
Diffstat (limited to 'lib/Driver/ToolChains/Arch/ARM.cpp')
| -rw-r--r-- | lib/Driver/ToolChains/Arch/ARM.cpp | 132 |
1 files changed, 86 insertions, 46 deletions
diff --git a/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp index f55efc1a22e3..d1db583e5280 100644 --- a/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/lib/Driver/ToolChains/Arch/ARM.cpp @@ -1,9 +1,8 @@ //===--- ARM.cpp - ARM (not AArch64) Helpers for Tools ----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -73,15 +72,13 @@ static void getARMFPUFeatures(const Driver &D, const Arg *A, // 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<StringRef> &Features) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - StringRef FeatureName = llvm::ARM::getArchExtFeature(Feature); - if (!FeatureName.empty()) - Features.push_back(FeatureName); - else + if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features)) return false; } return true; @@ -89,6 +86,7 @@ static bool DecodeARMFeatures(const Driver &D, StringRef text, static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, std::vector<StringRef> &Features) { + CPU = CPU.split("+").first; if (CPU != "generic") { llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); unsigned Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); @@ -100,14 +98,16 @@ static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, // getARMArch is used here instead of just checking the -march value in order // to handle -march=native correctly. static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, - llvm::StringRef ArchName, + llvm::StringRef ArchName, llvm::StringRef CPUName, std::vector<StringRef> &Features, const llvm::Triple &Triple) { std::pair<StringRef, StringRef> Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); - if (llvm::ARM::parseArch(MArch) == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); + if (ArchKind == llvm::ARM::ArchKind::INVALID || + (Split.second.size() && !DecodeARMFeatures( + D, Split.second, CPUName, ArchKind, Features))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -119,8 +119,11 @@ static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, std::pair<StringRef, StringRef> Split = CPUName.split("+"); std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); - if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() || - (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) + 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))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -249,7 +252,7 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { ABI = FloatABI::SoftFP; break; case llvm::Triple::Android: - ABI = (SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; + ABI = (SubArch >= 7) ? FloatABI::SoftFP : FloatABI::Soft; break; default: // Assume "soft", but warn the user we are guessing. @@ -286,6 +289,13 @@ void arm::getARMTargetFeatures(const ToolChain &TC, const Arg *WaCPU = nullptr, *WaFPU = nullptr; const Arg *WaHDiv = nullptr, *WaArch = nullptr; + // This vector will accumulate features from the architecture + // extension suffixes on -mcpu and -march (e.g. the 'bar' in + // -mcpu=foo+bar). We want to apply those after the features derived + // from the FPU, in case -mfpu generates a negative feature which + // the +bar is supposed to override. + std::vector<StringRef> ExtensionFeatures; + 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 @@ -327,34 +337,35 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (ThreadPointer == arm::ReadTPMode::Cp15) Features.push_back("+read-tp-hard"); - // Check -march. ClangAs gives preference to -Wa,-march=. const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); + const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); StringRef ArchName; + StringRef CPUName; + + // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. + if (WaCPU) { + if (CPUArg) + D.Diag(clang::diag::warn_drv_unused_argument) + << CPUArg->getAsString(Args); + CPUName = StringRef(WaCPU->getValue()).substr(6); + CPUArg = WaCPU; + } else if (CPUArg) + CPUName = CPUArg->getValue(); + + // Check -march. ClangAs gives preference to -Wa,-march=. if (WaArch) { if (ArchArg) D.Diag(clang::diag::warn_drv_unused_argument) << ArchArg->getAsString(Args); ArchName = StringRef(WaArch->getValue()).substr(7); - checkARMArchName(D, WaArch, Args, ArchName, Features, Triple); + checkARMArchName(D, WaArch, Args, ArchName, CPUName, + ExtensionFeatures, Triple); // 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, Features, Triple); - } - - // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. - const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); - StringRef CPUName; - if (WaCPU) { - if (CPUArg) - D.Diag(clang::diag::warn_drv_unused_argument) - << CPUArg->getAsString(Args); - CPUName = StringRef(WaCPU->getValue()).substr(6); - checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple); - } else if (CPUArg) { - CPUName = CPUArg->getValue(); - checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple); + checkARMArchName(D, ArchArg, Args, ArchName, CPUName, + ExtensionFeatures, Triple); } // Add CPU features for generic CPUs @@ -365,9 +376,16 @@ void arm::getARMTargetFeatures(const ToolChain &TC, Features.push_back( Args.MakeArgString((F.second ? "+" : "-") + F.first())); } else if (!CPUName.empty()) { + // This sets the default features for the specified CPU. We certainly don't + // want to override the features that have been explicitly specified on the + // command line. Therefore, process them directly instead of appending them + // at the end later. DecodeARMFeaturesFromCPU(D, CPUName, Features); } + if (CPUArg) + checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, + ExtensionFeatures, Triple); // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); if (WaFPU) { @@ -379,14 +397,18 @@ void arm::getARMTargetFeatures(const ToolChain &TC, } else if (FPUArg) { getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { - // Android mandates minimum FPU requirements based on OS version. - const char *AndroidFPU = - Triple.isAndroidVersionLT(23) ? "vfpv3-d16" : "neon"; + const char *AndroidFPU = "neon"; if (!llvm::ARM::getFPUFeatures(llvm::ARM::parseFPU(AndroidFPU), Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << std::string("-mfpu=") + AndroidFPU; } + // Now we've finished accumulating features from arch, cpu and fpu, + // we can append the ones for architecture extensions that we + // collected separately. + Features.insert(std::end(Features), + std::begin(ExtensionFeatures), std::end(ExtensionFeatures)); + // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); if (WaHDiv) { @@ -431,16 +453,20 @@ fp16_fml_fallthrough: if (ABI == arm::FloatABI::Soft) { llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); - // Disable hardware FP features which have been enabled. - // FIXME: Disabling vfp2 and neon should be enough as all the other - // features are dependent on these 2 features in LLVM. However + // Disable all features relating to hardware FP. + // FIXME: Disabling fpregs should be enough all by itself, since all + // the other FP features are dependent on it. However // there is currently no easy way to test this in clang, so for // now just be explicit and disable all known dependent features // as well. - for (std::string Feature : {"vfp2", "vfp3", "vfp4", "fp-armv8", "fullfp16", - "neon", "crypto", "dotprod", "fp16fml"}) - if (std::find(std::begin(Features), std::end(Features), "+" + Feature) != std::end(Features)) - Features.push_back(Args.MakeArgString("-" + Feature)); + for (std::string Feature : { + "vfp2", "vfp2sp", "vfp2d16", "vfp2d16sp", + "vfp3", "vfp3sp", "vfp3d16", "vfp3d16sp", + "vfp4", "vfp4sp", "vfp4d16", "vfp4d16sp", + "fp-armv8", "fp-armv8sp", "fp-armv8d16", "fp-armv8d16sp", + "fullfp16", "neon", "crypto", "dotprod", "fp16fml", + "fp64", "d32", "fpregs"}) + Features.push_back(Args.MakeArgString("-" + Feature)); } // En/disable crc code generation. @@ -471,6 +497,10 @@ fp16_fml_fallthrough: } } + // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later. + if (Args.getLastArg(options::OPT_mcmse)) + Features.push_back("+8msecext"); + // Look for the last occurrence of -mlong-calls or -mno-long-calls. If // neither options are specified, see if we are compiling for kernel/kext and // decide whether to pass "+long-calls" based on the OS and its version. @@ -618,11 +648,12 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, return getARMCPUForMArch(Arch, Triple); } -/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular -/// CPU (or Arch, if CPU is generic). -// FIXME: This is redundant with -mcpu, why does LLVM use this. -StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple) { +/// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a +/// particular CPU (or Arch, if CPU is generic). This is needed to +/// pass to functions like llvm::ARM::getDefaultFPU which need an +/// ArchKind as well as a CPU name. +llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { llvm::ARM::ArchKind ArchKind; if (CPU == "generic") { std::string ARMArch = tools::arm::getARMArch(Arch, Triple); @@ -638,6 +669,15 @@ StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, ? llvm::ARM::ArchKind::ARMV7K : llvm::ARM::parseCPUArch(CPU); } + return ArchKind; +} + +/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular +/// CPU (or Arch, if CPU is generic). +// FIXME: This is redundant with -mcpu, why does LLVM use this. +StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { + llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple); if (ArchKind == llvm::ARM::ArchKind::INVALID) return ""; return llvm::ARM::getSubArch(ArchKind); |
