1 //===--- AArch64.cpp - Implement AArch64 target feature support -----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements AArch64 TargetInfo objects.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "AArch64.h"
15 #include "clang/Basic/TargetBuiltins.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/StringExtras.h"
19 
20 using namespace clang;
21 using namespace clang::targets;
22 
23 const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
24 #define BUILTIN(ID, TYPE, ATTRS)                                               \
25    {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
26 #include "clang/Basic/BuiltinsNEON.def"
27 
28 #define BUILTIN(ID, TYPE, ATTRS)                                               \
29    {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
30 #include "clang/Basic/BuiltinsAArch64.def"
31 };
32 
33 AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
34                                      const TargetOptions &Opts)
35     : TargetInfo(Triple), ABI("aapcs") {
36   if (getTriple().getOS() == llvm::Triple::NetBSD ||
37       getTriple().getOS() == llvm::Triple::OpenBSD) {
38     // NetBSD apparently prefers consistency across ARM targets to
39     // consistency across 64-bit targets.
40     Int64Type = SignedLongLong;
41     IntMaxType = SignedLongLong;
42   } else {
43     if (!getTriple().isOSDarwin())
44       WCharType = UnsignedInt;
45 
46     Int64Type = SignedLong;
47     IntMaxType = SignedLong;
48   }
49 
50 
51   LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
52   MaxVectorAlign = 128;
53   MaxAtomicInlineWidth = 128;
54   MaxAtomicPromoteWidth = 128;
55 
56   LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
57   LongDoubleFormat = &llvm::APFloat::IEEEquad();
58 
59   // Make __builtin_ms_va_list available.
60   HasBuiltinMSVaList = true;
61 
62   // {} in inline assembly are neon specifiers, not assembly variant
63   // specifiers.
64   NoAsmVariants = true;
65 
66   // AAPCS gives rules for bitfields. 7.1.7 says: "The container type
67   // contributes to the alignment of the containing aggregate in the same way
68   // a plain (non bit-field) member of that type would, without exception for
69   // zero-sized or anonymous bit-fields."
70   assert(UseBitFieldTypeAlignment && "bitfields affect type alignment");
71   UseZeroLengthBitfieldAlignment = true;
72 
73   // AArch64 targets default to using the ARM C++ ABI.
74   TheCXXABI.set(TargetCXXABI::GenericAArch64);
75 
76   if (Triple.getOS() == llvm::Triple::Linux)
77     this->MCountName = "\01_mcount";
78   else if (Triple.getOS() == llvm::Triple::UnknownOS)
79     this->MCountName =
80         Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount";
81 }
82 
83 StringRef AArch64TargetInfo::getABI() const { return ABI; }
84 
85 bool AArch64TargetInfo::setABI(const std::string &Name) {
86   if (Name != "aapcs" && Name != "darwinpcs")
87     return false;
88 
89   ABI = Name;
90   return true;
91 }
92 
93 bool AArch64TargetInfo::isValidCPUName(StringRef Name) const {
94   return Name == "generic" ||
95          llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID;
96 }
97 
98 bool AArch64TargetInfo::setCPU(const std::string &Name) {
99   return isValidCPUName(Name);
100 }
101 
102 void AArch64TargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts,
103                                                 MacroBuilder &Builder) const {
104   Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
105 }
106 
107 void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts,
108                                                 MacroBuilder &Builder) const {
109   // Also include the ARMv8.1 defines
110   getTargetDefinesARMV81A(Opts, Builder);
111 }
112 
113 void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
114                                          MacroBuilder &Builder) const {
115   // Target identification.
116   Builder.defineMacro("__aarch64__");
117   // For bare-metal none-eabi.
118   if (getTriple().getOS() == llvm::Triple::UnknownOS &&
119       (getTriple().getEnvironment() == llvm::Triple::EABI ||
120        getTriple().getEnvironment() == llvm::Triple::EABIHF))
121     Builder.defineMacro("__ELF__");
122 
123   // Target properties.
124   if (!getTriple().isOSWindows()) {
125     Builder.defineMacro("_LP64");
126     Builder.defineMacro("__LP64__");
127   }
128 
129   // ACLE predefines. Many can only have one possible value on v8 AArch64.
130   Builder.defineMacro("__ARM_ACLE", "200");
131   Builder.defineMacro("__ARM_ARCH", "8");
132   Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'");
133 
134   Builder.defineMacro("__ARM_64BIT_STATE", "1");
135   Builder.defineMacro("__ARM_PCS_AAPCS64", "1");
136   Builder.defineMacro("__ARM_ARCH_ISA_A64", "1");
137 
138   Builder.defineMacro("__ARM_FEATURE_CLZ", "1");
139   Builder.defineMacro("__ARM_FEATURE_FMA", "1");
140   Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF");
141   Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE
142   Builder.defineMacro("__ARM_FEATURE_DIV");       // For backwards compatibility
143   Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
144   Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1");
145 
146   Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
147 
148   // 0xe implies support for half, single and double precision operations.
149   Builder.defineMacro("__ARM_FP", "0xE");
150 
151   // PCS specifies this for SysV variants, which is all we support. Other ABIs
152   // may choose __ARM_FP16_FORMAT_ALTERNATIVE.
153   Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
154   Builder.defineMacro("__ARM_FP16_ARGS", "1");
155 
156   if (Opts.UnsafeFPMath)
157     Builder.defineMacro("__ARM_FP_FAST", "1");
158 
159   Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
160                       llvm::utostr(Opts.WCharSize ? Opts.WCharSize : 4));
161 
162   Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4");
163 
164   if (FPU & NeonMode) {
165     Builder.defineMacro("__ARM_NEON", "1");
166     // 64-bit NEON supports half, single and double precision operations.
167     Builder.defineMacro("__ARM_NEON_FP", "0xE");
168   }
169 
170   if (FPU & SveMode)
171     Builder.defineMacro("__ARM_FEATURE_SVE", "1");
172 
173   if (CRC)
174     Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
175 
176   if (Crypto)
177     Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
178 
179   if (Unaligned)
180     Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
181 
182   switch (ArchKind) {
183   default:
184     break;
185   case llvm::AArch64::ArchKind::ARMV8_1A:
186     getTargetDefinesARMV81A(Opts, Builder);
187     break;
188   case llvm::AArch64::ArchKind::ARMV8_2A:
189     getTargetDefinesARMV82A(Opts, Builder);
190     break;
191   }
192 
193   // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
194   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
195   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
196   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
197   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
198 }
199 
200 ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const {
201   return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin -
202                                              Builtin::FirstTSBuiltin);
203 }
204 
205 bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
206   return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" ||
207          (Feature == "neon" && (FPU & NeonMode)) ||
208          (Feature == "sve" && (FPU & SveMode));
209 }
210 
211 bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
212                                              DiagnosticsEngine &Diags) {
213   FPU = FPUMode;
214   CRC = 0;
215   Crypto = 0;
216   Unaligned = 1;
217   HasFullFP16 = 0;
218   ArchKind = llvm::AArch64::ArchKind::ARMV8A;
219 
220   for (const auto &Feature : Features) {
221     if (Feature == "+neon")
222       FPU |= NeonMode;
223     if (Feature == "+sve")
224       FPU |= SveMode;
225     if (Feature == "+crc")
226       CRC = 1;
227     if (Feature == "+crypto")
228       Crypto = 1;
229     if (Feature == "+strict-align")
230       Unaligned = 0;
231     if (Feature == "+v8.1a")
232       ArchKind = llvm::AArch64::ArchKind::ARMV8_1A;
233     if (Feature == "+v8.2a")
234       ArchKind = llvm::AArch64::ArchKind::ARMV8_2A;
235     if (Feature == "+fullfp16")
236       HasFullFP16 = 1;
237   }
238 
239   setDataLayout();
240 
241   return true;
242 }
243 
244 TargetInfo::CallingConvCheckResult
245 AArch64TargetInfo::checkCallingConvention(CallingConv CC) const {
246   switch (CC) {
247   case CC_C:
248   case CC_Swift:
249   case CC_PreserveMost:
250   case CC_PreserveAll:
251   case CC_OpenCLKernel:
252   case CC_Win64:
253     return CCCR_OK;
254   default:
255     return CCCR_Warning;
256   }
257 }
258 
259 bool AArch64TargetInfo::isCLZForZeroUndef() const { return false; }
260 
261 TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const {
262   return TargetInfo::AArch64ABIBuiltinVaList;
263 }
264 
265 const char *const AArch64TargetInfo::GCCRegNames[] = {
266     // 32-bit Integer registers
267     "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11",
268     "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22",
269     "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp",
270 
271     // 64-bit Integer registers
272     "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11",
273     "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22",
274     "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp",
275 
276     // 32-bit floating point regsisters
277     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
278     "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22",
279     "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
280 
281     // 64-bit floating point regsisters
282     "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11",
283     "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22",
284     "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
285 
286     // Vector registers
287     "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
288     "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
289     "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
290 };
291 
292 ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const {
293   return llvm::makeArrayRef(GCCRegNames);
294 }
295 
296 const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
297     {{"w31"}, "wsp"}, {{"x29"}, "fp"}, {{"x30"}, "lr"}, {{"x31"}, "sp"},
298     // The S/D/Q and W/X registers overlap, but aren't really aliases; we
299     // don't want to substitute one of these for a different-sized one.
300 };
301 
302 ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const {
303   return llvm::makeArrayRef(GCCRegAliases);
304 }
305 
306 bool AArch64TargetInfo::validateAsmConstraint(
307     const char *&Name, TargetInfo::ConstraintInfo &Info) const {
308   switch (*Name) {
309   default:
310     return false;
311   case 'w': // Floating point and SIMD registers (V0-V31)
312     Info.setAllowsRegister();
313     return true;
314   case 'I': // Constant that can be used with an ADD instruction
315   case 'J': // Constant that can be used with a SUB instruction
316   case 'K': // Constant that can be used with a 32-bit logical instruction
317   case 'L': // Constant that can be used with a 64-bit logical instruction
318   case 'M': // Constant that can be used as a 32-bit MOV immediate
319   case 'N': // Constant that can be used as a 64-bit MOV immediate
320   case 'Y': // Floating point constant zero
321   case 'Z': // Integer constant zero
322     return true;
323   case 'Q': // A memory reference with base register and no offset
324     Info.setAllowsMemory();
325     return true;
326   case 'S': // A symbolic address
327     Info.setAllowsRegister();
328     return true;
329   case 'U':
330     // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes.
331     // Utf: A memory address suitable for ldp/stp in TF mode.
332     // Usa: An absolute symbolic address.
333     // Ush: The high part (bits 32:12) of a pc-relative symbolic address.
334     llvm_unreachable("FIXME: Unimplemented support for U* constraints.");
335   case 'z': // Zero register, wzr or xzr
336     Info.setAllowsRegister();
337     return true;
338   case 'x': // Floating point and SIMD registers (V0-V15)
339     Info.setAllowsRegister();
340     return true;
341   }
342   return false;
343 }
344 
345 bool AArch64TargetInfo::validateConstraintModifier(
346     StringRef Constraint, char Modifier, unsigned Size,
347     std::string &SuggestedModifier) const {
348   // Strip off constraint modifiers.
349   while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
350     Constraint = Constraint.substr(1);
351 
352   switch (Constraint[0]) {
353   default:
354     return true;
355   case 'z':
356   case 'r': {
357     switch (Modifier) {
358     case 'x':
359     case 'w':
360       // For now assume that the person knows what they're
361       // doing with the modifier.
362       return true;
363     default:
364       // By default an 'r' constraint will be in the 'x'
365       // registers.
366       if (Size == 64)
367         return true;
368 
369       SuggestedModifier = "w";
370       return false;
371     }
372   }
373   }
374 }
375 
376 const char *AArch64TargetInfo::getClobbers() const { return ""; }
377 
378 int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
379   if (RegNo == 0)
380     return 0;
381   if (RegNo == 1)
382     return 1;
383   return -1;
384 }
385 
386 AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple,
387                                          const TargetOptions &Opts)
388     : AArch64TargetInfo(Triple, Opts) {}
389 
390 void AArch64leTargetInfo::setDataLayout() {
391   if (getTriple().isOSBinFormatMachO())
392     resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128");
393   else
394     resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
395 }
396 
397 void AArch64leTargetInfo::getTargetDefines(const LangOptions &Opts,
398                                            MacroBuilder &Builder) const {
399   Builder.defineMacro("__AARCH64EL__");
400   AArch64TargetInfo::getTargetDefines(Opts, Builder);
401 }
402 
403 AArch64beTargetInfo::AArch64beTargetInfo(const llvm::Triple &Triple,
404                                          const TargetOptions &Opts)
405     : AArch64TargetInfo(Triple, Opts) {}
406 
407 void AArch64beTargetInfo::getTargetDefines(const LangOptions &Opts,
408                                            MacroBuilder &Builder) const {
409   Builder.defineMacro("__AARCH64EB__");
410   Builder.defineMacro("__AARCH_BIG_ENDIAN");
411   Builder.defineMacro("__ARM_BIG_ENDIAN");
412   AArch64TargetInfo::getTargetDefines(Opts, Builder);
413 }
414 
415 void AArch64beTargetInfo::setDataLayout() {
416   assert(!getTriple().isOSBinFormatMachO());
417   resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
418 }
419 
420 WindowsARM64TargetInfo::WindowsARM64TargetInfo(const llvm::Triple &Triple,
421                                                const TargetOptions &Opts)
422     : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) {
423 
424   // This is an LLP64 platform.
425   // int:4, long:4, long long:8, long double:8.
426   IntWidth = IntAlign = 32;
427   LongWidth = LongAlign = 32;
428   DoubleAlign = LongLongAlign = 64;
429   LongDoubleWidth = LongDoubleAlign = 64;
430   LongDoubleFormat = &llvm::APFloat::IEEEdouble();
431   IntMaxType = SignedLongLong;
432   Int64Type = SignedLongLong;
433   SizeType = UnsignedLongLong;
434   PtrDiffType = SignedLongLong;
435   IntPtrType = SignedLongLong;
436 }
437 
438 void WindowsARM64TargetInfo::setDataLayout() {
439   resetDataLayout("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128");
440 }
441 
442 TargetInfo::BuiltinVaListKind
443 WindowsARM64TargetInfo::getBuiltinVaListKind() const {
444   return TargetInfo::CharPtrBuiltinVaList;
445 }
446 
447 TargetInfo::CallingConvCheckResult
448 WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const {
449   switch (CC) {
450   case CC_X86StdCall:
451   case CC_X86ThisCall:
452   case CC_X86FastCall:
453   case CC_X86VectorCall:
454     return CCCR_Ignore;
455   case CC_C:
456   case CC_OpenCLKernel:
457   case CC_PreserveMost:
458   case CC_PreserveAll:
459   case CC_Win64:
460     return CCCR_OK;
461   default:
462     return CCCR_Warning;
463   }
464 }
465 
466 MicrosoftARM64TargetInfo::MicrosoftARM64TargetInfo(const llvm::Triple &Triple,
467                                                    const TargetOptions &Opts)
468     : WindowsARM64TargetInfo(Triple, Opts) {
469   TheCXXABI.set(TargetCXXABI::Microsoft);
470 }
471 
472 void MicrosoftARM64TargetInfo::getVisualStudioDefines(
473     const LangOptions &Opts, MacroBuilder &Builder) const {
474   WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts, Builder);
475   Builder.defineMacro("_WIN32", "1");
476   Builder.defineMacro("_WIN64", "1");
477   Builder.defineMacro("_M_ARM64", "1");
478 }
479 
480 void MicrosoftARM64TargetInfo::getTargetDefines(const LangOptions &Opts,
481                                                 MacroBuilder &Builder) const {
482   WindowsTargetInfo::getTargetDefines(Opts, Builder);
483   getVisualStudioDefines(Opts, Builder);
484 }
485 
486 MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple,
487                                            const TargetOptions &Opts)
488     : WindowsARM64TargetInfo(Triple, Opts) {
489   TheCXXABI.set(TargetCXXABI::GenericAArch64);
490 }
491 
492 void MinGWARM64TargetInfo::getTargetDefines(const LangOptions &Opts,
493                                             MacroBuilder &Builder) const {
494   WindowsTargetInfo::getTargetDefines(Opts, Builder);
495   Builder.defineMacro("_WIN32", "1");
496   Builder.defineMacro("_WIN64", "1");
497   Builder.defineMacro("WIN32", "1");
498   Builder.defineMacro("WIN64", "1");
499   addMinGWDefines(Opts, Builder);
500 }
501 
502 
503 DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple,
504                                                  const TargetOptions &Opts)
505     : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) {
506   Int64Type = SignedLongLong;
507   UseSignedCharForObjCBool = false;
508 
509   LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64;
510   LongDoubleFormat = &llvm::APFloat::IEEEdouble();
511 
512   TheCXXABI.set(TargetCXXABI::iOS64);
513 }
514 
515 void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts,
516                                            const llvm::Triple &Triple,
517                                            MacroBuilder &Builder) const {
518   Builder.defineMacro("__AARCH64_SIMD__");
519   Builder.defineMacro("__ARM64_ARCH_8__");
520   Builder.defineMacro("__ARM_NEON__");
521   Builder.defineMacro("__LITTLE_ENDIAN__");
522   Builder.defineMacro("__REGISTER_PREFIX__", "");
523   Builder.defineMacro("__arm64", "1");
524   Builder.defineMacro("__arm64__", "1");
525 
526   getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
527 }
528 
529 TargetInfo::BuiltinVaListKind
530 DarwinAArch64TargetInfo::getBuiltinVaListKind() const {
531   return TargetInfo::CharPtrBuiltinVaList;
532 }
533 
534 // 64-bit RenderScript is aarch64
535 RenderScript64TargetInfo::RenderScript64TargetInfo(const llvm::Triple &Triple,
536                                                    const TargetOptions &Opts)
537     : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(),
538                                        Triple.getOSName(),
539                                        Triple.getEnvironmentName()),
540                           Opts) {
541   IsRenderScriptTarget = true;
542 }
543 
544 void RenderScript64TargetInfo::getTargetDefines(const LangOptions &Opts,
545                                                 MacroBuilder &Builder) const {
546   Builder.defineMacro("__RENDERSCRIPT__");
547   AArch64leTargetInfo::getTargetDefines(Opts, Builder);
548 }
549