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
28using namespace llvm;
29
30#define DEBUG_TYPE "xtensa-asm-parser"
31
32struct XtensaOperand;
33
34class 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
66public:
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].
82static 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
90struct 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
115public:
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
335unsigned XtensaAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
336                                                     unsigned Kind) {
337  return Match_InvalidOperand;
338}
339
340static 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
351bool 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
434ParseStatus 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
455bool 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
471ParseStatus 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
530ParseStatus 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
565ParseStatus 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.
572bool 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
598bool 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
655bool 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.
690extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() {
691  RegisterMCAsmParser<XtensaAsmParser> X(getTheXtensaTarget());
692}
693