ARMAsmParser.cpp revision b9a25b7744ed12b80031426978decce3d4cebbd7
1//===-- ARMAsmParser.cpp - Parse ARM assembly to MCInst instructions ------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "ARM.h" 11#include "llvm/ADT/SmallVector.h" 12#include "llvm/ADT/Twine.h" 13#include "llvm/MC/MCAsmLexer.h" 14#include "llvm/MC/MCAsmParser.h" 15#include "llvm/MC/MCParsedAsmOperand.h" 16#include "llvm/MC/MCStreamer.h" 17#include "llvm/MC/MCExpr.h" 18#include "llvm/MC/MCInst.h" 19#include "llvm/Support/Compiler.h" 20#include "llvm/Support/SourceMgr.h" 21#include "llvm/Target/TargetRegistry.h" 22#include "llvm/Target/TargetAsmParser.h" 23using namespace llvm; 24 25namespace { 26struct ARMOperand; 27 28// The shift types for register controlled shifts in arm memory addressing 29enum ShiftType { 30 Lsl, 31 Lsr, 32 Asr, 33 Ror, 34 Rrx 35}; 36 37class ARMAsmParser : public TargetAsmParser { 38 MCAsmParser &Parser; 39 40private: 41 MCAsmParser &getParser() const { return Parser; } 42 43 MCAsmLexer &getLexer() const { return Parser.getLexer(); } 44 45 void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); } 46 47 bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } 48 49 bool MaybeParseRegister(ARMOperand &Op, bool ParseWriteBack); 50 51 bool ParseRegisterList(ARMOperand &Op); 52 53 bool ParseMemory(ARMOperand &Op); 54 55 bool ParseMemoryOffsetReg(bool &Negative, 56 bool &OffsetRegShifted, 57 enum ShiftType &ShiftType, 58 const MCExpr *&ShiftAmount, 59 const MCExpr *&Offset, 60 bool &OffsetIsReg, 61 int &OffsetRegNum); 62 63 bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount); 64 65 bool ParseOperand(ARMOperand &Op); 66 67 bool ParseDirectiveWord(unsigned Size, SMLoc L); 68 69 bool ParseDirectiveThumb(SMLoc L); 70 71 bool ParseDirectiveThumbFunc(SMLoc L); 72 73 bool ParseDirectiveCode(SMLoc L); 74 75 bool ParseDirectiveSyntax(SMLoc L); 76 77 // TODO - For now hacked versions of the next two are in here in this file to 78 // allow some parser testing until the table gen versions are implemented. 79 80 /// @name Auto-generated Match Functions 81 /// { 82 bool MatchInstruction(const SmallVectorImpl<MCParsedAsmOperand*> &Operands, 83 MCInst &Inst); 84 85 /// MatchRegisterName - Match the given string to a register name and return 86 /// its register number, or -1 if there is no match. To allow return values 87 /// to be used directly in register lists, arm registers have values between 88 /// 0 and 15. 89 int MatchRegisterName(const StringRef &Name); 90 91 /// } 92 93 94public: 95 ARMAsmParser(const Target &T, MCAsmParser &_Parser) 96 : TargetAsmParser(T), Parser(_Parser) {} 97 98 virtual bool ParseInstruction(const StringRef &Name, SMLoc NameLoc, 99 SmallVectorImpl<MCParsedAsmOperand*> &Operands); 100 101 virtual bool ParseDirective(AsmToken DirectiveID); 102}; 103 104/// ARMOperand - Instances of this class represent a parsed ARM machine 105/// instruction. 106struct ARMOperand : public MCParsedAsmOperand { 107 enum { 108 Token, 109 Register, 110 Immediate, 111 Memory 112 } Kind; 113 114 115 union { 116 struct { 117 const char *Data; 118 unsigned Length; 119 } Tok; 120 121 struct { 122 unsigned RegNum; 123 bool Writeback; 124 } Reg; 125 126 struct { 127 const MCExpr *Val; 128 } Imm; 129 130 // This is for all forms of ARM address expressions 131 struct { 132 unsigned BaseRegNum; 133 unsigned OffsetRegNum; // used when OffsetIsReg is true 134 const MCExpr *Offset; // used when OffsetIsReg is false 135 const MCExpr *ShiftAmount; // used when OffsetRegShifted is true 136 enum ShiftType ShiftType; // used when OffsetRegShifted is true 137 unsigned 138 OffsetRegShifted : 1, // only used when OffsetIsReg is true 139 Preindexed : 1, 140 Postindexed : 1, 141 OffsetIsReg : 1, 142 Negative : 1, // only used when OffsetIsReg is true 143 Writeback : 1; 144 } Mem; 145 146 }; 147 148 StringRef getToken() const { 149 assert(Kind == Token && "Invalid access!"); 150 return StringRef(Tok.Data, Tok.Length); 151 } 152 153 unsigned getReg() const { 154 assert(Kind == Register && "Invalid access!"); 155 return Reg.RegNum; 156 } 157 158 const MCExpr *getImm() const { 159 assert(Kind == Immediate && "Invalid access!"); 160 return Imm.Val; 161 } 162 163 bool isToken() const {return Kind == Token; } 164 165 bool isReg() const { return Kind == Register; } 166 167 void addRegOperands(MCInst &Inst, unsigned N) const { 168 assert(N == 1 && "Invalid number of operands!"); 169 Inst.addOperand(MCOperand::CreateReg(getReg())); 170 } 171 172 static ARMOperand CreateToken(StringRef Str) { 173 ARMOperand Res; 174 Res.Kind = Token; 175 Res.Tok.Data = Str.data(); 176 Res.Tok.Length = Str.size(); 177 return Res; 178 } 179 180 static ARMOperand CreateReg(unsigned RegNum, bool Writeback) { 181 ARMOperand Res; 182 Res.Kind = Register; 183 Res.Reg.RegNum = RegNum; 184 Res.Reg.Writeback = Writeback; 185 return Res; 186 } 187 188 static ARMOperand CreateImm(const MCExpr *Val) { 189 ARMOperand Res; 190 Res.Kind = Immediate; 191 Res.Imm.Val = Val; 192 return Res; 193 } 194 195 static ARMOperand CreateMem(unsigned BaseRegNum, bool OffsetIsReg, 196 const MCExpr *Offset, unsigned OffsetRegNum, 197 bool OffsetRegShifted, enum ShiftType ShiftType, 198 const MCExpr *ShiftAmount, bool Preindexed, 199 bool Postindexed, bool Negative, bool Writeback) { 200 ARMOperand Res; 201 Res.Kind = Memory; 202 Res.Mem.BaseRegNum = BaseRegNum; 203 Res.Mem.OffsetIsReg = OffsetIsReg; 204 Res.Mem.Offset = Offset; 205 Res.Mem.OffsetRegNum = OffsetRegNum; 206 Res.Mem.OffsetRegShifted = OffsetRegShifted; 207 Res.Mem.ShiftType = ShiftType; 208 Res.Mem.ShiftAmount = ShiftAmount; 209 Res.Mem.Preindexed = Preindexed; 210 Res.Mem.Postindexed = Postindexed; 211 Res.Mem.Negative = Negative; 212 Res.Mem.Writeback = Writeback; 213 return Res; 214 } 215}; 216 217} // end anonymous namespace. 218 219/// Try to parse a register name. The token must be an Identifier when called, 220/// and if it is a register name a Reg operand is created, the token is eaten 221/// and false is returned. Else true is returned and no token is eaten. 222/// TODO this is likely to change to allow different register types and or to 223/// parse for a specific register type. 224bool ARMAsmParser::MaybeParseRegister(ARMOperand &Op, bool ParseWriteBack) { 225 const AsmToken &Tok = getLexer().getTok(); 226 assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); 227 228 // FIXME: Validate register for the current architecture; we have to do 229 // validation later, so maybe there is no need for this here. 230 int RegNum; 231 232 RegNum = MatchRegisterName(Tok.getString()); 233 if (RegNum == -1) 234 return true; 235 Parser.Lex(); // Eat identifier token. 236 237 bool Writeback = false; 238 if (ParseWriteBack) { 239 const AsmToken &ExclaimTok = getLexer().getTok(); 240 if (ExclaimTok.is(AsmToken::Exclaim)) { 241 Writeback = true; 242 Parser.Lex(); // Eat exclaim token 243 } 244 } 245 246 Op = ARMOperand::CreateReg(RegNum, Writeback); 247 248 return false; 249} 250 251/// Parse a register list, return false if successful else return true or an 252/// error. The first token must be a '{' when called. 253bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) { 254 assert(getLexer().getTok().is(AsmToken::LCurly) && 255 "Token is not an Left Curly Brace"); 256 Parser.Lex(); // Eat left curly brace token. 257 258 const AsmToken &RegTok = getLexer().getTok(); 259 SMLoc RegLoc = RegTok.getLoc(); 260 if (RegTok.isNot(AsmToken::Identifier)) 261 return Error(RegLoc, "register expected"); 262 int RegNum = MatchRegisterName(RegTok.getString()); 263 if (RegNum == -1) 264 return Error(RegLoc, "register expected"); 265 Parser.Lex(); // Eat identifier token. 266 unsigned RegList = 1 << RegNum; 267 268 int HighRegNum = RegNum; 269 // TODO ranges like "{Rn-Rm}" 270 while (getLexer().getTok().is(AsmToken::Comma)) { 271 Parser.Lex(); // Eat comma token. 272 273 const AsmToken &RegTok = getLexer().getTok(); 274 SMLoc RegLoc = RegTok.getLoc(); 275 if (RegTok.isNot(AsmToken::Identifier)) 276 return Error(RegLoc, "register expected"); 277 int RegNum = MatchRegisterName(RegTok.getString()); 278 if (RegNum == -1) 279 return Error(RegLoc, "register expected"); 280 281 if (RegList & (1 << RegNum)) 282 Warning(RegLoc, "register duplicated in register list"); 283 else if (RegNum <= HighRegNum) 284 Warning(RegLoc, "register not in ascending order in register list"); 285 RegList |= 1 << RegNum; 286 HighRegNum = RegNum; 287 288 Parser.Lex(); // Eat identifier token. 289 } 290 const AsmToken &RCurlyTok = getLexer().getTok(); 291 if (RCurlyTok.isNot(AsmToken::RCurly)) 292 return Error(RCurlyTok.getLoc(), "'}' expected"); 293 Parser.Lex(); // Eat left curly brace token. 294 295 return false; 296} 297 298/// Parse an arm memory expression, return false if successful else return true 299/// or an error. The first token must be a '[' when called. 300/// TODO Only preindexing and postindexing addressing are started, unindexed 301/// with option, etc are still to do. 302bool ARMAsmParser::ParseMemory(ARMOperand &Op) { 303 assert(getLexer().getTok().is(AsmToken::LBrac) && 304 "Token is not an Left Bracket"); 305 Parser.Lex(); // Eat left bracket token. 306 307 const AsmToken &BaseRegTok = getLexer().getTok(); 308 if (BaseRegTok.isNot(AsmToken::Identifier)) 309 return Error(BaseRegTok.getLoc(), "register expected"); 310 if (MaybeParseRegister(Op, false)) 311 return Error(BaseRegTok.getLoc(), "register expected"); 312 int BaseRegNum = Op.getReg(); 313 314 bool Preindexed = false; 315 bool Postindexed = false; 316 bool OffsetIsReg = false; 317 bool Negative = false; 318 bool Writeback = false; 319 320 // First look for preindexed address forms, that is after the "[Rn" we now 321 // have to see if the next token is a comma. 322 const AsmToken &Tok = getLexer().getTok(); 323 if (Tok.is(AsmToken::Comma)) { 324 Preindexed = true; 325 Parser.Lex(); // Eat comma token. 326 int OffsetRegNum; 327 bool OffsetRegShifted; 328 enum ShiftType ShiftType; 329 const MCExpr *ShiftAmount; 330 const MCExpr *Offset; 331 if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount, 332 Offset, OffsetIsReg, OffsetRegNum)) 333 return true; 334 const AsmToken &RBracTok = getLexer().getTok(); 335 if (RBracTok.isNot(AsmToken::RBrac)) 336 return Error(RBracTok.getLoc(), "']' expected"); 337 Parser.Lex(); // Eat right bracket token. 338 339 const AsmToken &ExclaimTok = getLexer().getTok(); 340 if (ExclaimTok.is(AsmToken::Exclaim)) { 341 Writeback = true; 342 Parser.Lex(); // Eat exclaim token 343 } 344 Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, 345 OffsetRegShifted, ShiftType, ShiftAmount, 346 Preindexed, Postindexed, Negative, Writeback); 347 return false; 348 } 349 // The "[Rn" we have so far was not followed by a comma. 350 else if (Tok.is(AsmToken::RBrac)) { 351 // This is a post indexing addressing forms, that is a ']' follows after 352 // the "[Rn". 353 Postindexed = true; 354 Writeback = true; 355 Parser.Lex(); // Eat right bracket token. 356 357 int OffsetRegNum = 0; 358 bool OffsetRegShifted = false; 359 enum ShiftType ShiftType; 360 const MCExpr *ShiftAmount; 361 const MCExpr *Offset; 362 363 const AsmToken &NextTok = getLexer().getTok(); 364 if (NextTok.isNot(AsmToken::EndOfStatement)) { 365 if (NextTok.isNot(AsmToken::Comma)) 366 return Error(NextTok.getLoc(), "',' expected"); 367 Parser.Lex(); // Eat comma token. 368 if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, 369 ShiftAmount, Offset, OffsetIsReg, OffsetRegNum)) 370 return true; 371 } 372 373 Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, 374 OffsetRegShifted, ShiftType, ShiftAmount, 375 Preindexed, Postindexed, Negative, Writeback); 376 return false; 377 } 378 379 return true; 380} 381 382/// Parse the offset of a memory operand after we have seen "[Rn," or "[Rn]," 383/// we will parse the following (were +/- means that a plus or minus is 384/// optional): 385/// +/-Rm 386/// +/-Rm, shift 387/// #offset 388/// we return false on success or an error otherwise. 389bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative, 390 bool &OffsetRegShifted, 391 enum ShiftType &ShiftType, 392 const MCExpr *&ShiftAmount, 393 const MCExpr *&Offset, 394 bool &OffsetIsReg, 395 int &OffsetRegNum) { 396 ARMOperand Op; 397 Negative = false; 398 OffsetRegShifted = false; 399 OffsetIsReg = false; 400 OffsetRegNum = -1; 401 const AsmToken &NextTok = getLexer().getTok(); 402 if (NextTok.is(AsmToken::Plus)) 403 Parser.Lex(); // Eat plus token. 404 else if (NextTok.is(AsmToken::Minus)) { 405 Negative = true; 406 Parser.Lex(); // Eat minus token 407 } 408 // See if there is a register following the "[Rn," or "[Rn]," we have so far. 409 const AsmToken &OffsetRegTok = getLexer().getTok(); 410 if (OffsetRegTok.is(AsmToken::Identifier)) { 411 OffsetIsReg = !MaybeParseRegister(Op, false); 412 if (OffsetIsReg) 413 OffsetRegNum = Op.getReg(); 414 } 415 // If we parsed a register as the offset then their can be a shift after that 416 if (OffsetRegNum != -1) { 417 // Look for a comma then a shift 418 const AsmToken &Tok = getLexer().getTok(); 419 if (Tok.is(AsmToken::Comma)) { 420 Parser.Lex(); // Eat comma token. 421 422 const AsmToken &Tok = getLexer().getTok(); 423 if (ParseShift(ShiftType, ShiftAmount)) 424 return Error(Tok.getLoc(), "shift expected"); 425 OffsetRegShifted = true; 426 } 427 } 428 else { // the "[Rn," or "[Rn,]" we have so far was not followed by "Rm" 429 // Look for #offset following the "[Rn," or "[Rn]," 430 const AsmToken &HashTok = getLexer().getTok(); 431 if (HashTok.isNot(AsmToken::Hash)) 432 return Error(HashTok.getLoc(), "'#' expected"); 433 Parser.Lex(); // Eat hash token. 434 435 if (getParser().ParseExpression(Offset)) 436 return true; 437 } 438 return false; 439} 440 441/// ParseShift as one of these two: 442/// ( lsl | lsr | asr | ror ) , # shift_amount 443/// rrx 444/// and returns true if it parses a shift otherwise it returns false. 445bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount) { 446 const AsmToken &Tok = getLexer().getTok(); 447 if (Tok.isNot(AsmToken::Identifier)) 448 return true; 449 const StringRef &ShiftName = Tok.getString(); 450 if (ShiftName == "lsl" || ShiftName == "LSL") 451 St = Lsl; 452 else if (ShiftName == "lsr" || ShiftName == "LSR") 453 St = Lsr; 454 else if (ShiftName == "asr" || ShiftName == "ASR") 455 St = Asr; 456 else if (ShiftName == "ror" || ShiftName == "ROR") 457 St = Ror; 458 else if (ShiftName == "rrx" || ShiftName == "RRX") 459 St = Rrx; 460 else 461 return true; 462 Parser.Lex(); // Eat shift type token. 463 464 // Rrx stands alone. 465 if (St == Rrx) 466 return false; 467 468 // Otherwise, there must be a '#' and a shift amount. 469 const AsmToken &HashTok = getLexer().getTok(); 470 if (HashTok.isNot(AsmToken::Hash)) 471 return Error(HashTok.getLoc(), "'#' expected"); 472 Parser.Lex(); // Eat hash token. 473 474 if (getParser().ParseExpression(ShiftAmount)) 475 return true; 476 477 return false; 478} 479 480/// A hack to allow some testing, to be replaced by a real table gen version. 481int ARMAsmParser::MatchRegisterName(const StringRef &Name) { 482 if (Name == "r0" || Name == "R0") 483 return 0; 484 else if (Name == "r1" || Name == "R1") 485 return 1; 486 else if (Name == "r2" || Name == "R2") 487 return 2; 488 else if (Name == "r3" || Name == "R3") 489 return 3; 490 else if (Name == "r3" || Name == "R3") 491 return 3; 492 else if (Name == "r4" || Name == "R4") 493 return 4; 494 else if (Name == "r5" || Name == "R5") 495 return 5; 496 else if (Name == "r6" || Name == "R6") 497 return 6; 498 else if (Name == "r7" || Name == "R7") 499 return 7; 500 else if (Name == "r8" || Name == "R8") 501 return 8; 502 else if (Name == "r9" || Name == "R9") 503 return 9; 504 else if (Name == "r10" || Name == "R10") 505 return 10; 506 else if (Name == "r11" || Name == "R11" || Name == "fp") 507 return 11; 508 else if (Name == "r12" || Name == "R12" || Name == "ip") 509 return 12; 510 else if (Name == "r13" || Name == "R13" || Name == "sp") 511 return 13; 512 else if (Name == "r14" || Name == "R14" || Name == "lr") 513 return 14; 514 else if (Name == "r15" || Name == "R15" || Name == "pc") 515 return 15; 516 return -1; 517} 518 519/// A hack to allow some testing, to be replaced by a real table gen version. 520bool ARMAsmParser:: 521MatchInstruction(const SmallVectorImpl<MCParsedAsmOperand*> &Operands, 522 MCInst &Inst) { 523 ARMOperand &Op0 = *(ARMOperand*)Operands[0]; 524 assert(Op0.Kind == ARMOperand::Token && "First operand not a Token"); 525 const StringRef &Mnemonic = Op0.getToken(); 526 if (Mnemonic == "add" || 527 Mnemonic == "stmfd" || 528 Mnemonic == "str" || 529 Mnemonic == "ldmfd" || 530 Mnemonic == "ldr" || 531 Mnemonic == "mov" || 532 Mnemonic == "sub" || 533 Mnemonic == "bl" || 534 Mnemonic == "push" || 535 Mnemonic == "blx" || 536 Mnemonic == "pop") { 537 // Hard-coded to a valid instruction, till we have a real matcher. 538 Inst = MCInst(); 539 Inst.setOpcode(ARM::MOVr); 540 Inst.addOperand(MCOperand::CreateReg(2)); 541 Inst.addOperand(MCOperand::CreateReg(2)); 542 Inst.addOperand(MCOperand::CreateImm(0)); 543 Inst.addOperand(MCOperand::CreateImm(0)); 544 Inst.addOperand(MCOperand::CreateReg(0)); 545 return false; 546 } 547 548 return true; 549} 550 551/// Parse a arm instruction operand. For now this parses the operand regardless 552/// of the mnemonic. 553bool ARMAsmParser::ParseOperand(ARMOperand &Op) { 554 switch (getLexer().getKind()) { 555 case AsmToken::Identifier: 556 if (!MaybeParseRegister(Op, true)) 557 return false; 558 // This was not a register so parse other operands that start with an 559 // identifier (like labels) as expressions and create them as immediates. 560 const MCExpr *IdVal; 561 if (getParser().ParseExpression(IdVal)) 562 return true; 563 Op = ARMOperand::CreateImm(IdVal); 564 return false; 565 case AsmToken::LBrac: 566 return ParseMemory(Op); 567 case AsmToken::LCurly: 568 return ParseRegisterList(Op); 569 case AsmToken::Hash: 570 // #42 -> immediate. 571 // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate 572 Parser.Lex(); 573 const MCExpr *ImmVal; 574 if (getParser().ParseExpression(ImmVal)) 575 return true; 576 Op = ARMOperand::CreateImm(ImmVal); 577 return false; 578 default: 579 return Error(getLexer().getTok().getLoc(), "unexpected token in operand"); 580 } 581} 582 583/// Parse an arm instruction mnemonic followed by its operands. 584bool ARMAsmParser::ParseInstruction(const StringRef &Name, SMLoc NameLoc, 585 SmallVectorImpl<MCParsedAsmOperand*> &Operands) { 586 Operands.push_back(new ARMOperand(ARMOperand::CreateToken(Name))); 587 588 SMLoc Loc = getLexer().getTok().getLoc(); 589 if (getLexer().isNot(AsmToken::EndOfStatement)) { 590 591 // Read the first operand. 592 ARMOperand Op; 593 if (ParseOperand(Op)) return true; 594 Operands.push_back(new ARMOperand(Op)); 595 596 while (getLexer().is(AsmToken::Comma)) { 597 Parser.Lex(); // Eat the comma. 598 599 // Parse and remember the operand. 600 if (ParseOperand(Op)) return true; 601 Operands.push_back(new ARMOperand(Op)); 602 } 603 } 604 return false; 605} 606 607/// ParseDirective parses the arm specific directives 608bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { 609 StringRef IDVal = DirectiveID.getIdentifier(); 610 if (IDVal == ".word") 611 return ParseDirectiveWord(4, DirectiveID.getLoc()); 612 else if (IDVal == ".thumb") 613 return ParseDirectiveThumb(DirectiveID.getLoc()); 614 else if (IDVal == ".thumb_func") 615 return ParseDirectiveThumbFunc(DirectiveID.getLoc()); 616 else if (IDVal == ".code") 617 return ParseDirectiveCode(DirectiveID.getLoc()); 618 else if (IDVal == ".syntax") 619 return ParseDirectiveSyntax(DirectiveID.getLoc()); 620 return true; 621} 622 623/// ParseDirectiveWord 624/// ::= .word [ expression (, expression)* ] 625bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { 626 if (getLexer().isNot(AsmToken::EndOfStatement)) { 627 for (;;) { 628 const MCExpr *Value; 629 if (getParser().ParseExpression(Value)) 630 return true; 631 632 getParser().getStreamer().EmitValue(Value, Size, 0/*addrspace*/); 633 634 if (getLexer().is(AsmToken::EndOfStatement)) 635 break; 636 637 // FIXME: Improve diagnostic. 638 if (getLexer().isNot(AsmToken::Comma)) 639 return Error(L, "unexpected token in directive"); 640 Parser.Lex(); 641 } 642 } 643 644 Parser.Lex(); 645 return false; 646} 647 648/// ParseDirectiveThumb 649/// ::= .thumb 650bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) { 651 if (getLexer().isNot(AsmToken::EndOfStatement)) 652 return Error(L, "unexpected token in directive"); 653 Parser.Lex(); 654 655 // TODO: set thumb mode 656 // TODO: tell the MC streamer the mode 657 // getParser().getStreamer().Emit???(); 658 return false; 659} 660 661/// ParseDirectiveThumbFunc 662/// ::= .thumbfunc symbol_name 663bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) { 664 const AsmToken &Tok = getLexer().getTok(); 665 if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) 666 return Error(L, "unexpected token in .syntax directive"); 667 StringRef ATTRIBUTE_UNUSED SymbolName = getLexer().getTok().getIdentifier(); 668 Parser.Lex(); // Consume the identifier token. 669 670 if (getLexer().isNot(AsmToken::EndOfStatement)) 671 return Error(L, "unexpected token in directive"); 672 Parser.Lex(); 673 674 // TODO: mark symbol as a thumb symbol 675 // getParser().getStreamer().Emit???(); 676 return false; 677} 678 679/// ParseDirectiveSyntax 680/// ::= .syntax unified | divided 681bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) { 682 const AsmToken &Tok = getLexer().getTok(); 683 if (Tok.isNot(AsmToken::Identifier)) 684 return Error(L, "unexpected token in .syntax directive"); 685 const StringRef &Mode = Tok.getString(); 686 bool unified_syntax; 687 if (Mode == "unified" || Mode == "UNIFIED") { 688 Parser.Lex(); 689 unified_syntax = true; 690 } 691 else if (Mode == "divided" || Mode == "DIVIDED") { 692 Parser.Lex(); 693 unified_syntax = false; 694 } 695 else 696 return Error(L, "unrecognized syntax mode in .syntax directive"); 697 698 if (getLexer().isNot(AsmToken::EndOfStatement)) 699 return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); 700 Parser.Lex(); 701 702 // TODO tell the MC streamer the mode 703 // getParser().getStreamer().Emit???(); 704 return false; 705} 706 707/// ParseDirectiveCode 708/// ::= .code 16 | 32 709bool ARMAsmParser::ParseDirectiveCode(SMLoc L) { 710 const AsmToken &Tok = getLexer().getTok(); 711 if (Tok.isNot(AsmToken::Integer)) 712 return Error(L, "unexpected token in .code directive"); 713 int64_t Val = getLexer().getTok().getIntVal(); 714 bool thumb_mode; 715 if (Val == 16) { 716 Parser.Lex(); 717 thumb_mode = true; 718 } 719 else if (Val == 32) { 720 Parser.Lex(); 721 thumb_mode = false; 722 } 723 else 724 return Error(L, "invalid operand to .code directive"); 725 726 if (getLexer().isNot(AsmToken::EndOfStatement)) 727 return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); 728 Parser.Lex(); 729 730 // TODO tell the MC streamer the mode 731 // getParser().getStreamer().Emit???(); 732 return false; 733} 734 735/// Force static initialization. 736extern "C" void LLVMInitializeARMAsmParser() { 737 RegisterAsmParser<ARMAsmParser> X(TheARMTarget); 738 RegisterAsmParser<ARMAsmParser> Y(TheThumbTarget); 739} 740