1 | // LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=// |
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 | #include "MCTargetDesc/LoongArchInstPrinter.h" |
10 | #include "MCTargetDesc/LoongArchMCExpr.h" |
11 | #include "MCTargetDesc/LoongArchMCTargetDesc.h" |
12 | #include "MCTargetDesc/LoongArchMatInt.h" |
13 | #include "TargetInfo/LoongArchTargetInfo.h" |
14 | #include "llvm/MC/MCContext.h" |
15 | #include "llvm/MC/MCInstBuilder.h" |
16 | #include "llvm/MC/MCInstrInfo.h" |
17 | #include "llvm/MC/MCParser/MCAsmLexer.h" |
18 | #include "llvm/MC/MCParser/MCParsedAsmOperand.h" |
19 | #include "llvm/MC/MCParser/MCTargetAsmParser.h" |
20 | #include "llvm/MC/MCRegisterInfo.h" |
21 | #include "llvm/MC/MCStreamer.h" |
22 | #include "llvm/MC/MCSubtargetInfo.h" |
23 | #include "llvm/MC/MCValue.h" |
24 | #include "llvm/MC/TargetRegistry.h" |
25 | #include "llvm/Support/Casting.h" |
26 | |
27 | using namespace llvm; |
28 | |
29 | #define DEBUG_TYPE "loongarch-asm-parser" |
30 | |
31 | namespace { |
32 | class LoongArchAsmParser : public MCTargetAsmParser { |
33 | SMLoc getLoc() const { return getParser().getTok().getLoc(); } |
34 | bool is64Bit() const { return getSTI().hasFeature(Feature: LoongArch::Feature64Bit); } |
35 | |
36 | struct Inst { |
37 | unsigned Opc; |
38 | LoongArchMCExpr::VariantKind VK; |
39 | Inst(unsigned Opc, |
40 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None) |
41 | : Opc(Opc), VK(VK) {} |
42 | }; |
43 | using InstSeq = SmallVector<Inst>; |
44 | |
45 | /// Parse a register as used in CFI directives. |
46 | bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override; |
47 | ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, |
48 | SMLoc &EndLoc) override; |
49 | |
50 | bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, |
51 | SMLoc NameLoc, OperandVector &Operands) override; |
52 | |
53 | bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, |
54 | OperandVector &Operands, MCStreamer &Out, |
55 | uint64_t &ErrorInfo, |
56 | bool MatchingInlineAsm) override; |
57 | |
58 | unsigned checkTargetMatchPredicate(MCInst &Inst) override; |
59 | |
60 | unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, |
61 | unsigned Kind) override; |
62 | |
63 | bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, |
64 | int64_t Lower, int64_t Upper, |
65 | const Twine &Msg); |
66 | |
67 | /// Helper for processing MC instructions that have been successfully matched |
68 | /// by MatchAndEmitInstruction. |
69 | bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, |
70 | MCStreamer &Out); |
71 | |
72 | // Auto-generated instruction matching functions. |
73 | #define |
74 | #include "LoongArchGenAsmMatcher.inc" |
75 | |
76 | ParseStatus parseRegister(OperandVector &Operands); |
77 | ParseStatus parseImmediate(OperandVector &Operands); |
78 | ParseStatus parseOperandWithModifier(OperandVector &Operands); |
79 | ParseStatus parseSImm26Operand(OperandVector &Operands); |
80 | ParseStatus parseAtomicMemOp(OperandVector &Operands); |
81 | |
82 | bool parseOperand(OperandVector &Operands, StringRef Mnemonic); |
83 | |
84 | // Helper to emit the sequence of instructions generated by the |
85 | // "emitLoadAddress*" functions. |
86 | void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg, |
87 | const MCExpr *Symbol, SmallVectorImpl<Inst> &Insts, |
88 | SMLoc IDLoc, MCStreamer &Out, bool RelaxHint = false); |
89 | |
90 | // Helper to emit pseudo instruction "la.abs $rd, sym". |
91 | void emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
92 | |
93 | // Helper to emit pseudo instruction "la.pcrel $rd, sym". |
94 | void emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
95 | // Helper to emit pseudo instruction "la.pcrel $rd, $rj, sym". |
96 | void emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
97 | |
98 | // Helper to emit pseudo instruction "la.got $rd, sym". |
99 | void emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
100 | // Helper to emit pseudo instruction "la.got $rd, $rj, sym". |
101 | void emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
102 | |
103 | // Helper to emit pseudo instruction "la.tls.le $rd, sym". |
104 | void emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
105 | |
106 | // Helper to emit pseudo instruction "la.tls.ie $rd, sym". |
107 | void emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
108 | // Helper to emit pseudo instruction "la.tls.ie $rd, $rj, sym". |
109 | void emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
110 | |
111 | // Helper to emit pseudo instruction "la.tls.ld $rd, sym". |
112 | void emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
113 | // Helper to emit pseudo instruction "la.tls.ld $rd, $rj, sym". |
114 | void emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
115 | |
116 | // Helper to emit pseudo instruction "la.tls.gd $rd, sym". |
117 | void emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
118 | // Helper to emit pseudo instruction "la.tls.gd $rd, $rj, sym". |
119 | void emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
120 | |
121 | // Helper to emit pseudo instruction "la.tls.desc $rd, sym". |
122 | void emitLoadAddressTLSDescAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
123 | void emitLoadAddressTLSDescPcrel(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
124 | // Helper to emit pseudo instruction "la.tls.desc $rd, $rj, sym". |
125 | void emitLoadAddressTLSDescPcrelLarge(MCInst &Inst, SMLoc IDLoc, |
126 | MCStreamer &Out); |
127 | |
128 | // Helper to emit pseudo instruction "li.w/d $rd, $imm". |
129 | void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); |
130 | |
131 | // Helper to emit pseudo instruction "call36 sym" or "tail36 $rj, sym". |
132 | void emitFuncCall36(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, |
133 | bool IsTailCall); |
134 | |
135 | public: |
136 | enum LoongArchMatchResultTy { |
137 | Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, |
138 | Match_RequiresMsbNotLessThanLsb, |
139 | Match_RequiresOpnd2NotR0R1, |
140 | Match_RequiresAMORdDifferRkRj, |
141 | Match_RequiresLAORdDifferRj, |
142 | Match_RequiresLAORdR4, |
143 | #define GET_OPERAND_DIAGNOSTIC_TYPES |
144 | #include "LoongArchGenAsmMatcher.inc" |
145 | #undef GET_OPERAND_DIAGNOSTIC_TYPES |
146 | }; |
147 | |
148 | static bool classifySymbolRef(const MCExpr *Expr, |
149 | LoongArchMCExpr::VariantKind &Kind); |
150 | |
151 | LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, |
152 | const MCInstrInfo &MII, const MCTargetOptions &Options) |
153 | : MCTargetAsmParser(Options, STI, MII) { |
154 | Parser.addAliasForDirective(Directive: ".half" , Alias: ".2byte" ); |
155 | Parser.addAliasForDirective(Directive: ".hword" , Alias: ".2byte" ); |
156 | Parser.addAliasForDirective(Directive: ".word" , Alias: ".4byte" ); |
157 | Parser.addAliasForDirective(Directive: ".dword" , Alias: ".8byte" ); |
158 | |
159 | // Initialize the set of available features. |
160 | setAvailableFeatures(ComputeAvailableFeatures(FB: STI.getFeatureBits())); |
161 | } |
162 | }; |
163 | |
164 | // Instances of this class represent a parsed LoongArch machine instruction. |
165 | class LoongArchOperand : public MCParsedAsmOperand { |
166 | enum class KindTy { |
167 | Token, |
168 | Register, |
169 | Immediate, |
170 | } Kind; |
171 | |
172 | struct RegOp { |
173 | MCRegister RegNum; |
174 | }; |
175 | |
176 | struct ImmOp { |
177 | const MCExpr *Val; |
178 | }; |
179 | |
180 | SMLoc StartLoc, EndLoc; |
181 | union { |
182 | StringRef Tok; |
183 | struct RegOp Reg; |
184 | struct ImmOp Imm; |
185 | }; |
186 | |
187 | public: |
188 | LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} |
189 | |
190 | bool isToken() const override { return Kind == KindTy::Token; } |
191 | bool isReg() const override { return Kind == KindTy::Register; } |
192 | bool isImm() const override { return Kind == KindTy::Immediate; } |
193 | bool isMem() const override { return false; } |
194 | void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; } |
195 | bool isGPR() const { |
196 | return Kind == KindTy::Register && |
197 | LoongArchMCRegisterClasses[LoongArch::GPRRegClassID].contains( |
198 | Reg: Reg.RegNum); |
199 | } |
200 | |
201 | static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm, |
202 | LoongArchMCExpr::VariantKind &VK) { |
203 | if (auto *LE = dyn_cast<LoongArchMCExpr>(Val: Expr)) { |
204 | VK = LE->getKind(); |
205 | return false; |
206 | } |
207 | |
208 | if (auto CE = dyn_cast<MCConstantExpr>(Val: Expr)) { |
209 | Imm = CE->getValue(); |
210 | return true; |
211 | } |
212 | |
213 | return false; |
214 | } |
215 | |
216 | template <unsigned N, int P = 0> bool isUImm() const { |
217 | if (!isImm()) |
218 | return false; |
219 | |
220 | int64_t Imm; |
221 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
222 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
223 | return IsConstantImm && isUInt<N>(Imm - P) && |
224 | VK == LoongArchMCExpr::VK_LoongArch_None; |
225 | } |
226 | |
227 | template <unsigned N, unsigned S = 0> bool isSImm() const { |
228 | if (!isImm()) |
229 | return false; |
230 | |
231 | int64_t Imm; |
232 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
233 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
234 | return IsConstantImm && isShiftedInt<N, S>(Imm) && |
235 | VK == LoongArchMCExpr::VK_LoongArch_None; |
236 | } |
237 | |
238 | bool isBareSymbol() const { |
239 | int64_t Imm; |
240 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
241 | // Must be of 'immediate' type but not a constant. |
242 | if (!isImm() || evaluateConstantImm(Expr: getImm(), Imm, VK)) |
243 | return false; |
244 | return LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
245 | VK == LoongArchMCExpr::VK_LoongArch_None; |
246 | } |
247 | |
248 | bool isTPRelAddSymbol() const { |
249 | int64_t Imm; |
250 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
251 | // Must be of 'immediate' type but not a constant. |
252 | if (!isImm() || evaluateConstantImm(Expr: getImm(), Imm, VK)) |
253 | return false; |
254 | return LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
255 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_ADD_R; |
256 | } |
257 | |
258 | bool isUImm1() const { return isUImm<1>(); } |
259 | bool isUImm2() const { return isUImm<2>(); } |
260 | bool isUImm2plus1() const { return isUImm<2, 1>(); } |
261 | bool isUImm3() const { return isUImm<3>(); } |
262 | bool isUImm4() const { return isUImm<4>(); } |
263 | bool isSImm5() const { return isSImm<5>(); } |
264 | bool isUImm5() const { return isUImm<5>(); } |
265 | bool isUImm6() const { return isUImm<6>(); } |
266 | bool isUImm7() const { return isUImm<7>(); } |
267 | bool isSImm8() const { return isSImm<8>(); } |
268 | bool isSImm8lsl1() const { return isSImm<8, 1>(); } |
269 | bool isSImm8lsl2() const { return isSImm<8, 2>(); } |
270 | bool isSImm8lsl3() const { return isSImm<8, 3>(); } |
271 | bool isUImm8() const { return isUImm<8>(); } |
272 | bool isSImm9lsl3() const { return isSImm<9, 3>(); } |
273 | bool isSImm10() const { return isSImm<10>(); } |
274 | bool isSImm10lsl2() const { return isSImm<10, 2>(); } |
275 | bool isSImm11lsl1() const { return isSImm<11, 1>(); } |
276 | bool isSImm12() const { return isSImm<12>(); } |
277 | |
278 | bool isSImm12addlike() const { |
279 | if (!isImm()) |
280 | return false; |
281 | |
282 | int64_t Imm; |
283 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
284 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
285 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
286 | VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 || |
287 | VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 || |
288 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12 || |
289 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12_R || |
290 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12 || |
291 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD; |
292 | return IsConstantImm |
293 | ? isInt<12>(x: Imm) && IsValidKind |
294 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
295 | IsValidKind; |
296 | } |
297 | |
298 | bool isSImm12lu52id() const { |
299 | if (!isImm()) |
300 | return false; |
301 | |
302 | int64_t Imm; |
303 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
304 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
305 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
306 | VK == LoongArchMCExpr::VK_LoongArch_ABS64_HI12 || |
307 | VK == LoongArchMCExpr::VK_LoongArch_PCALA64_HI12 || |
308 | VK == LoongArchMCExpr::VK_LoongArch_GOT64_HI12 || |
309 | VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12 || |
310 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_HI12 || |
311 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_HI12 || |
312 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12 || |
313 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_HI12 || |
314 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_HI12; |
315 | return IsConstantImm |
316 | ? isInt<12>(x: Imm) && IsValidKind |
317 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
318 | IsValidKind; |
319 | } |
320 | |
321 | bool isUImm12() const { return isUImm<12>(); } |
322 | |
323 | bool isUImm12ori() const { |
324 | if (!isImm()) |
325 | return false; |
326 | |
327 | int64_t Imm; |
328 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
329 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
330 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
331 | VK == LoongArchMCExpr::VK_LoongArch_ABS_LO12 || |
332 | VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 || |
333 | VK == LoongArchMCExpr::VK_LoongArch_GOT_LO12 || |
334 | VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 || |
335 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12 || |
336 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_LO12 || |
337 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12 || |
338 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_LO12; |
339 | return IsConstantImm |
340 | ? isUInt<12>(x: Imm) && IsValidKind |
341 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
342 | IsValidKind; |
343 | } |
344 | |
345 | bool isSImm13() const { return isSImm<13>(); } |
346 | bool isUImm14() const { return isUImm<14>(); } |
347 | bool isUImm15() const { return isUImm<15>(); } |
348 | |
349 | bool isSImm14lsl2() const { return isSImm<14, 2>(); } |
350 | bool isSImm16() const { return isSImm<16>(); } |
351 | |
352 | bool isSImm16lsl2() const { |
353 | if (!isImm()) |
354 | return false; |
355 | |
356 | int64_t Imm; |
357 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
358 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
359 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
360 | VK == LoongArchMCExpr::VK_LoongArch_B16 || |
361 | VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 || |
362 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL; |
363 | return IsConstantImm |
364 | ? isShiftedInt<16, 2>(x: Imm) && IsValidKind |
365 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
366 | IsValidKind; |
367 | } |
368 | |
369 | bool isSImm20() const { return isSImm<20>(); } |
370 | |
371 | bool isSImm20pcalau12i() const { |
372 | if (!isImm()) |
373 | return false; |
374 | |
375 | int64_t Imm; |
376 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
377 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
378 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
379 | VK == LoongArchMCExpr::VK_LoongArch_PCALA_HI20 || |
380 | VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20 || |
381 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20 || |
382 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20 || |
383 | VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20 || |
384 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20; |
385 | return IsConstantImm |
386 | ? isInt<20>(x: Imm) && IsValidKind |
387 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
388 | IsValidKind; |
389 | } |
390 | |
391 | bool isSImm20lu12iw() const { |
392 | if (!isImm()) |
393 | return false; |
394 | |
395 | int64_t Imm; |
396 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
397 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
398 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
399 | VK == LoongArchMCExpr::VK_LoongArch_ABS_HI20 || |
400 | VK == LoongArchMCExpr::VK_LoongArch_GOT_HI20 || |
401 | VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20 || |
402 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_HI20 || |
403 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_HI20 || |
404 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20 || |
405 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20_R || |
406 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_HI20; |
407 | return IsConstantImm |
408 | ? isInt<20>(x: Imm) && IsValidKind |
409 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
410 | IsValidKind; |
411 | } |
412 | |
413 | bool isSImm20lu32id() const { |
414 | if (!isImm()) |
415 | return false; |
416 | |
417 | int64_t Imm; |
418 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
419 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
420 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
421 | VK == LoongArchMCExpr::VK_LoongArch_ABS64_LO20 || |
422 | VK == LoongArchMCExpr::VK_LoongArch_PCALA64_LO20 || |
423 | VK == LoongArchMCExpr::VK_LoongArch_GOT64_LO20 || |
424 | VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20 || |
425 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_LO20 || |
426 | VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20 || |
427 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20 || |
428 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_LO20 || |
429 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_LO20; |
430 | |
431 | return IsConstantImm |
432 | ? isInt<20>(x: Imm) && IsValidKind |
433 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
434 | IsValidKind; |
435 | } |
436 | |
437 | bool isSImm20pcaddu18i() const { |
438 | if (!isImm()) |
439 | return false; |
440 | |
441 | int64_t Imm; |
442 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
443 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
444 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
445 | VK == LoongArchMCExpr::VK_LoongArch_CALL36; |
446 | |
447 | return IsConstantImm |
448 | ? isInt<20>(x: Imm) && IsValidKind |
449 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
450 | IsValidKind; |
451 | } |
452 | |
453 | bool isSImm20pcaddi() const { |
454 | if (!isImm()) |
455 | return false; |
456 | |
457 | int64_t Imm; |
458 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
459 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
460 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
461 | VK == LoongArchMCExpr::VK_LoongArch_PCREL20_S2 || |
462 | VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_PCREL20_S2 || |
463 | VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PCREL20_S2 || |
464 | VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_PCREL20_S2; |
465 | return IsConstantImm |
466 | ? isInt<20>(x: Imm) && IsValidKind |
467 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
468 | IsValidKind; |
469 | } |
470 | |
471 | bool isSImm21lsl2() const { |
472 | if (!isImm()) |
473 | return false; |
474 | |
475 | int64_t Imm; |
476 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
477 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
478 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
479 | VK == LoongArchMCExpr::VK_LoongArch_B21; |
480 | return IsConstantImm |
481 | ? isShiftedInt<21, 2>(x: Imm) && IsValidKind |
482 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
483 | IsValidKind; |
484 | } |
485 | |
486 | bool isSImm26Operand() const { |
487 | if (!isImm()) |
488 | return false; |
489 | |
490 | int64_t Imm; |
491 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
492 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
493 | bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None || |
494 | VK == LoongArchMCExpr::VK_LoongArch_CALL || |
495 | VK == LoongArchMCExpr::VK_LoongArch_CALL_PLT || |
496 | VK == LoongArchMCExpr::VK_LoongArch_B26; |
497 | return IsConstantImm |
498 | ? isShiftedInt<26, 2>(x: Imm) && IsValidKind |
499 | : LoongArchAsmParser::classifySymbolRef(Expr: getImm(), Kind&: VK) && |
500 | IsValidKind; |
501 | } |
502 | |
503 | bool isImm32() const { return isSImm<32>() || isUImm<32>(); } |
504 | bool isImm64() const { |
505 | if (!isImm()) |
506 | return false; |
507 | int64_t Imm; |
508 | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; |
509 | bool IsConstantImm = evaluateConstantImm(Expr: getImm(), Imm, VK); |
510 | return IsConstantImm && VK == LoongArchMCExpr::VK_LoongArch_None; |
511 | } |
512 | |
513 | /// Gets location of the first token of this operand. |
514 | SMLoc getStartLoc() const override { return StartLoc; } |
515 | /// Gets location of the last token of this operand. |
516 | SMLoc getEndLoc() const override { return EndLoc; } |
517 | |
518 | MCRegister getReg() const override { |
519 | assert(Kind == KindTy::Register && "Invalid type access!" ); |
520 | return Reg.RegNum; |
521 | } |
522 | |
523 | const MCExpr *getImm() const { |
524 | assert(Kind == KindTy::Immediate && "Invalid type access!" ); |
525 | return Imm.Val; |
526 | } |
527 | |
528 | StringRef getToken() const { |
529 | assert(Kind == KindTy::Token && "Invalid type access!" ); |
530 | return Tok; |
531 | } |
532 | |
533 | void print(raw_ostream &OS) const override { |
534 | auto RegName = [](MCRegister Reg) { |
535 | if (Reg) |
536 | return LoongArchInstPrinter::getRegisterName(Reg); |
537 | else |
538 | return "noreg" ; |
539 | }; |
540 | |
541 | switch (Kind) { |
542 | case KindTy::Immediate: |
543 | OS << *getImm(); |
544 | break; |
545 | case KindTy::Register: |
546 | OS << "<register " << RegName(getReg()) << ">" ; |
547 | break; |
548 | case KindTy::Token: |
549 | OS << "'" << getToken() << "'" ; |
550 | break; |
551 | } |
552 | } |
553 | |
554 | static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) { |
555 | auto Op = std::make_unique<LoongArchOperand>(args: KindTy::Token); |
556 | Op->Tok = Str; |
557 | Op->StartLoc = S; |
558 | Op->EndLoc = S; |
559 | return Op; |
560 | } |
561 | |
562 | static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S, |
563 | SMLoc E) { |
564 | auto Op = std::make_unique<LoongArchOperand>(args: KindTy::Register); |
565 | Op->Reg.RegNum = RegNo; |
566 | Op->StartLoc = S; |
567 | Op->EndLoc = E; |
568 | return Op; |
569 | } |
570 | |
571 | static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S, |
572 | SMLoc E) { |
573 | auto Op = std::make_unique<LoongArchOperand>(args: KindTy::Immediate); |
574 | Op->Imm.Val = Val; |
575 | Op->StartLoc = S; |
576 | Op->EndLoc = E; |
577 | return Op; |
578 | } |
579 | |
580 | void addExpr(MCInst &Inst, const MCExpr *Expr) const { |
581 | if (auto CE = dyn_cast<MCConstantExpr>(Val: Expr)) |
582 | Inst.addOperand(Op: MCOperand::createImm(Val: CE->getValue())); |
583 | else |
584 | Inst.addOperand(Op: MCOperand::createExpr(Val: Expr)); |
585 | } |
586 | |
587 | // Used by the TableGen Code. |
588 | void addRegOperands(MCInst &Inst, unsigned N) const { |
589 | assert(N == 1 && "Invalid number of operands!" ); |
590 | Inst.addOperand(Op: MCOperand::createReg(Reg: getReg())); |
591 | } |
592 | void addImmOperands(MCInst &Inst, unsigned N) const { |
593 | assert(N == 1 && "Invalid number of operands!" ); |
594 | addExpr(Inst, Expr: getImm()); |
595 | } |
596 | }; |
597 | } // end namespace |
598 | |
599 | #define GET_REGISTER_MATCHER |
600 | #define GET_SUBTARGET_FEATURE_NAME |
601 | #define GET_MATCHER_IMPLEMENTATION |
602 | #define GET_MNEMONIC_SPELL_CHECKER |
603 | #include "LoongArchGenAsmMatcher.inc" |
604 | |
605 | static MCRegister convertFPR32ToFPR64(MCRegister Reg) { |
606 | assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register" ); |
607 | return Reg - LoongArch::F0 + LoongArch::F0_64; |
608 | } |
609 | |
610 | // Attempts to match Name as a register (either using the default name or |
611 | // alternative ABI names), setting RegNo to the matching register. Upon |
612 | // failure, returns true and sets RegNo to 0. |
613 | static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) { |
614 | RegNo = MatchRegisterName(Name); |
615 | // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial |
616 | // match always matches the 32-bit variant, and not the 64-bit one. |
617 | assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64)); |
618 | // The default FPR register class is based on the tablegen enum ordering. |
619 | static_assert(LoongArch::F0 < LoongArch::F0_64, |
620 | "FPR matching must be updated" ); |
621 | if (RegNo == LoongArch::NoRegister) |
622 | RegNo = MatchRegisterAltName(Name); |
623 | |
624 | return RegNo == LoongArch::NoRegister; |
625 | } |
626 | |
627 | bool LoongArchAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc, |
628 | SMLoc &EndLoc) { |
629 | return Error(L: getLoc(), Msg: "invalid register number" ); |
630 | } |
631 | |
632 | ParseStatus LoongArchAsmParser::tryParseRegister(MCRegister &Reg, |
633 | SMLoc &StartLoc, |
634 | SMLoc &EndLoc) { |
635 | llvm_unreachable("Unimplemented function." ); |
636 | } |
637 | |
638 | bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr, |
639 | LoongArchMCExpr::VariantKind &Kind) { |
640 | Kind = LoongArchMCExpr::VK_LoongArch_None; |
641 | |
642 | if (const LoongArchMCExpr *RE = dyn_cast<LoongArchMCExpr>(Val: Expr)) { |
643 | Kind = RE->getKind(); |
644 | Expr = RE->getSubExpr(); |
645 | } |
646 | |
647 | MCValue Res; |
648 | if (Expr->evaluateAsRelocatable(Res, Asm: nullptr, Fixup: nullptr)) |
649 | return Res.getRefKind() == LoongArchMCExpr::VK_LoongArch_None; |
650 | return false; |
651 | } |
652 | |
653 | ParseStatus LoongArchAsmParser::parseRegister(OperandVector &Operands) { |
654 | if (!parseOptionalToken(T: AsmToken::Dollar)) |
655 | return ParseStatus::NoMatch; |
656 | if (getLexer().getKind() != AsmToken::Identifier) |
657 | return ParseStatus::NoMatch; |
658 | |
659 | StringRef Name = getLexer().getTok().getIdentifier(); |
660 | MCRegister RegNo; |
661 | matchRegisterNameHelper(RegNo, Name); |
662 | if (RegNo == LoongArch::NoRegister) |
663 | return ParseStatus::NoMatch; |
664 | |
665 | SMLoc S = getLoc(); |
666 | SMLoc E = SMLoc::getFromPointer(Ptr: S.getPointer() + Name.size()); |
667 | getLexer().Lex(); |
668 | Operands.push_back(Elt: LoongArchOperand::createReg(RegNo, S, E)); |
669 | |
670 | return ParseStatus::Success; |
671 | } |
672 | |
673 | ParseStatus LoongArchAsmParser::parseImmediate(OperandVector &Operands) { |
674 | SMLoc S = getLoc(); |
675 | SMLoc E; |
676 | const MCExpr *Res; |
677 | |
678 | switch (getLexer().getKind()) { |
679 | default: |
680 | return ParseStatus::NoMatch; |
681 | case AsmToken::LParen: |
682 | case AsmToken::Dot: |
683 | case AsmToken::Minus: |
684 | case AsmToken::Plus: |
685 | case AsmToken::Exclaim: |
686 | case AsmToken::Tilde: |
687 | case AsmToken::Integer: |
688 | case AsmToken::String: |
689 | case AsmToken::Identifier: |
690 | if (getParser().parseExpression(Res, EndLoc&: E)) |
691 | return ParseStatus::Failure; |
692 | break; |
693 | case AsmToken::Percent: |
694 | return parseOperandWithModifier(Operands); |
695 | } |
696 | |
697 | Operands.push_back(Elt: LoongArchOperand::createImm(Val: Res, S, E)); |
698 | return ParseStatus::Success; |
699 | } |
700 | |
701 | ParseStatus |
702 | LoongArchAsmParser::parseOperandWithModifier(OperandVector &Operands) { |
703 | SMLoc S = getLoc(); |
704 | SMLoc E; |
705 | |
706 | if (getLexer().getKind() != AsmToken::Percent) |
707 | return Error(L: getLoc(), Msg: "expected '%' for operand modifier" ); |
708 | |
709 | getParser().Lex(); // Eat '%' |
710 | |
711 | if (getLexer().getKind() != AsmToken::Identifier) |
712 | return Error(L: getLoc(), Msg: "expected valid identifier for operand modifier" ); |
713 | StringRef Identifier = getParser().getTok().getIdentifier(); |
714 | LoongArchMCExpr::VariantKind VK = |
715 | LoongArchMCExpr::getVariantKindForName(name: Identifier); |
716 | if (VK == LoongArchMCExpr::VK_LoongArch_Invalid) |
717 | return Error(L: getLoc(), Msg: "unrecognized operand modifier" ); |
718 | |
719 | getParser().Lex(); // Eat the identifier |
720 | if (getLexer().getKind() != AsmToken::LParen) |
721 | return Error(L: getLoc(), Msg: "expected '('" ); |
722 | getParser().Lex(); // Eat '(' |
723 | |
724 | const MCExpr *SubExpr; |
725 | if (getParser().parseParenExpression(Res&: SubExpr, EndLoc&: E)) |
726 | return ParseStatus::Failure; |
727 | |
728 | const MCExpr *ModExpr = LoongArchMCExpr::create(Expr: SubExpr, Kind: VK, Ctx&: getContext()); |
729 | Operands.push_back(Elt: LoongArchOperand::createImm(Val: ModExpr, S, E)); |
730 | return ParseStatus::Success; |
731 | } |
732 | |
733 | ParseStatus LoongArchAsmParser::parseSImm26Operand(OperandVector &Operands) { |
734 | SMLoc S = getLoc(); |
735 | const MCExpr *Res; |
736 | |
737 | if (getLexer().getKind() == AsmToken::Percent) |
738 | return parseOperandWithModifier(Operands); |
739 | |
740 | if (getLexer().getKind() != AsmToken::Identifier) |
741 | return ParseStatus::NoMatch; |
742 | |
743 | StringRef Identifier; |
744 | if (getParser().parseIdentifier(Res&: Identifier)) |
745 | return ParseStatus::Failure; |
746 | |
747 | SMLoc E = SMLoc::getFromPointer(Ptr: S.getPointer() + Identifier.size()); |
748 | |
749 | MCSymbol *Sym = getContext().getOrCreateSymbol(Name: Identifier); |
750 | Res = MCSymbolRefExpr::create(Symbol: Sym, Kind: MCSymbolRefExpr::VK_None, Ctx&: getContext()); |
751 | Res = LoongArchMCExpr::create(Expr: Res, Kind: LoongArchMCExpr::VK_LoongArch_CALL, |
752 | Ctx&: getContext()); |
753 | Operands.push_back(Elt: LoongArchOperand::createImm(Val: Res, S, E)); |
754 | return ParseStatus::Success; |
755 | } |
756 | |
757 | ParseStatus LoongArchAsmParser::parseAtomicMemOp(OperandVector &Operands) { |
758 | // Parse "$r*". |
759 | if (!parseRegister(Operands).isSuccess()) |
760 | return ParseStatus::NoMatch; |
761 | |
762 | // If there is a next operand and it is 0, ignore it. Otherwise print a |
763 | // diagnostic message. |
764 | if (parseOptionalToken(T: AsmToken::Comma)) { |
765 | int64_t ImmVal; |
766 | SMLoc ImmStart = getLoc(); |
767 | if (getParser().parseIntToken(V&: ImmVal, ErrMsg: "expected optional integer offset" )) |
768 | return ParseStatus::Failure; |
769 | if (ImmVal) |
770 | return Error(L: ImmStart, Msg: "optional integer offset must be 0" ); |
771 | } |
772 | |
773 | return ParseStatus::Success; |
774 | } |
775 | /// Looks at a token type and creates the relevant operand from this |
776 | /// information, adding to Operands. Return true upon an error. |
777 | bool LoongArchAsmParser::parseOperand(OperandVector &Operands, |
778 | StringRef Mnemonic) { |
779 | // Check if the current operand has a custom associated parser, if so, try to |
780 | // custom parse the operand, or fallback to the general approach. |
781 | ParseStatus Result = |
782 | MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true); |
783 | if (Result.isSuccess()) |
784 | return false; |
785 | if (Result.isFailure()) |
786 | return true; |
787 | |
788 | if (parseRegister(Operands).isSuccess() || |
789 | parseImmediate(Operands).isSuccess()) |
790 | return false; |
791 | |
792 | // Finally we have exhausted all options and must declare defeat. |
793 | return Error(L: getLoc(), Msg: "unknown operand" ); |
794 | } |
795 | |
796 | bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info, |
797 | StringRef Name, SMLoc NameLoc, |
798 | OperandVector &Operands) { |
799 | // First operand in MCInst is instruction mnemonic. |
800 | Operands.push_back(Elt: LoongArchOperand::createToken(Str: Name, S: NameLoc)); |
801 | |
802 | // If there are no more operands, then finish. |
803 | if (parseOptionalToken(T: AsmToken::EndOfStatement)) |
804 | return false; |
805 | |
806 | // Parse first operand. |
807 | if (parseOperand(Operands, Mnemonic: Name)) |
808 | return true; |
809 | |
810 | // Parse until end of statement, consuming commas between operands. |
811 | while (parseOptionalToken(T: AsmToken::Comma)) |
812 | if (parseOperand(Operands, Mnemonic: Name)) |
813 | return true; |
814 | |
815 | // Parse end of statement and return successfully. |
816 | if (parseOptionalToken(T: AsmToken::EndOfStatement)) |
817 | return false; |
818 | |
819 | SMLoc Loc = getLexer().getLoc(); |
820 | getParser().eatToEndOfStatement(); |
821 | return Error(L: Loc, Msg: "unexpected token" ); |
822 | } |
823 | |
824 | void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg, |
825 | const MCExpr *Symbol, |
826 | SmallVectorImpl<Inst> &Insts, |
827 | SMLoc IDLoc, MCStreamer &Out, |
828 | bool RelaxHint) { |
829 | MCContext &Ctx = getContext(); |
830 | for (LoongArchAsmParser::Inst &Inst : Insts) { |
831 | unsigned Opc = Inst.Opc; |
832 | LoongArchMCExpr::VariantKind VK = Inst.VK; |
833 | const LoongArchMCExpr *LE = |
834 | LoongArchMCExpr::create(Expr: Symbol, Kind: VK, Ctx, Hint: RelaxHint); |
835 | switch (Opc) { |
836 | default: |
837 | llvm_unreachable("unexpected opcode" ); |
838 | case LoongArch::PCALAU12I: |
839 | case LoongArch::LU12I_W: |
840 | Out.emitInstruction(Inst: MCInstBuilder(Opc).addReg(Reg: DestReg).addExpr(Val: LE), |
841 | STI: getSTI()); |
842 | break; |
843 | case LoongArch::ORI: |
844 | case LoongArch::ADDI_W: |
845 | case LoongArch::LD_W: |
846 | case LoongArch::LD_D: { |
847 | if (VK == LoongArchMCExpr::VK_LoongArch_None) { |
848 | Out.emitInstruction( |
849 | Inst: MCInstBuilder(Opc).addReg(Reg: DestReg).addReg(Reg: DestReg).addImm(Val: 0), |
850 | STI: getSTI()); |
851 | continue; |
852 | } else if (VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD) { |
853 | Out.emitInstruction(Inst: MCInstBuilder(Opc) |
854 | .addReg(Reg: LoongArch::R1) |
855 | .addReg(Reg: DestReg) |
856 | .addExpr(Val: LE), |
857 | STI: getSTI()); |
858 | continue; |
859 | } |
860 | Out.emitInstruction( |
861 | Inst: MCInstBuilder(Opc).addReg(Reg: DestReg).addReg(Reg: DestReg).addExpr(Val: LE), |
862 | STI: getSTI()); |
863 | break; |
864 | } |
865 | case LoongArch::LU32I_D: |
866 | Out.emitInstruction(Inst: MCInstBuilder(Opc) |
867 | .addReg(Reg: DestReg == TmpReg ? DestReg : TmpReg) |
868 | .addReg(Reg: DestReg == TmpReg ? DestReg : TmpReg) |
869 | .addExpr(Val: LE), |
870 | STI: getSTI()); |
871 | break; |
872 | case LoongArch::LU52I_D: |
873 | Out.emitInstruction( |
874 | Inst: MCInstBuilder(Opc).addReg(Reg: TmpReg).addReg(Reg: TmpReg).addExpr(Val: LE), |
875 | STI: getSTI()); |
876 | break; |
877 | case LoongArch::ADDI_D: |
878 | Out.emitInstruction( |
879 | Inst: MCInstBuilder(Opc) |
880 | .addReg(Reg: TmpReg) |
881 | .addReg(Reg: DestReg == TmpReg ? TmpReg : LoongArch::R0) |
882 | .addExpr(Val: LE), |
883 | STI: getSTI()); |
884 | break; |
885 | case LoongArch::ADD_D: |
886 | case LoongArch::LDX_D: |
887 | Out.emitInstruction( |
888 | Inst: MCInstBuilder(Opc).addReg(Reg: DestReg).addReg(Reg: DestReg).addReg(Reg: TmpReg), |
889 | STI: getSTI()); |
890 | break; |
891 | case LoongArch::JIRL: |
892 | Out.emitInstruction(Inst: MCInstBuilder(Opc) |
893 | .addReg(Reg: LoongArch::R1) |
894 | .addReg(Reg: LoongArch::R1) |
895 | .addExpr(Val: LE), |
896 | STI: getSTI()); |
897 | break; |
898 | } |
899 | } |
900 | } |
901 | |
902 | void LoongArchAsmParser::emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc, |
903 | MCStreamer &Out) { |
904 | // la.abs $rd, sym |
905 | // expands to: |
906 | // lu12i.w $rd, %abs_hi20(sym) |
907 | // ori $rd, $rd, %abs_lo12(sym) |
908 | // |
909 | // for 64bit appends: |
910 | // lu32i.d $rd, %abs64_lo20(sym) |
911 | // lu52i.d $rd, $rd, %abs64_hi12(sym) |
912 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
913 | const MCExpr *Symbol = Inst.getOpcode() == LoongArch::PseudoLA_ABS |
914 | ? Inst.getOperand(i: 1).getExpr() |
915 | : Inst.getOperand(i: 2).getExpr(); |
916 | InstSeq Insts; |
917 | |
918 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
919 | LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_ABS_HI20)); |
920 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
921 | LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_ABS_LO12)); |
922 | |
923 | if (is64Bit()) { |
924 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
925 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_ABS64_LO20)); |
926 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
927 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_ABS64_HI12)); |
928 | } |
929 | |
930 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
931 | } |
932 | |
933 | void LoongArchAsmParser::emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc, |
934 | MCStreamer &Out) { |
935 | // la.pcrel $rd, sym |
936 | // expands to: |
937 | // pcalau12i $rd, %pc_hi20(sym) |
938 | // addi.w/d $rd, rd, %pc_lo12(sym) |
939 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
940 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
941 | InstSeq Insts; |
942 | unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
943 | |
944 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
945 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20)); |
946 | Insts.push_back( |
947 | Elt: LoongArchAsmParser::Inst(ADDI, LoongArchMCExpr::VK_LoongArch_PCALA_LO12)); |
948 | |
949 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out, RelaxHint: true); |
950 | } |
951 | |
952 | void LoongArchAsmParser::emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc, |
953 | MCStreamer &Out) { |
954 | // la.pcrel $rd, $rj, sym |
955 | // expands to: |
956 | // pcalau12i $rd, %pc_hi20(sym) |
957 | // addi.d $rj, $r0, %pc_lo12(sym) |
958 | // lu32i.d $rj, %pc64_lo20(sym) |
959 | // lu52i.d $rj, $rj, %pc64_hi12(sym) |
960 | // add.d $rd, $rd, $rj |
961 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
962 | MCRegister TmpReg = Inst.getOperand(i: 1).getReg(); |
963 | const MCExpr *Symbol = Inst.getOperand(i: 2).getExpr(); |
964 | InstSeq Insts; |
965 | |
966 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
967 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20)); |
968 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
969 | LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_PCALA_LO12)); |
970 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
971 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_LO20)); |
972 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
973 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_HI12)); |
974 | Insts.push_back(Elt: LoongArchAsmParser::Inst(LoongArch::ADD_D)); |
975 | |
976 | emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out); |
977 | } |
978 | |
979 | void LoongArchAsmParser::emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc, |
980 | MCStreamer &Out) { |
981 | // la.got $rd, sym |
982 | // expands to: |
983 | // pcalau12i $rd, %got_pc_hi20(sym) |
984 | // ld.w/d $rd, $rd, %got_pc_lo12(sym) |
985 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
986 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
987 | InstSeq Insts; |
988 | unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
989 | |
990 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
991 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20)); |
992 | Insts.push_back( |
993 | Elt: LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12)); |
994 | |
995 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out, RelaxHint: true); |
996 | } |
997 | |
998 | void LoongArchAsmParser::emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc, |
999 | MCStreamer &Out) { |
1000 | // la.got $rd, $rj, sym |
1001 | // expands to: |
1002 | // pcalau12i $rd, %got_pc_hi20(sym) |
1003 | // addi.d $rj, $r0, %got_pc_lo12(sym) |
1004 | // lu32i.d $rj, %got64_pc_lo20(sym) |
1005 | // lu52i.d $rj, $rj, %got64_pc_hi12(sym) |
1006 | // ldx.d $rd, $rd, $rj |
1007 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1008 | MCRegister TmpReg = Inst.getOperand(i: 1).getReg(); |
1009 | const MCExpr *Symbol = Inst.getOperand(i: 2).getExpr(); |
1010 | InstSeq Insts; |
1011 | |
1012 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1013 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20)); |
1014 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1015 | LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12)); |
1016 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1017 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20)); |
1018 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1019 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12)); |
1020 | Insts.push_back(Elt: LoongArchAsmParser::Inst(LoongArch::LDX_D)); |
1021 | |
1022 | emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out); |
1023 | } |
1024 | |
1025 | void LoongArchAsmParser::emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc, |
1026 | MCStreamer &Out) { |
1027 | // la.tls.le $rd, sym |
1028 | // expands to: |
1029 | // lu12i.w $rd, %le_hi20(sym) |
1030 | // ori $rd, $rd, %le_lo12(sym) |
1031 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1032 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
1033 | InstSeq Insts; |
1034 | |
1035 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1036 | LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20)); |
1037 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1038 | LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12)); |
1039 | |
1040 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
1041 | } |
1042 | |
1043 | void LoongArchAsmParser::emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc, |
1044 | MCStreamer &Out) { |
1045 | // la.tls.ie $rd, sym |
1046 | // expands to: |
1047 | // pcalau12i $rd, %ie_pc_hi20(sym) |
1048 | // ld.w/d $rd, $rd, %ie_pc_lo12(sym) |
1049 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1050 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
1051 | InstSeq Insts; |
1052 | unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
1053 | |
1054 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1055 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20)); |
1056 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1057 | LD, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12)); |
1058 | |
1059 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
1060 | } |
1061 | |
1062 | void LoongArchAsmParser::emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc, |
1063 | MCStreamer &Out) { |
1064 | // la.tls.ie $rd, $rj, sym |
1065 | // expands to: |
1066 | // pcalau12i $rd, %ie_pc_hi20(sym) |
1067 | // addi.d $rj, $r0, %ie_pc_lo12(sym) |
1068 | // lu32i.d $rj, %ie64_pc_lo20(sym) |
1069 | // lu52i.d $rj, $rj, %ie64_pc_hi12(sym) |
1070 | // ldx.d $rd, $rd, $rj |
1071 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1072 | MCRegister TmpReg = Inst.getOperand(i: 1).getReg(); |
1073 | const MCExpr *Symbol = Inst.getOperand(i: 2).getExpr(); |
1074 | InstSeq Insts; |
1075 | |
1076 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1077 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20)); |
1078 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1079 | LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12)); |
1080 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1081 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20)); |
1082 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1083 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12)); |
1084 | Insts.push_back(Elt: LoongArchAsmParser::Inst(LoongArch::LDX_D)); |
1085 | |
1086 | emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out); |
1087 | } |
1088 | |
1089 | void LoongArchAsmParser::emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc, |
1090 | MCStreamer &Out) { |
1091 | // la.tls.ld $rd, sym |
1092 | // expands to: |
1093 | // pcalau12i $rd, %ld_pc_hi20(sym) |
1094 | // addi.w/d $rd, $rd, %got_pc_lo12(sym) |
1095 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1096 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
1097 | InstSeq Insts; |
1098 | unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
1099 | |
1100 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1101 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20)); |
1102 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1103 | ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12)); |
1104 | |
1105 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
1106 | } |
1107 | |
1108 | void LoongArchAsmParser::emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc, |
1109 | MCStreamer &Out) { |
1110 | // la.tls.ld $rd, $rj, sym |
1111 | // expands to: |
1112 | // pcalau12i $rd, %ld_pc_hi20(sym) |
1113 | // addi.d $rj, $r0, %got_pc_lo12(sym) |
1114 | // lu32i.d $rj, %got64_pc_lo20(sym) |
1115 | // lu52i.d $rj, $rj, %got64_pc_hi12(sym) |
1116 | // add.d $rd, $rd, $rj |
1117 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1118 | MCRegister TmpReg = Inst.getOperand(i: 1).getReg(); |
1119 | const MCExpr *Symbol = Inst.getOperand(i: 2).getExpr(); |
1120 | InstSeq Insts; |
1121 | |
1122 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1123 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20)); |
1124 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1125 | LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12)); |
1126 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1127 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20)); |
1128 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1129 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12)); |
1130 | Insts.push_back(Elt: LoongArchAsmParser::Inst(LoongArch::ADD_D)); |
1131 | |
1132 | emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out); |
1133 | } |
1134 | |
1135 | void LoongArchAsmParser::emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc, |
1136 | MCStreamer &Out) { |
1137 | // la.tls.gd $rd, sym |
1138 | // expands to: |
1139 | // pcalau12i $rd, %gd_pc_hi20(sym) |
1140 | // addi.w/d $rd, $rd, %got_pc_lo12(sym) |
1141 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1142 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
1143 | InstSeq Insts; |
1144 | unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
1145 | |
1146 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1147 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20)); |
1148 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1149 | ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12)); |
1150 | |
1151 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
1152 | } |
1153 | |
1154 | void LoongArchAsmParser::emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, |
1155 | MCStreamer &Out) { |
1156 | // la.tls.gd $rd, $rj, sym |
1157 | // expands to: |
1158 | // pcalau12i $rd, %gd_pc_hi20(sym) |
1159 | // addi.d $rj, $r0, %got_pc_lo12(sym) |
1160 | // lu32i.d $rj, %got64_pc_lo20(sym) |
1161 | // lu52i.d $rj, $rj, %got64_pc_hi12(sym) |
1162 | // add.d $rd, $rd, $rj |
1163 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1164 | MCRegister TmpReg = Inst.getOperand(i: 1).getReg(); |
1165 | const MCExpr *Symbol = Inst.getOperand(i: 2).getExpr(); |
1166 | InstSeq Insts; |
1167 | |
1168 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1169 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20)); |
1170 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1171 | LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12)); |
1172 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1173 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20)); |
1174 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1175 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12)); |
1176 | Insts.push_back(Elt: LoongArchAsmParser::Inst(LoongArch::ADD_D)); |
1177 | |
1178 | emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out); |
1179 | } |
1180 | |
1181 | void LoongArchAsmParser::emitLoadAddressTLSDescAbs(MCInst &Inst, SMLoc IDLoc, |
1182 | MCStreamer &Out) { |
1183 | // `la.tls.desc $rd, sym` with `la-global-with-abs` feature |
1184 | // for la32 expands to: |
1185 | // lu12i.w $rd, %desc_hi20(sym) |
1186 | // ori $rd, $rd, %desc_lo12(sym) |
1187 | // ld.w $ra, $rd, %desc_ld(sym) |
1188 | // jirl $ra, $ra, %desc_call(sym) |
1189 | // |
1190 | // for la64 expands to: |
1191 | // lu12i.w $rd, %desc_hi20(sym) |
1192 | // ori $rd, $rd, %desc_lo12(sym) |
1193 | // lu32i.d $rd, %desc64_lo20(sym) |
1194 | // lu52i.d $rd, $rd, %desc64_hi12(sym) |
1195 | // ld.d $ra, $rd, %desc_ld(sym) |
1196 | // jirl $ra, $ra, %desc_call(sym) |
1197 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1198 | const MCExpr *Symbol = Inst.getOpcode() == LoongArch::PseudoLA_TLS_DESC_ABS |
1199 | ? Inst.getOperand(i: 1).getExpr() |
1200 | : Inst.getOperand(i: 2).getExpr(); |
1201 | unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
1202 | InstSeq Insts; |
1203 | |
1204 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1205 | LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_TLS_DESC_HI20)); |
1206 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1207 | LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LO12)); |
1208 | |
1209 | if (is64Bit()) { |
1210 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1211 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_LO20)); |
1212 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1213 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_HI12)); |
1214 | } |
1215 | |
1216 | Insts.push_back( |
1217 | Elt: LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD)); |
1218 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1219 | LoongArch::JIRL, LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL)); |
1220 | |
1221 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
1222 | } |
1223 | |
1224 | void LoongArchAsmParser::emitLoadAddressTLSDescPcrel(MCInst &Inst, SMLoc IDLoc, |
1225 | MCStreamer &Out) { |
1226 | // la.tls.desc $rd, sym |
1227 | // expands to: |
1228 | // pcalau12i $rd, %desc_pc_hi20(sym) |
1229 | // addi.w/d $rd, $rd, %desc_pc_lo12(sym) |
1230 | // ld.w/d $ra, $rd, %desc_ld(sym) |
1231 | // jirl $ra, $ra, %desc_call(sym) |
1232 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1233 | const MCExpr *Symbol = Inst.getOperand(i: 1).getExpr(); |
1234 | unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
1235 | unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
1236 | InstSeq Insts; |
1237 | |
1238 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1239 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20)); |
1240 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1241 | ADDI, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12)); |
1242 | Insts.push_back( |
1243 | Elt: LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD)); |
1244 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1245 | LoongArch::JIRL, LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL)); |
1246 | |
1247 | emitLAInstSeq(DestReg, TmpReg: DestReg, Symbol, Insts, IDLoc, Out); |
1248 | } |
1249 | |
1250 | void LoongArchAsmParser::emitLoadAddressTLSDescPcrelLarge(MCInst &Inst, |
1251 | SMLoc IDLoc, |
1252 | MCStreamer &Out) { |
1253 | // la.tls.desc $rd, $rj, sym |
1254 | // expands to: |
1255 | // pcalau12i $rd, %desc_pc_hi20(sym) |
1256 | // addi.d $rj, $r0, %desc_pc_lo12(sym) |
1257 | // lu32i.d $rj, %desc64_pc_lo20(sym) |
1258 | // lu52i.d $rj, $rj, %desc64_pc_hi12(sym) |
1259 | // add.d $rd, $rd, $rj |
1260 | // ld.w/d $ra, $rd, %desc_ld(sym) |
1261 | // jirl $ra, $ra, %desc_call(sym) |
1262 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1263 | MCRegister TmpReg = Inst.getOperand(i: 1).getReg(); |
1264 | const MCExpr *Symbol = Inst.getOperand(i: 2).getExpr(); |
1265 | InstSeq Insts; |
1266 | |
1267 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1268 | LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20)); |
1269 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1270 | LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12)); |
1271 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1272 | LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_LO20)); |
1273 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1274 | LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_HI12)); |
1275 | Insts.push_back(Elt: LoongArchAsmParser::Inst(LoongArch::ADD_D)); |
1276 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1277 | LoongArch::LD_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD)); |
1278 | Insts.push_back(Elt: LoongArchAsmParser::Inst( |
1279 | LoongArch::JIRL, LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL)); |
1280 | |
1281 | emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out); |
1282 | } |
1283 | |
1284 | void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc, |
1285 | MCStreamer &Out) { |
1286 | MCRegister DestReg = Inst.getOperand(i: 0).getReg(); |
1287 | int64_t Imm = Inst.getOperand(i: 1).getImm(); |
1288 | MCRegister SrcReg = LoongArch::R0; |
1289 | |
1290 | if (Inst.getOpcode() == LoongArch::PseudoLI_W) |
1291 | Imm = SignExtend64<32>(x: Imm); |
1292 | |
1293 | for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Val: Imm)) { |
1294 | unsigned Opc = Inst.Opc; |
1295 | if (Opc == LoongArch::LU12I_W) |
1296 | Out.emitInstruction(Inst: MCInstBuilder(Opc).addReg(Reg: DestReg).addImm(Val: Inst.Imm), |
1297 | STI: getSTI()); |
1298 | else |
1299 | Out.emitInstruction( |
1300 | Inst: MCInstBuilder(Opc).addReg(Reg: DestReg).addReg(Reg: SrcReg).addImm(Val: Inst.Imm), |
1301 | STI: getSTI()); |
1302 | SrcReg = DestReg; |
1303 | } |
1304 | } |
1305 | |
1306 | void LoongArchAsmParser::emitFuncCall36(MCInst &Inst, SMLoc IDLoc, |
1307 | MCStreamer &Out, bool IsTailCall) { |
1308 | // call36 sym |
1309 | // expands to: |
1310 | // pcaddu18i $ra, %call36(sym) |
1311 | // jirl $ra, $ra, 0 |
1312 | // |
1313 | // tail36 $rj, sym |
1314 | // expands to: |
1315 | // pcaddu18i $rj, %call36(sym) |
1316 | // jirl $r0, $rj, 0 |
1317 | unsigned ScratchReg = |
1318 | IsTailCall ? Inst.getOperand(i: 0).getReg() : (unsigned)LoongArch::R1; |
1319 | const MCExpr *Sym = |
1320 | IsTailCall ? Inst.getOperand(i: 1).getExpr() : Inst.getOperand(i: 0).getExpr(); |
1321 | const LoongArchMCExpr *LE = LoongArchMCExpr::create( |
1322 | Expr: Sym, Kind: llvm::LoongArchMCExpr::VK_LoongArch_CALL36, Ctx&: getContext()); |
1323 | |
1324 | Out.emitInstruction( |
1325 | Inst: MCInstBuilder(LoongArch::PCADDU18I).addReg(Reg: ScratchReg).addExpr(Val: LE), |
1326 | STI: getSTI()); |
1327 | Out.emitInstruction( |
1328 | Inst: MCInstBuilder(LoongArch::JIRL) |
1329 | .addReg(Reg: IsTailCall ? (unsigned)LoongArch::R0 : ScratchReg) |
1330 | .addReg(Reg: ScratchReg) |
1331 | .addImm(Val: 0), |
1332 | STI: getSTI()); |
1333 | } |
1334 | |
1335 | bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, |
1336 | OperandVector &Operands, |
1337 | MCStreamer &Out) { |
1338 | Inst.setLoc(IDLoc); |
1339 | switch (Inst.getOpcode()) { |
1340 | default: |
1341 | break; |
1342 | case LoongArch::PseudoLA_ABS: |
1343 | case LoongArch::PseudoLA_ABS_LARGE: |
1344 | emitLoadAddressAbs(Inst, IDLoc, Out); |
1345 | return false; |
1346 | case LoongArch::PseudoLA_PCREL: |
1347 | emitLoadAddressPcrel(Inst, IDLoc, Out); |
1348 | return false; |
1349 | case LoongArch::PseudoLA_PCREL_LARGE: |
1350 | emitLoadAddressPcrelLarge(Inst, IDLoc, Out); |
1351 | return false; |
1352 | case LoongArch::PseudoLA_GOT: |
1353 | emitLoadAddressGot(Inst, IDLoc, Out); |
1354 | return false; |
1355 | case LoongArch::PseudoLA_GOT_LARGE: |
1356 | emitLoadAddressGotLarge(Inst, IDLoc, Out); |
1357 | return false; |
1358 | case LoongArch::PseudoLA_TLS_LE: |
1359 | emitLoadAddressTLSLE(Inst, IDLoc, Out); |
1360 | return false; |
1361 | case LoongArch::PseudoLA_TLS_IE: |
1362 | emitLoadAddressTLSIE(Inst, IDLoc, Out); |
1363 | return false; |
1364 | case LoongArch::PseudoLA_TLS_IE_LARGE: |
1365 | emitLoadAddressTLSIELarge(Inst, IDLoc, Out); |
1366 | return false; |
1367 | case LoongArch::PseudoLA_TLS_LD: |
1368 | emitLoadAddressTLSLD(Inst, IDLoc, Out); |
1369 | return false; |
1370 | case LoongArch::PseudoLA_TLS_LD_LARGE: |
1371 | emitLoadAddressTLSLDLarge(Inst, IDLoc, Out); |
1372 | return false; |
1373 | case LoongArch::PseudoLA_TLS_GD: |
1374 | emitLoadAddressTLSGD(Inst, IDLoc, Out); |
1375 | return false; |
1376 | case LoongArch::PseudoLA_TLS_GD_LARGE: |
1377 | emitLoadAddressTLSGDLarge(Inst, IDLoc, Out); |
1378 | return false; |
1379 | case LoongArch::PseudoLA_TLS_DESC_ABS: |
1380 | case LoongArch::PseudoLA_TLS_DESC_ABS_LARGE: |
1381 | emitLoadAddressTLSDescAbs(Inst, IDLoc, Out); |
1382 | return false; |
1383 | case LoongArch::PseudoLA_TLS_DESC_PC: |
1384 | emitLoadAddressTLSDescPcrel(Inst, IDLoc, Out); |
1385 | return false; |
1386 | case LoongArch::PseudoLA_TLS_DESC_PC_LARGE: |
1387 | emitLoadAddressTLSDescPcrelLarge(Inst, IDLoc, Out); |
1388 | return false; |
1389 | case LoongArch::PseudoLI_W: |
1390 | case LoongArch::PseudoLI_D: |
1391 | emitLoadImm(Inst, IDLoc, Out); |
1392 | return false; |
1393 | case LoongArch::PseudoCALL36: |
1394 | emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/false); |
1395 | return false; |
1396 | case LoongArch::PseudoTAIL36: |
1397 | emitFuncCall36(Inst, IDLoc, Out, /*IsTailCall=*/true); |
1398 | return false; |
1399 | } |
1400 | Out.emitInstruction(Inst, STI: getSTI()); |
1401 | return false; |
1402 | } |
1403 | |
1404 | unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) { |
1405 | unsigned Opc = Inst.getOpcode(); |
1406 | switch (Opc) { |
1407 | default: |
1408 | if (Opc >= LoongArch::AMADD_D && Opc <= LoongArch::AMXOR_W) { |
1409 | unsigned Rd = Inst.getOperand(i: 0).getReg(); |
1410 | unsigned Rk = Inst.getOperand(i: 1).getReg(); |
1411 | unsigned Rj = Inst.getOperand(i: 2).getReg(); |
1412 | if ((Rd == Rk || Rd == Rj) && Rd != LoongArch::R0) |
1413 | return Match_RequiresAMORdDifferRkRj; |
1414 | } |
1415 | break; |
1416 | case LoongArch::PseudoLA_TLS_DESC_ABS: |
1417 | case LoongArch::PseudoLA_TLS_DESC_ABS_LARGE: |
1418 | case LoongArch::PseudoLA_TLS_DESC_PC: |
1419 | case LoongArch::PseudoLA_TLS_DESC_PC_LARGE: { |
1420 | unsigned Rd = Inst.getOperand(i: 0).getReg(); |
1421 | if (Rd != LoongArch::R4) |
1422 | return Match_RequiresLAORdR4; |
1423 | break; |
1424 | } |
1425 | case LoongArch::PseudoLA_PCREL_LARGE: |
1426 | case LoongArch::PseudoLA_GOT_LARGE: |
1427 | case LoongArch::PseudoLA_TLS_IE_LARGE: |
1428 | case LoongArch::PseudoLA_TLS_LD_LARGE: |
1429 | case LoongArch::PseudoLA_TLS_GD_LARGE: { |
1430 | unsigned Rd = Inst.getOperand(i: 0).getReg(); |
1431 | unsigned Rj = Inst.getOperand(i: 1).getReg(); |
1432 | if (Rd == Rj) |
1433 | return Match_RequiresLAORdDifferRj; |
1434 | break; |
1435 | } |
1436 | case LoongArch::CSRXCHG: |
1437 | case LoongArch::GCSRXCHG: { |
1438 | unsigned Rj = Inst.getOperand(i: 2).getReg(); |
1439 | if (Rj == LoongArch::R0 || Rj == LoongArch::R1) |
1440 | return Match_RequiresOpnd2NotR0R1; |
1441 | return Match_Success; |
1442 | } |
1443 | case LoongArch::BSTRINS_W: |
1444 | case LoongArch::BSTRINS_D: |
1445 | case LoongArch::BSTRPICK_W: |
1446 | case LoongArch::BSTRPICK_D: { |
1447 | unsigned Opc = Inst.getOpcode(); |
1448 | const signed Msb = |
1449 | (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D) |
1450 | ? Inst.getOperand(i: 3).getImm() |
1451 | : Inst.getOperand(i: 2).getImm(); |
1452 | const signed Lsb = |
1453 | (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D) |
1454 | ? Inst.getOperand(i: 4).getImm() |
1455 | : Inst.getOperand(i: 3).getImm(); |
1456 | if (Msb < Lsb) |
1457 | return Match_RequiresMsbNotLessThanLsb; |
1458 | return Match_Success; |
1459 | } |
1460 | } |
1461 | |
1462 | return Match_Success; |
1463 | } |
1464 | |
1465 | unsigned |
1466 | LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, |
1467 | unsigned Kind) { |
1468 | LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp); |
1469 | if (!Op.isReg()) |
1470 | return Match_InvalidOperand; |
1471 | |
1472 | MCRegister Reg = Op.getReg(); |
1473 | // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the |
1474 | // register from FPR32 to FPR64 if necessary. |
1475 | if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) && |
1476 | Kind == MCK_FPR64) { |
1477 | Op.setReg(convertFPR32ToFPR64(Reg)); |
1478 | return Match_Success; |
1479 | } |
1480 | |
1481 | return Match_InvalidOperand; |
1482 | } |
1483 | |
1484 | bool LoongArchAsmParser::generateImmOutOfRangeError( |
1485 | OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, |
1486 | const Twine &Msg = "immediate must be an integer in the range" ) { |
1487 | SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); |
1488 | return Error(L: ErrorLoc, Msg: Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]" ); |
1489 | } |
1490 | |
1491 | bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, |
1492 | OperandVector &Operands, |
1493 | MCStreamer &Out, |
1494 | uint64_t &ErrorInfo, |
1495 | bool MatchingInlineAsm) { |
1496 | MCInst Inst; |
1497 | FeatureBitset MissingFeatures; |
1498 | |
1499 | auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures, |
1500 | matchingInlineAsm: MatchingInlineAsm); |
1501 | switch (Result) { |
1502 | default: |
1503 | break; |
1504 | case Match_Success: |
1505 | return processInstruction(Inst, IDLoc, Operands, Out); |
1506 | case Match_MissingFeature: { |
1507 | assert(MissingFeatures.any() && "Unknown missing features!" ); |
1508 | bool FirstFeature = true; |
1509 | std::string Msg = "instruction requires the following:" ; |
1510 | for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) { |
1511 | if (MissingFeatures[i]) { |
1512 | Msg += FirstFeature ? " " : ", " ; |
1513 | Msg += getSubtargetFeatureName(Val: i); |
1514 | FirstFeature = false; |
1515 | } |
1516 | } |
1517 | return Error(L: IDLoc, Msg); |
1518 | } |
1519 | case Match_MnemonicFail: { |
1520 | FeatureBitset FBS = ComputeAvailableFeatures(FB: getSTI().getFeatureBits()); |
1521 | std::string Suggestion = LoongArchMnemonicSpellCheck( |
1522 | S: ((LoongArchOperand &)*Operands[0]).getToken(), FBS, VariantID: 0); |
1523 | return Error(L: IDLoc, Msg: "unrecognized instruction mnemonic" + Suggestion); |
1524 | } |
1525 | case Match_InvalidOperand: { |
1526 | SMLoc ErrorLoc = IDLoc; |
1527 | if (ErrorInfo != ~0ULL) { |
1528 | if (ErrorInfo >= Operands.size()) |
1529 | return Error(L: ErrorLoc, Msg: "too few operands for instruction" ); |
1530 | |
1531 | ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); |
1532 | if (ErrorLoc == SMLoc()) |
1533 | ErrorLoc = IDLoc; |
1534 | } |
1535 | return Error(L: ErrorLoc, Msg: "invalid operand for instruction" ); |
1536 | } |
1537 | } |
1538 | |
1539 | // Handle the case when the error message is of specific type |
1540 | // other than the generic Match_InvalidOperand, and the |
1541 | // corresponding operand is missing. |
1542 | if (Result > FIRST_TARGET_MATCH_RESULT_TY) { |
1543 | SMLoc ErrorLoc = IDLoc; |
1544 | if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size()) |
1545 | return Error(L: ErrorLoc, Msg: "too few operands for instruction" ); |
1546 | } |
1547 | |
1548 | switch (Result) { |
1549 | default: |
1550 | break; |
1551 | case Match_RequiresMsbNotLessThanLsb: { |
1552 | SMLoc ErrorStart = Operands[3]->getStartLoc(); |
1553 | return Error(L: ErrorStart, Msg: "msb is less than lsb" , |
1554 | Range: SMRange(ErrorStart, Operands[4]->getEndLoc())); |
1555 | } |
1556 | case Match_RequiresOpnd2NotR0R1: |
1557 | return Error(L: Operands[2]->getStartLoc(), Msg: "must not be $r0 or $r1" ); |
1558 | case Match_RequiresAMORdDifferRkRj: |
1559 | return Error(L: Operands[1]->getStartLoc(), |
1560 | Msg: "$rd must be different from both $rk and $rj" ); |
1561 | case Match_RequiresLAORdDifferRj: |
1562 | return Error(L: Operands[1]->getStartLoc(), Msg: "$rd must be different from $rj" ); |
1563 | case Match_RequiresLAORdR4: |
1564 | return Error(L: Operands[1]->getStartLoc(), Msg: "$rd must be $r4" ); |
1565 | case Match_InvalidUImm1: |
1566 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1567 | /*Upper=*/(1 << 1) - 1); |
1568 | case Match_InvalidUImm2: |
1569 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1570 | /*Upper=*/(1 << 2) - 1); |
1571 | case Match_InvalidUImm2plus1: |
1572 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1, |
1573 | /*Upper=*/(1 << 2)); |
1574 | case Match_InvalidUImm3: |
1575 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1576 | /*Upper=*/(1 << 3) - 1); |
1577 | case Match_InvalidUImm4: |
1578 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1579 | /*Upper=*/(1 << 4) - 1); |
1580 | case Match_InvalidUImm5: |
1581 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1582 | /*Upper=*/(1 << 5) - 1); |
1583 | case Match_InvalidUImm6: |
1584 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1585 | /*Upper=*/(1 << 6) - 1); |
1586 | case Match_InvalidUImm7: |
1587 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1588 | /*Upper=*/(1 << 7) - 1); |
1589 | case Match_InvalidUImm8: |
1590 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1591 | /*Upper=*/(1 << 8) - 1); |
1592 | case Match_InvalidUImm12: |
1593 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1594 | /*Upper=*/(1 << 12) - 1); |
1595 | case Match_InvalidUImm12ori: |
1596 | return generateImmOutOfRangeError( |
1597 | Operands, ErrorInfo, /*Lower=*/0, |
1598 | /*Upper=*/(1 << 12) - 1, |
1599 | Msg: "operand must be a symbol with modifier (e.g. %abs_lo12) or an " |
1600 | "integer in the range" ); |
1601 | case Match_InvalidUImm14: |
1602 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1603 | /*Upper=*/(1 << 14) - 1); |
1604 | case Match_InvalidUImm15: |
1605 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, |
1606 | /*Upper=*/(1 << 15) - 1); |
1607 | case Match_InvalidSImm5: |
1608 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 4), |
1609 | /*Upper=*/(1 << 4) - 1); |
1610 | case Match_InvalidSImm8: |
1611 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 7), |
1612 | /*Upper=*/(1 << 7) - 1); |
1613 | case Match_InvalidSImm8lsl1: |
1614 | return generateImmOutOfRangeError( |
1615 | Operands, ErrorInfo, /*Lower=*/-(1 << 8), /*Upper=*/(1 << 8) - 2, |
1616 | Msg: "immediate must be a multiple of 2 in the range" ); |
1617 | case Match_InvalidSImm8lsl2: |
1618 | return generateImmOutOfRangeError( |
1619 | Operands, ErrorInfo, /*Lower=*/-(1 << 9), /*Upper=*/(1 << 9) - 4, |
1620 | Msg: "immediate must be a multiple of 4 in the range" ); |
1621 | case Match_InvalidSImm10: |
1622 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 9), |
1623 | /*Upper=*/(1 << 9) - 1); |
1624 | case Match_InvalidSImm8lsl3: |
1625 | return generateImmOutOfRangeError( |
1626 | Operands, ErrorInfo, /*Lower=*/-(1 << 10), /*Upper=*/(1 << 10) - 8, |
1627 | Msg: "immediate must be a multiple of 8 in the range" ); |
1628 | case Match_InvalidSImm9lsl3: |
1629 | return generateImmOutOfRangeError( |
1630 | Operands, ErrorInfo, /*Lower=*/-(1 << 11), /*Upper=*/(1 << 11) - 8, |
1631 | Msg: "immediate must be a multiple of 8 in the range" ); |
1632 | case Match_InvalidSImm10lsl2: |
1633 | return generateImmOutOfRangeError( |
1634 | Operands, ErrorInfo, /*Lower=*/-(1 << 11), /*Upper=*/(1 << 11) - 4, |
1635 | Msg: "immediate must be a multiple of 4 in the range" ); |
1636 | case Match_InvalidSImm11lsl1: |
1637 | return generateImmOutOfRangeError( |
1638 | Operands, ErrorInfo, /*Lower=*/-(1 << 11), /*Upper=*/(1 << 11) - 2, |
1639 | Msg: "immediate must be a multiple of 2 in the range" ); |
1640 | case Match_InvalidSImm12: |
1641 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11), |
1642 | /*Upper=*/(1 << 11) - 1); |
1643 | case Match_InvalidSImm12addlike: |
1644 | return generateImmOutOfRangeError( |
1645 | Operands, ErrorInfo, /*Lower=*/-(1 << 11), |
1646 | /*Upper=*/(1 << 11) - 1, |
1647 | Msg: "operand must be a symbol with modifier (e.g. %pc_lo12) or an integer " |
1648 | "in the range" ); |
1649 | case Match_InvalidSImm12lu52id: |
1650 | return generateImmOutOfRangeError( |
1651 | Operands, ErrorInfo, /*Lower=*/-(1 << 11), |
1652 | /*Upper=*/(1 << 11) - 1, |
1653 | Msg: "operand must be a symbol with modifier (e.g. %pc64_hi12) or an " |
1654 | "integer in the range" ); |
1655 | case Match_InvalidSImm13: |
1656 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 12), |
1657 | /*Upper=*/(1 << 12) - 1); |
1658 | case Match_InvalidSImm14lsl2: |
1659 | return generateImmOutOfRangeError( |
1660 | Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4, |
1661 | Msg: "immediate must be a multiple of 4 in the range" ); |
1662 | case Match_InvalidSImm16: |
1663 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15), |
1664 | /*Upper=*/(1 << 15) - 1); |
1665 | case Match_InvalidSImm16lsl2: |
1666 | return generateImmOutOfRangeError( |
1667 | Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4, |
1668 | Msg: "operand must be a symbol with modifier (e.g. %b16) or an integer " |
1669 | "in the range" ); |
1670 | case Match_InvalidSImm20: |
1671 | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19), |
1672 | /*Upper=*/(1 << 19) - 1); |
1673 | case Match_InvalidSImm20lu12iw: |
1674 | return generateImmOutOfRangeError( |
1675 | Operands, ErrorInfo, /*Lower=*/-(1 << 19), |
1676 | /*Upper=*/(1 << 19) - 1, |
1677 | Msg: "operand must be a symbol with modifier (e.g. %abs_hi20) or an integer " |
1678 | "in the range" ); |
1679 | case Match_InvalidSImm20lu32id: |
1680 | return generateImmOutOfRangeError( |
1681 | Operands, ErrorInfo, /*Lower=*/-(1 << 19), |
1682 | /*Upper=*/(1 << 19) - 1, |
1683 | Msg: "operand must be a symbol with modifier (e.g. %abs64_lo20) or an " |
1684 | "integer in the range" ); |
1685 | case Match_InvalidSImm20pcalau12i: |
1686 | return generateImmOutOfRangeError( |
1687 | Operands, ErrorInfo, /*Lower=*/-(1 << 19), |
1688 | /*Upper=*/(1 << 19) - 1, |
1689 | Msg: "operand must be a symbol with modifier (e.g. %pc_hi20) or an integer " |
1690 | "in the range" ); |
1691 | case Match_InvalidSImm20pcaddu18i: |
1692 | return generateImmOutOfRangeError( |
1693 | Operands, ErrorInfo, /*Lower=*/-(1 << 19), |
1694 | /*Upper=*/(1 << 19) - 1, |
1695 | Msg: "operand must be a symbol with modifier (e.g. %call36) or an integer " |
1696 | "in the range" ); |
1697 | case Match_InvalidSImm20pcaddi: |
1698 | return generateImmOutOfRangeError( |
1699 | Operands, ErrorInfo, /*Lower=*/-(1 << 19), |
1700 | /*Upper=*/(1 << 19) - 1, |
1701 | Msg: "operand must be a symbol with modifier (e.g. %pcrel_20) or an integer " |
1702 | "in the range" ); |
1703 | case Match_InvalidSImm21lsl2: |
1704 | return generateImmOutOfRangeError( |
1705 | Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4, |
1706 | Msg: "operand must be a symbol with modifier (e.g. %b21) or an integer " |
1707 | "in the range" ); |
1708 | case Match_InvalidSImm26Operand: |
1709 | return generateImmOutOfRangeError( |
1710 | Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4, |
1711 | Msg: "operand must be a bare symbol name or an immediate must be a multiple " |
1712 | "of 4 in the range" ); |
1713 | case Match_InvalidImm32: { |
1714 | SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); |
1715 | return Error(L: ErrorLoc, Msg: "operand must be a 32 bit immediate" ); |
1716 | } |
1717 | case Match_InvalidImm64: { |
1718 | SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); |
1719 | return Error(L: ErrorLoc, Msg: "operand must be a 64 bit immediate" ); |
1720 | } |
1721 | case Match_InvalidBareSymbol: { |
1722 | SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); |
1723 | return Error(L: ErrorLoc, Msg: "operand must be a bare symbol name" ); |
1724 | } |
1725 | case Match_InvalidTPRelAddSymbol: { |
1726 | SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); |
1727 | return Error(L: ErrorLoc, Msg: "operand must be a symbol with %le_add_r modifier" ); |
1728 | } |
1729 | } |
1730 | llvm_unreachable("Unknown match type detected!" ); |
1731 | } |
1732 | |
1733 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() { |
1734 | RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target()); |
1735 | RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target()); |
1736 | } |
1737 | |