1//===--- AArch64.cpp - AArch64 (not ARM) Helpers for Tools ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "AArch64.h"
10#include "clang/Driver/Driver.h"
11#include "clang/Driver/DriverDiagnostic.h"
12#include "clang/Driver/Options.h"
13#include "llvm/Option/ArgList.h"
14#include "llvm/Support/TargetParser.h"
15#include "llvm/Support/Host.h"
16
17using namespace clang::driver;
18using namespace clang::driver::tools;
19using namespace clang;
20using namespace llvm::opt;
21
22/// \returns true if the given triple can determine the default CPU type even
23/// if -arch is not specified.
24static bool isCPUDeterminedByTriple(const llvm::Triple &Triple) {
25  return Triple.isOSDarwin();
26}
27
28/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
29/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is
30/// provided, or to nullptr otherwise.
31std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
32                                         const llvm::Triple &Triple, Arg *&A) {
33  std::string CPU;
34  // If we have -mcpu, use that.
35  if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
36    StringRef Mcpu = A->getValue();
37    CPU = Mcpu.split("+").first.lower();
38  }
39
40  // Handle CPU name is 'native'.
41  if (CPU == "native")
42    return llvm::sys::getHostCPUName();
43  else if (CPU.size())
44    return CPU;
45
46  // Make sure we pick the appropriate Apple CPU if -arch is used or when
47  // targetting a Darwin OS.
48  if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin())
49    return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4"
50                                                        : "apple-a7";
51
52  return "generic";
53}
54
55// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
56static bool DecodeAArch64Features(const Driver &D, StringRef text,
57                                  std::vector<StringRef> &Features) {
58  SmallVector<StringRef, 8> Split;
59  text.split(Split, StringRef("+"), -1, false);
60
61  for (StringRef Feature : Split) {
62    StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
63    if (!FeatureName.empty())
64      Features.push_back(FeatureName);
65    else if (Feature == "neon" || Feature == "noneon")
66      D.Diag(clang::diag::err_drv_no_neon_modifier);
67    else
68      return false;
69  }
70  return true;
71}
72
73// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
74// decode CPU and feature.
75static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
76                              std::vector<StringRef> &Features) {
77  std::pair<StringRef, StringRef> Split = Mcpu.split("+");
78  CPU = Split.first;
79
80  if (CPU == "native")
81    CPU = llvm::sys::getHostCPUName();
82
83  if (CPU == "generic") {
84    Features.push_back("+neon");
85  } else {
86    llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU);
87    if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
88      return false;
89
90    unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind);
91    if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
92      return false;
93   }
94
95  if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
96    return false;
97
98  return true;
99}
100
101static bool
102getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
103                                const ArgList &Args,
104                                std::vector<StringRef> &Features) {
105  std::string MarchLowerCase = March.lower();
106  std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
107
108  llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first);
109  if (ArchKind == llvm::AArch64::ArchKind::INVALID ||
110      !llvm::AArch64::getArchFeatures(ArchKind, Features) ||
111      (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)))
112    return false;
113
114  return true;
115}
116
117static bool
118getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
119                               const ArgList &Args,
120                               std::vector<StringRef> &Features) {
121  StringRef CPU;
122  std::string McpuLowerCase = Mcpu.lower();
123  if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
124    return false;
125
126  return true;
127}
128
129static bool
130getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
131                                     const ArgList &Args,
132                                     std::vector<StringRef> &Features) {
133  std::string MtuneLowerCase = Mtune.lower();
134  // Check CPU name is valid
135  std::vector<StringRef> MtuneFeatures;
136  StringRef Tune;
137  if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures))
138    return false;
139
140  // Handle CPU name is 'native'.
141  if (MtuneLowerCase == "native")
142    MtuneLowerCase = llvm::sys::getHostCPUName();
143  if (MtuneLowerCase == "cyclone" || MtuneLowerCase.find("apple") == 0) {
144    Features.push_back("+zcm");
145    Features.push_back("+zcz");
146  }
147  return true;
148}
149
150static bool
151getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
152                                    const ArgList &Args,
153                                    std::vector<StringRef> &Features) {
154  StringRef CPU;
155  std::vector<StringRef> DecodedFeature;
156  std::string McpuLowerCase = Mcpu.lower();
157  if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
158    return false;
159
160  return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
161}
162
163void aarch64::getAArch64TargetFeatures(const Driver &D,
164                                       const llvm::Triple &Triple,
165                                       const ArgList &Args,
166                                       std::vector<StringRef> &Features) {
167  Arg *A;
168  bool success = true;
169  // Enable NEON by default.
170  Features.push_back("+neon");
171  if ((A = Args.getLastArg(options::OPT_march_EQ)))
172    success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
173  else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
174    success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
175  else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))
176    success = getAArch64ArchFeaturesFromMcpu(
177        D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
178
179  if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
180    success =
181        getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
182  else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
183    success =
184        getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
185  else if (success &&
186           (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)))
187    success = getAArch64MicroArchFeaturesFromMcpu(
188        D, getAArch64TargetCPU(Args, Triple, A), Args, Features);
189
190  if (!success)
191    D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
192
193  if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
194    Features.push_back("-fp-armv8");
195    Features.push_back("-crypto");
196    Features.push_back("-neon");
197  }
198
199  if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
200    StringRef Mtp = A->getValue();
201    if (Mtp == "el3")
202      Features.push_back("+tpidr-el3");
203    else if (Mtp == "el2")
204      Features.push_back("+tpidr-el2");
205    else if (Mtp == "el1")
206      Features.push_back("+tpidr-el1");
207    else if (Mtp != "el0")
208      D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
209  }
210
211  // En/disable crc
212  if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
213    if (A->getOption().matches(options::OPT_mcrc))
214      Features.push_back("+crc");
215    else
216      Features.push_back("-crc");
217  }
218
219  // Handle (arch-dependent) fp16fml/fullfp16 relationship.
220  // FIXME: this fp16fml option handling will be reimplemented after the
221  // TargetParser rewrite.
222  const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16");
223  const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml");
224  if (llvm::is_contained(Features, "+v8.4a")) {
225    const auto ItRFullFP16  = std::find(Features.rbegin(), Features.rend(), "+fullfp16");
226    if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) {
227      // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml.
228      // Only append the +fp16fml if there is no -fp16fml after the +fullfp16.
229      if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16)
230        Features.push_back("+fp16fml");
231    }
232    else
233      goto fp16_fml_fallthrough;
234  } else {
235fp16_fml_fallthrough:
236    // In both of these cases, putting the 'other' feature on the end of the vector will
237    // result in the same effect as placing it immediately after the current feature.
238    if (ItRNoFullFP16 < ItRFP16FML)
239      Features.push_back("-fp16fml");
240    else if (ItRNoFullFP16 > ItRFP16FML)
241      Features.push_back("+fullfp16");
242  }
243
244  // FIXME: this needs reimplementation too after the TargetParser rewrite
245  //
246  // Context sensitive meaning of Crypto:
247  // 1) For Arch >= ARMv8.4a:  crypto = sm4 + sha3 + sha2 + aes
248  // 2) For Arch <= ARMv8.3a:  crypto = sha2 + aes
249  const auto ItBegin = Features.begin();
250  const auto ItEnd = Features.end();
251  const auto ItRBegin = Features.rbegin();
252  const auto ItREnd = Features.rend();
253  const auto ItRCrypto = std::find(ItRBegin, ItREnd, "+crypto");
254  const auto ItRNoCrypto = std::find(ItRBegin, ItREnd, "-crypto");
255  const auto HasCrypto  = ItRCrypto != ItREnd;
256  const auto HasNoCrypto = ItRNoCrypto != ItREnd;
257  const ptrdiff_t PosCrypto = ItRCrypto - ItRBegin;
258  const ptrdiff_t PosNoCrypto = ItRNoCrypto - ItRBegin;
259
260  bool NoCrypto = false;
261  if (HasCrypto && HasNoCrypto) {
262    if (PosNoCrypto < PosCrypto)
263      NoCrypto = true;
264  }
265
266  if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd) {
267    if (HasCrypto && !NoCrypto) {
268      // Check if we have NOT disabled an algorithm with something like:
269      //   +crypto, -algorithm
270      // And if "-algorithm" does not occur, we enable that crypto algorithm.
271      const bool HasSM4  = (std::find(ItBegin, ItEnd, "-sm4") == ItEnd);
272      const bool HasSHA3 = (std::find(ItBegin, ItEnd, "-sha3") == ItEnd);
273      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd);
274      const bool HasAES  = (std::find(ItBegin, ItEnd, "-aes") == ItEnd);
275      if (HasSM4)
276        Features.push_back("+sm4");
277      if (HasSHA3)
278        Features.push_back("+sha3");
279      if (HasSHA2)
280        Features.push_back("+sha2");
281      if (HasAES)
282        Features.push_back("+aes");
283    } else if (HasNoCrypto) {
284      // Check if we have NOT enabled a crypto algorithm with something like:
285      //   -crypto, +algorithm
286      // And if "+algorithm" does not occur, we disable that crypto algorithm.
287      const bool HasSM4  = (std::find(ItBegin, ItEnd, "+sm4") != ItEnd);
288      const bool HasSHA3 = (std::find(ItBegin, ItEnd, "+sha3") != ItEnd);
289      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd);
290      const bool HasAES  = (std::find(ItBegin, ItEnd, "+aes") != ItEnd);
291      if (!HasSM4)
292        Features.push_back("-sm4");
293      if (!HasSHA3)
294        Features.push_back("-sha3");
295      if (!HasSHA2)
296        Features.push_back("-sha2");
297      if (!HasAES)
298        Features.push_back("-aes");
299    }
300  } else {
301    if (HasCrypto && !NoCrypto) {
302      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd);
303      const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd);
304      if (HasSHA2)
305        Features.push_back("+sha2");
306      if (HasAES)
307        Features.push_back("+aes");
308    } else if (HasNoCrypto) {
309      const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd);
310      const bool HasAES  = (std::find(ItBegin, ItEnd, "+aes") != ItEnd);
311      const bool HasV82a = (std::find(ItBegin, ItEnd, "+v8.2a") != ItEnd);
312      const bool HasV83a = (std::find(ItBegin, ItEnd, "+v8.3a") != ItEnd);
313      const bool HasV84a = (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd);
314      if (!HasSHA2)
315        Features.push_back("-sha2");
316      if (!HasAES)
317        Features.push_back("-aes");
318      if (HasV82a || HasV83a || HasV84a) {
319        Features.push_back("-sm4");
320        Features.push_back("-sha3");
321      }
322    }
323  }
324
325  if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
326                               options::OPT_munaligned_access))
327    if (A->getOption().matches(options::OPT_mno_unaligned_access))
328      Features.push_back("+strict-align");
329
330  if (Args.hasArg(options::OPT_ffixed_x1))
331    Features.push_back("+reserve-x1");
332
333  if (Args.hasArg(options::OPT_ffixed_x2))
334    Features.push_back("+reserve-x2");
335
336  if (Args.hasArg(options::OPT_ffixed_x3))
337    Features.push_back("+reserve-x3");
338
339  if (Args.hasArg(options::OPT_ffixed_x4))
340    Features.push_back("+reserve-x4");
341
342  if (Args.hasArg(options::OPT_ffixed_x5))
343    Features.push_back("+reserve-x5");
344
345  if (Args.hasArg(options::OPT_ffixed_x6))
346    Features.push_back("+reserve-x6");
347
348  if (Args.hasArg(options::OPT_ffixed_x7))
349    Features.push_back("+reserve-x7");
350
351  if (Args.hasArg(options::OPT_ffixed_x9))
352    Features.push_back("+reserve-x9");
353
354  if (Args.hasArg(options::OPT_ffixed_x10))
355    Features.push_back("+reserve-x10");
356
357  if (Args.hasArg(options::OPT_ffixed_x11))
358    Features.push_back("+reserve-x11");
359
360  if (Args.hasArg(options::OPT_ffixed_x12))
361    Features.push_back("+reserve-x12");
362
363  if (Args.hasArg(options::OPT_ffixed_x13))
364    Features.push_back("+reserve-x13");
365
366  if (Args.hasArg(options::OPT_ffixed_x14))
367    Features.push_back("+reserve-x14");
368
369  if (Args.hasArg(options::OPT_ffixed_x15))
370    Features.push_back("+reserve-x15");
371
372  if (Args.hasArg(options::OPT_ffixed_x18))
373    Features.push_back("+reserve-x18");
374
375  if (Args.hasArg(options::OPT_ffixed_x20))
376    Features.push_back("+reserve-x20");
377
378  if (Args.hasArg(options::OPT_ffixed_x21))
379    Features.push_back("+reserve-x21");
380
381  if (Args.hasArg(options::OPT_ffixed_x22))
382    Features.push_back("+reserve-x22");
383
384  if (Args.hasArg(options::OPT_ffixed_x23))
385    Features.push_back("+reserve-x23");
386
387  if (Args.hasArg(options::OPT_ffixed_x24))
388    Features.push_back("+reserve-x24");
389
390  if (Args.hasArg(options::OPT_ffixed_x25))
391    Features.push_back("+reserve-x25");
392
393  if (Args.hasArg(options::OPT_ffixed_x26))
394    Features.push_back("+reserve-x26");
395
396  if (Args.hasArg(options::OPT_ffixed_x27))
397    Features.push_back("+reserve-x27");
398
399  if (Args.hasArg(options::OPT_ffixed_x28))
400    Features.push_back("+reserve-x28");
401
402  if (Args.hasArg(options::OPT_fcall_saved_x8))
403    Features.push_back("+call-saved-x8");
404
405  if (Args.hasArg(options::OPT_fcall_saved_x9))
406    Features.push_back("+call-saved-x9");
407
408  if (Args.hasArg(options::OPT_fcall_saved_x10))
409    Features.push_back("+call-saved-x10");
410
411  if (Args.hasArg(options::OPT_fcall_saved_x11))
412    Features.push_back("+call-saved-x11");
413
414  if (Args.hasArg(options::OPT_fcall_saved_x12))
415    Features.push_back("+call-saved-x12");
416
417  if (Args.hasArg(options::OPT_fcall_saved_x13))
418    Features.push_back("+call-saved-x13");
419
420  if (Args.hasArg(options::OPT_fcall_saved_x14))
421    Features.push_back("+call-saved-x14");
422
423  if (Args.hasArg(options::OPT_fcall_saved_x15))
424    Features.push_back("+call-saved-x15");
425
426  if (Args.hasArg(options::OPT_fcall_saved_x18))
427    Features.push_back("+call-saved-x18");
428
429  if (Args.hasArg(options::OPT_mno_neg_immediates))
430    Features.push_back("+no-neg-immediates");
431}
432