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