xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 //===- XtensaAsmParser.cpp - Parse Xtensa assembly to MCInst instructions -===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 // See https://llvm.org/LICENSE.txt for license information.
7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "MCTargetDesc/XtensaMCTargetDesc.h"
12 #include "TargetInfo/XtensaTargetInfo.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCInstrInfo.h"
19 #include "llvm/MC/MCParser/MCAsmLexer.h"
20 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
21 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
22 #include "llvm/MC/MCRegisterInfo.h"
23 #include "llvm/MC/MCStreamer.h"
24 #include "llvm/MC/MCSubtargetInfo.h"
25 #include "llvm/MC/TargetRegistry.h"
26 #include "llvm/Support/Casting.h"
27 
28 using namespace llvm;
29 
30 #define DEBUG_TYPE "xtensa-asm-parser"
31 
32 struct XtensaOperand;
33 
34 class XtensaAsmParser : public MCTargetAsmParser {
35 
36   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
37 
38   // Override MCTargetAsmParser.
39   bool ParseDirective(AsmToken DirectiveID) override;
40   bool parseRegister(MCRegister &RegNo,
41                      SMLoc &StartLoc, SMLoc &EndLoc) override;
42   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
43                         SMLoc NameLoc, OperandVector &Operands) override;
44   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
45                                OperandVector &Operands, MCStreamer &Out,
46                                uint64_t &ErrorInfo,
47                                bool MatchingInlineAsm) override;
48   unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
49                                       unsigned Kind) override;
50 
51 // Auto-generated instruction matching functions
52 #define GET_ASSEMBLER_HEADER
53 #include "XtensaGenAsmMatcher.inc"
54 
55   OperandMatchResultTy parseImmediate(OperandVector &Operands);
56   OperandMatchResultTy parseRegister(OperandVector &Operands,
57                                      bool AllowParens = false, bool SR = false);
58   OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
59   bool parseOperand(OperandVector &Operands, StringRef Mnemonic,
60                     bool SR = false);
61   bool ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name,
62                               SMLoc NameLoc, OperandVector &Operands);
63   OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
64                                         SMLoc &EndLoc) override {
65     return MatchOperand_NoMatch;
66   }
67   OperandMatchResultTy parsePCRelTarget(OperandVector &Operands);
68 
69 public:
70   enum XtensaMatchResultTy {
71     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
72 #define GET_OPERAND_DIAGNOSTIC_TYPES
73 #include "XtensaGenAsmMatcher.inc"
74 #undef GET_OPERAND_DIAGNOSTIC_TYPES
75   };
76 
77   XtensaAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
78                   const MCInstrInfo &MII, const MCTargetOptions &Options)
79       : MCTargetAsmParser(Options, STI, MII) {
80     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
81   }
82 };
83 
84 // Return true if Expr is in the range [MinValue, MaxValue].
85 static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue) {
86   if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
87     int64_t Value = CE->getValue();
88     return Value >= MinValue && Value <= MaxValue;
89   }
90   return false;
91 }
92 
93 struct XtensaOperand : public MCParsedAsmOperand {
94 
95   enum KindTy {
96     Token,
97     Register,
98     Immediate,
99   } Kind;
100 
101   struct RegOp {
102     unsigned RegNum;
103   };
104 
105   struct ImmOp {
106     const MCExpr *Val;
107   };
108 
109   SMLoc StartLoc, EndLoc;
110   union {
111     StringRef Tok;
112     RegOp Reg;
113     ImmOp Imm;
114   };
115 
116   XtensaOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
117 
118 public:
119   XtensaOperand(const XtensaOperand &o) : MCParsedAsmOperand() {
120     Kind = o.Kind;
121     StartLoc = o.StartLoc;
122     EndLoc = o.EndLoc;
123     switch (Kind) {
124     case Register:
125       Reg = o.Reg;
126       break;
127     case Immediate:
128       Imm = o.Imm;
129       break;
130     case Token:
131       Tok = o.Tok;
132       break;
133     }
134   }
135 
136   bool isToken() const override { return Kind == Token; }
137   bool isReg() const override { return Kind == Register; }
138   bool isImm() const override { return Kind == Immediate; }
139   bool isMem() const override { return false; }
140 
141   bool isImm(int64_t MinValue, int64_t MaxValue) const {
142     return Kind == Immediate && inRange(getImm(), MinValue, MaxValue);
143   }
144 
145   bool isImm8() const { return isImm(-128, 127); }
146 
147   bool isImm8_sh8() const {
148     return isImm(-32768, 32512) &&
149            ((cast<MCConstantExpr>(getImm())->getValue() & 0xFF) == 0);
150   }
151 
152   bool isImm12() const { return isImm(-2048, 2047); }
153 
154   bool isImm12m() const { return isImm(-2048, 2047); }
155 
156   bool isOffset4m32() const {
157     return isImm(0, 60) &&
158            ((cast<MCConstantExpr>(getImm())->getValue() & 0x3) == 0);
159   }
160 
161   bool isOffset8m8() const { return isImm(0, 255); }
162 
163   bool isOffset8m16() const {
164     return isImm(0, 510) &&
165            ((cast<MCConstantExpr>(getImm())->getValue() & 0x1) == 0);
166   }
167 
168   bool isOffset8m32() const {
169     return isImm(0, 1020) &&
170            ((cast<MCConstantExpr>(getImm())->getValue() & 0x3) == 0);
171   }
172 
173   bool isUimm4() const { return isImm(0, 15); }
174 
175   bool isUimm5() const { return isImm(0, 31); }
176 
177   bool isImm8n_7() const { return isImm(-8, 7); }
178 
179   bool isShimm1_31() const { return isImm(1, 31); }
180 
181   bool isImm16_31() const { return isImm(16, 31); }
182 
183   bool isImm1_16() const { return isImm(1, 16); }
184 
185   bool isB4const() const {
186     if (Kind != Immediate)
187       return false;
188     if (auto *CE = dyn_cast<MCConstantExpr>(getImm())) {
189       int64_t Value = CE->getValue();
190       switch (Value) {
191       case -1:
192       case 1:
193       case 2:
194       case 3:
195       case 4:
196       case 5:
197       case 6:
198       case 7:
199       case 8:
200       case 10:
201       case 12:
202       case 16:
203       case 32:
204       case 64:
205       case 128:
206       case 256:
207         return true;
208       default:
209         return false;
210       }
211     }
212     return false;
213   }
214 
215   bool isB4constu() const {
216     if (Kind != Immediate)
217       return false;
218     if (auto *CE = dyn_cast<MCConstantExpr>(getImm())) {
219       int64_t Value = CE->getValue();
220       switch (Value) {
221       case 32768:
222       case 65536:
223       case 2:
224       case 3:
225       case 4:
226       case 5:
227       case 6:
228       case 7:
229       case 8:
230       case 10:
231       case 12:
232       case 16:
233       case 32:
234       case 64:
235       case 128:
236       case 256:
237         return true;
238       default:
239         return false;
240       }
241     }
242     return false;
243   }
244 
245   /// getStartLoc - Gets location of the first token of this operand
246   SMLoc getStartLoc() const override { return StartLoc; }
247   /// getEndLoc - Gets location of the last token of this operand
248   SMLoc getEndLoc() const override { return EndLoc; }
249 
250   unsigned getReg() const override {
251     assert(Kind == Register && "Invalid type access!");
252     return Reg.RegNum;
253   }
254 
255   const MCExpr *getImm() const {
256     assert(Kind == Immediate && "Invalid type access!");
257     return Imm.Val;
258   }
259 
260   StringRef getToken() const {
261     assert(Kind == Token && "Invalid type access!");
262     return Tok;
263   }
264 
265   void print(raw_ostream &OS) const override {
266     switch (Kind) {
267     case Immediate:
268       OS << *getImm();
269       break;
270     case Register:
271       OS << "<register x";
272       OS << getReg() << ">";
273       break;
274     case Token:
275       OS << "'" << getToken() << "'";
276       break;
277     }
278   }
279 
280   static std::unique_ptr<XtensaOperand> createToken(StringRef Str, SMLoc S) {
281     auto Op = std::make_unique<XtensaOperand>(Token);
282     Op->Tok = Str;
283     Op->StartLoc = S;
284     Op->EndLoc = S;
285     return Op;
286   }
287 
288   static std::unique_ptr<XtensaOperand> createReg(unsigned RegNo, SMLoc S,
289                                                   SMLoc E) {
290     auto Op = std::make_unique<XtensaOperand>(Register);
291     Op->Reg.RegNum = RegNo;
292     Op->StartLoc = S;
293     Op->EndLoc = E;
294     return Op;
295   }
296 
297   static std::unique_ptr<XtensaOperand> createImm(const MCExpr *Val, SMLoc S,
298                                                   SMLoc E) {
299     auto Op = std::make_unique<XtensaOperand>(Immediate);
300     Op->Imm.Val = Val;
301     Op->StartLoc = S;
302     Op->EndLoc = E;
303     return Op;
304   }
305 
306   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
307     assert(Expr && "Expr shouldn't be null!");
308     int64_t Imm = 0;
309     bool IsConstant = false;
310 
311     if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
312       IsConstant = true;
313       Imm = CE->getValue();
314     }
315 
316     if (IsConstant)
317       Inst.addOperand(MCOperand::createImm(Imm));
318     else
319       Inst.addOperand(MCOperand::createExpr(Expr));
320   }
321 
322   // Used by the TableGen Code
323   void addRegOperands(MCInst &Inst, unsigned N) const {
324     assert(N == 1 && "Invalid number of operands!");
325     Inst.addOperand(MCOperand::createReg(getReg()));
326   }
327 
328   void addImmOperands(MCInst &Inst, unsigned N) const {
329     assert(N == 1 && "Invalid number of operands!");
330     addExpr(Inst, getImm());
331   }
332 };
333 
334 #define GET_REGISTER_MATCHER
335 #define GET_MATCHER_IMPLEMENTATION
336 #include "XtensaGenAsmMatcher.inc"
337 
338 unsigned XtensaAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
339                                                      unsigned Kind) {
340   return Match_InvalidOperand;
341 }
342 
343 static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands,
344                             uint64_t ErrorInfo) {
345   if (ErrorInfo != ~0ULL && ErrorInfo < Operands.size()) {
346     SMLoc ErrorLoc = Operands[ErrorInfo]->getStartLoc();
347     if (ErrorLoc == SMLoc())
348       return Loc;
349     return ErrorLoc;
350   }
351   return Loc;
352 }
353 
354 bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
355                                               OperandVector &Operands,
356                                               MCStreamer &Out,
357                                               uint64_t &ErrorInfo,
358                                               bool MatchingInlineAsm) {
359   MCInst Inst;
360   auto Result =
361       MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
362 
363   switch (Result) {
364   default:
365     break;
366   case Match_Success:
367     Inst.setLoc(IDLoc);
368     Out.emitInstruction(Inst, getSTI());
369     return false;
370   case Match_MissingFeature:
371     return Error(IDLoc, "instruction use requires an option to be enabled");
372   case Match_MnemonicFail:
373     return Error(IDLoc, "unrecognized instruction mnemonic");
374   case Match_InvalidOperand: {
375     SMLoc ErrorLoc = IDLoc;
376     if (ErrorInfo != ~0U) {
377       if (ErrorInfo >= Operands.size())
378         return Error(ErrorLoc, "too few operands for instruction");
379 
380       ErrorLoc = ((XtensaOperand &)*Operands[ErrorInfo]).getStartLoc();
381       if (ErrorLoc == SMLoc())
382         ErrorLoc = IDLoc;
383     }
384     return Error(ErrorLoc, "invalid operand for instruction");
385   }
386   case Match_InvalidImm8:
387     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
388                  "expected immediate in range [-128, 127]");
389   case Match_InvalidImm8_sh8:
390     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
391                  "expected immediate in range [-32768, 32512], first 8 bits "
392                  "should be zero");
393   case Match_InvalidB4const:
394     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
395                  "expected b4const immediate");
396   case Match_InvalidB4constu:
397     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
398                  "expected b4constu immediate");
399   case Match_InvalidImm12:
400     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
401                  "expected immediate in range [-2048, 2047]");
402   case Match_InvalidImm12m:
403     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
404                  "expected immediate in range [-2048, 2047]");
405   case Match_InvalidImm1_16:
406     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
407                  "expected immediate in range [1, 16]");
408   case Match_InvalidShimm1_31:
409     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
410                  "expected immediate in range [1, 31]");
411   case Match_InvalidUimm4:
412     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
413                  "expected immediate in range [0, 15]");
414   case Match_InvalidUimm5:
415     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
416                  "expected immediate in range [0, 31]");
417   case Match_InvalidOffset8m8:
418     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
419                  "expected immediate in range [0, 255]");
420   case Match_InvalidOffset8m16:
421     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
422                  "expected immediate in range [0, 510], first bit "
423                  "should be zero");
424   case Match_InvalidOffset8m32:
425     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
426                  "expected immediate in range [0, 1020], first 2 bits "
427                  "should be zero");
428   case Match_InvalidOffset4m32:
429     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
430                  "expected immediate in range [0, 60], first 2 bits "
431                  "should be zero");
432   }
433 
434   report_fatal_error("Unknown match type detected!");
435 }
436 
437 OperandMatchResultTy
438 XtensaAsmParser::parsePCRelTarget(OperandVector &Operands) {
439   MCAsmParser &Parser = getParser();
440   LLVM_DEBUG(dbgs() << "parsePCRelTarget\n");
441 
442   SMLoc S = getLexer().getLoc();
443 
444   // Expressions are acceptable
445   const MCExpr *Expr = nullptr;
446   if (Parser.parseExpression(Expr)) {
447     // We have no way of knowing if a symbol was consumed so we must ParseFail
448     return MatchOperand_ParseFail;
449   }
450 
451   // Currently not support constants
452   if (Expr->getKind() == MCExpr::ExprKind::Constant) {
453     Error(getLoc(), "unknown operand");
454     return MatchOperand_ParseFail;
455   }
456 
457   Operands.push_back(XtensaOperand::createImm(Expr, S, getLexer().getLoc()));
458   return MatchOperand_Success;
459 }
460 
461 bool XtensaAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
462                                     SMLoc &EndLoc) {
463   const AsmToken &Tok = getParser().getTok();
464   StartLoc = Tok.getLoc();
465   EndLoc = Tok.getEndLoc();
466   RegNo = 0;
467   StringRef Name = getLexer().getTok().getIdentifier();
468 
469   if (!MatchRegisterName(Name) && !MatchRegisterAltName(Name)) {
470     getParser().Lex(); // Eat identifier token.
471     return false;
472   }
473 
474   return Error(StartLoc, "invalid register name");
475 }
476 
477 OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands,
478                                                     bool AllowParens, bool SR) {
479   SMLoc FirstS = getLoc();
480   bool HadParens = false;
481   AsmToken Buf[2];
482   StringRef RegName;
483 
484   // If this a parenthesised register name is allowed, parse it atomically
485   if (AllowParens && getLexer().is(AsmToken::LParen)) {
486     size_t ReadCount = getLexer().peekTokens(Buf);
487     if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) {
488       if ((Buf[0].getKind() == AsmToken::Integer) && (!SR))
489         return MatchOperand_NoMatch;
490       HadParens = true;
491       getParser().Lex(); // Eat '('
492     }
493   }
494 
495   unsigned RegNo = 0;
496 
497   switch (getLexer().getKind()) {
498   default:
499     return MatchOperand_NoMatch;
500   case AsmToken::Integer:
501     if (!SR)
502       return MatchOperand_NoMatch;
503     RegName = StringRef(std::to_string(getLexer().getTok().getIntVal()));
504     RegNo = MatchRegisterName(RegName);
505     if (RegNo == 0)
506       RegNo = MatchRegisterAltName(RegName);
507     break;
508   case AsmToken::Identifier:
509     RegName = getLexer().getTok().getIdentifier();
510     RegNo = MatchRegisterName(RegName);
511     if (RegNo == 0)
512       RegNo = MatchRegisterAltName(RegName);
513     break;
514   }
515 
516   if (RegNo == 0) {
517     if (HadParens)
518       getLexer().UnLex(Buf[0]);
519     return MatchOperand_NoMatch;
520   }
521   if (HadParens)
522     Operands.push_back(XtensaOperand::createToken("(", FirstS));
523   SMLoc S = getLoc();
524   SMLoc E = getParser().getTok().getEndLoc();
525   getLexer().Lex();
526   Operands.push_back(XtensaOperand::createReg(RegNo, S, E));
527 
528   if (HadParens) {
529     getParser().Lex(); // Eat ')'
530     Operands.push_back(XtensaOperand::createToken(")", getLoc()));
531   }
532 
533   return MatchOperand_Success;
534 }
535 
536 OperandMatchResultTy XtensaAsmParser::parseImmediate(OperandVector &Operands) {
537   SMLoc S = getLoc();
538   SMLoc E;
539   const MCExpr *Res;
540 
541   switch (getLexer().getKind()) {
542   default:
543     return MatchOperand_NoMatch;
544   case AsmToken::LParen:
545   case AsmToken::Minus:
546   case AsmToken::Plus:
547   case AsmToken::Tilde:
548   case AsmToken::Integer:
549   case AsmToken::String:
550     if (getParser().parseExpression(Res))
551       return MatchOperand_ParseFail;
552     break;
553   case AsmToken::Identifier: {
554     StringRef Identifier;
555     if (getParser().parseIdentifier(Identifier))
556       return MatchOperand_ParseFail;
557 
558     MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
559     Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
560     break;
561   }
562   case AsmToken::Percent:
563     return parseOperandWithModifier(Operands);
564   }
565 
566   E = SMLoc::getFromPointer(S.getPointer() - 1);
567   Operands.push_back(XtensaOperand::createImm(Res, S, E));
568   return MatchOperand_Success;
569 }
570 
571 OperandMatchResultTy
572 XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) {
573   return MatchOperand_ParseFail;
574 }
575 
576 /// Looks at a token type and creates the relevant operand
577 /// from this information, adding to Operands.
578 /// If operand was parsed, returns false, else true.
579 bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
580                                    bool SR) {
581   // Check if the current operand has a custom associated parser, if so, try to
582   // custom parse the operand, or fallback to the general approach.
583   OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
584   if (ResTy == MatchOperand_Success)
585     return false;
586 
587   // If there wasn't a custom match, try the generic matcher below. Otherwise,
588   // there was a match, but an error occurred, in which case, just return that
589   // the operand parsing failed.
590   if (ResTy == MatchOperand_ParseFail)
591     return true;
592 
593   // Attempt to parse token as register
594   if (parseRegister(Operands, true, SR) == MatchOperand_Success)
595     return false;
596 
597   // Attempt to parse token as an immediate
598   if (parseImmediate(Operands) == MatchOperand_Success) {
599     return false;
600   }
601 
602   // Finally we have exhausted all options and must declare defeat.
603   Error(getLoc(), "unknown operand");
604   return true;
605 }
606 
607 bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
608                                              StringRef Name, SMLoc NameLoc,
609                                              OperandVector &Operands) {
610   if ((Name.startswith("wsr.") || Name.startswith("rsr.") ||
611        Name.startswith("xsr.")) &&
612       (Name.size() > 4)) {
613     // Parse case when instruction name is concatenated with SR register
614     // name, like "wsr.sar a1"
615 
616     // First operand is token for instruction
617     Operands.push_back(XtensaOperand::createToken(Name.take_front(3), NameLoc));
618 
619     StringRef RegName = Name.drop_front(4);
620     unsigned RegNo = MatchRegisterName(RegName);
621 
622     if (RegNo == 0)
623       RegNo = MatchRegisterAltName(RegName);
624 
625     if (RegNo == 0) {
626       Error(NameLoc, "invalid register name");
627       return true;
628     }
629 
630     // Parse operand
631     if (parseOperand(Operands, Name))
632       return true;
633 
634     SMLoc S = getLoc();
635     SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
636     Operands.push_back(XtensaOperand::createReg(RegNo, S, E));
637   } else {
638     // First operand is token for instruction
639     Operands.push_back(XtensaOperand::createToken(Name, NameLoc));
640 
641     // Parse first operand
642     if (parseOperand(Operands, Name))
643       return true;
644 
645     if (!getLexer().is(AsmToken::Comma)) {
646       SMLoc Loc = getLexer().getLoc();
647       getParser().eatToEndOfStatement();
648       return Error(Loc, "unexpected token");
649     }
650 
651     getLexer().Lex();
652 
653     // Parse second operand
654     if (parseOperand(Operands, Name, true))
655       return true;
656   }
657 
658   if (getLexer().isNot(AsmToken::EndOfStatement)) {
659     SMLoc Loc = getLexer().getLoc();
660     getParser().eatToEndOfStatement();
661     return Error(Loc, "unexpected token");
662   }
663 
664   getParser().Lex(); // Consume the EndOfStatement.
665   return false;
666 }
667 
668 bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info,
669                                        StringRef Name, SMLoc NameLoc,
670                                        OperandVector &Operands) {
671   if (Name.startswith("wsr") || Name.startswith("rsr") ||
672       Name.startswith("xsr")) {
673     return ParseInstructionWithSR(Info, Name, NameLoc, Operands);
674   }
675 
676   // First operand is token for instruction
677   Operands.push_back(XtensaOperand::createToken(Name, NameLoc));
678 
679   // If there are no more operands, then finish
680   if (getLexer().is(AsmToken::EndOfStatement))
681     return false;
682 
683   // Parse first operand
684   if (parseOperand(Operands, Name))
685     return true;
686 
687   // Parse until end of statement, consuming commas between operands
688   while (getLexer().is(AsmToken::Comma)) {
689     // Consume comma token
690     getLexer().Lex();
691 
692     // Parse next operand
693     if (parseOperand(Operands, Name))
694       return true;
695   }
696 
697   if (getLexer().isNot(AsmToken::EndOfStatement)) {
698     SMLoc Loc = getLexer().getLoc();
699     getParser().eatToEndOfStatement();
700     return Error(Loc, "unexpected token");
701   }
702 
703   getParser().Lex(); // Consume the EndOfStatement.
704   return false;
705 }
706 
707 bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
708 
709 // Force static initialization.
710 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() {
711   RegisterMCAsmParser<XtensaAsmParser> X(getTheXtensaTarget());
712 }
713