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
18using namespace llvm;
19
20void PPCELFMCAsmInfo::anchor() { }
21
22const 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
99const 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
112static 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
138bool 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
153static 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
172PPCELFMCAsmInfo::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
210void PPCELFMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
211 const MCSpecifierExpr &Expr) const {
212 printExpr(OS, *Expr.getSubExpr());
213 OS << '@' << getSpecifierName(S: Expr.getSpecifier());
214}
215
216bool PPCELFMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr,
217 MCValue &Res,
218 const MCAssembler *Asm) const {
219 return evaluateAsRelocatable(Expr, Res, Asm);
220}
221
222void PPCXCOFFMCAsmInfo::anchor() {}
223
224PPCXCOFFMCAsmInfo::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
246void PPCXCOFFMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
247 const MCSpecifierExpr &Expr) const {
248 printExpr(OS, *Expr.getSubExpr());
249 OS << '@' << getSpecifierName(S: Expr.getSpecifier());
250}
251
252bool PPCXCOFFMCAsmInfo::evaluateAsRelocatableImpl(
253 const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const {
254 return evaluateAsRelocatable(Expr, Res, Asm);
255}
256