ARMAsmParser.cpp revision 515d509360d81946247fd0f937034cdf1f237c72
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 const AsmToken &CommaTok = getLexer().getTok(); 387 if (CommaTok.isNot(AsmToken::Comma)) 388 return Error(CommaTok.getLoc(), "',' expected"); 389 getLexer().Lex(); // Eat comma token. 390 391 const AsmToken &NextTok = getLexer().getTok(); 392 if (NextTok.is(AsmToken::Plus)) 393 getLexer().Lex(); // Eat plus token. 394 else if (NextTok.is(AsmToken::Minus)) { 395 Negative = true; 396 getLexer().Lex(); // Eat minus token 397 } 398 399 // See if there is a register following the "[Rn]," we have so far. 400 const AsmToken &OffsetRegTok = getLexer().getTok(); 401 int OffsetRegNum = MatchRegisterName(OffsetRegTok.getString()); 402 bool OffsetRegShifted = false; 403 enum ShiftType ShiftType; 404 const MCExpr *ShiftAmount; 405 const MCExpr *Offset; 406 if (OffsetRegNum != -1) { 407 OffsetIsReg = true; 408 getLexer().Lex(); // Eat identifier token for the offset register. 409 // Look for a comma then a shift 410 const AsmToken &Tok = getLexer().getTok(); 411 if (Tok.is(AsmToken::Comma)) { 412 getLexer().Lex(); // Eat comma token. 413 414 const AsmToken &Tok = getLexer().getTok(); 415 if (ParseShift(&ShiftType, ShiftAmount)) 416 return Error(Tok.getLoc(), "shift expected"); 417 OffsetRegShifted = true; 418 } 419 } 420 else { // "[Rn]," we have so far was not followed by "Rm" 421 // Look for #offset following the "[Rn]," 422 const AsmToken &HashTok = getLexer().getTok(); 423 if (HashTok.isNot(AsmToken::Hash)) 424 return Error(HashTok.getLoc(), "'#' expected"); 425 getLexer().Lex(); // Eat hash token. 426 427 if (getParser().ParseExpression(Offset)) 428 return true; 429 } 430 Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, 431 OffsetRegShifted, ShiftType, ShiftAmount, 432 Preindexed, Postindexed, Negative, Writeback); 433 return false; 434 } 435 436 return true; 437} 438 439/// ParseShift as one of these two: 440/// ( lsl | lsr | asr | ror ) , # shift_amount 441/// rrx 442/// and returns true if it parses a shift otherwise it returns false. 443bool ARMAsmParser::ParseShift(ShiftType *St, const MCExpr *&ShiftAmount) { 444 const AsmToken &Tok = getLexer().getTok(); 445 if (Tok.isNot(AsmToken::Identifier)) 446 return true; 447 const StringRef &ShiftName = Tok.getString(); 448 if (ShiftName == "lsl" || ShiftName == "LSL") 449 *St = Lsl; 450 else if (ShiftName == "lsr" || ShiftName == "LSR") 451 *St = Lsr; 452 else if (ShiftName == "asr" || ShiftName == "ASR") 453 *St = Asr; 454 else if (ShiftName == "ror" || ShiftName == "ROR") 455 *St = Ror; 456 else if (ShiftName == "rrx" || ShiftName == "RRX") 457 *St = Rrx; 458 else 459 return true; 460 getLexer().Lex(); // Eat shift type token. 461 462 // For all but a Rotate right there must be a '#' and a shift amount 463 if (*St != Rrx) { 464 // Look for # following the shift type 465 const AsmToken &HashTok = getLexer().getTok(); 466 if (HashTok.isNot(AsmToken::Hash)) 467 return Error(HashTok.getLoc(), "'#' expected"); 468 getLexer().Lex(); // Eat hash token. 469 470 if (getParser().ParseExpression(ShiftAmount)) 471 return true; 472 } 473 474 return false; 475} 476 477// A hack to allow some testing, to be replaced by a real table gen version. 478int ARMAsmParser::MatchRegisterName(const StringRef &Name) { 479 if (Name == "r0" || Name == "R0") 480 return 0; 481 else if (Name == "r1" || Name == "R1") 482 return 1; 483 else if (Name == "r2" || Name == "R2") 484 return 2; 485 else if (Name == "r3" || Name == "R3") 486 return 3; 487 else if (Name == "r3" || Name == "R3") 488 return 3; 489 else if (Name == "r4" || Name == "R4") 490 return 4; 491 else if (Name == "r5" || Name == "R5") 492 return 5; 493 else if (Name == "r6" || Name == "R6") 494 return 6; 495 else if (Name == "r7" || Name == "R7") 496 return 7; 497 else if (Name == "r8" || Name == "R8") 498 return 8; 499 else if (Name == "r9" || Name == "R9") 500 return 9; 501 else if (Name == "r10" || Name == "R10") 502 return 10; 503 else if (Name == "r11" || Name == "R11" || Name == "fp") 504 return 11; 505 else if (Name == "r12" || Name == "R12" || Name == "ip") 506 return 12; 507 else if (Name == "r13" || Name == "R13" || Name == "sp") 508 return 13; 509 else if (Name == "r14" || Name == "R14" || Name == "lr") 510 return 14; 511 else if (Name == "r15" || Name == "R15" || Name == "pc") 512 return 15; 513 return -1; 514} 515 516// A hack to allow some testing, to be replaced by a real table gen version. 517bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands, 518 MCInst &Inst) { 519 struct ARMOperand Op0 = Operands[0]; 520 assert(Op0.Kind == ARMOperand::Token && "First operand not a Token"); 521 const StringRef &Mnemonic = Op0.getToken(); 522 if (Mnemonic == "add" || 523 Mnemonic == "stmfd" || 524 Mnemonic == "str" || 525 Mnemonic == "ldmfd" || 526 Mnemonic == "ldr" || 527 Mnemonic == "mov" || 528 Mnemonic == "sub" || 529 Mnemonic == "bl" || 530 Mnemonic == "push" || 531 Mnemonic == "blx" || 532 Mnemonic == "pop") 533 return false; 534 535 return true; 536} 537 538// Parse a arm instruction operand. For now this parses the operand regardless 539// of the mnemonic. 540bool ARMAsmParser::ParseOperand(ARMOperand &Op) { 541 switch (getLexer().getKind()) { 542 case AsmToken::Identifier: 543 if (!ParseRegister(Op)) 544 return false; 545 // This was not a register so parse other operands that start with an 546 // identifier (like labels) as expressions and create them as immediates. 547 const MCExpr *IdVal; 548 if (getParser().ParseExpression(IdVal)) 549 return true; 550 Op = ARMOperand::CreateImm(IdVal); 551 return false; 552 case AsmToken::LBrac: 553 return ParseMemory(Op); 554 case AsmToken::LCurly: 555 return ParseRegisterList(Op); 556 case AsmToken::Hash: 557 // #42 -> immediate. 558 // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate 559 getLexer().Lex(); 560 const MCExpr *ImmVal; 561 if (getParser().ParseExpression(ImmVal)) 562 return true; 563 Op = ARMOperand::CreateImm(ImmVal); 564 return false; 565 default: 566 return Error(getLexer().getTok().getLoc(), "unexpected token in operand"); 567 } 568} 569 570// Parse an arm instruction mnemonic followed by its operands. 571bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { 572 SmallVector<ARMOperand, 7> Operands; 573 574 Operands.push_back(ARMOperand::CreateToken(Name)); 575 576 SMLoc Loc = getLexer().getTok().getLoc(); 577 if (getLexer().isNot(AsmToken::EndOfStatement)) { 578 579 // Read the first operand. 580 Operands.push_back(ARMOperand()); 581 if (ParseOperand(Operands.back())) 582 return true; 583 584 while (getLexer().is(AsmToken::Comma)) { 585 getLexer().Lex(); // Eat the comma. 586 587 // Parse and remember the operand. 588 Operands.push_back(ARMOperand()); 589 if (ParseOperand(Operands.back())) 590 return true; 591 } 592 } 593 if (!MatchInstruction(Operands, Inst)) 594 return false; 595 596 Error(Loc, "ARMAsmParser::ParseInstruction only partly implemented"); 597 return true; 598} 599 600/// ParseDirective parses the arm specific directives 601bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { 602 StringRef IDVal = DirectiveID.getIdentifier(); 603 if (IDVal == ".word") 604 return ParseDirectiveWord(4, DirectiveID.getLoc()); 605 else if (IDVal == ".thumb") 606 return ParseDirectiveThumb(DirectiveID.getLoc()); 607 else if (IDVal == ".thumb_func") 608 return ParseDirectiveThumbFunc(DirectiveID.getLoc()); 609 else if (IDVal == ".code") 610 return ParseDirectiveCode(DirectiveID.getLoc()); 611 else if (IDVal == ".syntax") 612 return ParseDirectiveSyntax(DirectiveID.getLoc()); 613 return true; 614} 615 616/// ParseDirectiveWord 617/// ::= .word [ expression (, expression)* ] 618bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { 619 if (getLexer().isNot(AsmToken::EndOfStatement)) { 620 for (;;) { 621 const MCExpr *Value; 622 if (getParser().ParseExpression(Value)) 623 return true; 624 625 getParser().getStreamer().EmitValue(Value, Size); 626 627 if (getLexer().is(AsmToken::EndOfStatement)) 628 break; 629 630 // FIXME: Improve diagnostic. 631 if (getLexer().isNot(AsmToken::Comma)) 632 return Error(L, "unexpected token in directive"); 633 getLexer().Lex(); 634 } 635 } 636 637 getLexer().Lex(); 638 return false; 639} 640 641/// ParseDirectiveThumb 642/// ::= .thumb 643bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) { 644 if (getLexer().isNot(AsmToken::EndOfStatement)) 645 return Error(L, "unexpected token in directive"); 646 getLexer().Lex(); 647 648 // TODO: set thumb mode 649 // TODO: tell the MC streamer the mode 650 // getParser().getStreamer().Emit???(); 651 return false; 652} 653 654/// ParseDirectiveThumbFunc 655/// ::= .thumbfunc symbol_name 656bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) { 657 const AsmToken &Tok = getLexer().getTok(); 658 if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) 659 return Error(L, "unexpected token in .syntax directive"); 660 StringRef SymbolName = getLexer().getTok().getIdentifier(); 661 getLexer().Lex(); // Consume the identifier token. 662 663 if (getLexer().isNot(AsmToken::EndOfStatement)) 664 return Error(L, "unexpected token in directive"); 665 getLexer().Lex(); 666 667 // TODO: mark symbol as a thumb symbol 668 // getParser().getStreamer().Emit???(); 669 return false; 670} 671 672/// ParseDirectiveSyntax 673/// ::= .syntax unified | divided 674bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) { 675 const AsmToken &Tok = getLexer().getTok(); 676 if (Tok.isNot(AsmToken::Identifier)) 677 return Error(L, "unexpected token in .syntax directive"); 678 const StringRef &Mode = Tok.getString(); 679 bool unified_syntax; 680 if (Mode == "unified" || Mode == "UNIFIED") { 681 getLexer().Lex(); 682 unified_syntax = true; 683 } 684 else if (Mode == "divided" || Mode == "DIVIDED") { 685 getLexer().Lex(); 686 unified_syntax = false; 687 } 688 else 689 return Error(L, "unrecognized syntax mode in .syntax directive"); 690 691 if (getLexer().isNot(AsmToken::EndOfStatement)) 692 return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); 693 getLexer().Lex(); 694 695 // TODO tell the MC streamer the mode 696 // getParser().getStreamer().Emit???(); 697 return false; 698} 699 700/// ParseDirectiveCode 701/// ::= .code 16 | 32 702bool ARMAsmParser::ParseDirectiveCode(SMLoc L) { 703 const AsmToken &Tok = getLexer().getTok(); 704 if (Tok.isNot(AsmToken::Integer)) 705 return Error(L, "unexpected token in .code directive"); 706 int64_t Val = getLexer().getTok().getIntVal(); 707 bool thumb_mode; 708 if (Val == 16) { 709 getLexer().Lex(); 710 thumb_mode = true; 711 } 712 else if (Val == 32) { 713 getLexer().Lex(); 714 thumb_mode = false; 715 } 716 else 717 return Error(L, "invalid operand to .code directive"); 718 719 if (getLexer().isNot(AsmToken::EndOfStatement)) 720 return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); 721 getLexer().Lex(); 722 723 // TODO tell the MC streamer the mode 724 // getParser().getStreamer().Emit???(); 725 return false; 726} 727 728// Force static initialization. 729extern "C" void LLVMInitializeARMAsmParser() { 730 RegisterAsmParser<ARMAsmParser> X(TheARMTarget); 731 RegisterAsmParser<ARMAsmParser> Y(TheThumbTarget); 732} 733