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