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