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 | |
24 | using namespace llvm; |
25 | |
26 | #define DEBUG_TYPE "loongarch-mcexpr" |
27 | |
28 | const LoongArchMCExpr *LoongArchMCExpr::create(const MCExpr *Expr, |
29 | VariantKind Kind, MCContext &Ctx, |
30 | bool Hint) { |
31 | return new (Ctx) LoongArchMCExpr(Expr, Kind, Hint); |
32 | } |
33 | |
34 | void 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 | |
46 | bool 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 | |
61 | void LoongArchMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
62 | Streamer.visitUsedExpr(Expr: *getSubExpr()); |
63 | } |
64 | |
65 | StringRef 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 | |
180 | LoongArchMCExpr::VariantKind |
181 | LoongArchMCExpr::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 | |
240 | static 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 | |
266 | void 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 | |