xref: /openbsd-src/gnu/llvm/clang/lib/Driver/ToolChains/Arch/AArch64.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- AArch64.cpp - AArch64 (not ARM) Helpers for Tools ------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "AArch64.h"
10*12c85518Srobert #include "../CommonArgs.h"
11e5dd7070Spatrick #include "clang/Driver/Driver.h"
12e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h"
13e5dd7070Spatrick #include "clang/Driver/Options.h"
14e5dd7070Spatrick #include "llvm/Option/ArgList.h"
15*12c85518Srobert #include "llvm/Support/AArch64TargetParser.h"
16e5dd7070Spatrick #include "llvm/Support/TargetParser.h"
17e5dd7070Spatrick #include "llvm/Support/Host.h"
18e5dd7070Spatrick 
19e5dd7070Spatrick using namespace clang::driver;
20e5dd7070Spatrick using namespace clang::driver::tools;
21e5dd7070Spatrick using namespace clang;
22e5dd7070Spatrick using namespace llvm::opt;
23e5dd7070Spatrick 
24e5dd7070Spatrick /// \returns true if the given triple can determine the default CPU type even
25e5dd7070Spatrick /// if -arch is not specified.
isCPUDeterminedByTriple(const llvm::Triple & Triple)26e5dd7070Spatrick static bool isCPUDeterminedByTriple(const llvm::Triple &Triple) {
27e5dd7070Spatrick   return Triple.isOSDarwin();
28e5dd7070Spatrick }
29e5dd7070Spatrick 
30e5dd7070Spatrick /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
31e5dd7070Spatrick /// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is
32e5dd7070Spatrick /// provided, or to nullptr otherwise.
getAArch64TargetCPU(const ArgList & Args,const llvm::Triple & Triple,Arg * & A)33e5dd7070Spatrick std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
34e5dd7070Spatrick                                          const llvm::Triple &Triple, Arg *&A) {
35e5dd7070Spatrick   std::string CPU;
36e5dd7070Spatrick   // If we have -mcpu, use that.
37e5dd7070Spatrick   if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
38e5dd7070Spatrick     StringRef Mcpu = A->getValue();
39e5dd7070Spatrick     CPU = Mcpu.split("+").first.lower();
40e5dd7070Spatrick   }
41e5dd7070Spatrick 
42*12c85518Srobert   CPU = llvm::AArch64::resolveCPUAlias(CPU);
43*12c85518Srobert 
44e5dd7070Spatrick   // Handle CPU name is 'native'.
45e5dd7070Spatrick   if (CPU == "native")
46ec727ea7Spatrick     return std::string(llvm::sys::getHostCPUName());
47a9ac8606Spatrick 
48a9ac8606Spatrick   if (CPU.size())
49e5dd7070Spatrick     return CPU;
50e5dd7070Spatrick 
51a9ac8606Spatrick   if (Triple.isTargetMachineMac() &&
52a9ac8606Spatrick       Triple.getArch() == llvm::Triple::aarch64) {
53a9ac8606Spatrick     // Apple Silicon macs default to M1 CPUs.
54a9ac8606Spatrick     return "apple-m1";
55a9ac8606Spatrick   }
56a9ac8606Spatrick 
57a9ac8606Spatrick   // arm64e requires v8.3a and only runs on apple-a12 and later CPUs.
58a9ac8606Spatrick   if (Triple.isArm64e())
59a9ac8606Spatrick     return "apple-a12";
60a9ac8606Spatrick 
61e5dd7070Spatrick   // Make sure we pick the appropriate Apple CPU if -arch is used or when
62e5dd7070Spatrick   // targetting a Darwin OS.
63e5dd7070Spatrick   if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin())
64e5dd7070Spatrick     return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4"
65e5dd7070Spatrick                                                         : "apple-a7";
66e5dd7070Spatrick 
67e5dd7070Spatrick   return "generic";
68e5dd7070Spatrick }
69e5dd7070Spatrick 
70e5dd7070Spatrick // Decode AArch64 features from string like +[no]featureA+[no]featureB+...
DecodeAArch64Features(const Driver & D,StringRef text,std::vector<StringRef> & Features,const llvm::AArch64::ArchInfo & ArchInfo)71e5dd7070Spatrick static bool DecodeAArch64Features(const Driver &D, StringRef text,
72ec727ea7Spatrick                                   std::vector<StringRef> &Features,
73*12c85518Srobert                                   const llvm::AArch64::ArchInfo &ArchInfo) {
74e5dd7070Spatrick   SmallVector<StringRef, 8> Split;
75e5dd7070Spatrick   text.split(Split, StringRef("+"), -1, false);
76e5dd7070Spatrick 
77e5dd7070Spatrick   for (StringRef Feature : Split) {
78e5dd7070Spatrick     StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
79e5dd7070Spatrick     if (!FeatureName.empty())
80e5dd7070Spatrick       Features.push_back(FeatureName);
81e5dd7070Spatrick     else if (Feature == "neon" || Feature == "noneon")
82e5dd7070Spatrick       D.Diag(clang::diag::err_drv_no_neon_modifier);
83e5dd7070Spatrick     else
84e5dd7070Spatrick       return false;
85ec727ea7Spatrick 
86*12c85518Srobert     if (Feature == "sve2")
87*12c85518Srobert       Features.push_back("+sve");
88*12c85518Srobert     else if (Feature == "sve2-bitperm" || Feature == "sve2-sha3" ||
89*12c85518Srobert              Feature == "sve2-aes" || Feature == "sve2-sm4") {
90*12c85518Srobert       Features.push_back("+sve");
91*12c85518Srobert       Features.push_back("+sve2");
92*12c85518Srobert     } else if (Feature == "nosve") {
93*12c85518Srobert       Features.push_back("-sve2");
94*12c85518Srobert       Features.push_back("-sve2-bitperm");
95*12c85518Srobert       Features.push_back("-sve2-sha3");
96*12c85518Srobert       Features.push_back("-sve2-aes");
97*12c85518Srobert       Features.push_back("-sve2-sm4");
98*12c85518Srobert     } else if (Feature == "nosve2") {
99*12c85518Srobert       Features.push_back("-sve2-bitperm");
100*12c85518Srobert       Features.push_back("-sve2-sha3");
101*12c85518Srobert       Features.push_back("-sve2-aes");
102*12c85518Srobert       Features.push_back("-sve2-sm4");
103*12c85518Srobert     }
104*12c85518Srobert 
105*12c85518Srobert     // +sve implies +f32mm if the base architecture is >= v8.6A (except v9A)
106*12c85518Srobert     // It isn't the case in general that sve implies both f64mm and f32mm
107*12c85518Srobert     if ((ArchInfo == llvm::AArch64::ARMV8_6A ||
108*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV8_7A ||
109*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV8_8A ||
110*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV8_9A ||
111*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV9_1A ||
112*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV9_2A ||
113*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV9_3A ||
114*12c85518Srobert          ArchInfo == llvm::AArch64::ARMV9_4A) &&
115*12c85518Srobert         Feature == "sve")
116ec727ea7Spatrick       Features.push_back("+f32mm");
117e5dd7070Spatrick   }
118e5dd7070Spatrick   return true;
119e5dd7070Spatrick }
120e5dd7070Spatrick 
121e5dd7070Spatrick // Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
122e5dd7070Spatrick // decode CPU and feature.
DecodeAArch64Mcpu(const Driver & D,StringRef Mcpu,StringRef & CPU,std::vector<StringRef> & Features)123e5dd7070Spatrick static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
124e5dd7070Spatrick                               std::vector<StringRef> &Features) {
125e5dd7070Spatrick   std::pair<StringRef, StringRef> Split = Mcpu.split("+");
126*12c85518Srobert   const llvm::AArch64::ArchInfo *ArchInfo = &llvm::AArch64::ARMV8A;
127*12c85518Srobert   CPU = llvm::AArch64::resolveCPUAlias(Split.first);
128e5dd7070Spatrick 
129e5dd7070Spatrick   if (CPU == "native")
130e5dd7070Spatrick     CPU = llvm::sys::getHostCPUName();
131e5dd7070Spatrick 
132e5dd7070Spatrick   if (CPU == "generic") {
133e5dd7070Spatrick     Features.push_back("+neon");
134e5dd7070Spatrick   } else {
135*12c85518Srobert     ArchInfo = &llvm::AArch64::parseCpu(CPU).Arch;
136*12c85518Srobert     if (*ArchInfo == llvm::AArch64::INVALID)
137e5dd7070Spatrick       return false;
138*12c85518Srobert     Features.push_back(ArchInfo->ArchFeature);
139e5dd7070Spatrick 
140*12c85518Srobert     uint64_t Extension = llvm::AArch64::getDefaultExtensions(CPU, *ArchInfo);
141e5dd7070Spatrick     if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
142e5dd7070Spatrick       return false;
143e5dd7070Spatrick   }
144e5dd7070Spatrick 
145ec727ea7Spatrick   if (Split.second.size() &&
146*12c85518Srobert       !DecodeAArch64Features(D, Split.second, Features, *ArchInfo))
147e5dd7070Spatrick     return false;
148e5dd7070Spatrick 
149e5dd7070Spatrick   return true;
150e5dd7070Spatrick }
151e5dd7070Spatrick 
152e5dd7070Spatrick static bool
getAArch64ArchFeaturesFromMarch(const Driver & D,StringRef March,const ArgList & Args,std::vector<StringRef> & Features)153e5dd7070Spatrick getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
154e5dd7070Spatrick                                 const ArgList &Args,
155e5dd7070Spatrick                                 std::vector<StringRef> &Features) {
156e5dd7070Spatrick   std::string MarchLowerCase = March.lower();
157e5dd7070Spatrick   std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
158e5dd7070Spatrick 
159*12c85518Srobert   const llvm::AArch64::ArchInfo *ArchInfo =
160*12c85518Srobert       &llvm::AArch64::parseArch(Split.first);
161*12c85518Srobert   if (Split.first == "native")
162*12c85518Srobert     ArchInfo = &llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str());
163*12c85518Srobert   if (*ArchInfo == llvm::AArch64::INVALID)
164*12c85518Srobert     return false;
165*12c85518Srobert   Features.push_back(ArchInfo->ArchFeature);
166*12c85518Srobert 
167*12c85518Srobert   // Enable SVE2 by default on Armv9-A.
168*12c85518Srobert   // It can still be disabled if +nosve2 is present.
169*12c85518Srobert   // We must do this early so that DecodeAArch64Features has the correct state
170*12c85518Srobert   if ((*ArchInfo == llvm::AArch64::ARMV9A ||
171*12c85518Srobert        *ArchInfo == llvm::AArch64::ARMV9_1A ||
172*12c85518Srobert        *ArchInfo == llvm::AArch64::ARMV9_2A)) {
173*12c85518Srobert     Features.push_back("+sve");
174*12c85518Srobert     Features.push_back("+sve2");
175*12c85518Srobert   }
176*12c85518Srobert 
177*12c85518Srobert   if ((Split.second.size() &&
178*12c85518Srobert        !DecodeAArch64Features(D, Split.second, Features, *ArchInfo)))
179e5dd7070Spatrick     return false;
180e5dd7070Spatrick 
181e5dd7070Spatrick   return true;
182e5dd7070Spatrick }
183e5dd7070Spatrick 
184e5dd7070Spatrick static bool
getAArch64ArchFeaturesFromMcpu(const Driver & D,StringRef Mcpu,const ArgList & Args,std::vector<StringRef> & Features)185e5dd7070Spatrick getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
186e5dd7070Spatrick                                const ArgList &Args,
187e5dd7070Spatrick                                std::vector<StringRef> &Features) {
188e5dd7070Spatrick   StringRef CPU;
189e5dd7070Spatrick   std::string McpuLowerCase = Mcpu.lower();
190e5dd7070Spatrick   if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
191e5dd7070Spatrick     return false;
192e5dd7070Spatrick 
193e5dd7070Spatrick   return true;
194e5dd7070Spatrick }
195e5dd7070Spatrick 
196e5dd7070Spatrick static bool
getAArch64MicroArchFeaturesFromMtune(const Driver & D,StringRef Mtune,const ArgList & Args,std::vector<StringRef> & Features)197e5dd7070Spatrick getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
198e5dd7070Spatrick                                      const ArgList &Args,
199e5dd7070Spatrick                                      std::vector<StringRef> &Features) {
200e5dd7070Spatrick   std::string MtuneLowerCase = Mtune.lower();
201e5dd7070Spatrick   // Check CPU name is valid
202e5dd7070Spatrick   std::vector<StringRef> MtuneFeatures;
203e5dd7070Spatrick   StringRef Tune;
204e5dd7070Spatrick   if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures))
205e5dd7070Spatrick     return false;
206e5dd7070Spatrick 
207e5dd7070Spatrick   // Handle CPU name is 'native'.
208e5dd7070Spatrick   if (MtuneLowerCase == "native")
209ec727ea7Spatrick     MtuneLowerCase = std::string(llvm::sys::getHostCPUName());
210ec727ea7Spatrick   if (MtuneLowerCase == "cyclone" ||
211ec727ea7Spatrick       StringRef(MtuneLowerCase).startswith("apple")) {
212e5dd7070Spatrick     Features.push_back("+zcm");
213e5dd7070Spatrick     Features.push_back("+zcz");
214e5dd7070Spatrick   }
215e5dd7070Spatrick   return true;
216e5dd7070Spatrick }
217e5dd7070Spatrick 
218e5dd7070Spatrick static bool
getAArch64MicroArchFeaturesFromMcpu(const Driver & D,StringRef Mcpu,const ArgList & Args,std::vector<StringRef> & Features)219e5dd7070Spatrick getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
220e5dd7070Spatrick                                     const ArgList &Args,
221e5dd7070Spatrick                                     std::vector<StringRef> &Features) {
222e5dd7070Spatrick   StringRef CPU;
223e5dd7070Spatrick   std::vector<StringRef> DecodedFeature;
224e5dd7070Spatrick   std::string McpuLowerCase = Mcpu.lower();
225e5dd7070Spatrick   if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
226e5dd7070Spatrick     return false;
227e5dd7070Spatrick 
228e5dd7070Spatrick   return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
229e5dd7070Spatrick }
230e5dd7070Spatrick 
getAArch64TargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & Features,bool ForAS)231e5dd7070Spatrick void aarch64::getAArch64TargetFeatures(const Driver &D,
232e5dd7070Spatrick                                        const llvm::Triple &Triple,
233e5dd7070Spatrick                                        const ArgList &Args,
234a9ac8606Spatrick                                        std::vector<StringRef> &Features,
235a9ac8606Spatrick                                        bool ForAS) {
236e5dd7070Spatrick   Arg *A;
237e5dd7070Spatrick   bool success = true;
238e5dd7070Spatrick   // Enable NEON by default.
239e5dd7070Spatrick   Features.push_back("+neon");
240*12c85518Srobert   llvm::StringRef WaMArch;
241a9ac8606Spatrick   if (ForAS)
242a9ac8606Spatrick     for (const auto *A :
243a9ac8606Spatrick          Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler))
244a9ac8606Spatrick       for (StringRef Value : A->getValues())
245a9ac8606Spatrick         if (Value.startswith("-march="))
246a9ac8606Spatrick           WaMArch = Value.substr(7);
247a9ac8606Spatrick   // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or
248a9ac8606Spatrick   // "-Xassembler -march" is detected. Otherwise it may return false
249a9ac8606Spatrick   // and causes Clang to error out.
250*12c85518Srobert   if (!WaMArch.empty())
251a9ac8606Spatrick     success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Features);
252a9ac8606Spatrick   else if ((A = Args.getLastArg(options::OPT_march_EQ)))
253e5dd7070Spatrick     success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
254e5dd7070Spatrick   else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
255e5dd7070Spatrick     success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
256e5dd7070Spatrick   else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))
257e5dd7070Spatrick     success = getAArch64ArchFeaturesFromMcpu(
258e5dd7070Spatrick         D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
259*12c85518Srobert   else
260*12c85518Srobert     // Default to 'A' profile if the architecture is not specified.
261*12c85518Srobert     success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Features);
262e5dd7070Spatrick 
263e5dd7070Spatrick   if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
264e5dd7070Spatrick     success =
265e5dd7070Spatrick         getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
266e5dd7070Spatrick   else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
267e5dd7070Spatrick     success =
268e5dd7070Spatrick         getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
269e5dd7070Spatrick   else if (success &&
270e5dd7070Spatrick            (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)))
271e5dd7070Spatrick     success = getAArch64MicroArchFeaturesFromMcpu(
272e5dd7070Spatrick         D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
273e5dd7070Spatrick 
274*12c85518Srobert   if (!success) {
275*12c85518Srobert     auto Diag = D.Diag(diag::err_drv_unsupported_option_argument);
276*12c85518Srobert     // If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value,
277*12c85518Srobert     // while 'A' is uninitialized. Only dereference 'A' in the other case.
278*12c85518Srobert     if (!WaMArch.empty())
279*12c85518Srobert       Diag << "-march=" << WaMArch;
280*12c85518Srobert     else
281*12c85518Srobert       Diag << A->getSpelling() << A->getValue();
282*12c85518Srobert   }
283e5dd7070Spatrick 
284e5dd7070Spatrick   if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
285e5dd7070Spatrick     Features.push_back("-fp-armv8");
286e5dd7070Spatrick     Features.push_back("-crypto");
287e5dd7070Spatrick     Features.push_back("-neon");
288e5dd7070Spatrick   }
289e5dd7070Spatrick 
290e5dd7070Spatrick   if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
291e5dd7070Spatrick     StringRef Mtp = A->getValue();
292e5dd7070Spatrick     if (Mtp == "el3")
293e5dd7070Spatrick       Features.push_back("+tpidr-el3");
294e5dd7070Spatrick     else if (Mtp == "el2")
295e5dd7070Spatrick       Features.push_back("+tpidr-el2");
296e5dd7070Spatrick     else if (Mtp == "el1")
297e5dd7070Spatrick       Features.push_back("+tpidr-el1");
298e5dd7070Spatrick     else if (Mtp != "el0")
299e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
300e5dd7070Spatrick   }
301e5dd7070Spatrick 
302ec727ea7Spatrick   // Enable/disable straight line speculation hardening.
303ec727ea7Spatrick   if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
304ec727ea7Spatrick     StringRef Scope = A->getValue();
305ec727ea7Spatrick     bool EnableRetBr = false;
306ec727ea7Spatrick     bool EnableBlr = false;
307a9ac8606Spatrick     bool DisableComdat = false;
308a9ac8606Spatrick     if (Scope != "none") {
309ec727ea7Spatrick       SmallVector<StringRef, 4> Opts;
310ec727ea7Spatrick       Scope.split(Opts, ",");
311ec727ea7Spatrick       for (auto Opt : Opts) {
312ec727ea7Spatrick         Opt = Opt.trim();
313a9ac8606Spatrick         if (Opt == "all") {
314a9ac8606Spatrick           EnableBlr = true;
315a9ac8606Spatrick           EnableRetBr = true;
316a9ac8606Spatrick           continue;
317a9ac8606Spatrick         }
318ec727ea7Spatrick         if (Opt == "retbr") {
319ec727ea7Spatrick           EnableRetBr = true;
320ec727ea7Spatrick           continue;
321ec727ea7Spatrick         }
322ec727ea7Spatrick         if (Opt == "blr") {
323ec727ea7Spatrick           EnableBlr = true;
324ec727ea7Spatrick           continue;
325ec727ea7Spatrick         }
326a9ac8606Spatrick         if (Opt == "comdat") {
327a9ac8606Spatrick           DisableComdat = false;
328a9ac8606Spatrick           continue;
329a9ac8606Spatrick         }
330a9ac8606Spatrick         if (Opt == "nocomdat") {
331a9ac8606Spatrick           DisableComdat = true;
332a9ac8606Spatrick           continue;
333a9ac8606Spatrick         }
334*12c85518Srobert         D.Diag(diag::err_drv_unsupported_option_argument)
335*12c85518Srobert             << A->getSpelling() << Scope;
336ec727ea7Spatrick         break;
337ec727ea7Spatrick       }
338ec727ea7Spatrick     }
339ec727ea7Spatrick 
340ec727ea7Spatrick     if (EnableRetBr)
341ec727ea7Spatrick       Features.push_back("+harden-sls-retbr");
342ec727ea7Spatrick     if (EnableBlr)
343ec727ea7Spatrick       Features.push_back("+harden-sls-blr");
344a9ac8606Spatrick     if (DisableComdat) {
345a9ac8606Spatrick       Features.push_back("+harden-sls-nocomdat");
346a9ac8606Spatrick     }
347ec727ea7Spatrick   }
348ec727ea7Spatrick 
349e5dd7070Spatrick   // En/disable crc
350e5dd7070Spatrick   if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
351e5dd7070Spatrick     if (A->getOption().matches(options::OPT_mcrc))
352e5dd7070Spatrick       Features.push_back("+crc");
353e5dd7070Spatrick     else
354e5dd7070Spatrick       Features.push_back("-crc");
355e5dd7070Spatrick   }
356e5dd7070Spatrick 
357*12c85518Srobert   int V8Version = -1;
358*12c85518Srobert   int V9Version = -1;
359*12c85518Srobert   bool HasNoSM4 = false;
360*12c85518Srobert   bool HasNoSHA3 = false;
361*12c85518Srobert   bool HasNoSHA2 = false;
362*12c85518Srobert   bool HasNoAES = false;
363*12c85518Srobert   bool HasSM4 = false;
364*12c85518Srobert   bool HasSHA3 = false;
365*12c85518Srobert   bool HasSHA2 = false;
366*12c85518Srobert   bool HasAES = false;
367*12c85518Srobert   bool HasCrypto = false;
368*12c85518Srobert   bool HasNoCrypto = false;
369*12c85518Srobert   int FullFP16Pos = -1;
370*12c85518Srobert   int NoFullFP16Pos = -1;
371*12c85518Srobert   int FP16FMLPos = -1;
372*12c85518Srobert   int NoFP16FMLPos = -1;
373*12c85518Srobert   int ArchFeatPos = -1;
374*12c85518Srobert 
375*12c85518Srobert   for (auto I = Features.begin(), E = Features.end(); I != E; I++) {
376*12c85518Srobert     if (*I == "+v8a")   V8Version = 0;
377*12c85518Srobert     else if (*I == "+v8.1a") V8Version = 1;
378*12c85518Srobert     else if (*I == "+v8.2a") V8Version = 2;
379*12c85518Srobert     else if (*I == "+v8.3a") V8Version = 3;
380*12c85518Srobert     else if (*I == "+v8.4a") V8Version = 4;
381*12c85518Srobert     else if (*I == "+v8.5a") V8Version = 5;
382*12c85518Srobert     else if (*I == "+v8.6a") V8Version = 6;
383*12c85518Srobert     else if (*I == "+v8.7a") V8Version = 7;
384*12c85518Srobert     else if (*I == "+v8.8a") V8Version = 8;
385*12c85518Srobert     else if (*I == "+v8.9a") V8Version = 9;
386*12c85518Srobert     else if (*I == "+v9a")   V9Version = 0;
387*12c85518Srobert     else if (*I == "+v9.1a") V9Version = 1;
388*12c85518Srobert     else if (*I == "+v9.2a") V9Version = 2;
389*12c85518Srobert     else if (*I == "+v9.3a") V9Version = 3;
390*12c85518Srobert     else if (*I == "+v9.4a") V9Version = 4;
391*12c85518Srobert     else if (*I == "+sm4")  HasSM4 = true;
392*12c85518Srobert     else if (*I == "+sha3") HasSHA3 = true;
393*12c85518Srobert     else if (*I == "+sha2") HasSHA2 = true;
394*12c85518Srobert     else if (*I == "+aes")  HasAES = true;
395*12c85518Srobert     else if (*I == "-sm4")  HasNoSM4 = true;
396*12c85518Srobert     else if (*I == "-sha3") HasNoSHA3 = true;
397*12c85518Srobert     else if (*I == "-sha2") HasNoSHA2 = true;
398*12c85518Srobert     else if (*I == "-aes")  HasNoAES = true;
399*12c85518Srobert     else if (*I == "+fp16fml")  FP16FMLPos = I - Features.begin();
400*12c85518Srobert     else if (*I == "-fp16fml")  NoFP16FMLPos = I - Features.begin();
401*12c85518Srobert     else if (*I == "-fullfp16") NoFullFP16Pos = I - Features.begin();
402*12c85518Srobert     else if (*I == "+fullfp16") FullFP16Pos = I - Features.begin();
403*12c85518Srobert     // Whichever option comes after (right-most option) will win
404*12c85518Srobert     else if (*I == "+crypto") {
405*12c85518Srobert       HasCrypto = true;
406*12c85518Srobert       HasNoCrypto = false;
407*12c85518Srobert     } else if (*I == "-crypto") {
408*12c85518Srobert       HasCrypto = false;
409*12c85518Srobert       HasNoCrypto = true;
410*12c85518Srobert     }
411*12c85518Srobert     // Register the iterator position if this is an architecture feature
412*12c85518Srobert     if (ArchFeatPos == -1 && (V8Version != -1 || V9Version != -1))
413*12c85518Srobert       ArchFeatPos = I - Features.begin();
414*12c85518Srobert   }
415*12c85518Srobert 
416e5dd7070Spatrick   // Handle (arch-dependent) fp16fml/fullfp16 relationship.
417e5dd7070Spatrick   // FIXME: this fp16fml option handling will be reimplemented after the
418e5dd7070Spatrick   // TargetParser rewrite.
419*12c85518Srobert   if (V8Version >= 4) {
420*12c85518Srobert     // "-fullfp16" "+fullfp16" && "+fp16fml" "+fullfp16" && no "+fullfp16" "-fp16fml" = "+fp16fml"
421*12c85518Srobert     if (FullFP16Pos > NoFullFP16Pos && FullFP16Pos > FP16FMLPos && FullFP16Pos > NoFP16FMLPos)
422e5dd7070Spatrick       // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml.
423e5dd7070Spatrick       // Only append the +fp16fml if there is no -fp16fml after the +fullfp16.
424e5dd7070Spatrick       Features.push_back("+fp16fml");
425e5dd7070Spatrick     else
426e5dd7070Spatrick       goto fp16_fml_fallthrough;
427e5dd7070Spatrick   } else {
428e5dd7070Spatrick fp16_fml_fallthrough:
429e5dd7070Spatrick     // In both of these cases, putting the 'other' feature on the end of the vector will
430e5dd7070Spatrick     // result in the same effect as placing it immediately after the current feature.
431*12c85518Srobert     // "+fp16fml"  "-fullfp16" = "-fp16fml"
432*12c85518Srobert     if (NoFullFP16Pos > FP16FMLPos)
433e5dd7070Spatrick       Features.push_back("-fp16fml");
434*12c85518Srobert     // "-fullfp16" "+fp16fml" = "+fullfp16"
435*12c85518Srobert     else if (NoFullFP16Pos < FP16FMLPos)
436e5dd7070Spatrick       Features.push_back("+fullfp16");
437e5dd7070Spatrick   }
438e5dd7070Spatrick 
439e5dd7070Spatrick   // FIXME: this needs reimplementation too after the TargetParser rewrite
440e5dd7070Spatrick   //
441e5dd7070Spatrick   // Context sensitive meaning of Crypto:
442e5dd7070Spatrick   // 1) For Arch >= ARMv8.4a:  crypto = sm4 + sha3 + sha2 + aes
443e5dd7070Spatrick   // 2) For Arch <= ARMv8.3a:  crypto = sha2 + aes
444*12c85518Srobert   if (V8Version >= 4 || V9Version >= 0) {
445*12c85518Srobert     if (HasCrypto && !HasNoCrypto) {
446e5dd7070Spatrick       // Check if we have NOT disabled an algorithm with something like:
447e5dd7070Spatrick       //   +crypto, -algorithm
448e5dd7070Spatrick       // And if "-algorithm" does not occur, we enable that crypto algorithm.
449*12c85518Srobert       if (!HasNoSM4)
450e5dd7070Spatrick         Features.push_back("+sm4");
451*12c85518Srobert       if (!HasNoSHA3)
452e5dd7070Spatrick         Features.push_back("+sha3");
453*12c85518Srobert       if (!HasNoSHA2)
454e5dd7070Spatrick         Features.push_back("+sha2");
455*12c85518Srobert       if (!HasNoAES)
456e5dd7070Spatrick         Features.push_back("+aes");
457e5dd7070Spatrick     } else if (HasNoCrypto) {
458e5dd7070Spatrick       // Check if we have NOT enabled a crypto algorithm with something like:
459e5dd7070Spatrick       //   -crypto, +algorithm
460e5dd7070Spatrick       // And if "+algorithm" does not occur, we disable that crypto algorithm.
461e5dd7070Spatrick       if (!HasSM4)
462e5dd7070Spatrick         Features.push_back("-sm4");
463e5dd7070Spatrick       if (!HasSHA3)
464e5dd7070Spatrick         Features.push_back("-sha3");
465e5dd7070Spatrick       if (!HasSHA2)
466e5dd7070Spatrick         Features.push_back("-sha2");
467e5dd7070Spatrick       if (!HasAES)
468e5dd7070Spatrick         Features.push_back("-aes");
469e5dd7070Spatrick     }
470e5dd7070Spatrick   } else {
471*12c85518Srobert     if (HasCrypto && !HasNoCrypto) {
472*12c85518Srobert       if (!HasNoSHA2)
473e5dd7070Spatrick         Features.push_back("+sha2");
474*12c85518Srobert       if (!HasNoAES)
475e5dd7070Spatrick         Features.push_back("+aes");
476e5dd7070Spatrick     } else if (HasNoCrypto) {
477e5dd7070Spatrick       if (!HasSHA2)
478e5dd7070Spatrick         Features.push_back("-sha2");
479e5dd7070Spatrick       if (!HasAES)
480e5dd7070Spatrick         Features.push_back("-aes");
481*12c85518Srobert       if (V8Version == 2 || V8Version == 3) {
482e5dd7070Spatrick         Features.push_back("-sm4");
483e5dd7070Spatrick         Features.push_back("-sha3");
484e5dd7070Spatrick       }
485e5dd7070Spatrick     }
486e5dd7070Spatrick   }
487e5dd7070Spatrick 
488e5dd7070Spatrick   if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
489e5dd7070Spatrick                                options::OPT_munaligned_access)) {
490e5dd7070Spatrick     if (A->getOption().matches(options::OPT_mno_unaligned_access))
491e5dd7070Spatrick       Features.push_back("+strict-align");
492e5dd7070Spatrick   } else if (Triple.isOSOpenBSD())
493e5dd7070Spatrick     Features.push_back("+strict-align");
494e5dd7070Spatrick 
495e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x1))
496e5dd7070Spatrick     Features.push_back("+reserve-x1");
497e5dd7070Spatrick 
498e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x2))
499e5dd7070Spatrick     Features.push_back("+reserve-x2");
500e5dd7070Spatrick 
501e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x3))
502e5dd7070Spatrick     Features.push_back("+reserve-x3");
503e5dd7070Spatrick 
504e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x4))
505e5dd7070Spatrick     Features.push_back("+reserve-x4");
506e5dd7070Spatrick 
507e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x5))
508e5dd7070Spatrick     Features.push_back("+reserve-x5");
509e5dd7070Spatrick 
510e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x6))
511e5dd7070Spatrick     Features.push_back("+reserve-x6");
512e5dd7070Spatrick 
513e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x7))
514e5dd7070Spatrick     Features.push_back("+reserve-x7");
515e5dd7070Spatrick 
516e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x9))
517e5dd7070Spatrick     Features.push_back("+reserve-x9");
518e5dd7070Spatrick 
519e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x10))
520e5dd7070Spatrick     Features.push_back("+reserve-x10");
521e5dd7070Spatrick 
522e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x11))
523e5dd7070Spatrick     Features.push_back("+reserve-x11");
524e5dd7070Spatrick 
525e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x12))
526e5dd7070Spatrick     Features.push_back("+reserve-x12");
527e5dd7070Spatrick 
528e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x13))
529e5dd7070Spatrick     Features.push_back("+reserve-x13");
530e5dd7070Spatrick 
531e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x14))
532e5dd7070Spatrick     Features.push_back("+reserve-x14");
533e5dd7070Spatrick 
534e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x15))
535e5dd7070Spatrick     Features.push_back("+reserve-x15");
536e5dd7070Spatrick 
537e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x18))
538e5dd7070Spatrick     Features.push_back("+reserve-x18");
539e5dd7070Spatrick 
540e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x20))
541e5dd7070Spatrick     Features.push_back("+reserve-x20");
542e5dd7070Spatrick 
543e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x21))
544e5dd7070Spatrick     Features.push_back("+reserve-x21");
545e5dd7070Spatrick 
546e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x22))
547e5dd7070Spatrick     Features.push_back("+reserve-x22");
548e5dd7070Spatrick 
549e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x23))
550e5dd7070Spatrick     Features.push_back("+reserve-x23");
551e5dd7070Spatrick 
552e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x24))
553e5dd7070Spatrick     Features.push_back("+reserve-x24");
554e5dd7070Spatrick 
555e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x25))
556e5dd7070Spatrick     Features.push_back("+reserve-x25");
557e5dd7070Spatrick 
558e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x26))
559e5dd7070Spatrick     Features.push_back("+reserve-x26");
560e5dd7070Spatrick 
561e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x27))
562e5dd7070Spatrick     Features.push_back("+reserve-x27");
563e5dd7070Spatrick 
564e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x28))
565e5dd7070Spatrick     Features.push_back("+reserve-x28");
566e5dd7070Spatrick 
567ec727ea7Spatrick   if (Args.hasArg(options::OPT_ffixed_x30))
568ec727ea7Spatrick     Features.push_back("+reserve-x30");
569ec727ea7Spatrick 
570e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x8))
571e5dd7070Spatrick     Features.push_back("+call-saved-x8");
572e5dd7070Spatrick 
573e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x9))
574e5dd7070Spatrick     Features.push_back("+call-saved-x9");
575e5dd7070Spatrick 
576e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x10))
577e5dd7070Spatrick     Features.push_back("+call-saved-x10");
578e5dd7070Spatrick 
579e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x11))
580e5dd7070Spatrick     Features.push_back("+call-saved-x11");
581e5dd7070Spatrick 
582e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x12))
583e5dd7070Spatrick     Features.push_back("+call-saved-x12");
584e5dd7070Spatrick 
585e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x13))
586e5dd7070Spatrick     Features.push_back("+call-saved-x13");
587e5dd7070Spatrick 
588e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x14))
589e5dd7070Spatrick     Features.push_back("+call-saved-x14");
590e5dd7070Spatrick 
591e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x15))
592e5dd7070Spatrick     Features.push_back("+call-saved-x15");
593e5dd7070Spatrick 
594e5dd7070Spatrick   if (Args.hasArg(options::OPT_fcall_saved_x18))
595e5dd7070Spatrick     Features.push_back("+call-saved-x18");
596e5dd7070Spatrick 
597e5dd7070Spatrick   if (Args.hasArg(options::OPT_mno_neg_immediates))
598e5dd7070Spatrick     Features.push_back("+no-neg-immediates");
599*12c85518Srobert 
600*12c85518Srobert   if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
601*12c85518Srobert                                options::OPT_mno_fix_cortex_a53_835769)) {
602*12c85518Srobert     if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
603*12c85518Srobert       Features.push_back("+fix-cortex-a53-835769");
604*12c85518Srobert     else
605*12c85518Srobert       Features.push_back("-fix-cortex-a53-835769");
606*12c85518Srobert   } else if (Triple.isAndroid()) {
607*12c85518Srobert     // Enabled A53 errata (835769) workaround by default on android
608*12c85518Srobert     Features.push_back("+fix-cortex-a53-835769");
609*12c85518Srobert   } else if (Triple.isOSFuchsia()) {
610*12c85518Srobert     std::string CPU = getCPUName(D, Args, Triple);
611*12c85518Srobert     if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
612*12c85518Srobert       Features.push_back("+fix-cortex-a53-835769");
613*12c85518Srobert   }
614*12c85518Srobert 
615*12c85518Srobert   if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
616*12c85518Srobert     Features.push_back("+no-bti-at-return-twice");
617e5dd7070Spatrick }
618