| 1 | //===-- PPCMCAsmInfo.cpp - PPC 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 MCAsmInfoDarwin properties. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "MCTargetDesc/PPCMCAsmInfo.h" |
| 14 | #include "llvm/MC/MCExpr.h" |
| 15 | #include "llvm/Support/raw_ostream.h" |
| 16 | #include "llvm/TargetParser/Triple.h" |
| 17 | |
| 18 | using namespace llvm; |
| 19 | |
| 20 | void PPCELFMCAsmInfo::anchor() { } |
| 21 | |
| 22 | const MCAsmInfo::AtSpecifier elfAtSpecifiers[] = { |
| 23 | {.Kind: PPC::S_DTPREL, .Name: "DTPREL" }, |
| 24 | {.Kind: PPC::S_GOT, .Name: "GOT" }, |
| 25 | {.Kind: PPC::S_GOT_HA, .Name: "got@ha" }, |
| 26 | {.Kind: PPC::S_GOT_HI, .Name: "got@h" }, |
| 27 | {.Kind: PPC::S_GOT_LO, .Name: "got@l" }, |
| 28 | {.Kind: PPC::S_HA, .Name: "ha" }, |
| 29 | {.Kind: PPC::S_HI, .Name: "h" }, |
| 30 | {.Kind: PPC::S_HIGH, .Name: "high" }, |
| 31 | {.Kind: PPC::S_HIGHA, .Name: "higha" }, |
| 32 | {.Kind: PPC::S_HIGHER, .Name: "higher" }, |
| 33 | {.Kind: PPC::S_HIGHERA, .Name: "highera" }, |
| 34 | {.Kind: PPC::S_HIGHEST, .Name: "highest" }, |
| 35 | {.Kind: PPC::S_HIGHESTA, .Name: "highesta" }, |
| 36 | {.Kind: PPC::S_LO, .Name: "l" }, |
| 37 | {.Kind: PPC::S_PCREL, .Name: "PCREL" }, |
| 38 | {.Kind: PPC::S_PLT, .Name: "PLT" }, |
| 39 | {.Kind: PPC::S_TLSGD, .Name: "tlsgd" }, |
| 40 | {.Kind: PPC::S_TLSLD, .Name: "tlsld" }, |
| 41 | {.Kind: PPC::S_TOC, .Name: "toc" }, |
| 42 | {.Kind: PPC::S_TOCBASE, .Name: "tocbase" }, |
| 43 | {.Kind: PPC::S_TOC_HA, .Name: "toc@ha" }, |
| 44 | {.Kind: PPC::S_TOC_HI, .Name: "toc@h" }, |
| 45 | {.Kind: PPC::S_TOC_LO, .Name: "toc@l" }, |
| 46 | {.Kind: PPC::S_TPREL, .Name: "TPREL" }, |
| 47 | {.Kind: PPC::S_AIX_TLSGD, .Name: "gd" }, |
| 48 | {.Kind: PPC::S_AIX_TLSGDM, .Name: "m" }, |
| 49 | {.Kind: PPC::S_AIX_TLSIE, .Name: "ie" }, |
| 50 | {.Kind: PPC::S_AIX_TLSLD, .Name: "ld" }, |
| 51 | {.Kind: PPC::S_AIX_TLSLE, .Name: "le" }, |
| 52 | {.Kind: PPC::S_AIX_TLSML, .Name: "ml" }, |
| 53 | {.Kind: PPC::S_DTPMOD, .Name: "dtpmod" }, |
| 54 | {.Kind: PPC::S_DTPREL_HA, .Name: "dtprel@ha" }, |
| 55 | {.Kind: PPC::S_DTPREL_HI, .Name: "dtprel@h" }, |
| 56 | {.Kind: PPC::S_DTPREL_HIGH, .Name: "dtprel@high" }, |
| 57 | {.Kind: PPC::S_DTPREL_HIGHA, .Name: "dtprel@higha" }, |
| 58 | {.Kind: PPC::S_DTPREL_HIGHER, .Name: "dtprel@higher" }, |
| 59 | {.Kind: PPC::S_DTPREL_HIGHERA, .Name: "dtprel@highera" }, |
| 60 | {.Kind: PPC::S_DTPREL_HIGHEST, .Name: "dtprel@highest" }, |
| 61 | {.Kind: PPC::S_DTPREL_HIGHESTA, .Name: "dtprel@highesta" }, |
| 62 | {.Kind: PPC::S_DTPREL_LO, .Name: "dtprel@l" }, |
| 63 | {.Kind: PPC::S_GOT_DTPREL, .Name: "got@dtprel" }, |
| 64 | {.Kind: PPC::S_GOT_DTPREL_HA, .Name: "got@dtprel@ha" }, |
| 65 | {.Kind: PPC::S_GOT_DTPREL_HI, .Name: "got@dtprel@h" }, |
| 66 | {.Kind: PPC::S_GOT_DTPREL_LO, .Name: "got@dtprel@l" }, |
| 67 | {.Kind: PPC::S_GOT_PCREL, .Name: "got@pcrel" }, |
| 68 | {.Kind: PPC::S_GOT_TLSGD, .Name: "got@tlsgd" }, |
| 69 | {.Kind: PPC::S_GOT_TLSGD_HA, .Name: "got@tlsgd@ha" }, |
| 70 | {.Kind: PPC::S_GOT_TLSGD_HI, .Name: "got@tlsgd@h" }, |
| 71 | {.Kind: PPC::S_GOT_TLSGD_LO, .Name: "got@tlsgd@l" }, |
| 72 | {.Kind: PPC::S_GOT_TLSGD_PCREL, .Name: "got@tlsgd@pcrel" }, |
| 73 | {.Kind: PPC::S_GOT_TLSLD, .Name: "got@tlsld" }, |
| 74 | {.Kind: PPC::S_GOT_TLSLD_HA, .Name: "got@tlsld@ha" }, |
| 75 | {.Kind: PPC::S_GOT_TLSLD_HI, .Name: "got@tlsld@h" }, |
| 76 | {.Kind: PPC::S_GOT_TLSLD_LO, .Name: "got@tlsld@l" }, |
| 77 | {.Kind: PPC::S_GOT_TLSLD_PCREL, .Name: "got@tlsld@pcrel" }, |
| 78 | {.Kind: PPC::S_GOT_TPREL, .Name: "got@tprel" }, |
| 79 | {.Kind: PPC::S_GOT_TPREL_HA, .Name: "got@tprel@ha" }, |
| 80 | {.Kind: PPC::S_GOT_TPREL_HI, .Name: "got@tprel@h" }, |
| 81 | {.Kind: PPC::S_GOT_TPREL_LO, .Name: "got@tprel@l" }, |
| 82 | {.Kind: PPC::S_GOT_TPREL_PCREL, .Name: "got@tprel@pcrel" }, |
| 83 | {.Kind: PPC::S_LOCAL, .Name: "local" }, |
| 84 | {.Kind: PPC::S_NOTOC, .Name: "notoc" }, |
| 85 | {.Kind: PPC::S_PCREL_OPT, .Name: "<<invalid>>" }, |
| 86 | {.Kind: PPC::S_TLS, .Name: "tls" }, |
| 87 | {.Kind: PPC::S_TLS_PCREL, .Name: "tls@pcrel" }, |
| 88 | {.Kind: PPC::S_TPREL_HA, .Name: "tprel@ha" }, |
| 89 | {.Kind: PPC::S_TPREL_HI, .Name: "tprel@h" }, |
| 90 | {.Kind: PPC::S_TPREL_HIGH, .Name: "tprel@high" }, |
| 91 | {.Kind: PPC::S_TPREL_HIGHA, .Name: "tprel@higha" }, |
| 92 | {.Kind: PPC::S_TPREL_HIGHER, .Name: "tprel@higher" }, |
| 93 | {.Kind: PPC::S_TPREL_HIGHERA, .Name: "tprel@highera" }, |
| 94 | {.Kind: PPC::S_TPREL_HIGHEST, .Name: "tprel@highest" }, |
| 95 | {.Kind: PPC::S_TPREL_HIGHESTA, .Name: "tprel@highesta" }, |
| 96 | {.Kind: PPC::S_TPREL_LO, .Name: "tprel@l" }, |
| 97 | }; |
| 98 | |
| 99 | const MCAsmInfo::AtSpecifier xcoffAtSpecifiers[] = { |
| 100 | // clang-format off |
| 101 | {.Kind: PPC::S_AIX_TLSGD, .Name: "gd" }, |
| 102 | {.Kind: PPC::S_AIX_TLSGDM, .Name: "m" }, |
| 103 | {.Kind: PPC::S_AIX_TLSIE, .Name: "ie" }, |
| 104 | {.Kind: PPC::S_AIX_TLSLD, .Name: "ld" }, |
| 105 | {.Kind: PPC::S_AIX_TLSLE, .Name: "le" }, |
| 106 | {.Kind: PPC::S_AIX_TLSML, .Name: "ml" }, |
| 107 | {.Kind: PPC::S_L, .Name: "l" }, |
| 108 | {.Kind: PPC::S_U, .Name: "u" }, |
| 109 | // clang-format on |
| 110 | }; |
| 111 | |
| 112 | static std::optional<int64_t> evaluateAsInt64(uint16_t specifier, |
| 113 | int64_t Value) { |
| 114 | switch (specifier) { |
| 115 | case PPC::S_LO: |
| 116 | return Value & 0xffff; |
| 117 | case PPC::S_HI: |
| 118 | return (Value >> 16) & 0xffff; |
| 119 | case PPC::S_HA: |
| 120 | return ((Value + 0x8000) >> 16) & 0xffff; |
| 121 | case PPC::S_HIGH: |
| 122 | return (Value >> 16) & 0xffff; |
| 123 | case PPC::S_HIGHA: |
| 124 | return ((Value + 0x8000) >> 16) & 0xffff; |
| 125 | case PPC::S_HIGHER: |
| 126 | return (Value >> 32) & 0xffff; |
| 127 | case PPC::S_HIGHERA: |
| 128 | return ((Value + 0x8000) >> 32) & 0xffff; |
| 129 | case PPC::S_HIGHEST: |
| 130 | return (Value >> 48) & 0xffff; |
| 131 | case PPC::S_HIGHESTA: |
| 132 | return ((Value + 0x8000) >> 48) & 0xffff; |
| 133 | default: |
| 134 | return {}; |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | bool PPC::evaluateAsConstant(const MCSpecifierExpr &Expr, int64_t &Res) { |
| 139 | MCValue Value; |
| 140 | |
| 141 | if (!Expr.getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm: nullptr)) |
| 142 | return false; |
| 143 | |
| 144 | if (!Value.isAbsolute()) |
| 145 | return false; |
| 146 | auto Tmp = evaluateAsInt64(specifier: Expr.getSpecifier(), Value: Value.getConstant()); |
| 147 | if (!Tmp) |
| 148 | return false; |
| 149 | Res = *Tmp; |
| 150 | return true; |
| 151 | } |
| 152 | |
| 153 | static bool evaluateAsRelocatable(const MCSpecifierExpr &Expr, MCValue &Res, |
| 154 | const MCAssembler *Asm) { |
| 155 | if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) |
| 156 | return false; |
| 157 | |
| 158 | // The signedness of the result is dependent on the instruction operand. E.g. |
| 159 | // in addis 3,3,65535@l, 65535@l is signed. In the absence of information at |
| 160 | // parse time (!Asm), disable the folding. |
| 161 | std::optional<int64_t> MaybeInt = |
| 162 | evaluateAsInt64(specifier: Expr.getSpecifier(), Value: Res.getConstant()); |
| 163 | if (Res.isAbsolute() && MaybeInt) { |
| 164 | Res = MCValue::get(Val: *MaybeInt); |
| 165 | } else { |
| 166 | Res.setSpecifier(Expr.getSpecifier()); |
| 167 | } |
| 168 | |
| 169 | return true; |
| 170 | } |
| 171 | |
| 172 | PPCELFMCAsmInfo::PPCELFMCAsmInfo(bool is64Bit, const Triple& T) { |
| 173 | // FIXME: This is not always needed. For example, it is not needed in the |
| 174 | // v2 abi. |
| 175 | NeedsLocalForSize = true; |
| 176 | |
| 177 | if (is64Bit) { |
| 178 | CodePointerSize = CalleeSaveStackSlotSize = 8; |
| 179 | } |
| 180 | IsLittleEndian = |
| 181 | T.getArch() == Triple::ppc64le || T.getArch() == Triple::ppcle; |
| 182 | |
| 183 | // ".comm align is in bytes but .align is pow-2." |
| 184 | AlignmentIsInBytes = false; |
| 185 | |
| 186 | CommentString = "#" ; |
| 187 | |
| 188 | // Uses '.section' before '.bss' directive |
| 189 | UsesELFSectionDirectiveForBSS = true; |
| 190 | |
| 191 | // Debug Information |
| 192 | SupportsDebugInformation = true; |
| 193 | |
| 194 | DollarIsPC = true; |
| 195 | |
| 196 | // Set up DWARF directives |
| 197 | MinInstAlignment = 4; |
| 198 | |
| 199 | // Exceptions handling |
| 200 | ExceptionsType = ExceptionHandling::DwarfCFI; |
| 201 | |
| 202 | ZeroDirective = "\t.space\t" ; |
| 203 | Data64bitsDirective = is64Bit ? "\t.quad\t" : nullptr; |
| 204 | AssemblerDialect = 1; // New-Style mnemonics. |
| 205 | LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment; |
| 206 | |
| 207 | initializeAtSpecifiers(elfAtSpecifiers); |
| 208 | } |
| 209 | |
| 210 | void PPCELFMCAsmInfo::printSpecifierExpr(raw_ostream &OS, |
| 211 | const MCSpecifierExpr &Expr) const { |
| 212 | printExpr(OS, *Expr.getSubExpr()); |
| 213 | OS << '@' << getSpecifierName(S: Expr.getSpecifier()); |
| 214 | } |
| 215 | |
| 216 | bool PPCELFMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr, |
| 217 | MCValue &Res, |
| 218 | const MCAssembler *Asm) const { |
| 219 | return evaluateAsRelocatable(Expr, Res, Asm); |
| 220 | } |
| 221 | |
| 222 | void PPCXCOFFMCAsmInfo::anchor() {} |
| 223 | |
| 224 | PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool Is64Bit, const Triple &T) { |
| 225 | if (T.getArch() == Triple::ppc64le || T.getArch() == Triple::ppcle) |
| 226 | report_fatal_error(reason: "XCOFF is not supported for little-endian targets" ); |
| 227 | CodePointerSize = CalleeSaveStackSlotSize = Is64Bit ? 8 : 4; |
| 228 | |
| 229 | // A size of 8 is only supported by the assembler under 64-bit. |
| 230 | Data64bitsDirective = Is64Bit ? "\t.vbyte\t8, " : nullptr; |
| 231 | |
| 232 | // Debug Information |
| 233 | SupportsDebugInformation = true; |
| 234 | |
| 235 | // Set up DWARF directives |
| 236 | MinInstAlignment = 4; |
| 237 | |
| 238 | // Support $ as PC in inline asm |
| 239 | DollarIsPC = true; |
| 240 | |
| 241 | UsesSetToEquateSymbol = true; |
| 242 | |
| 243 | initializeAtSpecifiers(xcoffAtSpecifiers); |
| 244 | } |
| 245 | |
| 246 | void PPCXCOFFMCAsmInfo::printSpecifierExpr(raw_ostream &OS, |
| 247 | const MCSpecifierExpr &Expr) const { |
| 248 | printExpr(OS, *Expr.getSubExpr()); |
| 249 | OS << '@' << getSpecifierName(S: Expr.getSpecifier()); |
| 250 | } |
| 251 | |
| 252 | bool PPCXCOFFMCAsmInfo::evaluateAsRelocatableImpl( |
| 253 | const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const { |
| 254 | return evaluateAsRelocatable(Expr, Res, Asm); |
| 255 | } |
| 256 | |