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