1 //===-- ARMAsmParser.cpp - Parse ARM assembly to MCInst instructions ------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 #include "ARMSubtarget.h"
12 #include "llvm/MC/MCParser/MCAsmLexer.h"
13 #include "llvm/MC/MCParser/MCAsmParser.h"
14 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
15 #include "llvm/MC/MCStreamer.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/Target/TargetRegistry.h"
19 #include "llvm/Target/TargetAsmParser.h"
20 #include "llvm/Support/Compiler.h"
21 #include "llvm/Support/SourceMgr.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/ADT/OwningPtr.h"
24 #include "llvm/ADT/SmallVector.h"
25 #include "llvm/ADT/StringSwitch.h"
26 #include "llvm/ADT/Twine.h"
32 // The shift types for register controlled shifts in arm memory addressing
41 class ARMAsmParser : public TargetAsmParser {
46 MCAsmParser &getParser() const { return Parser; }
48 MCAsmLexer &getLexer() const { return Parser.getLexer(); }
50 void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); }
52 bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
54 bool MaybeParseRegister(OwningPtr<ARMOperand> &Op, bool ParseWriteBack);
56 bool ParseRegisterList(OwningPtr<ARMOperand> &Op);
58 bool ParseMemory(OwningPtr<ARMOperand> &Op);
60 bool ParseMemoryOffsetReg(bool &Negative,
61 bool &OffsetRegShifted,
62 enum ShiftType &ShiftType,
63 const MCExpr *&ShiftAmount,
64 const MCExpr *&Offset,
69 bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E);
71 bool ParseOperand(OwningPtr<ARMOperand> &Op);
73 bool ParseDirectiveWord(unsigned Size, SMLoc L);
75 bool ParseDirectiveThumb(SMLoc L);
77 bool ParseDirectiveThumbFunc(SMLoc L);
79 bool ParseDirectiveCode(SMLoc L);
81 bool ParseDirectiveSyntax(SMLoc L);
83 bool MatchInstruction(const SmallVectorImpl<MCParsedAsmOperand*> &Operands,
85 return MatchInstructionImpl(Operands, Inst);
88 /// @name Auto-generated Match Functions
91 unsigned ComputeAvailableFeatures(const ARMSubtarget *Subtarget) const;
93 bool MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>
101 ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
102 : TargetAsmParser(T), Parser(_Parser), TM(_TM) {}
104 virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc,
105 SmallVectorImpl<MCParsedAsmOperand*> &Operands);
107 virtual bool ParseDirective(AsmToken DirectiveID);
110 /// ARMOperand - Instances of this class represent a parsed ARM machine
112 struct ARMOperand : public MCParsedAsmOperand {
124 SMLoc StartLoc, EndLoc;
128 ARMCC::CondCodes Val;
145 // This is for all forms of ARM address expressions
148 unsigned OffsetRegNum; // used when OffsetIsReg is true
149 const MCExpr *Offset; // used when OffsetIsReg is false
150 const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
151 enum ShiftType ShiftType; // used when OffsetRegShifted is true
153 OffsetRegShifted : 1, // only used when OffsetIsReg is true
157 Negative : 1, // only used when OffsetIsReg is true
163 ARMOperand(KindTy K, SMLoc S, SMLoc E)
164 : Kind(K), StartLoc(S), EndLoc(E) {}
166 ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() {
168 StartLoc = o.StartLoc;
189 /// getStartLoc - Get the location of the first token of this operand.
190 SMLoc getStartLoc() const { return StartLoc; }
191 /// getEndLoc - Get the location of the last token of this operand.
192 SMLoc getEndLoc() const { return EndLoc; }
194 ARMCC::CondCodes getCondCode() const {
195 assert(Kind == CondCode && "Invalid access!");
199 StringRef getToken() const {
200 assert(Kind == Token && "Invalid access!");
201 return StringRef(Tok.Data, Tok.Length);
204 unsigned getReg() const {
205 assert(Kind == Register && "Invalid access!");
209 const MCExpr *getImm() const {
210 assert(Kind == Immediate && "Invalid access!");
214 bool isCondCode() const { return Kind == CondCode; }
216 bool isImm() const { return Kind == Immediate; }
218 bool isReg() const { return Kind == Register; }
220 bool isToken() const {return Kind == Token; }
222 void addExpr(MCInst &Inst, const MCExpr *Expr) const {
223 // Add as immediates when possible.
224 if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
225 Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
227 Inst.addOperand(MCOperand::CreateExpr(Expr));
230 void addCondCodeOperands(MCInst &Inst, unsigned N) const {
231 assert(N == 2 && "Invalid number of operands!");
232 Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode())));
233 // FIXME: What belongs here?
234 Inst.addOperand(MCOperand::CreateReg(0));
237 void addRegOperands(MCInst &Inst, unsigned N) const {
238 assert(N == 1 && "Invalid number of operands!");
239 Inst.addOperand(MCOperand::CreateReg(getReg()));
242 void addImmOperands(MCInst &Inst, unsigned N) const {
243 assert(N == 1 && "Invalid number of operands!");
244 addExpr(Inst, getImm());
247 virtual void dump(raw_ostream &OS) const;
249 static void CreateCondCode(OwningPtr<ARMOperand> &Op, ARMCC::CondCodes CC,
251 Op.reset(new ARMOperand);
258 static void CreateToken(OwningPtr<ARMOperand> &Op, StringRef Str,
260 Op.reset(new ARMOperand);
262 Op->Tok.Data = Str.data();
263 Op->Tok.Length = Str.size();
268 static void CreateReg(OwningPtr<ARMOperand> &Op, unsigned RegNum,
269 bool Writeback, SMLoc S, SMLoc E) {
270 Op.reset(new ARMOperand);
272 Op->Reg.RegNum = RegNum;
273 Op->Reg.Writeback = Writeback;
279 static void CreateImm(OwningPtr<ARMOperand> &Op, const MCExpr *Val,
281 Op.reset(new ARMOperand);
282 Op->Kind = Immediate;
289 static void CreateMem(OwningPtr<ARMOperand> &Op,
290 unsigned BaseRegNum, bool OffsetIsReg,
291 const MCExpr *Offset, unsigned OffsetRegNum,
292 bool OffsetRegShifted, enum ShiftType ShiftType,
293 const MCExpr *ShiftAmount, bool Preindexed,
294 bool Postindexed, bool Negative, bool Writeback,
296 Op.reset(new ARMOperand);
298 Op->Mem.BaseRegNum = BaseRegNum;
299 Op->Mem.OffsetIsReg = OffsetIsReg;
300 Op->Mem.Offset = Offset;
301 Op->Mem.OffsetRegNum = OffsetRegNum;
302 Op->Mem.OffsetRegShifted = OffsetRegShifted;
303 Op->Mem.ShiftType = ShiftType;
304 Op->Mem.ShiftAmount = ShiftAmount;
305 Op->Mem.Preindexed = Preindexed;
306 Op->Mem.Postindexed = Postindexed;
307 Op->Mem.Negative = Negative;
308 Op->Mem.Writeback = Writeback;
315 } // end anonymous namespace.
317 void ARMOperand::dump(raw_ostream &OS) const {
320 OS << ARMCondCodeToString(getCondCode());
329 OS << "<register " << getReg() << ">";
332 OS << "'" << getToken() << "'";
337 /// @name Auto-generated Match Functions
340 static unsigned MatchRegisterName(StringRef Name);
344 /// Try to parse a register name. The token must be an Identifier when called,
345 /// and if it is a register name a Reg operand is created, the token is eaten
346 /// and false is returned. Else true is returned and no token is eaten.
347 /// TODO this is likely to change to allow different register types and or to
348 /// parse for a specific register type.
349 bool ARMAsmParser::MaybeParseRegister
350 (OwningPtr<ARMOperand> &Op, bool ParseWriteBack) {
352 const AsmToken &Tok = Parser.getTok();
353 assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
355 // FIXME: Validate register for the current architecture; we have to do
356 // validation later, so maybe there is no need for this here.
359 RegNum = MatchRegisterName(Tok.getString());
365 Parser.Lex(); // Eat identifier token.
367 E = Parser.getTok().getLoc();
369 bool Writeback = false;
370 if (ParseWriteBack) {
371 const AsmToken &ExclaimTok = Parser.getTok();
372 if (ExclaimTok.is(AsmToken::Exclaim)) {
373 E = ExclaimTok.getLoc();
375 Parser.Lex(); // Eat exclaim token
379 ARMOperand::CreateReg(Op, RegNum, Writeback, S, E);
384 /// Parse a register list, return false if successful else return true or an
385 /// error. The first token must be a '{' when called.
386 bool ARMAsmParser::ParseRegisterList(OwningPtr<ARMOperand> &Op) {
388 assert(Parser.getTok().is(AsmToken::LCurly) &&
389 "Token is not an Left Curly Brace");
390 S = Parser.getTok().getLoc();
391 Parser.Lex(); // Eat left curly brace token.
393 const AsmToken &RegTok = Parser.getTok();
394 SMLoc RegLoc = RegTok.getLoc();
395 if (RegTok.isNot(AsmToken::Identifier))
396 return Error(RegLoc, "register expected");
397 int RegNum = MatchRegisterName(RegTok.getString());
399 return Error(RegLoc, "register expected");
400 Parser.Lex(); // Eat identifier token.
401 unsigned RegList = 1 << RegNum;
403 int HighRegNum = RegNum;
404 // TODO ranges like "{Rn-Rm}"
405 while (Parser.getTok().is(AsmToken::Comma)) {
406 Parser.Lex(); // Eat comma token.
408 const AsmToken &RegTok = Parser.getTok();
409 SMLoc RegLoc = RegTok.getLoc();
410 if (RegTok.isNot(AsmToken::Identifier))
411 return Error(RegLoc, "register expected");
412 int RegNum = MatchRegisterName(RegTok.getString());
414 return Error(RegLoc, "register expected");
416 if (RegList & (1 << RegNum))
417 Warning(RegLoc, "register duplicated in register list");
418 else if (RegNum <= HighRegNum)
419 Warning(RegLoc, "register not in ascending order in register list");
420 RegList |= 1 << RegNum;
423 Parser.Lex(); // Eat identifier token.
425 const AsmToken &RCurlyTok = Parser.getTok();
426 if (RCurlyTok.isNot(AsmToken::RCurly))
427 return Error(RCurlyTok.getLoc(), "'}' expected");
428 E = RCurlyTok.getLoc();
429 Parser.Lex(); // Eat left curly brace token.
434 /// Parse an arm memory expression, return false if successful else return true
435 /// or an error. The first token must be a '[' when called.
436 /// TODO Only preindexing and postindexing addressing are started, unindexed
437 /// with option, etc are still to do.
438 bool ARMAsmParser::ParseMemory(OwningPtr<ARMOperand> &Op) {
440 assert(Parser.getTok().is(AsmToken::LBrac) &&
441 "Token is not an Left Bracket");
442 S = Parser.getTok().getLoc();
443 Parser.Lex(); // Eat left bracket token.
445 const AsmToken &BaseRegTok = Parser.getTok();
446 if (BaseRegTok.isNot(AsmToken::Identifier))
447 return Error(BaseRegTok.getLoc(), "register expected");
448 if (MaybeParseRegister(Op, false))
449 return Error(BaseRegTok.getLoc(), "register expected");
450 int BaseRegNum = Op->getReg();
452 bool Preindexed = false;
453 bool Postindexed = false;
454 bool OffsetIsReg = false;
455 bool Negative = false;
456 bool Writeback = false;
458 // First look for preindexed address forms, that is after the "[Rn" we now
459 // have to see if the next token is a comma.
460 const AsmToken &Tok = Parser.getTok();
461 if (Tok.is(AsmToken::Comma)) {
463 Parser.Lex(); // Eat comma token.
465 bool OffsetRegShifted;
466 enum ShiftType ShiftType;
467 const MCExpr *ShiftAmount;
468 const MCExpr *Offset;
469 if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount,
470 Offset, OffsetIsReg, OffsetRegNum, E))
472 const AsmToken &RBracTok = Parser.getTok();
473 if (RBracTok.isNot(AsmToken::RBrac))
474 return Error(RBracTok.getLoc(), "']' expected");
475 E = RBracTok.getLoc();
476 Parser.Lex(); // Eat right bracket token.
478 const AsmToken &ExclaimTok = Parser.getTok();
479 if (ExclaimTok.is(AsmToken::Exclaim)) {
480 E = ExclaimTok.getLoc();
482 Parser.Lex(); // Eat exclaim token
484 ARMOperand::CreateMem(Op, BaseRegNum, OffsetIsReg, Offset, OffsetRegNum,
485 OffsetRegShifted, ShiftType, ShiftAmount,
486 Preindexed, Postindexed, Negative, Writeback, S, E);
489 // The "[Rn" we have so far was not followed by a comma.
490 else if (Tok.is(AsmToken::RBrac)) {
491 // This is a post indexing addressing forms, that is a ']' follows after
496 Parser.Lex(); // Eat right bracket token.
498 int OffsetRegNum = 0;
499 bool OffsetRegShifted = false;
500 enum ShiftType ShiftType;
501 const MCExpr *ShiftAmount;
502 const MCExpr *Offset;
504 const AsmToken &NextTok = Parser.getTok();
505 if (NextTok.isNot(AsmToken::EndOfStatement)) {
506 if (NextTok.isNot(AsmToken::Comma))
507 return Error(NextTok.getLoc(), "',' expected");
508 Parser.Lex(); // Eat comma token.
509 if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType,
510 ShiftAmount, Offset, OffsetIsReg, OffsetRegNum,
515 ARMOperand::CreateMem(Op, BaseRegNum, OffsetIsReg, Offset, OffsetRegNum,
516 OffsetRegShifted, ShiftType, ShiftAmount,
517 Preindexed, Postindexed, Negative, Writeback, S, E);
524 /// Parse the offset of a memory operand after we have seen "[Rn," or "[Rn],"
525 /// we will parse the following (were +/- means that a plus or minus is
530 /// we return false on success or an error otherwise.
531 bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative,
532 bool &OffsetRegShifted,
533 enum ShiftType &ShiftType,
534 const MCExpr *&ShiftAmount,
535 const MCExpr *&Offset,
539 OwningPtr<ARMOperand> Op;
541 OffsetRegShifted = false;
544 const AsmToken &NextTok = Parser.getTok();
545 E = NextTok.getLoc();
546 if (NextTok.is(AsmToken::Plus))
547 Parser.Lex(); // Eat plus token.
548 else if (NextTok.is(AsmToken::Minus)) {
550 Parser.Lex(); // Eat minus token
552 // See if there is a register following the "[Rn," or "[Rn]," we have so far.
553 const AsmToken &OffsetRegTok = Parser.getTok();
554 if (OffsetRegTok.is(AsmToken::Identifier)) {
555 OffsetIsReg = !MaybeParseRegister(Op, false);
558 OffsetRegNum = Op->getReg();
561 // If we parsed a register as the offset then their can be a shift after that
562 if (OffsetRegNum != -1) {
563 // Look for a comma then a shift
564 const AsmToken &Tok = Parser.getTok();
565 if (Tok.is(AsmToken::Comma)) {
566 Parser.Lex(); // Eat comma token.
568 const AsmToken &Tok = Parser.getTok();
569 if (ParseShift(ShiftType, ShiftAmount, E))
570 return Error(Tok.getLoc(), "shift expected");
571 OffsetRegShifted = true;
574 else { // the "[Rn," or "[Rn,]" we have so far was not followed by "Rm"
575 // Look for #offset following the "[Rn," or "[Rn],"
576 const AsmToken &HashTok = Parser.getTok();
577 if (HashTok.isNot(AsmToken::Hash))
578 return Error(HashTok.getLoc(), "'#' expected");
580 Parser.Lex(); // Eat hash token.
582 if (getParser().ParseExpression(Offset))
584 E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
589 /// ParseShift as one of these two:
590 /// ( lsl | lsr | asr | ror ) , # shift_amount
592 /// and returns true if it parses a shift otherwise it returns false.
593 bool ARMAsmParser::ParseShift(ShiftType &St,
594 const MCExpr *&ShiftAmount,
596 const AsmToken &Tok = Parser.getTok();
597 if (Tok.isNot(AsmToken::Identifier))
599 StringRef ShiftName = Tok.getString();
600 if (ShiftName == "lsl" || ShiftName == "LSL")
602 else if (ShiftName == "lsr" || ShiftName == "LSR")
604 else if (ShiftName == "asr" || ShiftName == "ASR")
606 else if (ShiftName == "ror" || ShiftName == "ROR")
608 else if (ShiftName == "rrx" || ShiftName == "RRX")
612 Parser.Lex(); // Eat shift type token.
618 // Otherwise, there must be a '#' and a shift amount.
619 const AsmToken &HashTok = Parser.getTok();
620 if (HashTok.isNot(AsmToken::Hash))
621 return Error(HashTok.getLoc(), "'#' expected");
622 Parser.Lex(); // Eat hash token.
624 if (getParser().ParseExpression(ShiftAmount))
630 /// Parse a arm instruction operand. For now this parses the operand regardless
632 bool ARMAsmParser::ParseOperand(OwningPtr<ARMOperand> &Op) {
635 switch (getLexer().getKind()) {
636 case AsmToken::Identifier:
637 if (!MaybeParseRegister(Op, true))
639 // This was not a register so parse other operands that start with an
640 // identifier (like labels) as expressions and create them as immediates.
642 S = Parser.getTok().getLoc();
643 if (getParser().ParseExpression(IdVal))
645 E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
646 ARMOperand::CreateImm(Op, IdVal, S, E);
648 case AsmToken::LBrac:
649 return ParseMemory(Op);
650 case AsmToken::LCurly:
651 return ParseRegisterList(Op);
654 // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate
655 S = Parser.getTok().getLoc();
657 const MCExpr *ImmVal;
658 if (getParser().ParseExpression(ImmVal))
660 E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
661 ARMOperand::CreateImm(Op, ImmVal, S, E);
664 return Error(Parser.getTok().getLoc(), "unexpected token in operand");
668 /// Parse an arm instruction mnemonic followed by its operands.
669 bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
670 SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
671 OwningPtr<ARMOperand> Op;
673 // Create the leading tokens for the mnemonic, split by '.' characters.
674 size_t Start = 0, Next = Name.find('.');
675 StringRef Head = Name.slice(Start, Next);
677 // Determine the predicate, if any.
679 // FIXME: We need a way to check whether a prefix supports predication,
680 // otherwise we will end up with an ambiguity for instructions that happen to
681 // end with a predicate name.
682 unsigned CC = StringSwitch<unsigned>(Head.substr(Head.size()-2))
683 .Case("eq", ARMCC::EQ)
684 .Case("ne", ARMCC::NE)
685 .Case("hs", ARMCC::HS)
686 .Case("lo", ARMCC::LO)
687 .Case("mi", ARMCC::MI)
688 .Case("pl", ARMCC::PL)
689 .Case("vs", ARMCC::VS)
690 .Case("vc", ARMCC::VC)
691 .Case("hi", ARMCC::HI)
692 .Case("ls", ARMCC::LS)
693 .Case("ge", ARMCC::GE)
694 .Case("lt", ARMCC::LT)
695 .Case("gt", ARMCC::GT)
696 .Case("le", ARMCC::LE)
697 .Case("al", ARMCC::AL)
700 Head = Head.slice(0, Head.size() - 2);
704 ARMOperand::CreateToken(Op, Head, NameLoc);
705 Operands.push_back(Op.take());
707 ARMOperand::CreateCondCode(Op, ARMCC::CondCodes(CC), NameLoc);
708 Operands.push_back(Op.take());
710 // Add the remaining tokens in the mnemonic.
711 while (Next != StringRef::npos) {
713 Next = Name.find('.', Start + 1);
714 Head = Name.slice(Start, Next);
716 ARMOperand::CreateToken(Op, Head, NameLoc);
717 Operands.push_back(Op.take());
720 // Read the remaining operands.
721 if (getLexer().isNot(AsmToken::EndOfStatement)) {
722 // Read the first operand.
723 OwningPtr<ARMOperand> Op;
724 if (ParseOperand(Op)) return true;
725 Operands.push_back(Op.take());
727 while (getLexer().is(AsmToken::Comma)) {
728 Parser.Lex(); // Eat the comma.
730 // Parse and remember the operand.
731 if (ParseOperand(Op)) return true;
732 Operands.push_back(Op.take());
738 /// ParseDirective parses the arm specific directives
739 bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
740 StringRef IDVal = DirectiveID.getIdentifier();
741 if (IDVal == ".word")
742 return ParseDirectiveWord(4, DirectiveID.getLoc());
743 else if (IDVal == ".thumb")
744 return ParseDirectiveThumb(DirectiveID.getLoc());
745 else if (IDVal == ".thumb_func")
746 return ParseDirectiveThumbFunc(DirectiveID.getLoc());
747 else if (IDVal == ".code")
748 return ParseDirectiveCode(DirectiveID.getLoc());
749 else if (IDVal == ".syntax")
750 return ParseDirectiveSyntax(DirectiveID.getLoc());
754 /// ParseDirectiveWord
755 /// ::= .word [ expression (, expression)* ]
756 bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
757 if (getLexer().isNot(AsmToken::EndOfStatement)) {
760 if (getParser().ParseExpression(Value))
763 getParser().getStreamer().EmitValue(Value, Size, 0/*addrspace*/);
765 if (getLexer().is(AsmToken::EndOfStatement))
768 // FIXME: Improve diagnostic.
769 if (getLexer().isNot(AsmToken::Comma))
770 return Error(L, "unexpected token in directive");
779 /// ParseDirectiveThumb
781 bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) {
782 if (getLexer().isNot(AsmToken::EndOfStatement))
783 return Error(L, "unexpected token in directive");
786 // TODO: set thumb mode
787 // TODO: tell the MC streamer the mode
788 // getParser().getStreamer().Emit???();
792 /// ParseDirectiveThumbFunc
793 /// ::= .thumbfunc symbol_name
794 bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) {
795 const AsmToken &Tok = Parser.getTok();
796 if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String))
797 return Error(L, "unexpected token in .syntax directive");
798 StringRef ATTRIBUTE_UNUSED SymbolName = Parser.getTok().getIdentifier();
799 Parser.Lex(); // Consume the identifier token.
801 if (getLexer().isNot(AsmToken::EndOfStatement))
802 return Error(L, "unexpected token in directive");
805 // TODO: mark symbol as a thumb symbol
806 // getParser().getStreamer().Emit???();
810 /// ParseDirectiveSyntax
811 /// ::= .syntax unified | divided
812 bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) {
813 const AsmToken &Tok = Parser.getTok();
814 if (Tok.isNot(AsmToken::Identifier))
815 return Error(L, "unexpected token in .syntax directive");
816 StringRef Mode = Tok.getString();
817 if (Mode == "unified" || Mode == "UNIFIED")
819 else if (Mode == "divided" || Mode == "DIVIDED")
822 return Error(L, "unrecognized syntax mode in .syntax directive");
824 if (getLexer().isNot(AsmToken::EndOfStatement))
825 return Error(Parser.getTok().getLoc(), "unexpected token in directive");
828 // TODO tell the MC streamer the mode
829 // getParser().getStreamer().Emit???();
833 /// ParseDirectiveCode
834 /// ::= .code 16 | 32
835 bool ARMAsmParser::ParseDirectiveCode(SMLoc L) {
836 const AsmToken &Tok = Parser.getTok();
837 if (Tok.isNot(AsmToken::Integer))
838 return Error(L, "unexpected token in .code directive");
839 int64_t Val = Parser.getTok().getIntVal();
845 return Error(L, "invalid operand to .code directive");
847 if (getLexer().isNot(AsmToken::EndOfStatement))
848 return Error(Parser.getTok().getLoc(), "unexpected token in directive");
851 // TODO tell the MC streamer the mode
852 // getParser().getStreamer().Emit???();
856 extern "C" void LLVMInitializeARMAsmLexer();
858 /// Force static initialization.
859 extern "C" void LLVMInitializeARMAsmParser() {
860 RegisterAsmParser<ARMAsmParser> X(TheARMTarget);
861 RegisterAsmParser<ARMAsmParser> Y(TheThumbTarget);
862 LLVMInitializeARMAsmLexer();
865 #include "ARMGenAsmMatcher.inc"