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