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