1 //===-- CSKYAsmParser.cpp - Parse CSKY 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/CSKYMCExpr.h"
10 #include "MCTargetDesc/CSKYMCTargetDesc.h"
11 #include "TargetInfo/CSKYTargetInfo.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/CodeGen/Register.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCParser/MCAsmLexer.h"
19 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
20 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
21 #include "llvm/MC/MCRegisterInfo.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/MCSubtargetInfo.h"
24 #include "llvm/MC/TargetRegistry.h"
25 #include "llvm/Support/Casting.h"
26 
27 using namespace llvm;
28 
29 namespace {
30 struct CSKYOperand;
31 
32 class CSKYAsmParser : public MCTargetAsmParser {
33 
34   bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
35                                   int64_t Lower, int64_t Upper, Twine Msg);
36 
37   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
38 
39   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
40                                OperandVector &Operands, MCStreamer &Out,
41                                uint64_t &ErrorInfo,
42                                bool MatchingInlineAsm) override;
43 
44   bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
45 
46   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
47                         SMLoc NameLoc, OperandVector &Operands) override;
48 
49   bool ParseDirective(AsmToken DirectiveID) override;
50 
51   OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
52                                         SMLoc &EndLoc) override;
53 
54 // Auto-generated instruction matching functions
55 #define GET_ASSEMBLER_HEADER
56 #include "CSKYGenAsmMatcher.inc"
57 
58   OperandMatchResultTy parseImmediate(OperandVector &Operands);
59   OperandMatchResultTy parseRegister(OperandVector &Operands);
60   OperandMatchResultTy parseBaseRegImm(OperandVector &Operands);
61   OperandMatchResultTy parseCSKYSymbol(OperandVector &Operands);
62   OperandMatchResultTy parseConstpoolSymbol(OperandVector &Operands);
63 
64   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
65 
66 public:
67   enum CSKYMatchResultTy {
68     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
69 #define GET_OPERAND_DIAGNOSTIC_TYPES
70 #include "CSKYGenAsmMatcher.inc"
71 #undef GET_OPERAND_DIAGNOSTIC_TYPES
72   };
73 
74   CSKYAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
75                 const MCInstrInfo &MII, const MCTargetOptions &Options)
76       : MCTargetAsmParser(Options, STI, MII) {
77     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
78   }
79 };
80 
81 /// Instances of this class represent a parsed machine instruction.
82 struct CSKYOperand : public MCParsedAsmOperand {
83   enum KindTy {
84     Token,
85     Register,
86     Immediate,
87   } Kind;
88 
89   struct RegOp {
90     unsigned RegNum;
91   };
92 
93   struct ImmOp {
94     const MCExpr *Val;
95   };
96 
97   SMLoc StartLoc, EndLoc;
98   union {
99     StringRef Tok;
100     RegOp Reg;
101     ImmOp Imm;
102   };
103 
104   CSKYOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
105 
106 public:
107   CSKYOperand(const CSKYOperand &o) : MCParsedAsmOperand() {
108     Kind = o.Kind;
109     StartLoc = o.StartLoc;
110     EndLoc = o.EndLoc;
111     switch (Kind) {
112     case Register:
113       Reg = o.Reg;
114       break;
115     case Immediate:
116       Imm = o.Imm;
117       break;
118     case Token:
119       Tok = o.Tok;
120       break;
121     }
122   }
123 
124   bool isToken() const override { return Kind == Token; }
125   bool isReg() const override { return Kind == Register; }
126   bool isImm() const override { return Kind == Immediate; }
127   bool isMem() const override { return false; }
128 
129   static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) {
130     if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
131       Imm = CE->getValue();
132       return true;
133     }
134 
135     return false;
136   }
137 
138   template <unsigned num, unsigned shift = 0> bool isUImm() const {
139     if (!isImm())
140       return false;
141 
142     int64_t Imm;
143     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
144     return IsConstantImm && isShiftedUInt<num, shift>(Imm);
145   }
146 
147   template <unsigned num> bool isOImm() const {
148     if (!isImm())
149       return false;
150 
151     int64_t Imm;
152     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
153     return IsConstantImm && isUInt<num>(Imm - 1);
154   }
155 
156   template <unsigned num, unsigned shift = 0> bool isSImm() const {
157     if (!isImm())
158       return false;
159 
160     int64_t Imm;
161     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
162     return IsConstantImm && isShiftedInt<num, shift>(Imm);
163   }
164 
165   bool isUImm2() const { return isUImm<2>(); }
166   bool isUImm5() const { return isUImm<5>(); }
167   bool isUImm12() const { return isUImm<12>(); }
168   bool isUImm16() const { return isUImm<16>(); }
169 
170   bool isOImm12() const { return isOImm<12>(); }
171   bool isOImm16() const { return isOImm<16>(); }
172 
173   bool isUImm12Shift1() { return isUImm<12, 1>(); }
174   bool isUImm12Shift2() { return isUImm<12, 2>(); }
175 
176   bool isSImm16Shift1() { return isSImm<16, 1>(); }
177 
178   bool isCSKYSymbol() const {
179     int64_t Imm;
180     // Must be of 'immediate' type but not a constant.
181     return isImm() && !evaluateConstantImm(getImm(), Imm);
182   }
183 
184   bool isConstpoolSymbol() const {
185     int64_t Imm;
186     // Must be of 'immediate' type but not a constant.
187     return isImm() && !evaluateConstantImm(getImm(), Imm);
188   }
189 
190   /// Gets location of the first token of this operand.
191   SMLoc getStartLoc() const override { return StartLoc; }
192   /// Gets location of the last token of this operand.
193   SMLoc getEndLoc() const override { return EndLoc; }
194 
195   unsigned getReg() const override {
196     assert(Kind == Register && "Invalid type access!");
197     return Reg.RegNum;
198   }
199 
200   const MCExpr *getImm() const {
201     assert(Kind == Immediate && "Invalid type access!");
202     return Imm.Val;
203   }
204 
205   StringRef getToken() const {
206     assert(Kind == Token && "Invalid type access!");
207     return Tok;
208   }
209 
210   void print(raw_ostream &OS) const override {
211     switch (Kind) {
212     case Immediate:
213       OS << *getImm();
214       break;
215     case Register:
216       OS << "<register x" << getReg() << ">";
217       break;
218     case Token:
219       OS << "'" << getToken() << "'";
220       break;
221     }
222   }
223 
224   static std::unique_ptr<CSKYOperand> createToken(StringRef Str, SMLoc S) {
225     auto Op = std::make_unique<CSKYOperand>(Token);
226     Op->Tok = Str;
227     Op->StartLoc = S;
228     Op->EndLoc = S;
229     return Op;
230   }
231 
232   static std::unique_ptr<CSKYOperand> createReg(unsigned RegNo, SMLoc S,
233                                                 SMLoc E) {
234     auto Op = std::make_unique<CSKYOperand>(Register);
235     Op->Reg.RegNum = RegNo;
236     Op->StartLoc = S;
237     Op->EndLoc = E;
238     return Op;
239   }
240 
241   static std::unique_ptr<CSKYOperand> createImm(const MCExpr *Val, SMLoc S,
242                                                 SMLoc E) {
243     auto Op = std::make_unique<CSKYOperand>(Immediate);
244     Op->Imm.Val = Val;
245     Op->StartLoc = S;
246     Op->EndLoc = E;
247     return Op;
248   }
249 
250   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
251     assert(Expr && "Expr shouldn't be null!");
252     if (auto *CE = dyn_cast<MCConstantExpr>(Expr))
253       Inst.addOperand(MCOperand::createImm(CE->getValue()));
254     else
255       Inst.addOperand(MCOperand::createExpr(Expr));
256   }
257 
258   // Used by the TableGen Code.
259   void addRegOperands(MCInst &Inst, unsigned N) const {
260     assert(N == 1 && "Invalid number of operands!");
261     Inst.addOperand(MCOperand::createReg(getReg()));
262   }
263 
264   void addImmOperands(MCInst &Inst, unsigned N) const {
265     assert(N == 1 && "Invalid number of operands!");
266     addExpr(Inst, getImm());
267   }
268 };
269 } // end anonymous namespace.
270 
271 #define GET_REGISTER_MATCHER
272 #define GET_SUBTARGET_FEATURE_NAME
273 #define GET_MATCHER_IMPLEMENTATION
274 #define GET_MNEMONIC_SPELL_CHECKER
275 #include "CSKYGenAsmMatcher.inc"
276 
277 static std::string CSKYMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS,
278                                           unsigned VariantID = 0);
279 
280 bool CSKYAsmParser::generateImmOutOfRangeError(
281     OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
282     Twine Msg = "immediate must be an integer in the range") {
283   SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
284   return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
285 }
286 
287 bool CSKYAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
288                                             OperandVector &Operands,
289                                             MCStreamer &Out,
290                                             uint64_t &ErrorInfo,
291                                             bool MatchingInlineAsm) {
292   MCInst Inst;
293   FeatureBitset MissingFeatures;
294 
295   auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
296                                      MatchingInlineAsm);
297   switch (Result) {
298   default:
299     break;
300   case Match_Success:
301     Inst.setLoc(IDLoc);
302     Out.emitInstruction(Inst, getSTI());
303     return false;
304   case Match_MissingFeature: {
305     assert(MissingFeatures.any() && "Unknown missing features!");
306     ListSeparator LS;
307     std::string Msg = "instruction requires the following: ";
308     for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
309       if (MissingFeatures[i]) {
310         Msg += LS;
311         Msg += getSubtargetFeatureName(i);
312       }
313     }
314     return Error(IDLoc, Msg);
315   }
316   case Match_MnemonicFail: {
317     FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
318     std::string Suggestion =
319         CSKYMnemonicSpellCheck(((CSKYOperand &)*Operands[0]).getToken(), FBS);
320     return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
321   }
322   case Match_InvalidTiedOperand:
323   case Match_InvalidOperand: {
324     SMLoc ErrorLoc = IDLoc;
325     if (ErrorInfo != ~0U) {
326       if (ErrorInfo >= Operands.size())
327         return Error(ErrorLoc, "too few operands for instruction");
328 
329       ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
330       if (ErrorLoc == SMLoc())
331         ErrorLoc = IDLoc;
332     }
333     return Error(ErrorLoc, "invalid operand for instruction");
334   }
335   }
336 
337   // Handle the case when the error message is of specific type
338   // other than the generic Match_InvalidOperand, and the
339   // corresponding operand is missing.
340   if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
341     SMLoc ErrorLoc = IDLoc;
342     if (ErrorInfo != ~0U && ErrorInfo >= Operands.size())
343       return Error(ErrorLoc, "too few operands for instruction");
344   }
345 
346   switch (Result) {
347   default:
348     break;
349   case Match_InvalidOImm12:
350     return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 12));
351   case Match_InvalidOImm16:
352     return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 16));
353   case Match_InvalidUImm2:
354     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 2) - 1);
355   case Match_InvalidUImm5:
356     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1);
357   case Match_InvalidUImm12:
358     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1);
359   case Match_InvalidUImm12Shift1:
360     return generateImmOutOfRangeError(
361         Operands, ErrorInfo, 0, (1 << 12) - 2,
362         "immediate must be a multiple of 2 bytes in the range");
363   case Match_InvalidUImm12Shift2:
364     return generateImmOutOfRangeError(
365         Operands, ErrorInfo, 0, (1 << 12) - 4,
366         "immediate must be a multiple of 4 bytes in the range");
367   case Match_InvalidUImm16:
368     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 16) - 1);
369   case Match_InvalidCSKYSymbol: {
370     SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
371     return Error(ErrorLoc, "operand must be a symbol name");
372   }
373   case Match_InvalidConstpool: {
374     SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
375     return Error(ErrorLoc, "operand must be a constpool symbol name");
376   }
377   }
378 
379   llvm_unreachable("Unknown match type detected!");
380 }
381 
382 // Attempts to match Name as a register (either using the default name or
383 // alternative ABI names), setting RegNo to the matching register. Upon
384 // failure, returns true and sets RegNo to 0.
385 static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
386   RegNo = MatchRegisterName(Name);
387 
388   if (RegNo == CSKY::NoRegister)
389     RegNo = MatchRegisterAltName(Name);
390 
391   return RegNo == CSKY::NoRegister;
392 }
393 
394 bool CSKYAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
395                                   SMLoc &EndLoc) {
396   const AsmToken &Tok = getParser().getTok();
397   StartLoc = Tok.getLoc();
398   EndLoc = Tok.getEndLoc();
399   StringRef Name = getLexer().getTok().getIdentifier();
400 
401   if (!matchRegisterNameHelper((MCRegister &)RegNo, Name)) {
402     getParser().Lex(); // Eat identifier token.
403     return false;
404   }
405 
406   return Error(StartLoc, "invalid register name");
407 }
408 
409 OperandMatchResultTy CSKYAsmParser::parseRegister(OperandVector &Operands) {
410   SMLoc S = getLoc();
411   SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
412 
413   switch (getLexer().getKind()) {
414   default:
415     return MatchOperand_NoMatch;
416   case AsmToken::Identifier: {
417     StringRef Name = getLexer().getTok().getIdentifier();
418     MCRegister RegNo;
419 
420     if (matchRegisterNameHelper((MCRegister &)RegNo, Name))
421       return MatchOperand_NoMatch;
422 
423     getLexer().Lex();
424     Operands.push_back(CSKYOperand::createReg(RegNo, S, E));
425 
426     return MatchOperand_Success;
427   }
428   }
429 }
430 
431 OperandMatchResultTy CSKYAsmParser::parseBaseRegImm(OperandVector &Operands) {
432   assert(getLexer().is(AsmToken::LParen));
433 
434   Operands.push_back(CSKYOperand::createToken("(", getLoc()));
435 
436   auto Tok = getParser().Lex(); // Eat '('
437 
438   if (parseRegister(Operands) != MatchOperand_Success) {
439     getLexer().UnLex(Tok);
440     Operands.pop_back();
441     return MatchOperand_ParseFail;
442   }
443 
444   if (getLexer().isNot(AsmToken::Comma)) {
445     Error(getLoc(), "expected ','");
446     return MatchOperand_ParseFail;
447   }
448 
449   getParser().Lex(); // Eat ','
450 
451   if (parseRegister(Operands) == MatchOperand_Success) {
452     if (getLexer().isNot(AsmToken::LessLess)) {
453       Error(getLoc(), "expected '<<'");
454       return MatchOperand_ParseFail;
455     }
456 
457     Operands.push_back(CSKYOperand::createToken("<<", getLoc()));
458 
459     getParser().Lex(); // Eat '<<'
460 
461     if (parseImmediate(Operands) != MatchOperand_Success) {
462       Error(getLoc(), "expected imm");
463       return MatchOperand_ParseFail;
464     }
465 
466   } else if (parseImmediate(Operands) != MatchOperand_Success) {
467     Error(getLoc(), "expected imm");
468     return MatchOperand_ParseFail;
469   }
470 
471   if (getLexer().isNot(AsmToken::RParen)) {
472     Error(getLoc(), "expected ')'");
473     return MatchOperand_ParseFail;
474   }
475 
476   Operands.push_back(CSKYOperand::createToken(")", getLoc()));
477 
478   getParser().Lex(); // Eat ')'
479 
480   return MatchOperand_Success;
481 }
482 
483 OperandMatchResultTy CSKYAsmParser::parseImmediate(OperandVector &Operands) {
484   switch (getLexer().getKind()) {
485   default:
486     return MatchOperand_NoMatch;
487   case AsmToken::LParen:
488   case AsmToken::Minus:
489   case AsmToken::Plus:
490   case AsmToken::Integer:
491   case AsmToken::String:
492     break;
493   }
494 
495   const MCExpr *IdVal;
496   SMLoc S = getLoc();
497   if (getParser().parseExpression(IdVal))
498     return MatchOperand_ParseFail;
499 
500   SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
501   Operands.push_back(CSKYOperand::createImm(IdVal, S, E));
502   return MatchOperand_Success;
503 }
504 
505 /// Looks at a token type and creates the relevant operand from this
506 /// information, adding to Operands. If operand was parsed, returns false, else
507 /// true.
508 bool CSKYAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
509   // Check if the current operand has a custom associated parser, if so, try to
510   // custom parse the operand, or fallback to the general approach.
511   OperandMatchResultTy Result =
512       MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
513   if (Result == MatchOperand_Success)
514     return false;
515   if (Result == MatchOperand_ParseFail)
516     return true;
517 
518   // Attempt to parse token as register
519   if (parseRegister(Operands) == MatchOperand_Success)
520     return false;
521 
522   // Attempt to parse token as (register, imm)
523   if (getLexer().is(AsmToken::LParen))
524     if (parseBaseRegImm(Operands) == MatchOperand_Success)
525       return false;
526 
527   // Attempt to parse token as a imm.
528   if (parseImmediate(Operands) == MatchOperand_Success)
529     return false;
530 
531   // Finally we have exhausted all options and must declare defeat.
532   Error(getLoc(), "unknown operand");
533   return true;
534 }
535 
536 OperandMatchResultTy CSKYAsmParser::parseCSKYSymbol(OperandVector &Operands) {
537   SMLoc S = getLoc();
538   SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
539 
540   if (getLexer().getKind() != AsmToken::Identifier)
541     return MatchOperand_NoMatch;
542 
543   StringRef Identifier;
544   if (getParser().parseIdentifier(Identifier))
545     return MatchOperand_ParseFail;
546 
547   CSKYMCExpr::VariantKind Kind = CSKYMCExpr::VK_CSKY_None;
548 
549   if (Identifier.consume_back("@GOT"))
550     Kind = CSKYMCExpr::VK_CSKY_GOT;
551   else if (Identifier.consume_back("@GOTOFF"))
552     Kind = CSKYMCExpr::VK_CSKY_GOTOFF;
553   else if (Identifier.consume_back("@PLT"))
554     Kind = CSKYMCExpr::VK_CSKY_PLT;
555   else if (Identifier.consume_back("@GOTPC"))
556     Kind = CSKYMCExpr::VK_CSKY_GOTPC;
557 
558   MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
559   const MCExpr *Res =
560       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
561 
562   if (Kind != CSKYMCExpr::VK_CSKY_None)
563     Res = CSKYMCExpr::create(Res, Kind, getContext());
564 
565   Operands.push_back(CSKYOperand::createImm(Res, S, E));
566   return MatchOperand_Success;
567 }
568 
569 OperandMatchResultTy
570 CSKYAsmParser::parseConstpoolSymbol(OperandVector &Operands) {
571   SMLoc S = getLoc();
572   SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
573 
574   if (getLexer().getKind() != AsmToken::LBrac)
575     return MatchOperand_NoMatch;
576 
577   getLexer().Lex(); // Eat '['.
578 
579   if (getLexer().getKind() != AsmToken::Identifier)
580     return MatchOperand_NoMatch;
581 
582   StringRef Identifier;
583   if (getParser().parseIdentifier(Identifier))
584     return MatchOperand_ParseFail;
585 
586   if (getLexer().getKind() != AsmToken::RBrac)
587     return MatchOperand_NoMatch;
588 
589   getLexer().Lex(); // Eat ']'.
590 
591   MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
592   const MCExpr *Res =
593       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
594   Operands.push_back(CSKYOperand::createImm(Res, S, E));
595   return MatchOperand_Success;
596 }
597 
598 bool CSKYAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
599                                      SMLoc NameLoc, OperandVector &Operands) {
600   // First operand is token for instruction.
601   Operands.push_back(CSKYOperand::createToken(Name, NameLoc));
602 
603   // If there are no more operands, then finish.
604   if (getLexer().is(AsmToken::EndOfStatement))
605     return false;
606 
607   // Parse first operand.
608   if (parseOperand(Operands, Name))
609     return true;
610 
611   // Parse until end of statement, consuming commas between operands.
612   while (getLexer().is(AsmToken::Comma)) {
613     // Consume comma token.
614     getLexer().Lex();
615 
616     // Parse next operand.
617     if (parseOperand(Operands, Name))
618       return true;
619   }
620 
621   if (getLexer().isNot(AsmToken::EndOfStatement)) {
622     SMLoc Loc = getLexer().getLoc();
623     getParser().eatToEndOfStatement();
624     return Error(Loc, "unexpected token");
625   }
626 
627   getParser().Lex(); // Consume the EndOfStatement.
628   return false;
629 }
630 
631 OperandMatchResultTy CSKYAsmParser::tryParseRegister(unsigned &RegNo,
632                                                      SMLoc &StartLoc,
633                                                      SMLoc &EndLoc) {
634   const AsmToken &Tok = getParser().getTok();
635   StartLoc = Tok.getLoc();
636   EndLoc = Tok.getEndLoc();
637 
638   StringRef Name = getLexer().getTok().getIdentifier();
639 
640   if (matchRegisterNameHelper((MCRegister &)RegNo, Name))
641     return MatchOperand_NoMatch;
642 
643   getParser().Lex(); // Eat identifier token.
644   return MatchOperand_Success;
645 }
646 
647 bool CSKYAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
648 
649 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmParser() {
650   RegisterMCAsmParser<CSKYAsmParser> X(getTheCSKYTarget());
651 }
652