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/LoongArchMCTargetDesc.h"
11 #include "TargetInfo/LoongArchTargetInfo.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCInstrInfo.h"
14 #include "llvm/MC/MCParser/MCAsmLexer.h"
15 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
16 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
17 #include "llvm/MC/MCRegisterInfo.h"
18 #include "llvm/MC/MCStreamer.h"
19 #include "llvm/MC/MCSubtargetInfo.h"
20 #include "llvm/MC/TargetRegistry.h"
21 #include "llvm/Support/Casting.h"
22
23 using namespace llvm;
24
25 #define DEBUG_TYPE "loongarch-asm-parser"
26
27 namespace {
28 class LoongArchAsmParser : public MCTargetAsmParser {
getLoc() const29 SMLoc getLoc() const { return getParser().getTok().getLoc(); }
30
31 /// Parse a register as used in CFI directives.
32 bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
33 OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
34 SMLoc &EndLoc) override;
35
36 bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
37 SMLoc NameLoc, OperandVector &Operands) override;
38
ParseDirective(AsmToken DirectiveID)39 bool ParseDirective(AsmToken DirectiveID) override { return true; }
40
41 bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
42 OperandVector &Operands, MCStreamer &Out,
43 uint64_t &ErrorInfo,
44 bool MatchingInlineAsm) override;
45
46 unsigned checkTargetMatchPredicate(MCInst &Inst) override;
47
48 unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
49 unsigned Kind) override;
50
51 bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
52 int64_t Lower, int64_t Upper, Twine Msg);
53
54 /// Helper for processing MC instructions that have been successfully matched
55 /// by MatchAndEmitInstruction.
56 bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
57 MCStreamer &Out);
58
59 // Auto-generated instruction matching functions.
60 #define GET_ASSEMBLER_HEADER
61 #include "LoongArchGenAsmMatcher.inc"
62
63 OperandMatchResultTy parseRegister(OperandVector &Operands);
64 OperandMatchResultTy parseImmediate(OperandVector &Operands);
65
66 bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
67
68 public:
69 enum LoongArchMatchResultTy {
70 Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
71 Match_RequiresMsbNotLessThanLsb,
72 Match_RequiresOpnd2NotR0R1,
73 #define GET_OPERAND_DIAGNOSTIC_TYPES
74 #include "LoongArchGenAsmMatcher.inc"
75 #undef GET_OPERAND_DIAGNOSTIC_TYPES
76 };
77
LoongArchAsmParser(const MCSubtargetInfo & STI,MCAsmParser & Parser,const MCInstrInfo & MII,const MCTargetOptions & Options)78 LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
79 const MCInstrInfo &MII, const MCTargetOptions &Options)
80 : MCTargetAsmParser(Options, STI, MII) {
81 Parser.addAliasForDirective(".half", ".2byte");
82 Parser.addAliasForDirective(".hword", ".2byte");
83 Parser.addAliasForDirective(".word", ".4byte");
84 Parser.addAliasForDirective(".dword", ".8byte");
85
86 // Initialize the set of available features.
87 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
88 }
89 };
90
91 // Instances of this class represent a parsed LoongArch machine instruction.
92 class LoongArchOperand : public MCParsedAsmOperand {
93 enum class KindTy {
94 Token,
95 Register,
96 Immediate,
97 } Kind;
98
99 struct RegOp {
100 MCRegister RegNum;
101 };
102
103 struct ImmOp {
104 const MCExpr *Val;
105 };
106
107 SMLoc StartLoc, EndLoc;
108 union {
109 StringRef Tok;
110 struct RegOp Reg;
111 struct ImmOp Imm;
112 };
113
114 public:
LoongArchOperand(KindTy K)115 LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
116
isToken() const117 bool isToken() const override { return Kind == KindTy::Token; }
isReg() const118 bool isReg() const override { return Kind == KindTy::Register; }
isImm() const119 bool isImm() const override { return Kind == KindTy::Immediate; }
isMem() const120 bool isMem() const override { return false; }
setReg(MCRegister PhysReg)121 void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; }
122
evaluateConstantImm(const MCExpr * Expr,int64_t & Imm)123 static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) {
124 if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
125 Imm = CE->getValue();
126 return true;
127 }
128
129 return false;
130 }
131
isUImm() const132 template <unsigned N, int P = 0> bool isUImm() const {
133 if (!isImm())
134 return false;
135
136 int64_t Imm;
137 bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
138 return IsConstantImm && isUInt<N>(Imm - P);
139 }
140
isSImm() const141 template <unsigned N, unsigned S = 0> bool isSImm() const {
142 if (!isImm())
143 return false;
144
145 int64_t Imm;
146 bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
147 return IsConstantImm && isShiftedInt<N, S>(Imm);
148 }
149
isUImm2() const150 bool isUImm2() const { return isUImm<2>(); }
isUImm2plus1() const151 bool isUImm2plus1() const { return isUImm<2, 1>(); }
isUImm3() const152 bool isUImm3() const { return isUImm<3>(); }
isUImm5() const153 bool isUImm5() const { return isUImm<5>(); }
isUImm6() const154 bool isUImm6() const { return isUImm<6>(); }
isUImm8() const155 bool isUImm8() const { return isUImm<8>(); }
isUImm12() const156 bool isUImm12() const { return isUImm<12>(); }
isUImm14() const157 bool isUImm14() const { return isUImm<14>(); }
isUImm15() const158 bool isUImm15() const { return isUImm<15>(); }
isSImm12() const159 bool isSImm12() const { return isSImm<12>(); }
isSImm14lsl2() const160 bool isSImm14lsl2() const { return isSImm<14, 2>(); }
isSImm16() const161 bool isSImm16() const { return isSImm<16>(); }
isSImm16lsl2() const162 bool isSImm16lsl2() const { return isSImm<16, 2>(); }
isSImm20() const163 bool isSImm20() const { return isSImm<20>(); }
isSImm21lsl2() const164 bool isSImm21lsl2() const { return isSImm<21, 2>(); }
isSImm26lsl2() const165 bool isSImm26lsl2() const { return isSImm<26, 2>(); }
166
167 /// Gets location of the first token of this operand.
getStartLoc() const168 SMLoc getStartLoc() const override { return StartLoc; }
169 /// Gets location of the last token of this operand.
getEndLoc() const170 SMLoc getEndLoc() const override { return EndLoc; }
171
getReg() const172 unsigned getReg() const override {
173 assert(Kind == KindTy::Register && "Invalid type access!");
174 return Reg.RegNum.id();
175 }
176
getImm() const177 const MCExpr *getImm() const {
178 assert(Kind == KindTy::Immediate && "Invalid type access!");
179 return Imm.Val;
180 }
181
getToken() const182 StringRef getToken() const {
183 assert(Kind == KindTy::Token && "Invalid type access!");
184 return Tok;
185 }
186
print(raw_ostream & OS) const187 void print(raw_ostream &OS) const override {
188 auto RegName = [](unsigned Reg) {
189 if (Reg)
190 return LoongArchInstPrinter::getRegisterName(Reg);
191 else
192 return "noreg";
193 };
194
195 switch (Kind) {
196 case KindTy::Immediate:
197 OS << *getImm();
198 break;
199 case KindTy::Register:
200 OS << "<register " << RegName(getReg()) << ">";
201 break;
202 case KindTy::Token:
203 OS << "'" << getToken() << "'";
204 break;
205 }
206 }
207
createToken(StringRef Str,SMLoc S)208 static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
209 auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
210 Op->Tok = Str;
211 Op->StartLoc = S;
212 Op->EndLoc = S;
213 return Op;
214 }
215
createReg(unsigned RegNo,SMLoc S,SMLoc E)216 static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
217 SMLoc E) {
218 auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
219 Op->Reg.RegNum = RegNo;
220 Op->StartLoc = S;
221 Op->EndLoc = E;
222 return Op;
223 }
224
createImm(const MCExpr * Val,SMLoc S,SMLoc E)225 static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
226 SMLoc E) {
227 auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate);
228 Op->Imm.Val = Val;
229 Op->StartLoc = S;
230 Op->EndLoc = E;
231 return Op;
232 }
233
addExpr(MCInst & Inst,const MCExpr * Expr) const234 void addExpr(MCInst &Inst, const MCExpr *Expr) const {
235 if (auto CE = dyn_cast<MCConstantExpr>(Expr))
236 Inst.addOperand(MCOperand::createImm(CE->getValue()));
237 else
238 Inst.addOperand(MCOperand::createExpr(Expr));
239 }
240
241 // Used by the TableGen Code.
addRegOperands(MCInst & Inst,unsigned N) const242 void addRegOperands(MCInst &Inst, unsigned N) const {
243 assert(N == 1 && "Invalid number of operands!");
244 Inst.addOperand(MCOperand::createReg(getReg()));
245 }
addImmOperands(MCInst & Inst,unsigned N) const246 void addImmOperands(MCInst &Inst, unsigned N) const {
247 assert(N == 1 && "Invalid number of operands!");
248 addExpr(Inst, getImm());
249 }
250 };
251 } // end namespace
252
253 #define GET_REGISTER_MATCHER
254 #define GET_SUBTARGET_FEATURE_NAME
255 #define GET_MATCHER_IMPLEMENTATION
256 #define GET_MNEMONIC_SPELL_CHECKER
257 #include "LoongArchGenAsmMatcher.inc"
258
convertFPR32ToFPR64(MCRegister Reg)259 static MCRegister convertFPR32ToFPR64(MCRegister Reg) {
260 assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register");
261 return Reg - LoongArch::F0 + LoongArch::F0_64;
262 }
263
264 // Attempts to match Name as a register (either using the default name or
265 // alternative ABI names), setting RegNo to the matching register. Upon
266 // failure, returns true and sets RegNo to 0.
matchRegisterNameHelper(MCRegister & RegNo,StringRef Name)267 static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
268 RegNo = MatchRegisterName(Name);
269 // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial
270 // match always matches the 32-bit variant, and not the 64-bit one.
271 assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64));
272 // The default FPR register class is based on the tablegen enum ordering.
273 static_assert(LoongArch::F0 < LoongArch::F0_64,
274 "FPR matching must be updated");
275 if (RegNo == LoongArch::NoRegister)
276 RegNo = MatchRegisterAltName(Name);
277
278 return RegNo == LoongArch::NoRegister;
279 }
280
ParseRegister(unsigned & RegNo,SMLoc & StartLoc,SMLoc & EndLoc)281 bool LoongArchAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
282 SMLoc &EndLoc) {
283 return Error(getLoc(), "invalid register number");
284 }
285
tryParseRegister(unsigned & RegNo,SMLoc & StartLoc,SMLoc & EndLoc)286 OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo,
287 SMLoc &StartLoc,
288 SMLoc &EndLoc) {
289 llvm_unreachable("Unimplemented function.");
290 }
291
292 OperandMatchResultTy
parseRegister(OperandVector & Operands)293 LoongArchAsmParser::parseRegister(OperandVector &Operands) {
294 if (getLexer().getTok().isNot(AsmToken::Dollar))
295 return MatchOperand_NoMatch;
296
297 // Eat the $ prefix.
298 getLexer().Lex();
299 if (getLexer().getKind() != AsmToken::Identifier)
300 return MatchOperand_NoMatch;
301
302 StringRef Name = getLexer().getTok().getIdentifier();
303 MCRegister RegNo;
304 matchRegisterNameHelper(RegNo, Name);
305 if (RegNo == LoongArch::NoRegister)
306 return MatchOperand_NoMatch;
307
308 SMLoc S = getLoc();
309 SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
310 getLexer().Lex();
311 Operands.push_back(LoongArchOperand::createReg(RegNo, S, E));
312
313 return MatchOperand_Success;
314 }
315
316 OperandMatchResultTy
parseImmediate(OperandVector & Operands)317 LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
318 SMLoc S = getLoc();
319 SMLoc E;
320 const MCExpr *Res;
321
322 if (getParser().parseExpression(Res, E))
323 return MatchOperand_ParseFail;
324
325 Operands.push_back(LoongArchOperand::createImm(Res, S, E));
326 return MatchOperand_Success;
327 }
328
329 /// Looks at a token type and creates the relevant operand from this
330 /// information, adding to Operands. Return true upon an error.
parseOperand(OperandVector & Operands,StringRef Mnemonic)331 bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
332 StringRef Mnemonic) {
333 if (parseRegister(Operands) == MatchOperand_Success ||
334 parseImmediate(Operands) == MatchOperand_Success)
335 return false;
336
337 // Finally we have exhausted all options and must declare defeat.
338 Error(getLoc(), "unknown operand");
339 return true;
340 }
341
ParseInstruction(ParseInstructionInfo & Info,StringRef Name,SMLoc NameLoc,OperandVector & Operands)342 bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
343 StringRef Name, SMLoc NameLoc,
344 OperandVector &Operands) {
345 // First operand in MCInst is instruction mnemonic.
346 Operands.push_back(LoongArchOperand::createToken(Name, NameLoc));
347
348 // If there are no more operands, then finish.
349 if (parseOptionalToken(AsmToken::EndOfStatement))
350 return false;
351
352 // Parse first operand.
353 if (parseOperand(Operands, Name))
354 return true;
355
356 // Parse until end of statement, consuming commas between operands.
357 while (parseOptionalToken(AsmToken::Comma))
358 if (parseOperand(Operands, Name))
359 return true;
360
361 // Parse end of statement and return successfully.
362 if (parseOptionalToken(AsmToken::EndOfStatement))
363 return false;
364
365 SMLoc Loc = getLexer().getLoc();
366 getParser().eatToEndOfStatement();
367 return Error(Loc, "unexpected token");
368 }
369
processInstruction(MCInst & Inst,SMLoc IDLoc,OperandVector & Operands,MCStreamer & Out)370 bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
371 OperandVector &Operands,
372 MCStreamer &Out) {
373 Inst.setLoc(IDLoc);
374 Out.emitInstruction(Inst, getSTI());
375 return false;
376 }
377
checkTargetMatchPredicate(MCInst & Inst)378 unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
379 switch (Inst.getOpcode()) {
380 default:
381 break;
382 case LoongArch::CSRXCHG: {
383 unsigned Rj = Inst.getOperand(2).getReg();
384 if (Rj == LoongArch::R0 || Rj == LoongArch::R1)
385 return Match_RequiresOpnd2NotR0R1;
386 return Match_Success;
387 }
388 case LoongArch::BSTRINS_W:
389 case LoongArch::BSTRINS_D:
390 case LoongArch::BSTRPICK_W:
391 case LoongArch::BSTRPICK_D: {
392 unsigned Opc = Inst.getOpcode();
393 const signed Msb =
394 (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
395 ? Inst.getOperand(3).getImm()
396 : Inst.getOperand(2).getImm();
397 const signed Lsb =
398 (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
399 ? Inst.getOperand(4).getImm()
400 : Inst.getOperand(3).getImm();
401 if (Msb < Lsb)
402 return Match_RequiresMsbNotLessThanLsb;
403 return Match_Success;
404 }
405 }
406
407 return Match_Success;
408 }
409
410 unsigned
validateTargetOperandClass(MCParsedAsmOperand & AsmOp,unsigned Kind)411 LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
412 unsigned Kind) {
413 LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp);
414 if (!Op.isReg())
415 return Match_InvalidOperand;
416
417 MCRegister Reg = Op.getReg();
418 // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the
419 // register from FPR32 to FPR64 if necessary.
420 if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) &&
421 Kind == MCK_FPR64) {
422 Op.setReg(convertFPR32ToFPR64(Reg));
423 return Match_Success;
424 }
425
426 return Match_InvalidOperand;
427 }
428
generateImmOutOfRangeError(OperandVector & Operands,uint64_t ErrorInfo,int64_t Lower,int64_t Upper,Twine Msg="immediate must be an integer in the range")429 bool LoongArchAsmParser::generateImmOutOfRangeError(
430 OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
431 Twine Msg = "immediate must be an integer in the range") {
432 SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
433 return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
434 }
435
MatchAndEmitInstruction(SMLoc IDLoc,unsigned & Opcode,OperandVector & Operands,MCStreamer & Out,uint64_t & ErrorInfo,bool MatchingInlineAsm)436 bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
437 OperandVector &Operands,
438 MCStreamer &Out,
439 uint64_t &ErrorInfo,
440 bool MatchingInlineAsm) {
441 MCInst Inst;
442 FeatureBitset MissingFeatures;
443
444 auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
445 MatchingInlineAsm);
446 switch (Result) {
447 default:
448 break;
449 case Match_Success:
450 return processInstruction(Inst, IDLoc, Operands, Out);
451 case Match_MissingFeature: {
452 assert(MissingFeatures.any() && "Unknown missing features!");
453 bool FirstFeature = true;
454 std::string Msg = "instruction requires the following:";
455 for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
456 if (MissingFeatures[i]) {
457 Msg += FirstFeature ? " " : ", ";
458 Msg += getSubtargetFeatureName(i);
459 FirstFeature = false;
460 }
461 }
462 return Error(IDLoc, Msg);
463 }
464 case Match_MnemonicFail: {
465 FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
466 std::string Suggestion = LoongArchMnemonicSpellCheck(
467 ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0);
468 return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
469 }
470 case Match_InvalidOperand: {
471 SMLoc ErrorLoc = IDLoc;
472 if (ErrorInfo != ~0ULL) {
473 if (ErrorInfo >= Operands.size())
474 return Error(ErrorLoc, "too few operands for instruction");
475
476 ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
477 if (ErrorLoc == SMLoc())
478 ErrorLoc = IDLoc;
479 }
480 return Error(ErrorLoc, "invalid operand for instruction");
481 }
482 }
483
484 // Handle the case when the error message is of specific type
485 // other than the generic Match_InvalidOperand, and the
486 // corresponding operand is missing.
487 if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
488 SMLoc ErrorLoc = IDLoc;
489 if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size())
490 return Error(ErrorLoc, "too few operands for instruction");
491 }
492
493 switch (Result) {
494 default:
495 break;
496 case Match_RequiresMsbNotLessThanLsb: {
497 SMLoc ErrorStart = Operands[3]->getStartLoc();
498 return Error(ErrorStart, "msb is less than lsb",
499 SMRange(ErrorStart, Operands[4]->getEndLoc()));
500 }
501 case Match_RequiresOpnd2NotR0R1:
502 return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1");
503 case Match_InvalidUImm2:
504 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
505 /*Upper=*/(1 << 2) - 1);
506 case Match_InvalidUImm2plus1:
507 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1,
508 /*Upper=*/(1 << 2));
509 case Match_InvalidUImm3:
510 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
511 /*Upper=*/(1 << 3) - 1);
512 case Match_InvalidUImm5:
513 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
514 /*Upper=*/(1 << 5) - 1);
515 case Match_InvalidUImm6:
516 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
517 /*Upper=*/(1 << 6) - 1);
518 case Match_InvalidUImm12:
519 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
520 /*Upper=*/(1 << 12) - 1);
521 case Match_InvalidUImm15:
522 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
523 /*Upper=*/(1 << 15) - 1);
524 case Match_InvalidSImm12:
525 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
526 /*Upper=*/(1 << 11) - 1);
527 case Match_InvalidSImm14lsl2:
528 return generateImmOutOfRangeError(
529 Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
530 "immediate must be a multiple of 4 in the range");
531 case Match_InvalidSImm16:
532 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15),
533 /*Upper=*/(1 << 15) - 1);
534 case Match_InvalidSImm16lsl2:
535 return generateImmOutOfRangeError(
536 Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4,
537 "immediate must be a multiple of 4 in the range");
538 case Match_InvalidSImm20:
539 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
540 /*Upper=*/(1 << 19) - 1);
541 case Match_InvalidSImm21lsl2:
542 return generateImmOutOfRangeError(
543 Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
544 "immediate must be a multiple of 4 in the range");
545 case Match_InvalidSImm26lsl2:
546 return generateImmOutOfRangeError(
547 Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
548 "immediate must be a multiple of 4 in the range");
549 }
550 llvm_unreachable("Unknown match type detected!");
551 }
552
LLVMInitializeLoongArchAsmParser()553 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
554 RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
555 RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
556 }
557