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