1//===-- LoongArchMCExpr.cpp - LoongArch specific MC expression classes ----===//
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 implementation of the assembly expression modifiers
10// accepted by the LoongArch architecture.
11//
12//===----------------------------------------------------------------------===//
13
14#include "LoongArchMCExpr.h"
15#include "LoongArchAsmBackend.h"
16#include "LoongArchFixupKinds.h"
17#include "llvm/MC/MCContext.h"
18#include "llvm/MC/MCStreamer.h"
19#include "llvm/MC/MCSymbolELF.h"
20#include "llvm/MC/MCValue.h"
21#include "llvm/Support/Casting.h"
22#include "llvm/Support/ErrorHandling.h"
23
24using namespace llvm;
25
26#define DEBUG_TYPE "loongarch-mcexpr"
27
28const LoongArchMCExpr *LoongArchMCExpr::create(const MCExpr *Expr,
29 VariantKind Kind, MCContext &Ctx,
30 bool Hint) {
31 return new (Ctx) LoongArchMCExpr(Expr, Kind, Hint);
32}
33
34void LoongArchMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
35 VariantKind Kind = getKind();
36 bool HasVariant =
37 ((Kind != VK_LoongArch_None) && (Kind != VK_LoongArch_CALL));
38
39 if (HasVariant)
40 OS << '%' << getVariantKindName(Kind: getKind()) << '(';
41 Expr->print(OS, MAI);
42 if (HasVariant)
43 OS << ')';
44}
45
46bool LoongArchMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
47 const MCAssembler *Asm,
48 const MCFixup *Fixup) const {
49 // Explicitly drop the layout and assembler to prevent any symbolic folding in
50 // the expression handling. This is required to preserve symbolic difference
51 // expressions to emit the paired relocations.
52 if (!getSubExpr()->evaluateAsRelocatable(Res, Asm: nullptr, Fixup: nullptr))
53 return false;
54
55 Res =
56 MCValue::get(SymA: Res.getSymA(), SymB: Res.getSymB(), Val: Res.getConstant(), RefKind: getKind());
57 // Custom fixup types are not valid with symbol difference expressions.
58 return Res.getSymB() ? getKind() == VK_LoongArch_None : true;
59}
60
61void LoongArchMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
62 Streamer.visitUsedExpr(Expr: *getSubExpr());
63}
64
65StringRef LoongArchMCExpr::getVariantKindName(VariantKind Kind) {
66 switch (Kind) {
67 default:
68 llvm_unreachable("Invalid ELF symbol kind");
69 case VK_LoongArch_CALL_PLT:
70 return "plt";
71 case VK_LoongArch_B16:
72 return "b16";
73 case VK_LoongArch_B21:
74 return "b21";
75 case VK_LoongArch_B26:
76 return "b26";
77 case VK_LoongArch_ABS_HI20:
78 return "abs_hi20";
79 case VK_LoongArch_ABS_LO12:
80 return "abs_lo12";
81 case VK_LoongArch_ABS64_LO20:
82 return "abs64_lo20";
83 case VK_LoongArch_ABS64_HI12:
84 return "abs64_hi12";
85 case VK_LoongArch_PCALA_HI20:
86 return "pc_hi20";
87 case VK_LoongArch_PCALA_LO12:
88 return "pc_lo12";
89 case VK_LoongArch_PCALA64_LO20:
90 return "pc64_lo20";
91 case VK_LoongArch_PCALA64_HI12:
92 return "pc64_hi12";
93 case VK_LoongArch_GOT_PC_HI20:
94 return "got_pc_hi20";
95 case VK_LoongArch_GOT_PC_LO12:
96 return "got_pc_lo12";
97 case VK_LoongArch_GOT64_PC_LO20:
98 return "got64_pc_lo20";
99 case VK_LoongArch_GOT64_PC_HI12:
100 return "got64_pc_hi12";
101 case VK_LoongArch_GOT_HI20:
102 return "got_hi20";
103 case VK_LoongArch_GOT_LO12:
104 return "got_lo12";
105 case VK_LoongArch_GOT64_LO20:
106 return "got64_lo20";
107 case VK_LoongArch_GOT64_HI12:
108 return "got64_hi12";
109 case VK_LoongArch_TLS_LE_HI20:
110 return "le_hi20";
111 case VK_LoongArch_TLS_LE_LO12:
112 return "le_lo12";
113 case VK_LoongArch_TLS_LE64_LO20:
114 return "le64_lo20";
115 case VK_LoongArch_TLS_LE64_HI12:
116 return "le64_hi12";
117 case VK_LoongArch_TLS_IE_PC_HI20:
118 return "ie_pc_hi20";
119 case VK_LoongArch_TLS_IE_PC_LO12:
120 return "ie_pc_lo12";
121 case VK_LoongArch_TLS_IE64_PC_LO20:
122 return "ie64_pc_lo20";
123 case VK_LoongArch_TLS_IE64_PC_HI12:
124 return "ie64_pc_hi12";
125 case VK_LoongArch_TLS_IE_HI20:
126 return "ie_hi20";
127 case VK_LoongArch_TLS_IE_LO12:
128 return "ie_lo12";
129 case VK_LoongArch_TLS_IE64_LO20:
130 return "ie64_lo20";
131 case VK_LoongArch_TLS_IE64_HI12:
132 return "ie64_hi12";
133 case VK_LoongArch_TLS_LD_PC_HI20:
134 return "ld_pc_hi20";
135 case VK_LoongArch_TLS_LD_HI20:
136 return "ld_hi20";
137 case VK_LoongArch_TLS_GD_PC_HI20:
138 return "gd_pc_hi20";
139 case VK_LoongArch_TLS_GD_HI20:
140 return "gd_hi20";
141 case VK_LoongArch_CALL36:
142 return "call36";
143 case VK_LoongArch_TLS_DESC_PC_HI20:
144 return "desc_pc_hi20";
145 case VK_LoongArch_TLS_DESC_PC_LO12:
146 return "desc_pc_lo12";
147 case VK_LoongArch_TLS_DESC64_PC_LO20:
148 return "desc64_pc_lo20";
149 case VK_LoongArch_TLS_DESC64_PC_HI12:
150 return "desc64_pc_hi12";
151 case VK_LoongArch_TLS_DESC_HI20:
152 return "desc_hi20";
153 case VK_LoongArch_TLS_DESC_LO12:
154 return "desc_lo12";
155 case VK_LoongArch_TLS_DESC64_LO20:
156 return "desc64_lo20";
157 case VK_LoongArch_TLS_DESC64_HI12:
158 return "desc64_hi12";
159 case VK_LoongArch_TLS_DESC_LD:
160 return "desc_ld";
161 case VK_LoongArch_TLS_DESC_CALL:
162 return "desc_call";
163 case VK_LoongArch_TLS_LE_HI20_R:
164 return "le_hi20_r";
165 case VK_LoongArch_TLS_LE_ADD_R:
166 return "le_add_r";
167 case VK_LoongArch_TLS_LE_LO12_R:
168 return "le_lo12_r";
169 case VK_LoongArch_PCREL20_S2:
170 return "pcrel_20";
171 case VK_LoongArch_TLS_LD_PCREL20_S2:
172 return "ld_pcrel_20";
173 case VK_LoongArch_TLS_GD_PCREL20_S2:
174 return "gd_pcrel_20";
175 case VK_LoongArch_TLS_DESC_PCREL20_S2:
176 return "desc_pcrel_20";
177 }
178}
179
180LoongArchMCExpr::VariantKind
181LoongArchMCExpr::getVariantKindForName(StringRef name) {
182 return StringSwitch<LoongArchMCExpr::VariantKind>(name)
183 .Case(S: "plt", Value: VK_LoongArch_CALL_PLT)
184 .Case(S: "b16", Value: VK_LoongArch_B16)
185 .Case(S: "b21", Value: VK_LoongArch_B21)
186 .Case(S: "b26", Value: VK_LoongArch_B26)
187 .Case(S: "abs_hi20", Value: VK_LoongArch_ABS_HI20)
188 .Case(S: "abs_lo12", Value: VK_LoongArch_ABS_LO12)
189 .Case(S: "abs64_lo20", Value: VK_LoongArch_ABS64_LO20)
190 .Case(S: "abs64_hi12", Value: VK_LoongArch_ABS64_HI12)
191 .Case(S: "pc_hi20", Value: VK_LoongArch_PCALA_HI20)
192 .Case(S: "pc_lo12", Value: VK_LoongArch_PCALA_LO12)
193 .Case(S: "pc64_lo20", Value: VK_LoongArch_PCALA64_LO20)
194 .Case(S: "pc64_hi12", Value: VK_LoongArch_PCALA64_HI12)
195 .Case(S: "got_pc_hi20", Value: VK_LoongArch_GOT_PC_HI20)
196 .Case(S: "got_pc_lo12", Value: VK_LoongArch_GOT_PC_LO12)
197 .Case(S: "got64_pc_lo20", Value: VK_LoongArch_GOT64_PC_LO20)
198 .Case(S: "got64_pc_hi12", Value: VK_LoongArch_GOT64_PC_HI12)
199 .Case(S: "got_hi20", Value: VK_LoongArch_GOT_HI20)
200 .Case(S: "got_lo12", Value: VK_LoongArch_GOT_LO12)
201 .Case(S: "got64_lo20", Value: VK_LoongArch_GOT64_LO20)
202 .Case(S: "got64_hi12", Value: VK_LoongArch_GOT64_HI12)
203 .Case(S: "le_hi20", Value: VK_LoongArch_TLS_LE_HI20)
204 .Case(S: "le_lo12", Value: VK_LoongArch_TLS_LE_LO12)
205 .Case(S: "le64_lo20", Value: VK_LoongArch_TLS_LE64_LO20)
206 .Case(S: "le64_hi12", Value: VK_LoongArch_TLS_LE64_HI12)
207 .Case(S: "ie_pc_hi20", Value: VK_LoongArch_TLS_IE_PC_HI20)
208 .Case(S: "ie_pc_lo12", Value: VK_LoongArch_TLS_IE_PC_LO12)
209 .Case(S: "ie64_pc_lo20", Value: VK_LoongArch_TLS_IE64_PC_LO20)
210 .Case(S: "ie64_pc_hi12", Value: VK_LoongArch_TLS_IE64_PC_HI12)
211 .Case(S: "ie_hi20", Value: VK_LoongArch_TLS_IE_HI20)
212 .Case(S: "ie_lo12", Value: VK_LoongArch_TLS_IE_LO12)
213 .Case(S: "ie64_lo20", Value: VK_LoongArch_TLS_IE64_LO20)
214 .Case(S: "ie64_hi12", Value: VK_LoongArch_TLS_IE64_HI12)
215 .Case(S: "ld_pc_hi20", Value: VK_LoongArch_TLS_LD_PC_HI20)
216 .Case(S: "ld_hi20", Value: VK_LoongArch_TLS_LD_HI20)
217 .Case(S: "gd_pc_hi20", Value: VK_LoongArch_TLS_GD_PC_HI20)
218 .Case(S: "gd_hi20", Value: VK_LoongArch_TLS_GD_HI20)
219 .Case(S: "call36", Value: VK_LoongArch_CALL36)
220 .Case(S: "desc_pc_hi20", Value: VK_LoongArch_TLS_DESC_PC_HI20)
221 .Case(S: "desc_pc_lo12", Value: VK_LoongArch_TLS_DESC_PC_LO12)
222 .Case(S: "desc64_pc_lo20", Value: VK_LoongArch_TLS_DESC64_PC_LO20)
223 .Case(S: "desc64_pc_hi12", Value: VK_LoongArch_TLS_DESC64_PC_HI12)
224 .Case(S: "desc_hi20", Value: VK_LoongArch_TLS_DESC_HI20)
225 .Case(S: "desc_lo12", Value: VK_LoongArch_TLS_DESC_LO12)
226 .Case(S: "desc64_lo20", Value: VK_LoongArch_TLS_DESC64_LO20)
227 .Case(S: "desc64_hi12", Value: VK_LoongArch_TLS_DESC64_HI12)
228 .Case(S: "desc_ld", Value: VK_LoongArch_TLS_DESC_LD)
229 .Case(S: "desc_call", Value: VK_LoongArch_TLS_DESC_CALL)
230 .Case(S: "le_hi20_r", Value: VK_LoongArch_TLS_LE_HI20_R)
231 .Case(S: "le_add_r", Value: VK_LoongArch_TLS_LE_ADD_R)
232 .Case(S: "le_lo12_r", Value: VK_LoongArch_TLS_LE_LO12_R)
233 .Case(S: "pcrel_20", Value: VK_LoongArch_PCREL20_S2)
234 .Case(S: "ld_pcrel_20", Value: VK_LoongArch_TLS_LD_PCREL20_S2)
235 .Case(S: "gd_pcrel_20", Value: VK_LoongArch_TLS_GD_PCREL20_S2)
236 .Case(S: "desc_pcrel_20", Value: VK_LoongArch_TLS_DESC_PCREL20_S2)
237 .Default(Value: VK_LoongArch_Invalid);
238}
239
240static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
241 switch (Expr->getKind()) {
242 case MCExpr::Target:
243 llvm_unreachable("Can't handle nested target expression");
244 break;
245 case MCExpr::Constant:
246 break;
247 case MCExpr::Unary:
248 fixELFSymbolsInTLSFixupsImpl(Expr: cast<MCUnaryExpr>(Val: Expr)->getSubExpr(), Asm);
249 break;
250 case MCExpr::Binary: {
251 const MCBinaryExpr *BE = cast<MCBinaryExpr>(Val: Expr);
252 fixELFSymbolsInTLSFixupsImpl(Expr: BE->getLHS(), Asm);
253 fixELFSymbolsInTLSFixupsImpl(Expr: BE->getRHS(), Asm);
254 break;
255 }
256 case MCExpr::SymbolRef: {
257 // We're known to be under a TLS fixup, so any symbol should be
258 // modified. There should be only one.
259 const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Val: Expr);
260 cast<MCSymbolELF>(Val: SymRef.getSymbol()).setType(ELF::STT_TLS);
261 break;
262 }
263 }
264}
265
266void LoongArchMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
267 switch (getKind()) {
268 default:
269 return;
270 case VK_LoongArch_TLS_LE_HI20:
271 case VK_LoongArch_TLS_IE_PC_HI20:
272 case VK_LoongArch_TLS_IE_HI20:
273 case VK_LoongArch_TLS_LD_PC_HI20:
274 case VK_LoongArch_TLS_LD_HI20:
275 case VK_LoongArch_TLS_GD_PC_HI20:
276 case VK_LoongArch_TLS_GD_HI20:
277 case VK_LoongArch_TLS_DESC_PC_HI20:
278 case VK_LoongArch_TLS_DESC_HI20:
279 case VK_LoongArch_TLS_LD_PCREL20_S2:
280 case VK_LoongArch_TLS_GD_PCREL20_S2:
281 case VK_LoongArch_TLS_DESC_PCREL20_S2:
282 break;
283 }
284 fixELFSymbolsInTLSFixupsImpl(Expr: getSubExpr(), Asm);
285}
286