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