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