10b57cec5SDimitry Andric //===--- ARM.cpp - ARM (not AArch64) Helpers for Tools ----------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "ARM.h" 100b57cec5SDimitry Andric #include "clang/Driver/Driver.h" 110b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 120b57cec5SDimitry Andric #include "clang/Driver/Options.h" 130b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 140b57cec5SDimitry Andric #include "llvm/Option/ArgList.h" 1506c3fb27SDimitry Andric #include "llvm/TargetParser/ARMTargetParser.h" 1606c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace clang::driver; 190b57cec5SDimitry Andric using namespace clang::driver::tools; 200b57cec5SDimitry Andric using namespace clang; 210b57cec5SDimitry Andric using namespace llvm::opt; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric // Get SubArch (vN). 240b57cec5SDimitry Andric int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) { 250b57cec5SDimitry Andric llvm::StringRef Arch = Triple.getArchName(); 260b57cec5SDimitry Andric return llvm::ARM::parseArchVersion(Arch); 270b57cec5SDimitry Andric } 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric // True if M-profile. 300b57cec5SDimitry Andric bool arm::isARMMProfile(const llvm::Triple &Triple) { 310b57cec5SDimitry Andric llvm::StringRef Arch = Triple.getArchName(); 320b57cec5SDimitry Andric return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 3506c3fb27SDimitry Andric // On Arm the endianness of the output file is determined by the target and 3606c3fb27SDimitry Andric // can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and 3706c3fb27SDimitry Andric // '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a 3806c3fb27SDimitry Andric // normalized triple so we must handle the flag here. 3906c3fb27SDimitry Andric bool arm::isARMBigEndian(const llvm::Triple &Triple, const ArgList &Args) { 4006c3fb27SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, 4106c3fb27SDimitry Andric options::OPT_mbig_endian)) { 4206c3fb27SDimitry Andric return !A->getOption().matches(options::OPT_mlittle_endian); 4306c3fb27SDimitry Andric } 4406c3fb27SDimitry Andric 4506c3fb27SDimitry Andric return Triple.getArch() == llvm::Triple::armeb || 4606c3fb27SDimitry Andric Triple.getArch() == llvm::Triple::thumbeb; 4706c3fb27SDimitry Andric } 4806c3fb27SDimitry Andric 49e8d8bef9SDimitry Andric // True if A-profile. 50e8d8bef9SDimitry Andric bool arm::isARMAProfile(const llvm::Triple &Triple) { 51e8d8bef9SDimitry Andric llvm::StringRef Arch = Triple.getArchName(); 52e8d8bef9SDimitry Andric return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::A; 53e8d8bef9SDimitry Andric } 54e8d8bef9SDimitry Andric 550b57cec5SDimitry Andric // Get Arch/CPU from args. 560b57cec5SDimitry Andric void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, 570b57cec5SDimitry Andric llvm::StringRef &CPU, bool FromAs) { 580b57cec5SDimitry Andric if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) 590b57cec5SDimitry Andric CPU = A->getValue(); 600b57cec5SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) 610b57cec5SDimitry Andric Arch = A->getValue(); 620b57cec5SDimitry Andric if (!FromAs) 630b57cec5SDimitry Andric return; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric for (const Arg *A : 660b57cec5SDimitry Andric Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { 67fe6060f1SDimitry Andric // Use getValues because -Wa can have multiple arguments 68fe6060f1SDimitry Andric // e.g. -Wa,-mcpu=foo,-mcpu=bar 69fe6060f1SDimitry Andric for (StringRef Value : A->getValues()) { 705f757f3fSDimitry Andric if (Value.starts_with("-mcpu=")) 710b57cec5SDimitry Andric CPU = Value.substr(6); 725f757f3fSDimitry Andric if (Value.starts_with("-march=")) 730b57cec5SDimitry Andric Arch = Value.substr(7); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric } 76fe6060f1SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Handle -mhwdiv=. 790b57cec5SDimitry Andric // FIXME: Use ARMTargetParser. 800b57cec5SDimitry Andric static void getARMHWDivFeatures(const Driver &D, const Arg *A, 810b57cec5SDimitry Andric const ArgList &Args, StringRef HWDiv, 820b57cec5SDimitry Andric std::vector<StringRef> &Features) { 835ffd83dbSDimitry Andric uint64_t HWDivID = llvm::ARM::parseHWDiv(HWDiv); 840b57cec5SDimitry Andric if (!llvm::ARM::getHWDivFeatures(HWDivID, Features)) 850b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // Handle -mfpu=. 8906c3fb27SDimitry Andric static llvm::ARM::FPUKind getARMFPUFeatures(const Driver &D, const Arg *A, 900b57cec5SDimitry Andric const ArgList &Args, StringRef FPU, 910b57cec5SDimitry Andric std::vector<StringRef> &Features) { 9206c3fb27SDimitry Andric llvm::ARM::FPUKind FPUKind = llvm::ARM::parseFPU(FPU); 9306c3fb27SDimitry Andric if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) 940b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); 9506c3fb27SDimitry Andric return FPUKind; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Decode ARM features from string like +[no]featureA+[no]featureB+... 99e8d8bef9SDimitry Andric static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU, 100e8d8bef9SDimitry Andric llvm::ARM::ArchKind ArchKind, 101e8d8bef9SDimitry Andric std::vector<StringRef> &Features, 10206c3fb27SDimitry Andric llvm::ARM::FPUKind &ArgFPUKind) { 1030b57cec5SDimitry Andric SmallVector<StringRef, 8> Split; 1040b57cec5SDimitry Andric text.split(Split, StringRef("+"), -1, false); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric for (StringRef Feature : Split) { 10706c3fb27SDimitry Andric if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUKind)) 1080b57cec5SDimitry Andric return false; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric return true; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, 1140b57cec5SDimitry Andric std::vector<StringRef> &Features) { 1150b57cec5SDimitry Andric CPU = CPU.split("+").first; 1160b57cec5SDimitry Andric if (CPU != "generic") { 1170b57cec5SDimitry Andric llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); 1185ffd83dbSDimitry Andric uint64_t Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); 1190b57cec5SDimitry Andric llvm::ARM::getExtensionFeatures(Extension, Features); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Check if -march is valid by checking if it can be canonicalised and parsed. 1240b57cec5SDimitry Andric // getARMArch is used here instead of just checking the -march value in order 1250b57cec5SDimitry Andric // to handle -march=native correctly. 1260b57cec5SDimitry Andric static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, 1270b57cec5SDimitry Andric llvm::StringRef ArchName, llvm::StringRef CPUName, 1280b57cec5SDimitry Andric std::vector<StringRef> &Features, 12906c3fb27SDimitry Andric const llvm::Triple &Triple, 13006c3fb27SDimitry Andric llvm::ARM::FPUKind &ArgFPUKind) { 1310b57cec5SDimitry Andric std::pair<StringRef, StringRef> Split = ArchName.split("+"); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric std::string MArch = arm::getARMArch(ArchName, Triple); 1340b57cec5SDimitry Andric llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); 1350b57cec5SDimitry Andric if (ArchKind == llvm::ARM::ArchKind::INVALID || 13606c3fb27SDimitry Andric (Split.second.size() && 13706c3fb27SDimitry Andric !DecodeARMFeatures(D, Split.second, CPUName, ArchKind, Features, 13806c3fb27SDimitry Andric ArgFPUKind))) 13981ad6265SDimitry Andric D.Diag(clang::diag::err_drv_unsupported_option_argument) 140bdd1243dSDimitry Andric << A->getSpelling() << A->getValue(); 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric // Check -mcpu=. Needs ArchName to handle -mcpu=generic. 1440b57cec5SDimitry Andric static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, 1450b57cec5SDimitry Andric llvm::StringRef CPUName, llvm::StringRef ArchName, 1460b57cec5SDimitry Andric std::vector<StringRef> &Features, 14706c3fb27SDimitry Andric const llvm::Triple &Triple, 14806c3fb27SDimitry Andric llvm::ARM::FPUKind &ArgFPUKind) { 1490b57cec5SDimitry Andric std::pair<StringRef, StringRef> Split = CPUName.split("+"); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); 1520b57cec5SDimitry Andric llvm::ARM::ArchKind ArchKind = 1530b57cec5SDimitry Andric arm::getLLVMArchKindForARM(CPU, ArchName, Triple); 1540b57cec5SDimitry Andric if (ArchKind == llvm::ARM::ArchKind::INVALID || 15506c3fb27SDimitry Andric (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPU, ArchKind, 15606c3fb27SDimitry Andric Features, ArgFPUKind))) 15781ad6265SDimitry Andric D.Diag(clang::diag::err_drv_unsupported_option_argument) 158bdd1243dSDimitry Andric << A->getSpelling() << A->getValue(); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 16106c3fb27SDimitry Andric // If -mfloat-abi=hard or -mhard-float are specified explicitly then check that 16206c3fb27SDimitry Andric // floating point registers are available on the target CPU. 16306c3fb27SDimitry Andric static void checkARMFloatABI(const Driver &D, const ArgList &Args, 16406c3fb27SDimitry Andric bool HasFPRegs) { 16506c3fb27SDimitry Andric if (HasFPRegs) 16606c3fb27SDimitry Andric return; 16706c3fb27SDimitry Andric const Arg *A = 16806c3fb27SDimitry Andric Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, 16906c3fb27SDimitry Andric options::OPT_mfloat_abi_EQ); 17006c3fb27SDimitry Andric if (A && (A->getOption().matches(options::OPT_mhard_float) || 17106c3fb27SDimitry Andric (A->getOption().matches(options::OPT_mfloat_abi_EQ) && 17206c3fb27SDimitry Andric A->getValue() == StringRef("hard")))) 17306c3fb27SDimitry Andric D.Diag(clang::diag::warn_drv_no_floating_point_registers) 17406c3fb27SDimitry Andric << A->getAsString(Args); 17506c3fb27SDimitry Andric } 17606c3fb27SDimitry Andric 1770b57cec5SDimitry Andric bool arm::useAAPCSForMachO(const llvm::Triple &T) { 1780b57cec5SDimitry Andric // The backend is hardwired to assume AAPCS for M-class processors, ensure 1790b57cec5SDimitry Andric // the frontend matches that. 1800b57cec5SDimitry Andric return T.getEnvironment() == llvm::Triple::EABI || 181e8d8bef9SDimitry Andric T.getEnvironment() == llvm::Triple::EABIHF || 1820b57cec5SDimitry Andric T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 1850eae32dcSDimitry Andric // We follow GCC and support when the backend has support for the MRC/MCR 1860eae32dcSDimitry Andric // instructions that are used to set the hard thread pointer ("CP15 C13 1870eae32dcSDimitry Andric // Thread id"). 1880eae32dcSDimitry Andric bool arm::isHardTPSupported(const llvm::Triple &Triple) { 1890eae32dcSDimitry Andric int Ver = getARMSubArchVersionNumber(Triple); 1900eae32dcSDimitry Andric llvm::ARM::ArchKind AK = llvm::ARM::parseArch(Triple.getArchName()); 1910eae32dcSDimitry Andric return Triple.isARM() || AK == llvm::ARM::ArchKind::ARMV6T2 || 1920eae32dcSDimitry Andric (Ver >= 7 && AK != llvm::ARM::ArchKind::ARMV8MBaseline); 1930eae32dcSDimitry Andric } 1940eae32dcSDimitry Andric 1950b57cec5SDimitry Andric // Select mode for reading thread pointer (-mtp=soft/cp15). 196349cc55cSDimitry Andric arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args, 1970eae32dcSDimitry Andric const llvm::Triple &Triple, bool ForAS) { 1980b57cec5SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { 1990b57cec5SDimitry Andric arm::ReadTPMode ThreadPointer = 2000b57cec5SDimitry Andric llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) 20106c3fb27SDimitry Andric .Case("cp15", ReadTPMode::TPIDRURO) 20206c3fb27SDimitry Andric .Case("tpidrurw", ReadTPMode::TPIDRURW) 20306c3fb27SDimitry Andric .Case("tpidruro", ReadTPMode::TPIDRURO) 20406c3fb27SDimitry Andric .Case("tpidrprw", ReadTPMode::TPIDRPRW) 2050b57cec5SDimitry Andric .Case("soft", ReadTPMode::Soft) 2060b57cec5SDimitry Andric .Default(ReadTPMode::Invalid); 20706c3fb27SDimitry Andric if ((ThreadPointer == ReadTPMode::TPIDRURW || 20806c3fb27SDimitry Andric ThreadPointer == ReadTPMode::TPIDRURO || 20906c3fb27SDimitry Andric ThreadPointer == ReadTPMode::TPIDRPRW) && 21006c3fb27SDimitry Andric !isHardTPSupported(Triple) && !ForAS) { 211349cc55cSDimitry Andric D.Diag(diag::err_target_unsupported_tp_hard) << Triple.getArchName(); 212349cc55cSDimitry Andric return ReadTPMode::Invalid; 213349cc55cSDimitry Andric } 2140b57cec5SDimitry Andric if (ThreadPointer != ReadTPMode::Invalid) 2150b57cec5SDimitry Andric return ThreadPointer; 2160b57cec5SDimitry Andric if (StringRef(A->getValue()).empty()) 2170b57cec5SDimitry Andric D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args); 2180b57cec5SDimitry Andric else 2190b57cec5SDimitry Andric D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); 2200b57cec5SDimitry Andric return ReadTPMode::Invalid; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric return ReadTPMode::Soft; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 225fe6060f1SDimitry Andric void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, 226fe6060f1SDimitry Andric types::ID InputType, llvm::Triple &Triple) { 227fe6060f1SDimitry Andric StringRef MCPU, MArch; 228fe6060f1SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) 229fe6060f1SDimitry Andric MCPU = A->getValue(); 230fe6060f1SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) 231fe6060f1SDimitry Andric MArch = A->getValue(); 232fe6060f1SDimitry Andric 233fe6060f1SDimitry Andric std::string CPU = Triple.isOSBinFormatMachO() 234fe6060f1SDimitry Andric ? tools::arm::getARMCPUForMArch(MArch, Triple).str() 235fe6060f1SDimitry Andric : tools::arm::getARMTargetCPU(MCPU, MArch, Triple); 236fe6060f1SDimitry Andric StringRef Suffix = tools::arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); 237fe6060f1SDimitry Andric 238fe6060f1SDimitry Andric bool IsBigEndian = Triple.getArch() == llvm::Triple::armeb || 239fe6060f1SDimitry Andric Triple.getArch() == llvm::Triple::thumbeb; 240fe6060f1SDimitry Andric // Handle pseudo-target flags '-mlittle-endian'/'-EL' and 241fe6060f1SDimitry Andric // '-mbig-endian'/'-EB'. 242fe6060f1SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, 243fe6060f1SDimitry Andric options::OPT_mbig_endian)) { 244fe6060f1SDimitry Andric IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); 245fe6060f1SDimitry Andric } 246fe6060f1SDimitry Andric std::string ArchName = IsBigEndian ? "armeb" : "arm"; 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric // FIXME: Thumb should just be another -target-feaure, not in the triple. 249fe6060f1SDimitry Andric bool IsMProfile = 250fe6060f1SDimitry Andric llvm::ARM::parseArchProfile(Suffix) == llvm::ARM::ProfileKind::M; 251fe6060f1SDimitry Andric bool ThumbDefault = IsMProfile || 252fe6060f1SDimitry Andric // Thumb2 is the default for V7 on Darwin. 253fe6060f1SDimitry Andric (llvm::ARM::parseArchVersion(Suffix) == 7 && 254fe6060f1SDimitry Andric Triple.isOSBinFormatMachO()) || 255fe6060f1SDimitry Andric // FIXME: this is invalid for WindowsCE 256fe6060f1SDimitry Andric Triple.isOSWindows(); 257fe6060f1SDimitry Andric 258fe6060f1SDimitry Andric // Check if ARM ISA was explicitly selected (using -mno-thumb or -marm) for 259fe6060f1SDimitry Andric // M-Class CPUs/architecture variants, which is not supported. 260fe6060f1SDimitry Andric bool ARMModeRequested = 261fe6060f1SDimitry Andric !Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault); 262fe6060f1SDimitry Andric if (IsMProfile && ARMModeRequested) { 263fe6060f1SDimitry Andric if (MCPU.size()) 264fe6060f1SDimitry Andric D.Diag(diag::err_cpu_unsupported_isa) << CPU << "ARM"; 265fe6060f1SDimitry Andric else 266fe6060f1SDimitry Andric D.Diag(diag::err_arch_unsupported_isa) 267fe6060f1SDimitry Andric << tools::arm::getARMArch(MArch, Triple) << "ARM"; 268fe6060f1SDimitry Andric } 269fe6060f1SDimitry Andric 270fe6060f1SDimitry Andric // Check to see if an explicit choice to use thumb has been made via 271fe6060f1SDimitry Andric // -mthumb. For assembler files we must check for -mthumb in the options 272fe6060f1SDimitry Andric // passed to the assembler via -Wa or -Xassembler. 273fe6060f1SDimitry Andric bool IsThumb = false; 274fe6060f1SDimitry Andric if (InputType != types::TY_PP_Asm) 275fe6060f1SDimitry Andric IsThumb = 276fe6060f1SDimitry Andric Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault); 277fe6060f1SDimitry Andric else { 278fe6060f1SDimitry Andric // Ideally we would check for these flags in 279fe6060f1SDimitry Andric // CollectArgsForIntegratedAssembler but we can't change the ArchName at 280fe6060f1SDimitry Andric // that point. 281fe6060f1SDimitry Andric llvm::StringRef WaMArch, WaMCPU; 282fe6060f1SDimitry Andric for (const auto *A : 283fe6060f1SDimitry Andric Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { 284fe6060f1SDimitry Andric for (StringRef Value : A->getValues()) { 285fe6060f1SDimitry Andric // There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm. 286fe6060f1SDimitry Andric if (Value == "-mthumb") 287fe6060f1SDimitry Andric IsThumb = true; 2885f757f3fSDimitry Andric else if (Value.starts_with("-march=")) 289fe6060f1SDimitry Andric WaMArch = Value.substr(7); 2905f757f3fSDimitry Andric else if (Value.starts_with("-mcpu=")) 291fe6060f1SDimitry Andric WaMCPU = Value.substr(6); 292fe6060f1SDimitry Andric } 293fe6060f1SDimitry Andric } 294fe6060f1SDimitry Andric 295fe6060f1SDimitry Andric if (WaMCPU.size() || WaMArch.size()) { 296fe6060f1SDimitry Andric // The way this works means that we prefer -Wa,-mcpu's architecture 297fe6060f1SDimitry Andric // over -Wa,-march. Which matches the compiler behaviour. 298fe6060f1SDimitry Andric Suffix = tools::arm::getLLVMArchSuffixForARM(WaMCPU, WaMArch, Triple); 299fe6060f1SDimitry Andric } 300fe6060f1SDimitry Andric } 301fe6060f1SDimitry Andric 302fe6060f1SDimitry Andric // Assembly files should start in ARM mode, unless arch is M-profile, or 303fe6060f1SDimitry Andric // -mthumb has been passed explicitly to the assembler. Windows is always 304fe6060f1SDimitry Andric // thumb. 305fe6060f1SDimitry Andric if (IsThumb || IsMProfile || Triple.isOSWindows()) { 306fe6060f1SDimitry Andric if (IsBigEndian) 307fe6060f1SDimitry Andric ArchName = "thumbeb"; 308fe6060f1SDimitry Andric else 309fe6060f1SDimitry Andric ArchName = "thumb"; 310fe6060f1SDimitry Andric } 311fe6060f1SDimitry Andric Triple.setArchName(ArchName + Suffix.str()); 312fe6060f1SDimitry Andric } 313fe6060f1SDimitry Andric 314fe6060f1SDimitry Andric void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, 315fe6060f1SDimitry Andric llvm::Triple &Triple) { 31606c3fb27SDimitry Andric if (Triple.isOSLiteOS()) { 31706c3fb27SDimitry Andric Triple.setEnvironment(llvm::Triple::OpenHOS); 31806c3fb27SDimitry Andric return; 31906c3fb27SDimitry Andric } 32006c3fb27SDimitry Andric 321fe6060f1SDimitry Andric bool isHardFloat = 322fe6060f1SDimitry Andric (arm::getARMFloatABI(D, Triple, Args) == arm::FloatABI::Hard); 323fe6060f1SDimitry Andric 324fe6060f1SDimitry Andric switch (Triple.getEnvironment()) { 325fe6060f1SDimitry Andric case llvm::Triple::GNUEABI: 326fe6060f1SDimitry Andric case llvm::Triple::GNUEABIHF: 327fe6060f1SDimitry Andric Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHF 328fe6060f1SDimitry Andric : llvm::Triple::GNUEABI); 329fe6060f1SDimitry Andric break; 330*d686ce93SDimitry Andric case llvm::Triple::GNUEABIT64: 331*d686ce93SDimitry Andric case llvm::Triple::GNUEABIHFT64: 332*d686ce93SDimitry Andric Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHFT64 333*d686ce93SDimitry Andric : llvm::Triple::GNUEABIT64); 334*d686ce93SDimitry Andric break; 335fe6060f1SDimitry Andric case llvm::Triple::EABI: 336fe6060f1SDimitry Andric case llvm::Triple::EABIHF: 337fe6060f1SDimitry Andric Triple.setEnvironment(isHardFloat ? llvm::Triple::EABIHF 338fe6060f1SDimitry Andric : llvm::Triple::EABI); 339fe6060f1SDimitry Andric break; 340fe6060f1SDimitry Andric case llvm::Triple::MuslEABI: 341fe6060f1SDimitry Andric case llvm::Triple::MuslEABIHF: 342fe6060f1SDimitry Andric Triple.setEnvironment(isHardFloat ? llvm::Triple::MuslEABIHF 343fe6060f1SDimitry Andric : llvm::Triple::MuslEABI); 344fe6060f1SDimitry Andric break; 34506c3fb27SDimitry Andric case llvm::Triple::OpenHOS: 34606c3fb27SDimitry Andric break; 347fe6060f1SDimitry Andric default: { 348fe6060f1SDimitry Andric arm::FloatABI DefaultABI = arm::getDefaultFloatABI(Triple); 349fe6060f1SDimitry Andric if (DefaultABI != arm::FloatABI::Invalid && 350fe6060f1SDimitry Andric isHardFloat != (DefaultABI == arm::FloatABI::Hard)) { 351fe6060f1SDimitry Andric Arg *ABIArg = 352fe6060f1SDimitry Andric Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, 353fe6060f1SDimitry Andric options::OPT_mfloat_abi_EQ); 354fe6060f1SDimitry Andric assert(ABIArg && "Non-default float abi expected to be from arg"); 355fe6060f1SDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 356fe6060f1SDimitry Andric << ABIArg->getAsString(Args) << Triple.getTriple(); 357fe6060f1SDimitry Andric } 358fe6060f1SDimitry Andric break; 359fe6060f1SDimitry Andric } 360fe6060f1SDimitry Andric } 361fe6060f1SDimitry Andric } 362fe6060f1SDimitry Andric 3635ffd83dbSDimitry Andric arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { 3645ffd83dbSDimitry Andric return arm::getARMFloatABI(TC.getDriver(), TC.getEffectiveTriple(), Args); 3655ffd83dbSDimitry Andric } 3665ffd83dbSDimitry Andric 367e8d8bef9SDimitry Andric arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { 368e8d8bef9SDimitry Andric auto SubArch = getARMSubArchVersionNumber(Triple); 369e8d8bef9SDimitry Andric switch (Triple.getOS()) { 370e8d8bef9SDimitry Andric case llvm::Triple::Darwin: 371e8d8bef9SDimitry Andric case llvm::Triple::MacOSX: 372e8d8bef9SDimitry Andric case llvm::Triple::IOS: 373e8d8bef9SDimitry Andric case llvm::Triple::TvOS: 37481ad6265SDimitry Andric case llvm::Triple::DriverKit: 3757a6dacacSDimitry Andric case llvm::Triple::XROS: 376e8d8bef9SDimitry Andric // Darwin defaults to "softfp" for v6 and v7. 377e8d8bef9SDimitry Andric if (Triple.isWatchABI()) 378e8d8bef9SDimitry Andric return FloatABI::Hard; 379e8d8bef9SDimitry Andric else 380e8d8bef9SDimitry Andric return (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; 381e8d8bef9SDimitry Andric 382e8d8bef9SDimitry Andric case llvm::Triple::WatchOS: 383e8d8bef9SDimitry Andric return FloatABI::Hard; 384e8d8bef9SDimitry Andric 385e8d8bef9SDimitry Andric // FIXME: this is invalid for WindowsCE 386e8d8bef9SDimitry Andric case llvm::Triple::Win32: 387349cc55cSDimitry Andric // It is incorrect to select hard float ABI on MachO platforms if the ABI is 388349cc55cSDimitry Andric // "apcs-gnu". 389349cc55cSDimitry Andric if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple)) 390349cc55cSDimitry Andric return FloatABI::Soft; 391e8d8bef9SDimitry Andric return FloatABI::Hard; 392e8d8bef9SDimitry Andric 393e8d8bef9SDimitry Andric case llvm::Triple::NetBSD: 394e8d8bef9SDimitry Andric switch (Triple.getEnvironment()) { 395e8d8bef9SDimitry Andric case llvm::Triple::EABIHF: 396e8d8bef9SDimitry Andric case llvm::Triple::GNUEABIHF: 397e8d8bef9SDimitry Andric return FloatABI::Hard; 398e8d8bef9SDimitry Andric default: 399e8d8bef9SDimitry Andric return FloatABI::Soft; 400e8d8bef9SDimitry Andric } 401e8d8bef9SDimitry Andric break; 402e8d8bef9SDimitry Andric 403e8d8bef9SDimitry Andric case llvm::Triple::FreeBSD: 404e8d8bef9SDimitry Andric switch (Triple.getEnvironment()) { 405e8d8bef9SDimitry Andric case llvm::Triple::GNUEABIHF: 406e8d8bef9SDimitry Andric return FloatABI::Hard; 407e8d8bef9SDimitry Andric default: 408e8d8bef9SDimitry Andric // FreeBSD defaults to soft float 409e8d8bef9SDimitry Andric return FloatABI::Soft; 410e8d8bef9SDimitry Andric } 411e8d8bef9SDimitry Andric break; 412e8d8bef9SDimitry Andric 4135f757f3fSDimitry Andric case llvm::Triple::Haiku: 414e8d8bef9SDimitry Andric case llvm::Triple::OpenBSD: 415e8d8bef9SDimitry Andric return FloatABI::SoftFP; 416e8d8bef9SDimitry Andric 417e8d8bef9SDimitry Andric default: 41806c3fb27SDimitry Andric if (Triple.isOHOSFamily()) 41906c3fb27SDimitry Andric return FloatABI::Soft; 420e8d8bef9SDimitry Andric switch (Triple.getEnvironment()) { 421e8d8bef9SDimitry Andric case llvm::Triple::GNUEABIHF: 422*d686ce93SDimitry Andric case llvm::Triple::GNUEABIHFT64: 423e8d8bef9SDimitry Andric case llvm::Triple::MuslEABIHF: 424e8d8bef9SDimitry Andric case llvm::Triple::EABIHF: 425e8d8bef9SDimitry Andric return FloatABI::Hard; 426e8d8bef9SDimitry Andric case llvm::Triple::GNUEABI: 427*d686ce93SDimitry Andric case llvm::Triple::GNUEABIT64: 428e8d8bef9SDimitry Andric case llvm::Triple::MuslEABI: 429e8d8bef9SDimitry Andric case llvm::Triple::EABI: 430e8d8bef9SDimitry Andric // EABI is always AAPCS, and if it was not marked 'hard', it's softfp 431e8d8bef9SDimitry Andric return FloatABI::SoftFP; 432e8d8bef9SDimitry Andric case llvm::Triple::Android: 433e8d8bef9SDimitry Andric return (SubArch >= 7) ? FloatABI::SoftFP : FloatABI::Soft; 434e8d8bef9SDimitry Andric default: 435e8d8bef9SDimitry Andric return FloatABI::Invalid; 436e8d8bef9SDimitry Andric } 437e8d8bef9SDimitry Andric } 438e8d8bef9SDimitry Andric return FloatABI::Invalid; 439e8d8bef9SDimitry Andric } 440e8d8bef9SDimitry Andric 4410b57cec5SDimitry Andric // Select the float ABI as determined by -msoft-float, -mhard-float, and 4420b57cec5SDimitry Andric // -mfloat-abi=. 4435ffd83dbSDimitry Andric arm::FloatABI arm::getARMFloatABI(const Driver &D, const llvm::Triple &Triple, 4445ffd83dbSDimitry Andric const ArgList &Args) { 4450b57cec5SDimitry Andric arm::FloatABI ABI = FloatABI::Invalid; 4460b57cec5SDimitry Andric if (Arg *A = 4470b57cec5SDimitry Andric Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, 4480b57cec5SDimitry Andric options::OPT_mfloat_abi_EQ)) { 4490b57cec5SDimitry Andric if (A->getOption().matches(options::OPT_msoft_float)) { 4500b57cec5SDimitry Andric ABI = FloatABI::Soft; 4510b57cec5SDimitry Andric } else if (A->getOption().matches(options::OPT_mhard_float)) { 4520b57cec5SDimitry Andric ABI = FloatABI::Hard; 4530b57cec5SDimitry Andric } else { 4540b57cec5SDimitry Andric ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue()) 4550b57cec5SDimitry Andric .Case("soft", FloatABI::Soft) 4560b57cec5SDimitry Andric .Case("softfp", FloatABI::SoftFP) 4570b57cec5SDimitry Andric .Case("hard", FloatABI::Hard) 4580b57cec5SDimitry Andric .Default(FloatABI::Invalid); 4590b57cec5SDimitry Andric if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) { 4600b57cec5SDimitry Andric D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); 4610b57cec5SDimitry Andric ABI = FloatABI::Soft; 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // If unspecified, choose the default based on the platform. 467e8d8bef9SDimitry Andric if (ABI == FloatABI::Invalid) 468e8d8bef9SDimitry Andric ABI = arm::getDefaultFloatABI(Triple); 469e8d8bef9SDimitry Andric 4700b57cec5SDimitry Andric if (ABI == FloatABI::Invalid) { 4710b57cec5SDimitry Andric // Assume "soft", but warn the user we are guessing. 4720b57cec5SDimitry Andric if (Triple.isOSBinFormatMachO() && 4730b57cec5SDimitry Andric Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em) 4740b57cec5SDimitry Andric ABI = FloatABI::Hard; 4750b57cec5SDimitry Andric else 4760b57cec5SDimitry Andric ABI = FloatABI::Soft; 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric if (Triple.getOS() != llvm::Triple::UnknownOS || 4790b57cec5SDimitry Andric !Triple.isOSBinFormatMachO()) 4800b57cec5SDimitry Andric D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric assert(ABI != FloatABI::Invalid && "must select an ABI"); 4840b57cec5SDimitry Andric return ABI; 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 4875ffd83dbSDimitry Andric static bool hasIntegerMVE(const std::vector<StringRef> &F) { 4885ffd83dbSDimitry Andric auto MVE = llvm::find(llvm::reverse(F), "+mve"); 4895ffd83dbSDimitry Andric auto NoMVE = llvm::find(llvm::reverse(F), "-mve"); 4905ffd83dbSDimitry Andric return MVE != F.rend() && 4915ffd83dbSDimitry Andric (NoMVE == F.rend() || std::distance(MVE, NoMVE) > 0); 4925ffd83dbSDimitry Andric } 4930b57cec5SDimitry Andric 49406c3fb27SDimitry Andric llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D, 49506c3fb27SDimitry Andric const llvm::Triple &Triple, 49681ad6265SDimitry Andric const ArgList &Args, 49706c3fb27SDimitry Andric std::vector<StringRef> &Features, 49806c3fb27SDimitry Andric bool ForAS, bool ForMultilib) { 4990b57cec5SDimitry Andric bool KernelOrKext = 5000b57cec5SDimitry Andric Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); 5015ffd83dbSDimitry Andric arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); 502bdd1243dSDimitry Andric std::optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch; 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric // This vector will accumulate features from the architecture 5050b57cec5SDimitry Andric // extension suffixes on -mcpu and -march (e.g. the 'bar' in 5060b57cec5SDimitry Andric // -mcpu=foo+bar). We want to apply those after the features derived 5070b57cec5SDimitry Andric // from the FPU, in case -mfpu generates a negative feature which 5080b57cec5SDimitry Andric // the +bar is supposed to override. 5090b57cec5SDimitry Andric std::vector<StringRef> ExtensionFeatures; 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric if (!ForAS) { 5120b57cec5SDimitry Andric // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these 5130b57cec5SDimitry Andric // yet (it uses the -mfloat-abi and -msoft-float options), and it is 5140b57cec5SDimitry Andric // stripped out by the ARM target. We should probably pass this a new 5150b57cec5SDimitry Andric // -target-option, which is handled by the -cc1/-cc1as invocation. 5160b57cec5SDimitry Andric // 5170b57cec5SDimitry Andric // FIXME2: For consistency, it would be ideal if we set up the target 5180b57cec5SDimitry Andric // machine state the same when using the frontend or the assembler. We don't 5190b57cec5SDimitry Andric // currently do that for the assembler, we pass the options directly to the 5200b57cec5SDimitry Andric // backend and never even instantiate the frontend TargetInfo. If we did, 5210b57cec5SDimitry Andric // and used its handleTargetFeatures hook, then we could ensure the 5220b57cec5SDimitry Andric // assembler and the frontend behave the same. 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric // Use software floating point operations? 5250b57cec5SDimitry Andric if (ABI == arm::FloatABI::Soft) 5260b57cec5SDimitry Andric Features.push_back("+soft-float"); 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric // Use software floating point argument passing? 5290b57cec5SDimitry Andric if (ABI != arm::FloatABI::Hard) 5300b57cec5SDimitry Andric Features.push_back("+soft-float-abi"); 5310b57cec5SDimitry Andric } else { 5320b57cec5SDimitry Andric // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down 5330b57cec5SDimitry Andric // to the assembler correctly. 5340b57cec5SDimitry Andric for (const Arg *A : 5350b57cec5SDimitry Andric Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { 536fe6060f1SDimitry Andric // We use getValues here because you can have many options per -Wa 537fe6060f1SDimitry Andric // We will keep the last one we find for each of these 538fe6060f1SDimitry Andric for (StringRef Value : A->getValues()) { 5395f757f3fSDimitry Andric if (Value.starts_with("-mfpu=")) { 540fe6060f1SDimitry Andric WaFPU = std::make_pair(A, Value.substr(6)); 5415f757f3fSDimitry Andric } else if (Value.starts_with("-mcpu=")) { 542fe6060f1SDimitry Andric WaCPU = std::make_pair(A, Value.substr(6)); 5435f757f3fSDimitry Andric } else if (Value.starts_with("-mhwdiv=")) { 544fe6060f1SDimitry Andric WaHDiv = std::make_pair(A, Value.substr(8)); 5455f757f3fSDimitry Andric } else if (Value.starts_with("-march=")) { 546fe6060f1SDimitry Andric WaArch = std::make_pair(A, Value.substr(7)); 547fe6060f1SDimitry Andric } 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric } 55006c3fb27SDimitry Andric 55106c3fb27SDimitry Andric // The integrated assembler doesn't implement e_flags setting behavior for 55206c3fb27SDimitry Andric // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For 55306c3fb27SDimitry Andric // compatibility we accept but warn. 55406c3fb27SDimitry Andric if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) 55506c3fb27SDimitry Andric A->ignoreTargetSpecific(); 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric 55806c3fb27SDimitry Andric if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURW) 55906c3fb27SDimitry Andric Features.push_back("+read-tp-tpidrurw"); 56006c3fb27SDimitry Andric if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURO) 56106c3fb27SDimitry Andric Features.push_back("+read-tp-tpidruro"); 56206c3fb27SDimitry Andric if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRPRW) 56306c3fb27SDimitry Andric Features.push_back("+read-tp-tpidrprw"); 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); 5660b57cec5SDimitry Andric const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); 5670b57cec5SDimitry Andric StringRef ArchName; 5680b57cec5SDimitry Andric StringRef CPUName; 56906c3fb27SDimitry Andric llvm::ARM::FPUKind ArchArgFPUKind = llvm::ARM::FK_INVALID; 57006c3fb27SDimitry Andric llvm::ARM::FPUKind CPUArgFPUKind = llvm::ARM::FK_INVALID; 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. 5730b57cec5SDimitry Andric if (WaCPU) { 5740b57cec5SDimitry Andric if (CPUArg) 5750b57cec5SDimitry Andric D.Diag(clang::diag::warn_drv_unused_argument) 5760b57cec5SDimitry Andric << CPUArg->getAsString(Args); 577fe6060f1SDimitry Andric CPUName = WaCPU->second; 578fe6060f1SDimitry Andric CPUArg = WaCPU->first; 5790b57cec5SDimitry Andric } else if (CPUArg) 5800b57cec5SDimitry Andric CPUName = CPUArg->getValue(); 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric // Check -march. ClangAs gives preference to -Wa,-march=. 5830b57cec5SDimitry Andric if (WaArch) { 5840b57cec5SDimitry Andric if (ArchArg) 5850b57cec5SDimitry Andric D.Diag(clang::diag::warn_drv_unused_argument) 5860b57cec5SDimitry Andric << ArchArg->getAsString(Args); 587fe6060f1SDimitry Andric ArchName = WaArch->second; 588fe6060f1SDimitry Andric // This will set any features after the base architecture. 589fe6060f1SDimitry Andric checkARMArchName(D, WaArch->first, Args, ArchName, CPUName, 59006c3fb27SDimitry Andric ExtensionFeatures, Triple, ArchArgFPUKind); 591fe6060f1SDimitry Andric // The base architecture was handled in ToolChain::ComputeLLVMTriple because 592fe6060f1SDimitry Andric // triple is read only by this point. 5930b57cec5SDimitry Andric } else if (ArchArg) { 5940b57cec5SDimitry Andric ArchName = ArchArg->getValue(); 595e8d8bef9SDimitry Andric checkARMArchName(D, ArchArg, Args, ArchName, CPUName, ExtensionFeatures, 59606c3fb27SDimitry Andric Triple, ArchArgFPUKind); 5970b57cec5SDimitry Andric } 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric // Add CPU features for generic CPUs 6000b57cec5SDimitry Andric if (CPUName == "native") { 6010fca6ea1SDimitry Andric for (auto &F : llvm::sys::getHostCPUFeatures()) 6020b57cec5SDimitry Andric Features.push_back( 6030b57cec5SDimitry Andric Args.MakeArgString((F.second ? "+" : "-") + F.first())); 6040b57cec5SDimitry Andric } else if (!CPUName.empty()) { 6050b57cec5SDimitry Andric // This sets the default features for the specified CPU. We certainly don't 6060b57cec5SDimitry Andric // want to override the features that have been explicitly specified on the 6070b57cec5SDimitry Andric // command line. Therefore, process them directly instead of appending them 6080b57cec5SDimitry Andric // at the end later. 6090b57cec5SDimitry Andric DecodeARMFeaturesFromCPU(D, CPUName, Features); 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric if (CPUArg) 613e8d8bef9SDimitry Andric checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures, 61406c3fb27SDimitry Andric Triple, CPUArgFPUKind); 615972a253aSDimitry Andric 616972a253aSDimitry Andric // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a 617972a253aSDimitry Andric // longstanding behavior. 618972a253aSDimitry Andric (void)Args.getLastArg(options::OPT_mtune_EQ); 619972a253aSDimitry Andric 6200b57cec5SDimitry Andric // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. 62106c3fb27SDimitry Andric llvm::ARM::FPUKind FPUKind = llvm::ARM::FK_INVALID; 6220b57cec5SDimitry Andric const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); 6230b57cec5SDimitry Andric if (WaFPU) { 6240b57cec5SDimitry Andric if (FPUArg) 6250b57cec5SDimitry Andric D.Diag(clang::diag::warn_drv_unused_argument) 6260b57cec5SDimitry Andric << FPUArg->getAsString(Args); 627fe6060f1SDimitry Andric (void)getARMFPUFeatures(D, WaFPU->first, Args, WaFPU->second, Features); 6280b57cec5SDimitry Andric } else if (FPUArg) { 62906c3fb27SDimitry Andric FPUKind = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); 6300b57cec5SDimitry Andric } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { 6310b57cec5SDimitry Andric const char *AndroidFPU = "neon"; 63206c3fb27SDimitry Andric FPUKind = llvm::ARM::parseFPU(AndroidFPU); 63306c3fb27SDimitry Andric if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) 6340b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) 6350b57cec5SDimitry Andric << std::string("-mfpu=") + AndroidFPU; 6365f757f3fSDimitry Andric } else if (ArchArgFPUKind != llvm::ARM::FK_INVALID || 6375f757f3fSDimitry Andric CPUArgFPUKind != llvm::ARM::FK_INVALID) { 6385f757f3fSDimitry Andric FPUKind = 6395f757f3fSDimitry Andric CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind; 6405f757f3fSDimitry Andric (void)llvm::ARM::getFPUFeatures(FPUKind, Features); 641fe6060f1SDimitry Andric } else { 642fe6060f1SDimitry Andric if (!ForAS) { 643fe6060f1SDimitry Andric std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); 644fe6060f1SDimitry Andric llvm::ARM::ArchKind ArchKind = 645fe6060f1SDimitry Andric arm::getLLVMArchKindForARM(CPU, ArchName, Triple); 64606c3fb27SDimitry Andric FPUKind = llvm::ARM::getDefaultFPU(CPU, ArchKind); 64706c3fb27SDimitry Andric (void)llvm::ARM::getFPUFeatures(FPUKind, Features); 648fe6060f1SDimitry Andric } 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric // Now we've finished accumulating features from arch, cpu and fpu, 6520b57cec5SDimitry Andric // we can append the ones for architecture extensions that we 6530b57cec5SDimitry Andric // collected separately. 6540b57cec5SDimitry Andric Features.insert(std::end(Features), 6550b57cec5SDimitry Andric std::begin(ExtensionFeatures), std::end(ExtensionFeatures)); 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. 6580b57cec5SDimitry Andric const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); 6590b57cec5SDimitry Andric if (WaHDiv) { 6600b57cec5SDimitry Andric if (HDivArg) 6610b57cec5SDimitry Andric D.Diag(clang::diag::warn_drv_unused_argument) 6620b57cec5SDimitry Andric << HDivArg->getAsString(Args); 663fe6060f1SDimitry Andric getARMHWDivFeatures(D, WaHDiv->first, Args, WaHDiv->second, Features); 6640b57cec5SDimitry Andric } else if (HDivArg) 6650b57cec5SDimitry Andric getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric // Handle (arch-dependent) fp16fml/fullfp16 relationship. 6680b57cec5SDimitry Andric // Must happen before any features are disabled due to soft-float. 6690b57cec5SDimitry Andric // FIXME: this fp16fml option handling will be reimplemented after the 6700b57cec5SDimitry Andric // TargetParser rewrite. 6710b57cec5SDimitry Andric const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16"); 6720b57cec5SDimitry Andric const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml"); 6730b57cec5SDimitry Andric if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_4a) { 6740b57cec5SDimitry Andric const auto ItRFullFP16 = std::find(Features.rbegin(), Features.rend(), "+fullfp16"); 6750b57cec5SDimitry Andric if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { 6760b57cec5SDimitry Andric // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. 6770b57cec5SDimitry Andric // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. 6780b57cec5SDimitry Andric if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16) 6790b57cec5SDimitry Andric Features.push_back("+fp16fml"); 6800b57cec5SDimitry Andric } 6810b57cec5SDimitry Andric else 6820b57cec5SDimitry Andric goto fp16_fml_fallthrough; 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric else { 6850b57cec5SDimitry Andric fp16_fml_fallthrough: 6860b57cec5SDimitry Andric // In both of these cases, putting the 'other' feature on the end of the vector will 6870b57cec5SDimitry Andric // result in the same effect as placing it immediately after the current feature. 6880b57cec5SDimitry Andric if (ItRNoFullFP16 < ItRFP16FML) 6890b57cec5SDimitry Andric Features.push_back("-fp16fml"); 6900b57cec5SDimitry Andric else if (ItRNoFullFP16 > ItRFP16FML) 6910b57cec5SDimitry Andric Features.push_back("+fullfp16"); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 694e8d8bef9SDimitry Andric // Setting -msoft-float/-mfloat-abi=soft, -mfpu=none, or adding +nofp to 695e8d8bef9SDimitry Andric // -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in 696e8d8bef9SDimitry Andric // this case). Note that the ABI can also be set implicitly by the target 697e8d8bef9SDimitry Andric // selected. 69806c3fb27SDimitry Andric bool HasFPRegs = true; 6990b57cec5SDimitry Andric if (ABI == arm::FloatABI::Soft) { 7000b57cec5SDimitry Andric llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); 7010b57cec5SDimitry Andric 702480093f4SDimitry Andric // Disable all features relating to hardware FP, not already disabled by the 703480093f4SDimitry Andric // above call. 70406c3fb27SDimitry Andric Features.insert(Features.end(), 70506c3fb27SDimitry Andric {"-dotprod", "-fp16fml", "-bf16", "-mve", "-mve.fp"}); 70606c3fb27SDimitry Andric HasFPRegs = false; 70706c3fb27SDimitry Andric FPUKind = llvm::ARM::FK_NONE; 70806c3fb27SDimitry Andric } else if (FPUKind == llvm::ARM::FK_NONE || 70906c3fb27SDimitry Andric ArchArgFPUKind == llvm::ARM::FK_NONE || 71006c3fb27SDimitry Andric CPUArgFPUKind == llvm::ARM::FK_NONE) { 711e8d8bef9SDimitry Andric // -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to 712e8d8bef9SDimitry Andric // -mfloat-abi=soft, only that it should not disable MVE-I. They disable the 713e8d8bef9SDimitry Andric // FPU, but not the FPU registers, thus MVE-I, which depends only on the 714e8d8bef9SDimitry Andric // latter, is still supported. 7155ffd83dbSDimitry Andric Features.insert(Features.end(), 716e8d8bef9SDimitry Andric {"-dotprod", "-fp16fml", "-bf16", "-mve.fp"}); 71706c3fb27SDimitry Andric HasFPRegs = hasIntegerMVE(Features); 71806c3fb27SDimitry Andric FPUKind = llvm::ARM::FK_NONE; 7190b57cec5SDimitry Andric } 72006c3fb27SDimitry Andric if (!HasFPRegs) 72106c3fb27SDimitry Andric Features.emplace_back("-fpregs"); 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric // En/disable crc code generation. 7240b57cec5SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { 7250b57cec5SDimitry Andric if (A->getOption().matches(options::OPT_mcrc)) 7260b57cec5SDimitry Andric Features.push_back("+crc"); 7270b57cec5SDimitry Andric else 7280b57cec5SDimitry Andric Features.push_back("-crc"); 7290b57cec5SDimitry Andric } 7300b57cec5SDimitry Andric 731fe6060f1SDimitry Andric // For Arch >= ARMv8.0 && A or R profile: crypto = sha2 + aes 732fe6060f1SDimitry Andric // Rather than replace within the feature vector, determine whether each 733fe6060f1SDimitry Andric // algorithm is enabled and append this to the end of the vector. 734fe6060f1SDimitry Andric // The algorithms can be controlled by their specific feature or the crypto 735fe6060f1SDimitry Andric // feature, so their status can be determined by the last occurance of 736fe6060f1SDimitry Andric // either in the vector. This allows one to supercede the other. 737fe6060f1SDimitry Andric // e.g. +crypto+noaes in -march/-mcpu should enable sha2, but not aes 7380b57cec5SDimitry Andric // FIXME: this needs reimplementation after the TargetParser rewrite 739fe6060f1SDimitry Andric bool HasSHA2 = false; 740fe6060f1SDimitry Andric bool HasAES = false; 741fe6060f1SDimitry Andric const auto ItCrypto = 742fe6060f1SDimitry Andric llvm::find_if(llvm::reverse(Features), [](const StringRef F) { 743a7dea167SDimitry Andric return F.contains("crypto"); 744a7dea167SDimitry Andric }); 745fe6060f1SDimitry Andric const auto ItSHA2 = 746fe6060f1SDimitry Andric llvm::find_if(llvm::reverse(Features), [](const StringRef F) { 747fe6060f1SDimitry Andric return F.contains("crypto") || F.contains("sha2"); 748fe6060f1SDimitry Andric }); 749fe6060f1SDimitry Andric const auto ItAES = 750fe6060f1SDimitry Andric llvm::find_if(llvm::reverse(Features), [](const StringRef F) { 751fe6060f1SDimitry Andric return F.contains("crypto") || F.contains("aes"); 752fe6060f1SDimitry Andric }); 753fe6060f1SDimitry Andric const bool FoundSHA2 = ItSHA2 != Features.rend(); 754fe6060f1SDimitry Andric const bool FoundAES = ItAES != Features.rend(); 755fe6060f1SDimitry Andric if (FoundSHA2) 756fe6060f1SDimitry Andric HasSHA2 = ItSHA2->take_front() == "+"; 757fe6060f1SDimitry Andric if (FoundAES) 758fe6060f1SDimitry Andric HasAES = ItAES->take_front() == "+"; 759fe6060f1SDimitry Andric if (ItCrypto != Features.rend()) { 760fe6060f1SDimitry Andric if (HasSHA2 && HasAES) 761fe6060f1SDimitry Andric Features.push_back("+crypto"); 762fe6060f1SDimitry Andric else 763fe6060f1SDimitry Andric Features.push_back("-crypto"); 764fe6060f1SDimitry Andric if (HasSHA2) 765fe6060f1SDimitry Andric Features.push_back("+sha2"); 766fe6060f1SDimitry Andric else 767fe6060f1SDimitry Andric Features.push_back("-sha2"); 768fe6060f1SDimitry Andric if (HasAES) 769fe6060f1SDimitry Andric Features.push_back("+aes"); 770fe6060f1SDimitry Andric else 771fe6060f1SDimitry Andric Features.push_back("-aes"); 772fe6060f1SDimitry Andric } 773fe6060f1SDimitry Andric 774fe6060f1SDimitry Andric if (HasSHA2 || HasAES) { 775a7dea167SDimitry Andric StringRef ArchSuffix = arm::getLLVMArchSuffixForARM( 776a7dea167SDimitry Andric arm::getARMTargetCPU(CPUName, ArchName, Triple), ArchName, Triple); 777fe6060f1SDimitry Andric llvm::ARM::ProfileKind ArchProfile = 778fe6060f1SDimitry Andric llvm::ARM::parseArchProfile(ArchSuffix); 779fe6060f1SDimitry Andric if (!((llvm::ARM::parseArchVersion(ArchSuffix) >= 8) && 780fe6060f1SDimitry Andric (ArchProfile == llvm::ARM::ProfileKind::A || 781fe6060f1SDimitry Andric ArchProfile == llvm::ARM::ProfileKind::R))) { 782fe6060f1SDimitry Andric if (HasSHA2) 783a7dea167SDimitry Andric D.Diag(clang::diag::warn_target_unsupported_extension) 784fe6060f1SDimitry Andric << "sha2" 785a7dea167SDimitry Andric << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix)); 786fe6060f1SDimitry Andric if (HasAES) 787fe6060f1SDimitry Andric D.Diag(clang::diag::warn_target_unsupported_extension) 788fe6060f1SDimitry Andric << "aes" 789fe6060f1SDimitry Andric << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix)); 790fe6060f1SDimitry Andric // With -fno-integrated-as -mfpu=crypto-neon-fp-armv8 some assemblers such 791fe6060f1SDimitry Andric // as the GNU assembler will permit the use of crypto instructions as the 792fe6060f1SDimitry Andric // fpu will override the architecture. We keep the crypto feature in this 793fe6060f1SDimitry Andric // case to preserve compatibility. In all other cases we remove the crypto 794fe6060f1SDimitry Andric // feature. 795fe6060f1SDimitry Andric if (!Args.hasArg(options::OPT_fno_integrated_as)) { 796fe6060f1SDimitry Andric Features.push_back("-sha2"); 797fe6060f1SDimitry Andric Features.push_back("-aes"); 798a7dea167SDimitry Andric } 7990b57cec5SDimitry Andric } 8000b57cec5SDimitry Andric } 8010b57cec5SDimitry Andric 80281ad6265SDimitry Andric // Propagate frame-chain model selection 80381ad6265SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) { 80481ad6265SDimitry Andric StringRef FrameChainOption = A->getValue(); 8055f757f3fSDimitry Andric if (FrameChainOption.starts_with("aapcs")) 80681ad6265SDimitry Andric Features.push_back("+aapcs-frame-chain"); 80781ad6265SDimitry Andric } 80881ad6265SDimitry Andric 8090b57cec5SDimitry Andric // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later. 8100b57cec5SDimitry Andric if (Args.getLastArg(options::OPT_mcmse)) 8110b57cec5SDimitry Andric Features.push_back("+8msecext"); 8120b57cec5SDimitry Andric 813349cc55cSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mfix_cmse_cve_2021_35465, 814349cc55cSDimitry Andric options::OPT_mno_fix_cmse_cve_2021_35465)) { 815349cc55cSDimitry Andric if (!Args.getLastArg(options::OPT_mcmse)) 816349cc55cSDimitry Andric D.Diag(diag::err_opt_not_valid_without_opt) 817349cc55cSDimitry Andric << A->getOption().getName() << "-mcmse"; 818349cc55cSDimitry Andric 819349cc55cSDimitry Andric if (A->getOption().matches(options::OPT_mfix_cmse_cve_2021_35465)) 820349cc55cSDimitry Andric Features.push_back("+fix-cmse-cve-2021-35465"); 821349cc55cSDimitry Andric else 822349cc55cSDimitry Andric Features.push_back("-fix-cmse-cve-2021-35465"); 823349cc55cSDimitry Andric } 824349cc55cSDimitry Andric 82581ad6265SDimitry Andric // This also handles the -m(no-)fix-cortex-a72-1655431 arguments via aliases. 82681ad6265SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a57_aes_1742098, 82781ad6265SDimitry Andric options::OPT_mno_fix_cortex_a57_aes_1742098)) { 82881ad6265SDimitry Andric if (A->getOption().matches(options::OPT_mfix_cortex_a57_aes_1742098)) { 82981ad6265SDimitry Andric Features.push_back("+fix-cortex-a57-aes-1742098"); 83081ad6265SDimitry Andric } else { 83181ad6265SDimitry Andric Features.push_back("-fix-cortex-a57-aes-1742098"); 83281ad6265SDimitry Andric } 83381ad6265SDimitry Andric } 83481ad6265SDimitry Andric 8350b57cec5SDimitry Andric // Look for the last occurrence of -mlong-calls or -mno-long-calls. If 8360b57cec5SDimitry Andric // neither options are specified, see if we are compiling for kernel/kext and 8370b57cec5SDimitry Andric // decide whether to pass "+long-calls" based on the OS and its version. 8380b57cec5SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, 8390b57cec5SDimitry Andric options::OPT_mno_long_calls)) { 8400b57cec5SDimitry Andric if (A->getOption().matches(options::OPT_mlong_calls)) 8410b57cec5SDimitry Andric Features.push_back("+long-calls"); 8420b57cec5SDimitry Andric } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) && 8437a6dacacSDimitry Andric !Triple.isWatchOS() && !Triple.isXROS()) { 8440b57cec5SDimitry Andric Features.push_back("+long-calls"); 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric // Generate execute-only output (no data access to code sections). 8480b57cec5SDimitry Andric // This only makes sense for the compiler, not for the assembler. 84906c3fb27SDimitry Andric // It's not needed for multilib selection and may hide an unused 85006c3fb27SDimitry Andric // argument diagnostic if the code is always run. 85106c3fb27SDimitry Andric if (!ForAS && !ForMultilib) { 8520b57cec5SDimitry Andric // Supported only on ARMv6T2 and ARMv7 and above. 853bdd1243dSDimitry Andric // Cannot be combined with -mno-movt. 8540b57cec5SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { 8550b57cec5SDimitry Andric if (A->getOption().matches(options::OPT_mexecute_only)) { 8560b57cec5SDimitry Andric if (getARMSubArchVersionNumber(Triple) < 7 && 8575f757f3fSDimitry Andric llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2 && 8585f757f3fSDimitry Andric llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6M) 8590b57cec5SDimitry Andric D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); 8605f757f3fSDimitry Andric else if (llvm::ARM::parseArch(Triple.getArchName()) == llvm::ARM::ArchKind::ARMV6M) { 8615f757f3fSDimitry Andric if (Arg *PIArg = Args.getLastArg(options::OPT_fropi, options::OPT_frwpi, 8625f757f3fSDimitry Andric options::OPT_fpic, options::OPT_fpie, 8635f757f3fSDimitry Andric options::OPT_fPIC, options::OPT_fPIE)) 8645f757f3fSDimitry Andric D.Diag(diag::err_opt_not_valid_with_opt_on_target) 8655f757f3fSDimitry Andric << A->getAsString(Args) << PIArg->getAsString(Args) << Triple.getArchName(); 8665f757f3fSDimitry Andric } else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) 867bdd1243dSDimitry Andric D.Diag(diag::err_opt_not_valid_with_opt) 868bdd1243dSDimitry Andric << A->getAsString(Args) << B->getAsString(Args); 8690b57cec5SDimitry Andric Features.push_back("+execute-only"); 8700b57cec5SDimitry Andric } 8710b57cec5SDimitry Andric } 8720b57cec5SDimitry Andric } 8730b57cec5SDimitry Andric 8740fca6ea1SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, 8750fca6ea1SDimitry Andric options::OPT_munaligned_access, 8760fca6ea1SDimitry Andric options::OPT_mstrict_align, 8770fca6ea1SDimitry Andric options::OPT_mno_strict_align)) { 8780b57cec5SDimitry Andric // Kernel code has more strict alignment requirements. 8790fca6ea1SDimitry Andric if (KernelOrKext || 8800fca6ea1SDimitry Andric A->getOption().matches(options::OPT_mno_unaligned_access) || 8810fca6ea1SDimitry Andric A->getOption().matches(options::OPT_mstrict_align)) { 8820b57cec5SDimitry Andric Features.push_back("+strict-align"); 8830fca6ea1SDimitry Andric } else { 8840b57cec5SDimitry Andric // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). 8850b57cec5SDimitry Andric if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) 8860b57cec5SDimitry Andric D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; 8870b57cec5SDimitry Andric // v8M Baseline follows on from v6M, so doesn't support unaligned memory 8880b57cec5SDimitry Andric // access either. 8890b57cec5SDimitry Andric else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) 8900b57cec5SDimitry Andric D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; 8910fca6ea1SDimitry Andric } 8920b57cec5SDimitry Andric } else { 8930b57cec5SDimitry Andric // Assume pre-ARMv6 doesn't support unaligned accesses. 8940b57cec5SDimitry Andric // 8950b57cec5SDimitry Andric // ARMv6 may or may not support unaligned accesses depending on the 8960b57cec5SDimitry Andric // SCTLR.U bit, which is architecture-specific. We assume ARMv6 8970b57cec5SDimitry Andric // Darwin and NetBSD targets support unaligned accesses, and others don't. 8980b57cec5SDimitry Andric // 8990fca6ea1SDimitry Andric // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit which 9000fca6ea1SDimitry Andric // raises an alignment fault on unaligned accesses. Assume ARMv7+ supports 9010fca6ea1SDimitry Andric // unaligned accesses, except ARMv6-M, and ARMv8-M without the Main 9020fca6ea1SDimitry Andric // Extension. This aligns with the default behavior of ARM's downstream 9030fca6ea1SDimitry Andric // versions of GCC and Clang. 9040b57cec5SDimitry Andric // 9050fca6ea1SDimitry Andric // Users can change the default behavior via -m[no-]unaliged-access. 9060b57cec5SDimitry Andric int VersionNum = getARMSubArchVersionNumber(Triple); 9070b57cec5SDimitry Andric if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { 9080b57cec5SDimitry Andric if (VersionNum < 6 || 90981ad6265SDimitry Andric Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) 9100b57cec5SDimitry Andric Features.push_back("+strict-align"); 9110fca6ea1SDimitry Andric } else if (VersionNum < 7 || 9120fca6ea1SDimitry Andric Triple.getSubArch() == 9130fca6ea1SDimitry Andric llvm::Triple::SubArchType::ARMSubArch_v6m || 9140fca6ea1SDimitry Andric Triple.getSubArch() == 9150fca6ea1SDimitry Andric llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) { 9160b57cec5SDimitry Andric Features.push_back("+strict-align"); 9170fca6ea1SDimitry Andric } 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric // llvm does not support reserving registers in general. There is support 9210b57cec5SDimitry Andric // for reserving r9 on ARM though (defined as a platform-specific register 9220b57cec5SDimitry Andric // in ARM EABI). 9230b57cec5SDimitry Andric if (Args.hasArg(options::OPT_ffixed_r9)) 9240b57cec5SDimitry Andric Features.push_back("+reserve-r9"); 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric // The kext linker doesn't know how to deal with movw/movt. 9270b57cec5SDimitry Andric if (KernelOrKext || Args.hasArg(options::OPT_mno_movt)) 9280b57cec5SDimitry Andric Features.push_back("+no-movt"); 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric if (Args.hasArg(options::OPT_mno_neg_immediates)) 9310b57cec5SDimitry Andric Features.push_back("+no-neg-immediates"); 932e8d8bef9SDimitry Andric 933e8d8bef9SDimitry Andric // Enable/disable straight line speculation hardening. 934e8d8bef9SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) { 935e8d8bef9SDimitry Andric StringRef Scope = A->getValue(); 936e8d8bef9SDimitry Andric bool EnableRetBr = false; 937e8d8bef9SDimitry Andric bool EnableBlr = false; 938fe6060f1SDimitry Andric bool DisableComdat = false; 939fe6060f1SDimitry Andric if (Scope != "none") { 940e8d8bef9SDimitry Andric SmallVector<StringRef, 4> Opts; 941e8d8bef9SDimitry Andric Scope.split(Opts, ","); 942e8d8bef9SDimitry Andric for (auto Opt : Opts) { 943e8d8bef9SDimitry Andric Opt = Opt.trim(); 944fe6060f1SDimitry Andric if (Opt == "all") { 945fe6060f1SDimitry Andric EnableBlr = true; 946fe6060f1SDimitry Andric EnableRetBr = true; 947fe6060f1SDimitry Andric continue; 948fe6060f1SDimitry Andric } 949e8d8bef9SDimitry Andric if (Opt == "retbr") { 950e8d8bef9SDimitry Andric EnableRetBr = true; 951e8d8bef9SDimitry Andric continue; 952e8d8bef9SDimitry Andric } 953e8d8bef9SDimitry Andric if (Opt == "blr") { 954e8d8bef9SDimitry Andric EnableBlr = true; 955e8d8bef9SDimitry Andric continue; 956e8d8bef9SDimitry Andric } 957fe6060f1SDimitry Andric if (Opt == "comdat") { 958fe6060f1SDimitry Andric DisableComdat = false; 959fe6060f1SDimitry Andric continue; 960fe6060f1SDimitry Andric } 961fe6060f1SDimitry Andric if (Opt == "nocomdat") { 962fe6060f1SDimitry Andric DisableComdat = true; 963fe6060f1SDimitry Andric continue; 964fe6060f1SDimitry Andric } 96581ad6265SDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 966bdd1243dSDimitry Andric << A->getSpelling() << Scope; 967e8d8bef9SDimitry Andric break; 968e8d8bef9SDimitry Andric } 969e8d8bef9SDimitry Andric } 970e8d8bef9SDimitry Andric 971e8d8bef9SDimitry Andric if (EnableRetBr || EnableBlr) 972e8d8bef9SDimitry Andric if (!(isARMAProfile(Triple) && getARMSubArchVersionNumber(Triple) >= 7)) 973e8d8bef9SDimitry Andric D.Diag(diag::err_sls_hardening_arm_not_supported) 974e8d8bef9SDimitry Andric << Scope << A->getAsString(Args); 975e8d8bef9SDimitry Andric 976e8d8bef9SDimitry Andric if (EnableRetBr) 977e8d8bef9SDimitry Andric Features.push_back("+harden-sls-retbr"); 978e8d8bef9SDimitry Andric if (EnableBlr) 979e8d8bef9SDimitry Andric Features.push_back("+harden-sls-blr"); 980fe6060f1SDimitry Andric if (DisableComdat) { 981fe6060f1SDimitry Andric Features.push_back("+harden-sls-nocomdat"); 982fe6060f1SDimitry Andric } 983e8d8bef9SDimitry Andric } 984e8d8bef9SDimitry Andric 9850eae32dcSDimitry Andric if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) 9860eae32dcSDimitry Andric Features.push_back("+no-bti-at-return-twice"); 98706c3fb27SDimitry Andric 98806c3fb27SDimitry Andric checkARMFloatABI(D, Args, HasFPRegs); 98906c3fb27SDimitry Andric 99006c3fb27SDimitry Andric return FPUKind; 9910b57cec5SDimitry Andric } 9920b57cec5SDimitry Andric 993349cc55cSDimitry Andric std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { 9940b57cec5SDimitry Andric std::string MArch; 9950b57cec5SDimitry Andric if (!Arch.empty()) 9965ffd83dbSDimitry Andric MArch = std::string(Arch); 9970b57cec5SDimitry Andric else 9985ffd83dbSDimitry Andric MArch = std::string(Triple.getArchName()); 9990b57cec5SDimitry Andric MArch = StringRef(MArch).split("+").first.lower(); 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric // Handle -march=native. 10020b57cec5SDimitry Andric if (MArch == "native") { 10035ffd83dbSDimitry Andric std::string CPU = std::string(llvm::sys::getHostCPUName()); 10040b57cec5SDimitry Andric if (CPU != "generic") { 10050b57cec5SDimitry Andric // Translate the native cpu into the architecture suffix for that CPU. 10060b57cec5SDimitry Andric StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); 10070b57cec5SDimitry Andric // If there is no valid architecture suffix for this CPU we don't know how 10080b57cec5SDimitry Andric // to handle it, so return no architecture. 10090b57cec5SDimitry Andric if (Suffix.empty()) 10100b57cec5SDimitry Andric MArch = ""; 10110b57cec5SDimitry Andric else 10120b57cec5SDimitry Andric MArch = std::string("arm") + Suffix.str(); 10130b57cec5SDimitry Andric } 10140b57cec5SDimitry Andric } 10150b57cec5SDimitry Andric 10160b57cec5SDimitry Andric return MArch; 10170b57cec5SDimitry Andric } 10180b57cec5SDimitry Andric 10190b57cec5SDimitry Andric /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. 10200b57cec5SDimitry Andric StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { 10210b57cec5SDimitry Andric std::string MArch = getARMArch(Arch, Triple); 10220b57cec5SDimitry Andric // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch 10230b57cec5SDimitry Andric // here means an -march=native that we can't handle, so instead return no CPU. 10240b57cec5SDimitry Andric if (MArch.empty()) 10250b57cec5SDimitry Andric return StringRef(); 10260b57cec5SDimitry Andric 10270b57cec5SDimitry Andric // We need to return an empty string here on invalid MArch values as the 10280b57cec5SDimitry Andric // various places that call this function can't cope with a null result. 1029bdd1243dSDimitry Andric return llvm::ARM::getARMCPUForArch(Triple, MArch); 10300b57cec5SDimitry Andric } 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. 10330b57cec5SDimitry Andric std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, 10340b57cec5SDimitry Andric const llvm::Triple &Triple) { 10350b57cec5SDimitry Andric // FIXME: Warn on inconsistent use of -mcpu and -march. 10360b57cec5SDimitry Andric // If we have -mcpu=, use that. 10370b57cec5SDimitry Andric if (!CPU.empty()) { 10380b57cec5SDimitry Andric std::string MCPU = StringRef(CPU).split("+").first.lower(); 10390b57cec5SDimitry Andric // Handle -mcpu=native. 10400b57cec5SDimitry Andric if (MCPU == "native") 10415ffd83dbSDimitry Andric return std::string(llvm::sys::getHostCPUName()); 10420b57cec5SDimitry Andric else 10430b57cec5SDimitry Andric return MCPU; 10440b57cec5SDimitry Andric } 10450b57cec5SDimitry Andric 10465ffd83dbSDimitry Andric return std::string(getARMCPUForMArch(Arch, Triple)); 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric /// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a 10500b57cec5SDimitry Andric /// particular CPU (or Arch, if CPU is generic). This is needed to 10510b57cec5SDimitry Andric /// pass to functions like llvm::ARM::getDefaultFPU which need an 10520b57cec5SDimitry Andric /// ArchKind as well as a CPU name. 10530b57cec5SDimitry Andric llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, 10540b57cec5SDimitry Andric const llvm::Triple &Triple) { 10550b57cec5SDimitry Andric llvm::ARM::ArchKind ArchKind; 1056a7dea167SDimitry Andric if (CPU == "generic" || CPU.empty()) { 10570b57cec5SDimitry Andric std::string ARMArch = tools::arm::getARMArch(Arch, Triple); 10580b57cec5SDimitry Andric ArchKind = llvm::ARM::parseArch(ARMArch); 10590b57cec5SDimitry Andric if (ArchKind == llvm::ARM::ArchKind::INVALID) 10600b57cec5SDimitry Andric // In case of generic Arch, i.e. "arm", 10610b57cec5SDimitry Andric // extract arch from default cpu of the Triple 1062bdd1243dSDimitry Andric ArchKind = 1063bdd1243dSDimitry Andric llvm::ARM::parseCPUArch(llvm::ARM::getARMCPUForArch(Triple, ARMArch)); 10640b57cec5SDimitry Andric } else { 10650b57cec5SDimitry Andric // FIXME: horrible hack to get around the fact that Cortex-A7 is only an 10660b57cec5SDimitry Andric // armv7k triple if it's actually been specified via "-arch armv7k". 10670b57cec5SDimitry Andric ArchKind = (Arch == "armv7k" || Arch == "thumbv7k") 10680b57cec5SDimitry Andric ? llvm::ARM::ArchKind::ARMV7K 10690b57cec5SDimitry Andric : llvm::ARM::parseCPUArch(CPU); 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric return ArchKind; 10720b57cec5SDimitry Andric } 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular 10750b57cec5SDimitry Andric /// CPU (or Arch, if CPU is generic). 10760b57cec5SDimitry Andric // FIXME: This is redundant with -mcpu, why does LLVM use this. 10770b57cec5SDimitry Andric StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, 10780b57cec5SDimitry Andric const llvm::Triple &Triple) { 10790b57cec5SDimitry Andric llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple); 10800b57cec5SDimitry Andric if (ArchKind == llvm::ARM::ArchKind::INVALID) 10810b57cec5SDimitry Andric return ""; 10820b57cec5SDimitry Andric return llvm::ARM::getSubArch(ArchKind); 10830b57cec5SDimitry Andric } 10840b57cec5SDimitry Andric 10850b57cec5SDimitry Andric void arm::appendBE8LinkFlag(const ArgList &Args, ArgStringList &CmdArgs, 10860b57cec5SDimitry Andric const llvm::Triple &Triple) { 10870b57cec5SDimitry Andric if (Args.hasArg(options::OPT_r)) 10880b57cec5SDimitry Andric return; 10890b57cec5SDimitry Andric 10900b57cec5SDimitry Andric // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker 10910b57cec5SDimitry Andric // to generate BE-8 executables. 10920b57cec5SDimitry Andric if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple)) 10930b57cec5SDimitry Andric CmdArgs.push_back("--be8"); 10940b57cec5SDimitry Andric } 1095