| 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 | |