1//===-- AArch64MCAsmInfo.cpp - AArch64 asm properties ---------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains the declarations of the AArch64MCAsmInfo properties.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AArch64MCAsmInfo.h"
14#include "AArch64MCOptions.h"
15#include "llvm/ADT/Enum.h"
16#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCStreamer.h"
19#include "llvm/MC/MCValue.h"
20#include "llvm/TargetParser/Triple.h"
21using namespace llvm;
22
23constexpr EnumStringDef<MCAsmInfo::AtSpecifierKind> COFFAtSpecifierDefs[] = {
24 {.Names: {"IMGREL"}, .Value: MCSymbolRefExpr::VK_COFF_IMGREL32},
25 {.Names: {"PAGEOFF"}, .Value: AArch64::S_MACHO_PAGEOFF},
26};
27constexpr auto COFFAtSpecifiers = BUILD_ENUM_STRINGS(COFFAtSpecifierDefs);
28
29constexpr EnumStringDef<MCAsmInfo::AtSpecifierKind> ELFAtSpecifierDefs[] = {
30 {.Names: {"GOT"}, .Value: AArch64::S_GOT},
31};
32constexpr auto ELFAtSpecifiers = BUILD_ENUM_STRINGS(ELFAtSpecifierDefs);
33
34constexpr EnumStringDef<MCAsmInfo::AtSpecifierKind> MachOAtSpecifierDefs[] = {
35 {.Names: {"GOT"}, .Value: AArch64::S_MACHO_GOT},
36 {.Names: {"GOTPAGE"}, .Value: AArch64::S_MACHO_GOTPAGE},
37 {.Names: {"GOTPAGEOFF"}, .Value: AArch64::S_MACHO_GOTPAGEOFF},
38 {.Names: {"PAGE"}, .Value: AArch64::S_MACHO_PAGE},
39 {.Names: {"PAGEOFF"}, .Value: AArch64::S_MACHO_PAGEOFF},
40 {.Names: {"TLVP"}, .Value: AArch64::S_MACHO_TLVP},
41 {.Names: {"TLVPPAGE"}, .Value: AArch64::S_MACHO_TLVPPAGE},
42 {.Names: {"TLVPPAGEOFF"}, .Value: AArch64::S_MACHO_TLVPPAGEOFF},
43};
44constexpr auto MachOAtSpecifiers = BUILD_ENUM_STRINGS(MachOAtSpecifierDefs);
45
46StringRef AArch64::getSpecifierName(AArch64::Specifier S) {
47 // clang-format off
48 switch (static_cast<uint32_t>(S)) {
49 case AArch64::S_CALL: return "";
50 case AArch64::S_LO12: return ":lo12:";
51 case AArch64::S_ABS_G3: return ":abs_g3:";
52 case AArch64::S_ABS_G2: return ":abs_g2:";
53 case AArch64::S_ABS_G2_S: return ":abs_g2_s:";
54 case AArch64::S_ABS_G2_NC: return ":abs_g2_nc:";
55 case AArch64::S_ABS_G1: return ":abs_g1:";
56 case AArch64::S_ABS_G1_S: return ":abs_g1_s:";
57 case AArch64::S_ABS_G1_NC: return ":abs_g1_nc:";
58 case AArch64::S_ABS_G0: return ":abs_g0:";
59 case AArch64::S_ABS_G0_S: return ":abs_g0_s:";
60 case AArch64::S_ABS_G0_NC: return ":abs_g0_nc:";
61 case AArch64::S_PREL_G3: return ":prel_g3:";
62 case AArch64::S_PREL_G2: return ":prel_g2:";
63 case AArch64::S_PREL_G2_NC: return ":prel_g2_nc:";
64 case AArch64::S_PREL_G1: return ":prel_g1:";
65 case AArch64::S_PREL_G1_NC: return ":prel_g1_nc:";
66 case AArch64::S_PREL_G0: return ":prel_g0:";
67 case AArch64::S_PREL_G0_NC: return ":prel_g0_nc:";
68 case AArch64::S_DTPREL_G2: return ":dtprel_g2:";
69 case AArch64::S_DTPREL_G1: return ":dtprel_g1:";
70 case AArch64::S_DTPREL_G1_NC: return ":dtprel_g1_nc:";
71 case AArch64::S_DTPREL_G0: return ":dtprel_g0:";
72 case AArch64::S_DTPREL_G0_NC: return ":dtprel_g0_nc:";
73 case AArch64::S_DTPREL_HI12: return ":dtprel_hi12:";
74 case AArch64::S_DTPREL_LO12: return ":dtprel_lo12:";
75 case AArch64::S_DTPREL_LO12_NC: return ":dtprel_lo12_nc:";
76 case AArch64::S_TPREL_G2: return ":tprel_g2:";
77 case AArch64::S_TPREL_G1: return ":tprel_g1:";
78 case AArch64::S_TPREL_G1_NC: return ":tprel_g1_nc:";
79 case AArch64::S_TPREL_G0: return ":tprel_g0:";
80 case AArch64::S_TPREL_G0_NC: return ":tprel_g0_nc:";
81 case AArch64::S_TPREL_HI12: return ":tprel_hi12:";
82 case AArch64::S_TPREL_LO12: return ":tprel_lo12:";
83 case AArch64::S_TPREL_LO12_NC: return ":tprel_lo12_nc:";
84 case AArch64::S_TLSDESC_LO12: return ":tlsdesc_lo12:";
85 case AArch64::S_TLSDESC_AUTH_LO12: return ":tlsdesc_auth_lo12:";
86 case AArch64::S_ABS_PAGE: return "";
87 case AArch64::S_ABS_PAGE_NC: return ":pg_hi21_nc:";
88 case AArch64::S_GOT: return ":got:";
89 case AArch64::S_GOT_PAGE: return ":got:";
90 case AArch64::S_GOT_PAGE_LO15: return ":gotpage_lo15:";
91 case AArch64::S_GOT_LO12: return ":got_lo12:";
92 case AArch64::S_GOTTPREL: return ":gottprel:";
93 case AArch64::S_GOTTPREL_PAGE: return ":gottprel:";
94 case AArch64::S_GOTTPREL_LO12_NC: return ":gottprel_lo12:";
95 case AArch64::S_GOTTPREL_G1: return ":gottprel_g1:";
96 case AArch64::S_GOTTPREL_G0_NC: return ":gottprel_g0_nc:";
97 case AArch64::S_TLSDESC: return "";
98 case AArch64::S_TLSDESC_PAGE: return ":tlsdesc:";
99 case AArch64::S_TLSDESC_AUTH: return "";
100 case AArch64::S_TLSDESC_AUTH_PAGE: return ":tlsdesc_auth:";
101 case AArch64::S_SECREL_LO12: return ":secrel_lo12:";
102 case AArch64::S_SECREL_HI12: return ":secrel_hi12:";
103 case AArch64::S_GOT_AUTH: return ":got_auth:";
104 case AArch64::S_GOT_AUTH_PAGE: return ":got_auth:";
105 case AArch64::S_GOT_AUTH_LO12: return ":got_auth_lo12:";
106
107 case AArch64::S_GOTPCREL: return "%gotpcrel";
108 case AArch64::S_PLT: return "%pltpcrel";
109 case AArch64::S_DTPREL: return "%dtprel";
110 case AArch64::S_FUNCINIT: return "%funcinit";
111 default:
112 llvm_unreachable("Invalid relocation specifier");
113 }
114 // clang-format on
115}
116
117AArch64::Specifier AArch64::parsePercentSpecifierName(StringRef name) {
118 return StringSwitch<AArch64::Specifier>(name)
119 .Case(S: "pltpcrel", Value: AArch64::S_PLT)
120 .Case(S: "gotpcrel", Value: AArch64::S_GOTPCREL)
121 .Case(S: "dtprel", Value: AArch64::S_DTPREL)
122 .Case(S: "funcinit", Value: AArch64::S_FUNCINIT)
123 .Default(Value: 0);
124}
125
126static bool evaluate(const MCSpecifierExpr &Expr, MCValue &Res,
127 const MCAssembler *Asm) {
128 if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm))
129 return false;
130 Res.setSpecifier(Expr.getSpecifier());
131 return !Res.getSubSym();
132}
133
134AArch64MCAsmInfoDarwin::AArch64MCAsmInfoDarwin(bool IsILP32,
135 const MCTargetOptions &Options)
136 : MCAsmInfoDarwin(Options) {
137 // We prefer NEON instructions to be printed in the short, Apple-specific
138 // form when targeting Darwin.
139 AssemblerDialect =
140 AArch64MCOptions::Global.neon_syntax.value_or(u: AArch64::Apple);
141
142 InternalSymbolPrefix = "L";
143 SeparatorString = "%%";
144 CommentString = ";";
145 CalleeSaveStackSlotSize = 8;
146 CodePointerSize = IsILP32 ? 4 : 8;
147
148 AlignmentIsInBytes = false;
149 UsesELFSectionDirectiveForBSS = true;
150 SupportsDebugInformation = true;
151 UseDataRegionDirectives = true;
152 ExceptionsType = ExceptionHandling::DwarfCFI;
153
154 initializeAtSpecifiers(MachOAtSpecifiers);
155 UseAtForSpecifier = false;
156}
157
158const MCExpr *AArch64MCAsmInfoDarwin::getExprForPersonalitySymbol(
159 const MCSymbol *Sym, unsigned Encoding, MCStreamer &Streamer) const {
160 // On Darwin, we can reference dwarf symbols with foo@GOT-., which
161 // is an indirect pc-relative reference. The default implementation
162 // won't reference using the GOT, so we need this target-specific
163 // version.
164 MCContext &Context = Streamer.getContext();
165 const MCExpr *Res =
166 MCSymbolRefExpr::create(Symbol: Sym, specifier: AArch64::S_MACHO_GOT, Ctx&: Context);
167 MCSymbol *PCSym = Context.createTempSymbol();
168 Streamer.emitLabel(Symbol: PCSym);
169 const MCExpr *PC = MCSymbolRefExpr::create(Symbol: PCSym, Ctx&: Context);
170 return MCBinaryExpr::createSub(LHS: Res, RHS: PC, Ctx&: Context);
171}
172
173void AArch64AuthMCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const {
174 bool WrapSubExprInParens = !isa<MCSymbolRefExpr>(Val: getSubExpr());
175 if (WrapSubExprInParens)
176 OS << '(';
177 MAI->printExpr(OS, *getSubExpr());
178 if (WrapSubExprInParens)
179 OS << ')';
180
181 OS << "@AUTH(" << AArch64PACKeyIDToString(KeyID: Key) << ',' << Discriminator;
182 if (hasAddressDiversity())
183 OS << ",addr";
184 OS << ')';
185}
186
187void AArch64MCAsmInfoDarwin::printSpecifierExpr(
188 raw_ostream &OS, const MCSpecifierExpr &Expr) const {
189 if (auto *AE = dyn_cast<AArch64AuthMCExpr>(Val: &Expr))
190 return AE->print(OS, MAI: this);
191 OS << AArch64::getSpecifierName(S: Expr.getSpecifier());
192 printExpr(OS, *Expr.getSubExpr());
193}
194
195bool AArch64MCAsmInfoDarwin::evaluateAsRelocatableImpl(
196 const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const {
197 return evaluate(Expr, Res, Asm);
198}
199
200AArch64MCAsmInfoELF::AArch64MCAsmInfoELF(const Triple &T,
201 const MCTargetOptions &Options)
202 : MCAsmInfoELF(Options) {
203 if (T.getArch() == Triple::aarch64_be)
204 IsLittleEndian = false;
205
206 // We prefer NEON instructions to be printed in the generic form when
207 // targeting ELF.
208 AssemblerDialect =
209 AArch64MCOptions::Global.neon_syntax.value_or(u: AArch64::Generic);
210
211 CodePointerSize = T.getEnvironment() == Triple::GNUILP32 ? 4 : 8;
212
213 // ".comm align is in bytes but .align is pow-2."
214 AlignmentIsInBytes = false;
215
216 CommentString = "//";
217 InternalSymbolPrefix = ".L";
218
219 Data16bitsDirective = "\t.hword\t";
220 Data32bitsDirective = "\t.word\t";
221 Data64bitsDirective = "\t.xword\t";
222
223 UseDataRegionDirectives = false;
224
225 WeakRefDirective = "\t.weak\t";
226
227 SupportsDebugInformation = true;
228
229 // Exceptions handling
230 ExceptionsType = ExceptionHandling::DwarfCFI;
231
232 HasIdentDirective = true;
233
234 initializeAtSpecifiers(ELFAtSpecifiers);
235 UseAtForSpecifier = false;
236}
237
238void AArch64MCAsmInfoELF::printSpecifierExpr(
239 raw_ostream &OS, const MCSpecifierExpr &Expr) const {
240 if (auto *AE = dyn_cast<AArch64AuthMCExpr>(Val: &Expr))
241 return AE->print(OS, MAI: this);
242 auto Str = AArch64::getSpecifierName(S: Expr.getSpecifier());
243 OS << Str;
244 if (!Str.empty() && Str[0] == '%')
245 OS << '(';
246 printExpr(OS, *Expr.getSubExpr());
247 if (!Str.empty() && Str[0] == '%')
248 OS << ')';
249}
250
251bool AArch64MCAsmInfoELF::evaluateAsRelocatableImpl(
252 const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const {
253 return evaluate(Expr, Res, Asm);
254}
255
256AArch64MCAsmInfoMicrosoftCOFF::AArch64MCAsmInfoMicrosoftCOFF(
257 const MCTargetOptions &Options)
258 : MCAsmInfoMicrosoft(Options) {
259 InternalSymbolPrefix = ".L";
260
261 Data16bitsDirective = "\t.hword\t";
262 Data32bitsDirective = "\t.word\t";
263 Data64bitsDirective = "\t.xword\t";
264
265 AlignmentIsInBytes = false;
266 SupportsDebugInformation = true;
267 CodePointerSize = 8;
268
269 CommentString = "//";
270 ExceptionsType = ExceptionHandling::WinEH;
271 WinEHEncodingType = WinEH::EncodingType::Itanium;
272
273 initializeAtSpecifiers(COFFAtSpecifiers);
274}
275
276void AArch64MCAsmInfoMicrosoftCOFF::printSpecifierExpr(
277 raw_ostream &OS, const MCSpecifierExpr &Expr) const {
278 OS << AArch64::getSpecifierName(S: Expr.getSpecifier());
279 printExpr(OS, *Expr.getSubExpr());
280}
281
282bool AArch64MCAsmInfoMicrosoftCOFF::evaluateAsRelocatableImpl(
283 const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const {
284 return evaluate(Expr, Res, Asm);
285}
286
287AArch64MCAsmInfoGNUCOFF::AArch64MCAsmInfoGNUCOFF(const MCTargetOptions &Options)
288 : MCAsmInfoGNUCOFF(Options) {
289 InternalSymbolPrefix = ".L";
290
291 Data16bitsDirective = "\t.hword\t";
292 Data32bitsDirective = "\t.word\t";
293 Data64bitsDirective = "\t.xword\t";
294
295 AlignmentIsInBytes = false;
296 SupportsDebugInformation = true;
297 CodePointerSize = 8;
298
299 CommentString = "//";
300 ExceptionsType = ExceptionHandling::WinEH;
301 WinEHEncodingType = WinEH::EncodingType::Itanium;
302
303 initializeAtSpecifiers(COFFAtSpecifiers);
304}
305
306void AArch64MCAsmInfoGNUCOFF::printSpecifierExpr(
307 raw_ostream &OS, const MCSpecifierExpr &Expr) const {
308 OS << AArch64::getSpecifierName(S: Expr.getSpecifier());
309 printExpr(OS, *Expr.getSubExpr());
310}
311
312bool AArch64MCAsmInfoGNUCOFF::evaluateAsRelocatableImpl(
313 const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const {
314 return evaluate(Expr, Res, Asm);
315}
316