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