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