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