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