xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Driver/ToolChains/Arch/ARM.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- ARM.cpp - ARM (not AArch64) Helpers for Tools ----------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg 
97330f729Sjoerg #include "ARM.h"
107330f729Sjoerg #include "clang/Driver/Driver.h"
117330f729Sjoerg #include "clang/Driver/DriverDiagnostic.h"
127330f729Sjoerg #include "clang/Driver/Options.h"
137330f729Sjoerg #include "llvm/ADT/StringSwitch.h"
147330f729Sjoerg #include "llvm/Option/ArgList.h"
157330f729Sjoerg #include "llvm/Support/TargetParser.h"
167330f729Sjoerg #include "llvm/Support/Host.h"
177330f729Sjoerg 
187330f729Sjoerg using namespace clang::driver;
197330f729Sjoerg using namespace clang::driver::tools;
207330f729Sjoerg using namespace clang;
217330f729Sjoerg using namespace llvm::opt;
227330f729Sjoerg 
237330f729Sjoerg // Get SubArch (vN).
getARMSubArchVersionNumber(const llvm::Triple & Triple)247330f729Sjoerg int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) {
257330f729Sjoerg   llvm::StringRef Arch = Triple.getArchName();
267330f729Sjoerg   return llvm::ARM::parseArchVersion(Arch);
277330f729Sjoerg }
287330f729Sjoerg 
297330f729Sjoerg // True if M-profile.
isARMMProfile(const llvm::Triple & Triple)307330f729Sjoerg bool arm::isARMMProfile(const llvm::Triple &Triple) {
317330f729Sjoerg   llvm::StringRef Arch = Triple.getArchName();
327330f729Sjoerg   return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M;
337330f729Sjoerg }
347330f729Sjoerg 
35*e038c9c4Sjoerg // True if A-profile.
isARMAProfile(const llvm::Triple & Triple)36*e038c9c4Sjoerg bool arm::isARMAProfile(const llvm::Triple &Triple) {
37*e038c9c4Sjoerg   llvm::StringRef Arch = Triple.getArchName();
38*e038c9c4Sjoerg   return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::A;
39*e038c9c4Sjoerg }
40*e038c9c4Sjoerg 
417330f729Sjoerg // Get Arch/CPU from args.
getARMArchCPUFromArgs(const ArgList & Args,llvm::StringRef & Arch,llvm::StringRef & CPU,bool FromAs)427330f729Sjoerg void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
437330f729Sjoerg                                 llvm::StringRef &CPU, bool FromAs) {
447330f729Sjoerg   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ))
457330f729Sjoerg     CPU = A->getValue();
467330f729Sjoerg   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
477330f729Sjoerg     Arch = A->getValue();
487330f729Sjoerg   if (!FromAs)
497330f729Sjoerg     return;
507330f729Sjoerg 
517330f729Sjoerg   for (const Arg *A :
527330f729Sjoerg        Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
53*e038c9c4Sjoerg     // Use getValues because -Wa can have multiple arguments
54*e038c9c4Sjoerg     // e.g. -Wa,-mcpu=foo,-mcpu=bar
55*e038c9c4Sjoerg     for (StringRef Value : A->getValues()) {
567330f729Sjoerg       if (Value.startswith("-mcpu="))
577330f729Sjoerg         CPU = Value.substr(6);
587330f729Sjoerg       if (Value.startswith("-march="))
597330f729Sjoerg         Arch = Value.substr(7);
607330f729Sjoerg     }
617330f729Sjoerg   }
62*e038c9c4Sjoerg }
637330f729Sjoerg 
647330f729Sjoerg // Handle -mhwdiv=.
657330f729Sjoerg // FIXME: Use ARMTargetParser.
getARMHWDivFeatures(const Driver & D,const Arg * A,const ArgList & Args,StringRef HWDiv,std::vector<StringRef> & Features)667330f729Sjoerg static void getARMHWDivFeatures(const Driver &D, const Arg *A,
677330f729Sjoerg                                 const ArgList &Args, StringRef HWDiv,
687330f729Sjoerg                                 std::vector<StringRef> &Features) {
69*e038c9c4Sjoerg   uint64_t HWDivID = llvm::ARM::parseHWDiv(HWDiv);
707330f729Sjoerg   if (!llvm::ARM::getHWDivFeatures(HWDivID, Features))
717330f729Sjoerg     D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
727330f729Sjoerg }
737330f729Sjoerg 
747330f729Sjoerg // Handle -mfpu=.
getARMFPUFeatures(const Driver & D,const Arg * A,const ArgList & Args,StringRef FPU,std::vector<StringRef> & Features)75*e038c9c4Sjoerg static unsigned getARMFPUFeatures(const Driver &D, const Arg *A,
767330f729Sjoerg                                   const ArgList &Args, StringRef FPU,
777330f729Sjoerg                                   std::vector<StringRef> &Features) {
787330f729Sjoerg   unsigned FPUID = llvm::ARM::parseFPU(FPU);
797330f729Sjoerg   if (!llvm::ARM::getFPUFeatures(FPUID, Features))
807330f729Sjoerg     D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
81*e038c9c4Sjoerg   return FPUID;
827330f729Sjoerg }
837330f729Sjoerg 
847330f729Sjoerg // Decode ARM features from string like +[no]featureA+[no]featureB+...
DecodeARMFeatures(const Driver & D,StringRef text,StringRef CPU,llvm::ARM::ArchKind ArchKind,std::vector<StringRef> & Features,unsigned & ArgFPUID)85*e038c9c4Sjoerg static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU,
86*e038c9c4Sjoerg                               llvm::ARM::ArchKind ArchKind,
87*e038c9c4Sjoerg                               std::vector<StringRef> &Features,
88*e038c9c4Sjoerg                               unsigned &ArgFPUID) {
897330f729Sjoerg   SmallVector<StringRef, 8> Split;
907330f729Sjoerg   text.split(Split, StringRef("+"), -1, false);
917330f729Sjoerg 
927330f729Sjoerg   for (StringRef Feature : Split) {
93*e038c9c4Sjoerg     if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUID))
947330f729Sjoerg       return false;
957330f729Sjoerg   }
967330f729Sjoerg   return true;
977330f729Sjoerg }
987330f729Sjoerg 
DecodeARMFeaturesFromCPU(const Driver & D,StringRef CPU,std::vector<StringRef> & Features)997330f729Sjoerg static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU,
1007330f729Sjoerg                                      std::vector<StringRef> &Features) {
1017330f729Sjoerg   CPU = CPU.split("+").first;
1027330f729Sjoerg   if (CPU != "generic") {
1037330f729Sjoerg     llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU);
104*e038c9c4Sjoerg     uint64_t Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind);
1057330f729Sjoerg     llvm::ARM::getExtensionFeatures(Extension, Features);
1067330f729Sjoerg   }
1077330f729Sjoerg }
1087330f729Sjoerg 
1097330f729Sjoerg // Check if -march is valid by checking if it can be canonicalised and parsed.
1107330f729Sjoerg // getARMArch is used here instead of just checking the -march value in order
1117330f729Sjoerg // to handle -march=native correctly.
checkARMArchName(const Driver & D,const Arg * A,const ArgList & Args,llvm::StringRef ArchName,llvm::StringRef CPUName,std::vector<StringRef> & Features,const llvm::Triple & Triple,unsigned & ArgFPUID)1127330f729Sjoerg static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
1137330f729Sjoerg                              llvm::StringRef ArchName, llvm::StringRef CPUName,
1147330f729Sjoerg                              std::vector<StringRef> &Features,
115*e038c9c4Sjoerg                              const llvm::Triple &Triple, unsigned &ArgFPUID) {
1167330f729Sjoerg   std::pair<StringRef, StringRef> Split = ArchName.split("+");
1177330f729Sjoerg 
1187330f729Sjoerg   std::string MArch = arm::getARMArch(ArchName, Triple);
1197330f729Sjoerg   llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch);
1207330f729Sjoerg   if (ArchKind == llvm::ARM::ArchKind::INVALID ||
121*e038c9c4Sjoerg       (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPUName,
122*e038c9c4Sjoerg                                                  ArchKind, Features, ArgFPUID)))
1237330f729Sjoerg     D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
1247330f729Sjoerg }
1257330f729Sjoerg 
1267330f729Sjoerg // Check -mcpu=. Needs ArchName to handle -mcpu=generic.
checkARMCPUName(const Driver & D,const Arg * A,const ArgList & Args,llvm::StringRef CPUName,llvm::StringRef ArchName,std::vector<StringRef> & Features,const llvm::Triple & Triple,unsigned & ArgFPUID)1277330f729Sjoerg static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
1287330f729Sjoerg                             llvm::StringRef CPUName, llvm::StringRef ArchName,
1297330f729Sjoerg                             std::vector<StringRef> &Features,
130*e038c9c4Sjoerg                             const llvm::Triple &Triple, unsigned &ArgFPUID) {
1317330f729Sjoerg   std::pair<StringRef, StringRef> Split = CPUName.split("+");
1327330f729Sjoerg 
1337330f729Sjoerg   std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
1347330f729Sjoerg   llvm::ARM::ArchKind ArchKind =
1357330f729Sjoerg     arm::getLLVMArchKindForARM(CPU, ArchName, Triple);
1367330f729Sjoerg   if (ArchKind == llvm::ARM::ArchKind::INVALID ||
137*e038c9c4Sjoerg       (Split.second.size() &&
138*e038c9c4Sjoerg        !DecodeARMFeatures(D, Split.second, CPU, ArchKind, Features, ArgFPUID)))
1397330f729Sjoerg     D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
1407330f729Sjoerg }
1417330f729Sjoerg 
useAAPCSForMachO(const llvm::Triple & T)1427330f729Sjoerg bool arm::useAAPCSForMachO(const llvm::Triple &T) {
1437330f729Sjoerg   // The backend is hardwired to assume AAPCS for M-class processors, ensure
1447330f729Sjoerg   // the frontend matches that.
1457330f729Sjoerg   return T.getEnvironment() == llvm::Triple::EABI ||
146*e038c9c4Sjoerg          T.getEnvironment() == llvm::Triple::EABIHF ||
1477330f729Sjoerg          T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T);
1487330f729Sjoerg }
1497330f729Sjoerg 
1507330f729Sjoerg // Select mode for reading thread pointer (-mtp=soft/cp15).
getReadTPMode(const Driver & D,const ArgList & Args)151*e038c9c4Sjoerg arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args) {
1527330f729Sjoerg   if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
1537330f729Sjoerg     arm::ReadTPMode ThreadPointer =
1547330f729Sjoerg         llvm::StringSwitch<arm::ReadTPMode>(A->getValue())
1557330f729Sjoerg             .Case("cp15", ReadTPMode::Cp15)
1567330f729Sjoerg             .Case("soft", ReadTPMode::Soft)
1577330f729Sjoerg             .Default(ReadTPMode::Invalid);
1587330f729Sjoerg     if (ThreadPointer != ReadTPMode::Invalid)
1597330f729Sjoerg       return ThreadPointer;
1607330f729Sjoerg     if (StringRef(A->getValue()).empty())
1617330f729Sjoerg       D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args);
1627330f729Sjoerg     else
1637330f729Sjoerg       D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
1647330f729Sjoerg     return ReadTPMode::Invalid;
1657330f729Sjoerg   }
1667330f729Sjoerg   return ReadTPMode::Soft;
1677330f729Sjoerg }
1687330f729Sjoerg 
setArchNameInTriple(const Driver & D,const ArgList & Args,types::ID InputType,llvm::Triple & Triple)169*e038c9c4Sjoerg void arm::setArchNameInTriple(const Driver &D, const ArgList &Args,
170*e038c9c4Sjoerg                               types::ID InputType, llvm::Triple &Triple) {
171*e038c9c4Sjoerg   StringRef MCPU, MArch;
172*e038c9c4Sjoerg   if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
173*e038c9c4Sjoerg     MCPU = A->getValue();
174*e038c9c4Sjoerg   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
175*e038c9c4Sjoerg     MArch = A->getValue();
176*e038c9c4Sjoerg 
177*e038c9c4Sjoerg   std::string CPU = Triple.isOSBinFormatMachO()
178*e038c9c4Sjoerg                         ? tools::arm::getARMCPUForMArch(MArch, Triple).str()
179*e038c9c4Sjoerg                         : tools::arm::getARMTargetCPU(MCPU, MArch, Triple);
180*e038c9c4Sjoerg   StringRef Suffix = tools::arm::getLLVMArchSuffixForARM(CPU, MArch, Triple);
181*e038c9c4Sjoerg 
182*e038c9c4Sjoerg   bool IsBigEndian = Triple.getArch() == llvm::Triple::armeb ||
183*e038c9c4Sjoerg                      Triple.getArch() == llvm::Triple::thumbeb;
184*e038c9c4Sjoerg   // Handle pseudo-target flags '-mlittle-endian'/'-EL' and
185*e038c9c4Sjoerg   // '-mbig-endian'/'-EB'.
186*e038c9c4Sjoerg   if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
187*e038c9c4Sjoerg                                options::OPT_mbig_endian)) {
188*e038c9c4Sjoerg     IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
189*e038c9c4Sjoerg   }
190*e038c9c4Sjoerg   std::string ArchName = IsBigEndian ? "armeb" : "arm";
191*e038c9c4Sjoerg 
192*e038c9c4Sjoerg   // FIXME: Thumb should just be another -target-feaure, not in the triple.
193*e038c9c4Sjoerg   bool IsMProfile =
194*e038c9c4Sjoerg       llvm::ARM::parseArchProfile(Suffix) == llvm::ARM::ProfileKind::M;
195*e038c9c4Sjoerg   bool ThumbDefault = IsMProfile ||
196*e038c9c4Sjoerg                       // Thumb2 is the default for V7 on Darwin.
197*e038c9c4Sjoerg                       (llvm::ARM::parseArchVersion(Suffix) == 7 &&
198*e038c9c4Sjoerg                        Triple.isOSBinFormatMachO()) ||
199*e038c9c4Sjoerg                       // FIXME: this is invalid for WindowsCE
200*e038c9c4Sjoerg                       Triple.isOSWindows();
201*e038c9c4Sjoerg 
202*e038c9c4Sjoerg   // Check if ARM ISA was explicitly selected (using -mno-thumb or -marm) for
203*e038c9c4Sjoerg   // M-Class CPUs/architecture variants, which is not supported.
204*e038c9c4Sjoerg   bool ARMModeRequested =
205*e038c9c4Sjoerg       !Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault);
206*e038c9c4Sjoerg   if (IsMProfile && ARMModeRequested) {
207*e038c9c4Sjoerg     if (MCPU.size())
208*e038c9c4Sjoerg       D.Diag(diag::err_cpu_unsupported_isa) << CPU << "ARM";
209*e038c9c4Sjoerg     else
210*e038c9c4Sjoerg       D.Diag(diag::err_arch_unsupported_isa)
211*e038c9c4Sjoerg           << tools::arm::getARMArch(MArch, Triple) << "ARM";
212*e038c9c4Sjoerg   }
213*e038c9c4Sjoerg 
214*e038c9c4Sjoerg   // Check to see if an explicit choice to use thumb has been made via
215*e038c9c4Sjoerg   // -mthumb. For assembler files we must check for -mthumb in the options
216*e038c9c4Sjoerg   // passed to the assembler via -Wa or -Xassembler.
217*e038c9c4Sjoerg   bool IsThumb = false;
218*e038c9c4Sjoerg   if (InputType != types::TY_PP_Asm)
219*e038c9c4Sjoerg     IsThumb =
220*e038c9c4Sjoerg         Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault);
221*e038c9c4Sjoerg   else {
222*e038c9c4Sjoerg     // Ideally we would check for these flags in
223*e038c9c4Sjoerg     // CollectArgsForIntegratedAssembler but we can't change the ArchName at
224*e038c9c4Sjoerg     // that point.
225*e038c9c4Sjoerg     llvm::StringRef WaMArch, WaMCPU;
226*e038c9c4Sjoerg     for (const auto *A :
227*e038c9c4Sjoerg          Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
228*e038c9c4Sjoerg       for (StringRef Value : A->getValues()) {
229*e038c9c4Sjoerg         // There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm.
230*e038c9c4Sjoerg         if (Value == "-mthumb")
231*e038c9c4Sjoerg           IsThumb = true;
232*e038c9c4Sjoerg         else if (Value.startswith("-march="))
233*e038c9c4Sjoerg           WaMArch = Value.substr(7);
234*e038c9c4Sjoerg         else if (Value.startswith("-mcpu="))
235*e038c9c4Sjoerg           WaMCPU = Value.substr(6);
236*e038c9c4Sjoerg       }
237*e038c9c4Sjoerg     }
238*e038c9c4Sjoerg 
239*e038c9c4Sjoerg     if (WaMCPU.size() || WaMArch.size()) {
240*e038c9c4Sjoerg       // The way this works means that we prefer -Wa,-mcpu's architecture
241*e038c9c4Sjoerg       // over -Wa,-march. Which matches the compiler behaviour.
242*e038c9c4Sjoerg       Suffix = tools::arm::getLLVMArchSuffixForARM(WaMCPU, WaMArch, Triple);
243*e038c9c4Sjoerg     }
244*e038c9c4Sjoerg   }
245*e038c9c4Sjoerg 
246*e038c9c4Sjoerg   // Assembly files should start in ARM mode, unless arch is M-profile, or
247*e038c9c4Sjoerg   // -mthumb has been passed explicitly to the assembler. Windows is always
248*e038c9c4Sjoerg   // thumb.
249*e038c9c4Sjoerg   if (IsThumb || IsMProfile || Triple.isOSWindows()) {
250*e038c9c4Sjoerg     if (IsBigEndian)
251*e038c9c4Sjoerg       ArchName = "thumbeb";
252*e038c9c4Sjoerg     else
253*e038c9c4Sjoerg       ArchName = "thumb";
254*e038c9c4Sjoerg   }
255*e038c9c4Sjoerg   Triple.setArchName(ArchName + Suffix.str());
256*e038c9c4Sjoerg }
257*e038c9c4Sjoerg 
setFloatABIInTriple(const Driver & D,const ArgList & Args,llvm::Triple & Triple)258*e038c9c4Sjoerg void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args,
259*e038c9c4Sjoerg                               llvm::Triple &Triple) {
260*e038c9c4Sjoerg   bool isHardFloat =
261*e038c9c4Sjoerg       (arm::getARMFloatABI(D, Triple, Args) == arm::FloatABI::Hard);
262*e038c9c4Sjoerg 
263*e038c9c4Sjoerg   switch (Triple.getEnvironment()) {
264*e038c9c4Sjoerg   case llvm::Triple::GNUEABI:
265*e038c9c4Sjoerg   case llvm::Triple::GNUEABIHF:
266*e038c9c4Sjoerg     Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHF
267*e038c9c4Sjoerg                                       : llvm::Triple::GNUEABI);
268*e038c9c4Sjoerg     break;
269*e038c9c4Sjoerg   case llvm::Triple::EABI:
270*e038c9c4Sjoerg   case llvm::Triple::EABIHF:
271*e038c9c4Sjoerg     Triple.setEnvironment(isHardFloat ? llvm::Triple::EABIHF
272*e038c9c4Sjoerg                                       : llvm::Triple::EABI);
273*e038c9c4Sjoerg     break;
274*e038c9c4Sjoerg   case llvm::Triple::MuslEABI:
275*e038c9c4Sjoerg   case llvm::Triple::MuslEABIHF:
276*e038c9c4Sjoerg     Triple.setEnvironment(isHardFloat ? llvm::Triple::MuslEABIHF
277*e038c9c4Sjoerg                                       : llvm::Triple::MuslEABI);
278*e038c9c4Sjoerg     break;
279*e038c9c4Sjoerg   default: {
280*e038c9c4Sjoerg     arm::FloatABI DefaultABI = arm::getDefaultFloatABI(Triple);
281*e038c9c4Sjoerg     if (DefaultABI != arm::FloatABI::Invalid &&
282*e038c9c4Sjoerg         isHardFloat != (DefaultABI == arm::FloatABI::Hard)) {
283*e038c9c4Sjoerg       Arg *ABIArg =
284*e038c9c4Sjoerg           Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
285*e038c9c4Sjoerg                           options::OPT_mfloat_abi_EQ);
286*e038c9c4Sjoerg       assert(ABIArg && "Non-default float abi expected to be from arg");
287*e038c9c4Sjoerg       D.Diag(diag::err_drv_unsupported_opt_for_target)
288*e038c9c4Sjoerg           << ABIArg->getAsString(Args) << Triple.getTriple();
289*e038c9c4Sjoerg     }
290*e038c9c4Sjoerg     break;
291*e038c9c4Sjoerg   }
292*e038c9c4Sjoerg   }
293*e038c9c4Sjoerg }
294*e038c9c4Sjoerg 
getARMFloatABI(const ToolChain & TC,const ArgList & Args)295*e038c9c4Sjoerg arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) {
296*e038c9c4Sjoerg   return arm::getARMFloatABI(TC.getDriver(), TC.getEffectiveTriple(), Args);
297*e038c9c4Sjoerg }
298*e038c9c4Sjoerg 
getDefaultFloatABI(const llvm::Triple & Triple)299*e038c9c4Sjoerg arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) {
300*e038c9c4Sjoerg   auto SubArch = getARMSubArchVersionNumber(Triple);
301*e038c9c4Sjoerg   switch (Triple.getOS()) {
302*e038c9c4Sjoerg   case llvm::Triple::Darwin:
303*e038c9c4Sjoerg   case llvm::Triple::MacOSX:
304*e038c9c4Sjoerg   case llvm::Triple::IOS:
305*e038c9c4Sjoerg   case llvm::Triple::TvOS:
306*e038c9c4Sjoerg     // Darwin defaults to "softfp" for v6 and v7.
307*e038c9c4Sjoerg     if (Triple.isWatchABI())
308*e038c9c4Sjoerg       return FloatABI::Hard;
309*e038c9c4Sjoerg     else
310*e038c9c4Sjoerg       return (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
311*e038c9c4Sjoerg 
312*e038c9c4Sjoerg   case llvm::Triple::WatchOS:
313*e038c9c4Sjoerg     return FloatABI::Hard;
314*e038c9c4Sjoerg 
315*e038c9c4Sjoerg   // FIXME: this is invalid for WindowsCE
316*e038c9c4Sjoerg   case llvm::Triple::Win32:
317*e038c9c4Sjoerg     return FloatABI::Hard;
318*e038c9c4Sjoerg 
319*e038c9c4Sjoerg   case llvm::Triple::NetBSD:
320*e038c9c4Sjoerg     switch (Triple.getEnvironment()) {
321*e038c9c4Sjoerg     case llvm::Triple::EABIHF:
322*e038c9c4Sjoerg     case llvm::Triple::GNUEABIHF:
323*e038c9c4Sjoerg       return FloatABI::Hard;
324*e038c9c4Sjoerg     default:
325*e038c9c4Sjoerg       return FloatABI::Soft;
326*e038c9c4Sjoerg     }
327*e038c9c4Sjoerg     break;
328*e038c9c4Sjoerg 
329*e038c9c4Sjoerg   case llvm::Triple::FreeBSD:
330*e038c9c4Sjoerg     switch (Triple.getEnvironment()) {
331*e038c9c4Sjoerg     case llvm::Triple::GNUEABIHF:
332*e038c9c4Sjoerg       return FloatABI::Hard;
333*e038c9c4Sjoerg     default:
334*e038c9c4Sjoerg       // FreeBSD defaults to soft float
335*e038c9c4Sjoerg       return FloatABI::Soft;
336*e038c9c4Sjoerg     }
337*e038c9c4Sjoerg     break;
338*e038c9c4Sjoerg 
339*e038c9c4Sjoerg   case llvm::Triple::OpenBSD:
340*e038c9c4Sjoerg     return FloatABI::SoftFP;
341*e038c9c4Sjoerg 
342*e038c9c4Sjoerg   default:
343*e038c9c4Sjoerg     switch (Triple.getEnvironment()) {
344*e038c9c4Sjoerg     case llvm::Triple::GNUEABIHF:
345*e038c9c4Sjoerg     case llvm::Triple::MuslEABIHF:
346*e038c9c4Sjoerg     case llvm::Triple::EABIHF:
347*e038c9c4Sjoerg       return FloatABI::Hard;
348*e038c9c4Sjoerg     case llvm::Triple::GNUEABI:
349*e038c9c4Sjoerg     case llvm::Triple::MuslEABI:
350*e038c9c4Sjoerg     case llvm::Triple::EABI:
351*e038c9c4Sjoerg       // EABI is always AAPCS, and if it was not marked 'hard', it's softfp
352*e038c9c4Sjoerg       return FloatABI::SoftFP;
353*e038c9c4Sjoerg     case llvm::Triple::Android:
354*e038c9c4Sjoerg       return (SubArch >= 7) ? FloatABI::SoftFP : FloatABI::Soft;
355*e038c9c4Sjoerg     default:
356*e038c9c4Sjoerg       return FloatABI::Invalid;
357*e038c9c4Sjoerg     }
358*e038c9c4Sjoerg   }
359*e038c9c4Sjoerg   return FloatABI::Invalid;
360*e038c9c4Sjoerg }
361*e038c9c4Sjoerg 
3627330f729Sjoerg // Select the float ABI as determined by -msoft-float, -mhard-float, and
3637330f729Sjoerg // -mfloat-abi=.
getARMFloatABI(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)364*e038c9c4Sjoerg arm::FloatABI arm::getARMFloatABI(const Driver &D, const llvm::Triple &Triple,
365*e038c9c4Sjoerg                                   const ArgList &Args) {
3667330f729Sjoerg   arm::FloatABI ABI = FloatABI::Invalid;
3677330f729Sjoerg   if (Arg *A =
3687330f729Sjoerg           Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
3697330f729Sjoerg                           options::OPT_mfloat_abi_EQ)) {
3707330f729Sjoerg     if (A->getOption().matches(options::OPT_msoft_float)) {
3717330f729Sjoerg       ABI = FloatABI::Soft;
3727330f729Sjoerg     } else if (A->getOption().matches(options::OPT_mhard_float)) {
3737330f729Sjoerg       ABI = FloatABI::Hard;
3747330f729Sjoerg     } else {
3757330f729Sjoerg       ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue())
3767330f729Sjoerg                 .Case("soft", FloatABI::Soft)
3777330f729Sjoerg                 .Case("softfp", FloatABI::SoftFP)
3787330f729Sjoerg                 .Case("hard", FloatABI::Hard)
3797330f729Sjoerg                 .Default(FloatABI::Invalid);
3807330f729Sjoerg       if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
3817330f729Sjoerg         D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
3827330f729Sjoerg         ABI = FloatABI::Soft;
3837330f729Sjoerg       }
3847330f729Sjoerg     }
3857330f729Sjoerg   }
3867330f729Sjoerg 
3877330f729Sjoerg   // If unspecified, choose the default based on the platform.
388*e038c9c4Sjoerg   if (ABI == FloatABI::Invalid)
389*e038c9c4Sjoerg     ABI = arm::getDefaultFloatABI(Triple);
390*e038c9c4Sjoerg 
3917330f729Sjoerg   if (ABI == FloatABI::Invalid) {
3927330f729Sjoerg     // Assume "soft", but warn the user we are guessing.
3937330f729Sjoerg     if (Triple.isOSBinFormatMachO() &&
3947330f729Sjoerg         Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em)
3957330f729Sjoerg       ABI = FloatABI::Hard;
3967330f729Sjoerg     else
3977330f729Sjoerg       ABI = FloatABI::Soft;
3987330f729Sjoerg 
3997330f729Sjoerg     if (Triple.getOS() != llvm::Triple::UnknownOS ||
4007330f729Sjoerg         !Triple.isOSBinFormatMachO())
4017330f729Sjoerg       D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
4027330f729Sjoerg   }
4037330f729Sjoerg 
4047330f729Sjoerg   assert(ABI != FloatABI::Invalid && "must select an ABI");
4057330f729Sjoerg   return ABI;
4067330f729Sjoerg }
4077330f729Sjoerg 
hasIntegerMVE(const std::vector<StringRef> & F)408*e038c9c4Sjoerg static bool hasIntegerMVE(const std::vector<StringRef> &F) {
409*e038c9c4Sjoerg   auto MVE = llvm::find(llvm::reverse(F), "+mve");
410*e038c9c4Sjoerg   auto NoMVE = llvm::find(llvm::reverse(F), "-mve");
411*e038c9c4Sjoerg   return MVE != F.rend() &&
412*e038c9c4Sjoerg          (NoMVE == F.rend() || std::distance(MVE, NoMVE) > 0);
413*e038c9c4Sjoerg }
4147330f729Sjoerg 
getARMTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,ArgStringList & CmdArgs,std::vector<StringRef> & Features,bool ForAS)415*e038c9c4Sjoerg void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
416*e038c9c4Sjoerg                                const ArgList &Args, ArgStringList &CmdArgs,
417*e038c9c4Sjoerg                                std::vector<StringRef> &Features, bool ForAS) {
4187330f729Sjoerg   bool KernelOrKext =
4197330f729Sjoerg       Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
420*e038c9c4Sjoerg   arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args);
421*e038c9c4Sjoerg   arm::ReadTPMode ThreadPointer = arm::getReadTPMode(D, Args);
422*e038c9c4Sjoerg   llvm::Optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv,
423*e038c9c4Sjoerg       WaArch;
4247330f729Sjoerg 
4257330f729Sjoerg   // This vector will accumulate features from the architecture
4267330f729Sjoerg   // extension suffixes on -mcpu and -march (e.g. the 'bar' in
4277330f729Sjoerg   // -mcpu=foo+bar). We want to apply those after the features derived
4287330f729Sjoerg   // from the FPU, in case -mfpu generates a negative feature which
4297330f729Sjoerg   // the +bar is supposed to override.
4307330f729Sjoerg   std::vector<StringRef> ExtensionFeatures;
4317330f729Sjoerg 
4327330f729Sjoerg   if (!ForAS) {
4337330f729Sjoerg     // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
4347330f729Sjoerg     // yet (it uses the -mfloat-abi and -msoft-float options), and it is
4357330f729Sjoerg     // stripped out by the ARM target. We should probably pass this a new
4367330f729Sjoerg     // -target-option, which is handled by the -cc1/-cc1as invocation.
4377330f729Sjoerg     //
4387330f729Sjoerg     // FIXME2:  For consistency, it would be ideal if we set up the target
4397330f729Sjoerg     // machine state the same when using the frontend or the assembler. We don't
4407330f729Sjoerg     // currently do that for the assembler, we pass the options directly to the
4417330f729Sjoerg     // backend and never even instantiate the frontend TargetInfo. If we did,
4427330f729Sjoerg     // and used its handleTargetFeatures hook, then we could ensure the
4437330f729Sjoerg     // assembler and the frontend behave the same.
4447330f729Sjoerg 
4457330f729Sjoerg     // Use software floating point operations?
4467330f729Sjoerg     if (ABI == arm::FloatABI::Soft)
4477330f729Sjoerg       Features.push_back("+soft-float");
4487330f729Sjoerg 
4497330f729Sjoerg     // Use software floating point argument passing?
4507330f729Sjoerg     if (ABI != arm::FloatABI::Hard)
4517330f729Sjoerg       Features.push_back("+soft-float-abi");
4527330f729Sjoerg   } else {
4537330f729Sjoerg     // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down
4547330f729Sjoerg     // to the assembler correctly.
4557330f729Sjoerg     for (const Arg *A :
4567330f729Sjoerg          Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
457*e038c9c4Sjoerg       // We use getValues here because you can have many options per -Wa
458*e038c9c4Sjoerg       // We will keep the last one we find for each of these
459*e038c9c4Sjoerg       for (StringRef Value : A->getValues()) {
4607330f729Sjoerg         if (Value.startswith("-mfpu=")) {
461*e038c9c4Sjoerg           WaFPU = std::make_pair(A, Value.substr(6));
4627330f729Sjoerg         } else if (Value.startswith("-mcpu=")) {
463*e038c9c4Sjoerg           WaCPU = std::make_pair(A, Value.substr(6));
4647330f729Sjoerg         } else if (Value.startswith("-mhwdiv=")) {
465*e038c9c4Sjoerg           WaHDiv = std::make_pair(A, Value.substr(8));
4667330f729Sjoerg         } else if (Value.startswith("-march=")) {
467*e038c9c4Sjoerg           WaArch = std::make_pair(A, Value.substr(7));
468*e038c9c4Sjoerg         }
4697330f729Sjoerg       }
4707330f729Sjoerg     }
4717330f729Sjoerg   }
4727330f729Sjoerg 
4737330f729Sjoerg   if (ThreadPointer == arm::ReadTPMode::Cp15)
4747330f729Sjoerg     Features.push_back("+read-tp-hard");
4757330f729Sjoerg 
4767330f729Sjoerg   const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
4777330f729Sjoerg   const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
4787330f729Sjoerg   StringRef ArchName;
4797330f729Sjoerg   StringRef CPUName;
480*e038c9c4Sjoerg   unsigned ArchArgFPUID = llvm::ARM::FK_INVALID;
481*e038c9c4Sjoerg   unsigned CPUArgFPUID = llvm::ARM::FK_INVALID;
4827330f729Sjoerg 
4837330f729Sjoerg   // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=.
4847330f729Sjoerg   if (WaCPU) {
4857330f729Sjoerg     if (CPUArg)
4867330f729Sjoerg       D.Diag(clang::diag::warn_drv_unused_argument)
4877330f729Sjoerg           << CPUArg->getAsString(Args);
488*e038c9c4Sjoerg     CPUName = WaCPU->second;
489*e038c9c4Sjoerg     CPUArg = WaCPU->first;
4907330f729Sjoerg   } else if (CPUArg)
4917330f729Sjoerg     CPUName = CPUArg->getValue();
4927330f729Sjoerg 
4937330f729Sjoerg   // Check -march. ClangAs gives preference to -Wa,-march=.
4947330f729Sjoerg   if (WaArch) {
4957330f729Sjoerg     if (ArchArg)
4967330f729Sjoerg       D.Diag(clang::diag::warn_drv_unused_argument)
4977330f729Sjoerg           << ArchArg->getAsString(Args);
498*e038c9c4Sjoerg     ArchName = WaArch->second;
499*e038c9c4Sjoerg     // This will set any features after the base architecture.
500*e038c9c4Sjoerg     checkARMArchName(D, WaArch->first, Args, ArchName, CPUName,
501*e038c9c4Sjoerg                      ExtensionFeatures, Triple, ArchArgFPUID);
502*e038c9c4Sjoerg     // The base architecture was handled in ToolChain::ComputeLLVMTriple because
503*e038c9c4Sjoerg     // triple is read only by this point.
5047330f729Sjoerg   } else if (ArchArg) {
5057330f729Sjoerg     ArchName = ArchArg->getValue();
506*e038c9c4Sjoerg     checkARMArchName(D, ArchArg, Args, ArchName, CPUName, ExtensionFeatures,
507*e038c9c4Sjoerg                      Triple, ArchArgFPUID);
5087330f729Sjoerg   }
5097330f729Sjoerg 
5107330f729Sjoerg   // Add CPU features for generic CPUs
5117330f729Sjoerg   if (CPUName == "native") {
5127330f729Sjoerg     llvm::StringMap<bool> HostFeatures;
5137330f729Sjoerg     if (llvm::sys::getHostCPUFeatures(HostFeatures))
5147330f729Sjoerg       for (auto &F : HostFeatures)
5157330f729Sjoerg         Features.push_back(
5167330f729Sjoerg             Args.MakeArgString((F.second ? "+" : "-") + F.first()));
5177330f729Sjoerg   } else if (!CPUName.empty()) {
5187330f729Sjoerg     // This sets the default features for the specified CPU. We certainly don't
5197330f729Sjoerg     // want to override the features that have been explicitly specified on the
5207330f729Sjoerg     // command line. Therefore, process them directly instead of appending them
5217330f729Sjoerg     // at the end later.
5227330f729Sjoerg     DecodeARMFeaturesFromCPU(D, CPUName, Features);
5237330f729Sjoerg   }
5247330f729Sjoerg 
5257330f729Sjoerg   if (CPUArg)
526*e038c9c4Sjoerg     checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures,
527*e038c9c4Sjoerg                     Triple, CPUArgFPUID);
5287330f729Sjoerg   // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
529*e038c9c4Sjoerg   unsigned FPUID = llvm::ARM::FK_INVALID;
5307330f729Sjoerg   const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
5317330f729Sjoerg   if (WaFPU) {
5327330f729Sjoerg     if (FPUArg)
5337330f729Sjoerg       D.Diag(clang::diag::warn_drv_unused_argument)
5347330f729Sjoerg           << FPUArg->getAsString(Args);
535*e038c9c4Sjoerg     (void)getARMFPUFeatures(D, WaFPU->first, Args, WaFPU->second, Features);
5367330f729Sjoerg   } else if (FPUArg) {
537*e038c9c4Sjoerg     FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
5387330f729Sjoerg   } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) {
5397330f729Sjoerg     const char *AndroidFPU = "neon";
540*e038c9c4Sjoerg     FPUID = llvm::ARM::parseFPU(AndroidFPU);
541*e038c9c4Sjoerg     if (!llvm::ARM::getFPUFeatures(FPUID, Features))
5427330f729Sjoerg       D.Diag(clang::diag::err_drv_clang_unsupported)
5437330f729Sjoerg           << std::string("-mfpu=") + AndroidFPU;
544*e038c9c4Sjoerg   } else {
545*e038c9c4Sjoerg     if (!ForAS) {
546*e038c9c4Sjoerg       std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
547*e038c9c4Sjoerg       llvm::ARM::ArchKind ArchKind =
548*e038c9c4Sjoerg           arm::getLLVMArchKindForARM(CPU, ArchName, Triple);
549*e038c9c4Sjoerg       FPUID = llvm::ARM::getDefaultFPU(CPU, ArchKind);
550*e038c9c4Sjoerg       (void)llvm::ARM::getFPUFeatures(FPUID, Features);
551*e038c9c4Sjoerg     }
5527330f729Sjoerg   }
5537330f729Sjoerg 
5547330f729Sjoerg   // Now we've finished accumulating features from arch, cpu and fpu,
5557330f729Sjoerg   // we can append the ones for architecture extensions that we
5567330f729Sjoerg   // collected separately.
5577330f729Sjoerg   Features.insert(std::end(Features),
5587330f729Sjoerg                   std::begin(ExtensionFeatures), std::end(ExtensionFeatures));
5597330f729Sjoerg 
5607330f729Sjoerg   // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=.
5617330f729Sjoerg   const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ);
5627330f729Sjoerg   if (WaHDiv) {
5637330f729Sjoerg     if (HDivArg)
5647330f729Sjoerg       D.Diag(clang::diag::warn_drv_unused_argument)
5657330f729Sjoerg           << HDivArg->getAsString(Args);
566*e038c9c4Sjoerg     getARMHWDivFeatures(D, WaHDiv->first, Args, WaHDiv->second, Features);
5677330f729Sjoerg   } else if (HDivArg)
5687330f729Sjoerg     getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features);
5697330f729Sjoerg 
5707330f729Sjoerg   // Handle (arch-dependent) fp16fml/fullfp16 relationship.
5717330f729Sjoerg   // Must happen before any features are disabled due to soft-float.
5727330f729Sjoerg   // FIXME: this fp16fml option handling will be reimplemented after the
5737330f729Sjoerg   // TargetParser rewrite.
5747330f729Sjoerg   const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16");
5757330f729Sjoerg   const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml");
5767330f729Sjoerg   if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_4a) {
5777330f729Sjoerg     const auto ItRFullFP16  = std::find(Features.rbegin(), Features.rend(), "+fullfp16");
5787330f729Sjoerg     if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) {
5797330f729Sjoerg       // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml.
5807330f729Sjoerg       // Only append the +fp16fml if there is no -fp16fml after the +fullfp16.
5817330f729Sjoerg       if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16)
5827330f729Sjoerg         Features.push_back("+fp16fml");
5837330f729Sjoerg     }
5847330f729Sjoerg     else
5857330f729Sjoerg       goto fp16_fml_fallthrough;
5867330f729Sjoerg   }
5877330f729Sjoerg   else {
5887330f729Sjoerg fp16_fml_fallthrough:
5897330f729Sjoerg     // In both of these cases, putting the 'other' feature on the end of the vector will
5907330f729Sjoerg     // result in the same effect as placing it immediately after the current feature.
5917330f729Sjoerg     if (ItRNoFullFP16 < ItRFP16FML)
5927330f729Sjoerg       Features.push_back("-fp16fml");
5937330f729Sjoerg     else if (ItRNoFullFP16 > ItRFP16FML)
5947330f729Sjoerg       Features.push_back("+fullfp16");
5957330f729Sjoerg   }
5967330f729Sjoerg 
597*e038c9c4Sjoerg   // Setting -msoft-float/-mfloat-abi=soft, -mfpu=none, or adding +nofp to
598*e038c9c4Sjoerg   // -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in
599*e038c9c4Sjoerg   // this case). Note that the ABI can also be set implicitly by the target
600*e038c9c4Sjoerg   // selected.
6017330f729Sjoerg   if (ABI == arm::FloatABI::Soft) {
6027330f729Sjoerg     llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features);
6037330f729Sjoerg 
604*e038c9c4Sjoerg     // Disable all features relating to hardware FP, not already disabled by the
605*e038c9c4Sjoerg     // above call.
606*e038c9c4Sjoerg     Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve",
607*e038c9c4Sjoerg                                      "-mve.fp", "-fpregs"});
608*e038c9c4Sjoerg   } else if (FPUID == llvm::ARM::FK_NONE ||
609*e038c9c4Sjoerg              ArchArgFPUID == llvm::ARM::FK_NONE ||
610*e038c9c4Sjoerg              CPUArgFPUID == llvm::ARM::FK_NONE) {
611*e038c9c4Sjoerg     // -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to
612*e038c9c4Sjoerg     // -mfloat-abi=soft, only that it should not disable MVE-I. They disable the
613*e038c9c4Sjoerg     // FPU, but not the FPU registers, thus MVE-I, which depends only on the
614*e038c9c4Sjoerg     // latter, is still supported.
615*e038c9c4Sjoerg     Features.insert(Features.end(),
616*e038c9c4Sjoerg                     {"-dotprod", "-fp16fml", "-bf16", "-mve.fp"});
617*e038c9c4Sjoerg     if (!hasIntegerMVE(Features))
618*e038c9c4Sjoerg       Features.emplace_back("-fpregs");
6197330f729Sjoerg   }
6207330f729Sjoerg 
6217330f729Sjoerg   // En/disable crc code generation.
6227330f729Sjoerg   if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
6237330f729Sjoerg     if (A->getOption().matches(options::OPT_mcrc))
6247330f729Sjoerg       Features.push_back("+crc");
6257330f729Sjoerg     else
6267330f729Sjoerg       Features.push_back("-crc");
6277330f729Sjoerg   }
6287330f729Sjoerg 
629*e038c9c4Sjoerg   // For Arch >= ARMv8.0 && A or R profile:  crypto = sha2 + aes
630*e038c9c4Sjoerg   // Rather than replace within the feature vector, determine whether each
631*e038c9c4Sjoerg   // algorithm is enabled and append this to the end of the vector.
632*e038c9c4Sjoerg   // The algorithms can be controlled by their specific feature or the crypto
633*e038c9c4Sjoerg   // feature, so their status can be determined by the last occurance of
634*e038c9c4Sjoerg   // either in the vector. This allows one to supercede the other.
635*e038c9c4Sjoerg   // e.g. +crypto+noaes in -march/-mcpu should enable sha2, but not aes
6367330f729Sjoerg   // FIXME: this needs reimplementation after the TargetParser rewrite
637*e038c9c4Sjoerg   bool HasSHA2 = false;
638*e038c9c4Sjoerg   bool HasAES = false;
639*e038c9c4Sjoerg   const auto ItCrypto =
640*e038c9c4Sjoerg       llvm::find_if(llvm::reverse(Features), [](const StringRef F) {
6417330f729Sjoerg         return F.contains("crypto");
6427330f729Sjoerg       });
643*e038c9c4Sjoerg   const auto ItSHA2 =
644*e038c9c4Sjoerg       llvm::find_if(llvm::reverse(Features), [](const StringRef F) {
645*e038c9c4Sjoerg         return F.contains("crypto") || F.contains("sha2");
646*e038c9c4Sjoerg       });
647*e038c9c4Sjoerg   const auto ItAES =
648*e038c9c4Sjoerg       llvm::find_if(llvm::reverse(Features), [](const StringRef F) {
649*e038c9c4Sjoerg         return F.contains("crypto") || F.contains("aes");
650*e038c9c4Sjoerg       });
651*e038c9c4Sjoerg   const bool FoundSHA2 = ItSHA2 != Features.rend();
652*e038c9c4Sjoerg   const bool FoundAES = ItAES != Features.rend();
653*e038c9c4Sjoerg   if (FoundSHA2)
654*e038c9c4Sjoerg     HasSHA2 = ItSHA2->take_front() == "+";
655*e038c9c4Sjoerg   if (FoundAES)
656*e038c9c4Sjoerg     HasAES = ItAES->take_front() == "+";
657*e038c9c4Sjoerg   if (ItCrypto != Features.rend()) {
658*e038c9c4Sjoerg     if (HasSHA2 && HasAES)
659*e038c9c4Sjoerg       Features.push_back("+crypto");
660*e038c9c4Sjoerg     else
661*e038c9c4Sjoerg       Features.push_back("-crypto");
662*e038c9c4Sjoerg     if (HasSHA2)
663*e038c9c4Sjoerg       Features.push_back("+sha2");
664*e038c9c4Sjoerg     else
665*e038c9c4Sjoerg       Features.push_back("-sha2");
666*e038c9c4Sjoerg     if (HasAES)
667*e038c9c4Sjoerg       Features.push_back("+aes");
668*e038c9c4Sjoerg     else
669*e038c9c4Sjoerg       Features.push_back("-aes");
670*e038c9c4Sjoerg   }
671*e038c9c4Sjoerg 
672*e038c9c4Sjoerg   if (HasSHA2 || HasAES) {
6737330f729Sjoerg     StringRef ArchSuffix = arm::getLLVMArchSuffixForARM(
6747330f729Sjoerg         arm::getARMTargetCPU(CPUName, ArchName, Triple), ArchName, Triple);
675*e038c9c4Sjoerg     llvm::ARM::ProfileKind ArchProfile =
676*e038c9c4Sjoerg         llvm::ARM::parseArchProfile(ArchSuffix);
677*e038c9c4Sjoerg     if (!((llvm::ARM::parseArchVersion(ArchSuffix) >= 8) &&
678*e038c9c4Sjoerg           (ArchProfile == llvm::ARM::ProfileKind::A ||
679*e038c9c4Sjoerg            ArchProfile == llvm::ARM::ProfileKind::R))) {
680*e038c9c4Sjoerg       if (HasSHA2)
6817330f729Sjoerg         D.Diag(clang::diag::warn_target_unsupported_extension)
682*e038c9c4Sjoerg             << "sha2"
6837330f729Sjoerg             << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix));
684*e038c9c4Sjoerg       if (HasAES)
685*e038c9c4Sjoerg         D.Diag(clang::diag::warn_target_unsupported_extension)
686*e038c9c4Sjoerg             << "aes"
687*e038c9c4Sjoerg             << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix));
688*e038c9c4Sjoerg       // With -fno-integrated-as -mfpu=crypto-neon-fp-armv8 some assemblers such
689*e038c9c4Sjoerg       // as the GNU assembler will permit the use of crypto instructions as the
690*e038c9c4Sjoerg       // fpu will override the architecture. We keep the crypto feature in this
691*e038c9c4Sjoerg       // case to preserve compatibility. In all other cases we remove the crypto
692*e038c9c4Sjoerg       // feature.
693*e038c9c4Sjoerg       if (!Args.hasArg(options::OPT_fno_integrated_as)) {
694*e038c9c4Sjoerg         Features.push_back("-sha2");
695*e038c9c4Sjoerg         Features.push_back("-aes");
6967330f729Sjoerg       }
6977330f729Sjoerg     }
6987330f729Sjoerg   }
6997330f729Sjoerg 
7007330f729Sjoerg   // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later.
7017330f729Sjoerg   if (Args.getLastArg(options::OPT_mcmse))
7027330f729Sjoerg     Features.push_back("+8msecext");
7037330f729Sjoerg 
7047330f729Sjoerg   // Look for the last occurrence of -mlong-calls or -mno-long-calls. If
7057330f729Sjoerg   // neither options are specified, see if we are compiling for kernel/kext and
7067330f729Sjoerg   // decide whether to pass "+long-calls" based on the OS and its version.
7077330f729Sjoerg   if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
7087330f729Sjoerg                                options::OPT_mno_long_calls)) {
7097330f729Sjoerg     if (A->getOption().matches(options::OPT_mlong_calls))
7107330f729Sjoerg       Features.push_back("+long-calls");
7117330f729Sjoerg   } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) &&
7127330f729Sjoerg              !Triple.isWatchOS()) {
7137330f729Sjoerg       Features.push_back("+long-calls");
7147330f729Sjoerg   }
7157330f729Sjoerg 
7167330f729Sjoerg   // Generate execute-only output (no data access to code sections).
7177330f729Sjoerg   // This only makes sense for the compiler, not for the assembler.
7187330f729Sjoerg   if (!ForAS) {
7197330f729Sjoerg     // Supported only on ARMv6T2 and ARMv7 and above.
7207330f729Sjoerg     // Cannot be combined with -mno-movt or -mlong-calls
7217330f729Sjoerg     if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) {
7227330f729Sjoerg       if (A->getOption().matches(options::OPT_mexecute_only)) {
7237330f729Sjoerg         if (getARMSubArchVersionNumber(Triple) < 7 &&
7247330f729Sjoerg             llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2)
7257330f729Sjoerg               D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName();
7267330f729Sjoerg         else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
7277330f729Sjoerg           D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
7287330f729Sjoerg         // Long calls create constant pool entries and have not yet been fixed up
7297330f729Sjoerg         // to play nicely with execute-only. Hence, they cannot be used in
7307330f729Sjoerg         // execute-only code for now
7317330f729Sjoerg         else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) {
7327330f729Sjoerg           if (B->getOption().matches(options::OPT_mlong_calls))
7337330f729Sjoerg             D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
7347330f729Sjoerg         }
7357330f729Sjoerg         Features.push_back("+execute-only");
7367330f729Sjoerg       }
7377330f729Sjoerg     }
7387330f729Sjoerg   }
7397330f729Sjoerg 
7407330f729Sjoerg   // Kernel code has more strict alignment requirements.
7417330f729Sjoerg   if (KernelOrKext)
7427330f729Sjoerg     Features.push_back("+strict-align");
7437330f729Sjoerg   else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
7447330f729Sjoerg                                     options::OPT_munaligned_access)) {
7457330f729Sjoerg     if (A->getOption().matches(options::OPT_munaligned_access)) {
7467330f729Sjoerg       // No v6M core supports unaligned memory access (v6M ARM ARM A3.2).
7477330f729Sjoerg       if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
7487330f729Sjoerg         D.Diag(diag::err_target_unsupported_unaligned) << "v6m";
7497330f729Sjoerg       // v8M Baseline follows on from v6M, so doesn't support unaligned memory
7507330f729Sjoerg       // access either.
7517330f729Sjoerg       else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline)
7527330f729Sjoerg         D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base";
7537330f729Sjoerg     } else
7547330f729Sjoerg       Features.push_back("+strict-align");
7557330f729Sjoerg   } else {
7567330f729Sjoerg     // Assume pre-ARMv6 doesn't support unaligned accesses.
7577330f729Sjoerg     //
7587330f729Sjoerg     // ARMv6 may or may not support unaligned accesses depending on the
7597330f729Sjoerg     // SCTLR.U bit, which is architecture-specific. We assume ARMv6
7607330f729Sjoerg     // Darwin and NetBSD targets support unaligned accesses, and others don't.
7617330f729Sjoerg     //
7627330f729Sjoerg     // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
7637330f729Sjoerg     // which raises an alignment fault on unaligned accesses. Linux
7647330f729Sjoerg     // defaults this bit to 0 and handles it as a system-wide (not
7657330f729Sjoerg     // per-process) setting. It is therefore safe to assume that ARMv7+
7667330f729Sjoerg     // Linux targets support unaligned accesses. The same goes for NaCl.
7677330f729Sjoerg     //
7687330f729Sjoerg     // The above behavior is consistent with GCC.
7697330f729Sjoerg     int VersionNum = getARMSubArchVersionNumber(Triple);
7707330f729Sjoerg     if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
7717330f729Sjoerg       if (VersionNum < 6 ||
7727330f729Sjoerg           Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
7737330f729Sjoerg         Features.push_back("+strict-align");
7747330f729Sjoerg     } else if (Triple.isOSLinux() || Triple.isOSNaCl()) {
7757330f729Sjoerg       if (VersionNum < 7)
7767330f729Sjoerg         Features.push_back("+strict-align");
7777330f729Sjoerg     } else
7787330f729Sjoerg       Features.push_back("+strict-align");
7797330f729Sjoerg   }
7807330f729Sjoerg 
7817330f729Sjoerg   // llvm does not support reserving registers in general. There is support
7827330f729Sjoerg   // for reserving r9 on ARM though (defined as a platform-specific register
7837330f729Sjoerg   // in ARM EABI).
7847330f729Sjoerg   if (Args.hasArg(options::OPT_ffixed_r9))
7857330f729Sjoerg     Features.push_back("+reserve-r9");
7867330f729Sjoerg 
7877330f729Sjoerg   // The kext linker doesn't know how to deal with movw/movt.
7887330f729Sjoerg   if (KernelOrKext || Args.hasArg(options::OPT_mno_movt))
7897330f729Sjoerg     Features.push_back("+no-movt");
7907330f729Sjoerg 
7917330f729Sjoerg   if (Args.hasArg(options::OPT_mno_neg_immediates))
7927330f729Sjoerg     Features.push_back("+no-neg-immediates");
793*e038c9c4Sjoerg 
794*e038c9c4Sjoerg   // Enable/disable straight line speculation hardening.
795*e038c9c4Sjoerg   if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
796*e038c9c4Sjoerg     StringRef Scope = A->getValue();
797*e038c9c4Sjoerg     bool EnableRetBr = false;
798*e038c9c4Sjoerg     bool EnableBlr = false;
799*e038c9c4Sjoerg     bool DisableComdat = false;
800*e038c9c4Sjoerg     if (Scope != "none") {
801*e038c9c4Sjoerg       SmallVector<StringRef, 4> Opts;
802*e038c9c4Sjoerg       Scope.split(Opts, ",");
803*e038c9c4Sjoerg       for (auto Opt : Opts) {
804*e038c9c4Sjoerg         Opt = Opt.trim();
805*e038c9c4Sjoerg         if (Opt == "all") {
806*e038c9c4Sjoerg           EnableBlr = true;
807*e038c9c4Sjoerg           EnableRetBr = true;
808*e038c9c4Sjoerg           continue;
809*e038c9c4Sjoerg         }
810*e038c9c4Sjoerg         if (Opt == "retbr") {
811*e038c9c4Sjoerg           EnableRetBr = true;
812*e038c9c4Sjoerg           continue;
813*e038c9c4Sjoerg         }
814*e038c9c4Sjoerg         if (Opt == "blr") {
815*e038c9c4Sjoerg           EnableBlr = true;
816*e038c9c4Sjoerg           continue;
817*e038c9c4Sjoerg         }
818*e038c9c4Sjoerg         if (Opt == "comdat") {
819*e038c9c4Sjoerg           DisableComdat = false;
820*e038c9c4Sjoerg           continue;
821*e038c9c4Sjoerg         }
822*e038c9c4Sjoerg         if (Opt == "nocomdat") {
823*e038c9c4Sjoerg           DisableComdat = true;
824*e038c9c4Sjoerg           continue;
825*e038c9c4Sjoerg         }
826*e038c9c4Sjoerg         D.Diag(diag::err_invalid_sls_hardening)
827*e038c9c4Sjoerg             << Scope << A->getAsString(Args);
828*e038c9c4Sjoerg         break;
829*e038c9c4Sjoerg       }
830*e038c9c4Sjoerg     }
831*e038c9c4Sjoerg 
832*e038c9c4Sjoerg     if (EnableRetBr || EnableBlr)
833*e038c9c4Sjoerg       if (!(isARMAProfile(Triple) && getARMSubArchVersionNumber(Triple) >= 7))
834*e038c9c4Sjoerg         D.Diag(diag::err_sls_hardening_arm_not_supported)
835*e038c9c4Sjoerg             << Scope << A->getAsString(Args);
836*e038c9c4Sjoerg 
837*e038c9c4Sjoerg     if (EnableRetBr)
838*e038c9c4Sjoerg       Features.push_back("+harden-sls-retbr");
839*e038c9c4Sjoerg     if (EnableBlr)
840*e038c9c4Sjoerg       Features.push_back("+harden-sls-blr");
841*e038c9c4Sjoerg     if (DisableComdat) {
842*e038c9c4Sjoerg       Features.push_back("+harden-sls-nocomdat");
843*e038c9c4Sjoerg     }
844*e038c9c4Sjoerg   }
845*e038c9c4Sjoerg 
8467330f729Sjoerg }
8477330f729Sjoerg 
getARMArch(StringRef Arch,const llvm::Triple & Triple)8487330f729Sjoerg const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
8497330f729Sjoerg   std::string MArch;
8507330f729Sjoerg   if (!Arch.empty())
851*e038c9c4Sjoerg     MArch = std::string(Arch);
8527330f729Sjoerg   else
853*e038c9c4Sjoerg     MArch = std::string(Triple.getArchName());
8547330f729Sjoerg   MArch = StringRef(MArch).split("+").first.lower();
8557330f729Sjoerg 
8567330f729Sjoerg   // Handle -march=native.
8577330f729Sjoerg   if (MArch == "native") {
858*e038c9c4Sjoerg     std::string CPU = std::string(llvm::sys::getHostCPUName());
8597330f729Sjoerg     if (CPU != "generic") {
8607330f729Sjoerg       // Translate the native cpu into the architecture suffix for that CPU.
8617330f729Sjoerg       StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple);
8627330f729Sjoerg       // If there is no valid architecture suffix for this CPU we don't know how
8637330f729Sjoerg       // to handle it, so return no architecture.
8647330f729Sjoerg       if (Suffix.empty())
8657330f729Sjoerg         MArch = "";
8667330f729Sjoerg       else
8677330f729Sjoerg         MArch = std::string("arm") + Suffix.str();
8687330f729Sjoerg     }
8697330f729Sjoerg   }
8707330f729Sjoerg 
8717330f729Sjoerg   return MArch;
8727330f729Sjoerg }
8737330f729Sjoerg 
8747330f729Sjoerg /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
getARMCPUForMArch(StringRef Arch,const llvm::Triple & Triple)8757330f729Sjoerg StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) {
8767330f729Sjoerg   std::string MArch = getARMArch(Arch, Triple);
8777330f729Sjoerg   // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch
8787330f729Sjoerg   // here means an -march=native that we can't handle, so instead return no CPU.
8797330f729Sjoerg   if (MArch.empty())
8807330f729Sjoerg     return StringRef();
8817330f729Sjoerg 
8827330f729Sjoerg   // We need to return an empty string here on invalid MArch values as the
8837330f729Sjoerg   // various places that call this function can't cope with a null result.
8847330f729Sjoerg   return Triple.getARMCPUForArch(MArch);
8857330f729Sjoerg }
8867330f729Sjoerg 
8877330f729Sjoerg /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
getARMTargetCPU(StringRef CPU,StringRef Arch,const llvm::Triple & Triple)8887330f729Sjoerg std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch,
8897330f729Sjoerg                                  const llvm::Triple &Triple) {
8907330f729Sjoerg   // FIXME: Warn on inconsistent use of -mcpu and -march.
8917330f729Sjoerg   // If we have -mcpu=, use that.
8927330f729Sjoerg   if (!CPU.empty()) {
8937330f729Sjoerg     std::string MCPU = StringRef(CPU).split("+").first.lower();
8947330f729Sjoerg     // Handle -mcpu=native.
8957330f729Sjoerg     if (MCPU == "native")
896*e038c9c4Sjoerg       return std::string(llvm::sys::getHostCPUName());
8977330f729Sjoerg     else
8987330f729Sjoerg       return MCPU;
8997330f729Sjoerg   }
9007330f729Sjoerg 
901*e038c9c4Sjoerg   return std::string(getARMCPUForMArch(Arch, Triple));
9027330f729Sjoerg }
9037330f729Sjoerg 
9047330f729Sjoerg /// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a
9057330f729Sjoerg /// particular CPU (or Arch, if CPU is generic). This is needed to
9067330f729Sjoerg /// pass to functions like llvm::ARM::getDefaultFPU which need an
9077330f729Sjoerg /// ArchKind as well as a CPU name.
getLLVMArchKindForARM(StringRef CPU,StringRef Arch,const llvm::Triple & Triple)9087330f729Sjoerg llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch,
9097330f729Sjoerg                                                const llvm::Triple &Triple) {
9107330f729Sjoerg   llvm::ARM::ArchKind ArchKind;
9117330f729Sjoerg   if (CPU == "generic" || CPU.empty()) {
9127330f729Sjoerg     std::string ARMArch = tools::arm::getARMArch(Arch, Triple);
9137330f729Sjoerg     ArchKind = llvm::ARM::parseArch(ARMArch);
9147330f729Sjoerg     if (ArchKind == llvm::ARM::ArchKind::INVALID)
9157330f729Sjoerg       // In case of generic Arch, i.e. "arm",
9167330f729Sjoerg       // extract arch from default cpu of the Triple
9177330f729Sjoerg       ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch));
9187330f729Sjoerg   } else {
9197330f729Sjoerg     // FIXME: horrible hack to get around the fact that Cortex-A7 is only an
9207330f729Sjoerg     // armv7k triple if it's actually been specified via "-arch armv7k".
9217330f729Sjoerg     ArchKind = (Arch == "armv7k" || Arch == "thumbv7k")
9227330f729Sjoerg                           ? llvm::ARM::ArchKind::ARMV7K
9237330f729Sjoerg                           : llvm::ARM::parseCPUArch(CPU);
9247330f729Sjoerg   }
9257330f729Sjoerg   return ArchKind;
9267330f729Sjoerg }
9277330f729Sjoerg 
9287330f729Sjoerg /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
9297330f729Sjoerg /// CPU  (or Arch, if CPU is generic).
9307330f729Sjoerg // FIXME: This is redundant with -mcpu, why does LLVM use this.
getLLVMArchSuffixForARM(StringRef CPU,StringRef Arch,const llvm::Triple & Triple)9317330f729Sjoerg StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
9327330f729Sjoerg                                        const llvm::Triple &Triple) {
9337330f729Sjoerg   llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple);
9347330f729Sjoerg   if (ArchKind == llvm::ARM::ArchKind::INVALID)
9357330f729Sjoerg     return "";
9367330f729Sjoerg   return llvm::ARM::getSubArch(ArchKind);
9377330f729Sjoerg }
9387330f729Sjoerg 
appendBE8LinkFlag(const ArgList & Args,ArgStringList & CmdArgs,const llvm::Triple & Triple)9397330f729Sjoerg void arm::appendBE8LinkFlag(const ArgList &Args, ArgStringList &CmdArgs,
9407330f729Sjoerg                             const llvm::Triple &Triple) {
9417330f729Sjoerg   if (Args.hasArg(options::OPT_r))
9427330f729Sjoerg     return;
9437330f729Sjoerg 
9447330f729Sjoerg   // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker
9457330f729Sjoerg   // to generate BE-8 executables.
9467330f729Sjoerg   if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple))
9477330f729Sjoerg     CmdArgs.push_back("--be8");
9487330f729Sjoerg }
949