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