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
19using namespace llvm;
20
21void PPCELFMCAsmInfo::anchor() { }
22
23constexpr 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};
99constexpr auto elfAtSpecifiers = BUILD_ENUM_STRINGS(ELFAtSpecifierDefs);
100
101constexpr 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};
113constexpr auto xcoffAtSpecifiers = BUILD_ENUM_STRINGS(XCOFFAtSpecifierDefs);
114
115static 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
141bool 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
156static 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
175PPCELFMCAsmInfo::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
215void PPCELFMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
216 const MCSpecifierExpr &Expr) const {
217 printExpr(OS, *Expr.getSubExpr());
218 OS << '@' << getSpecifierName(S: Expr.getSpecifier());
219}
220
221bool PPCELFMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr,
222 MCValue &Res,
223 const MCAssembler *Asm) const {
224 return evaluateAsRelocatable(Expr, Res, Asm);
225}
226
227PPCXCOFFMCAsmInfo::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
251void PPCXCOFFMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
252 const MCSpecifierExpr &Expr) const {
253 printExpr(OS, *Expr.getSubExpr());
254 OS << '@' << getSpecifierName(S: Expr.getSpecifier());
255}
256
257bool PPCXCOFFMCAsmInfo::evaluateAsRelocatableImpl(
258 const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const {
259 return evaluateAsRelocatable(Expr, Res, Asm);
260}
261