1//===-- MBlazeAsmParser.cpp - Parse MBlaze asm 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 "MCTargetDesc/MBlazeBaseInfo.h"
11#include "llvm/MC/MCParser/MCAsmLexer.h"
12#include "llvm/MC/MCParser/MCAsmParser.h"
13#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
14#include "llvm/MC/MCStreamer.h"
15#include "llvm/MC/MCExpr.h"
16#include "llvm/MC/MCInst.h"
17#include "llvm/MC/MCTargetAsmParser.h"
18#include "llvm/Support/SourceMgr.h"
19#include "llvm/Support/TargetRegistry.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/Twine.h"
23using namespace llvm;
24
25namespace {
26struct MBlazeOperand;
27
28class MBlazeAsmParser : public MCTargetAsmParser {
29  MCAsmParser &Parser;
30
31  MCAsmParser &getParser() const { return Parser; }
32  MCAsmLexer &getLexer() const { return Parser.getLexer(); }
33
34  void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); }
35  bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
36
37  MBlazeOperand *ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
38  MBlazeOperand *ParseRegister(unsigned &RegNo);
39  MBlazeOperand *ParseImmediate();
40  MBlazeOperand *ParseFsl();
41  MBlazeOperand* ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
42
43  virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
44
45  bool ParseDirectiveWord(unsigned Size, SMLoc L);
46
47  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
48                               SmallVectorImpl<MCParsedAsmOperand*> &Operands,
49                               MCStreamer &Out, unsigned &ErrorInfo,
50                               bool MatchingInlineAsm);
51
52  /// @name Auto-generated Match Functions
53  /// {
54
55#define GET_ASSEMBLER_HEADER
56#include "MBlazeGenAsmMatcher.inc"
57
58  /// }
59
60public:
61  MBlazeAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser)
62    : MCTargetAsmParser(), Parser(_Parser) {}
63
64  virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
65                                SMLoc NameLoc,
66                                SmallVectorImpl<MCParsedAsmOperand*> &Operands);
67
68  virtual bool ParseDirective(AsmToken DirectiveID);
69};
70
71/// MBlazeOperand - Instances of this class represent a parsed MBlaze machine
72/// instruction.
73struct MBlazeOperand : public MCParsedAsmOperand {
74  enum KindTy {
75    Token,
76    Immediate,
77    Register,
78    Memory,
79    Fsl
80  } Kind;
81
82  SMLoc StartLoc, EndLoc;
83
84  union {
85    struct {
86      const char *Data;
87      unsigned Length;
88    } Tok;
89
90    struct {
91      unsigned RegNum;
92    } Reg;
93
94    struct {
95      const MCExpr *Val;
96    } Imm;
97
98    struct {
99      unsigned Base;
100      unsigned OffReg;
101      const MCExpr *Off;
102    } Mem;
103
104    struct {
105      const MCExpr *Val;
106    } FslImm;
107  };
108
109  MBlazeOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
110public:
111  MBlazeOperand(const MBlazeOperand &o) : MCParsedAsmOperand() {
112    Kind = o.Kind;
113    StartLoc = o.StartLoc;
114    EndLoc = o.EndLoc;
115    switch (Kind) {
116    case Register:
117      Reg = o.Reg;
118      break;
119    case Immediate:
120      Imm = o.Imm;
121      break;
122    case Token:
123      Tok = o.Tok;
124      break;
125    case Memory:
126      Mem = o.Mem;
127      break;
128    case Fsl:
129      FslImm = o.FslImm;
130      break;
131    }
132  }
133
134  /// getStartLoc - Get the location of the first token of this operand.
135  SMLoc getStartLoc() const { return StartLoc; }
136
137  /// getEndLoc - Get the location of the last token of this operand.
138  SMLoc getEndLoc() const { return EndLoc; }
139
140  unsigned getReg() const {
141    assert(Kind == Register && "Invalid access!");
142    return Reg.RegNum;
143  }
144
145  const MCExpr *getImm() const {
146    assert(Kind == Immediate && "Invalid access!");
147    return Imm.Val;
148  }
149
150  const MCExpr *getFslImm() const {
151    assert(Kind == Fsl && "Invalid access!");
152    return FslImm.Val;
153  }
154
155  unsigned getMemBase() const {
156    assert(Kind == Memory && "Invalid access!");
157    return Mem.Base;
158  }
159
160  const MCExpr* getMemOff() const {
161    assert(Kind == Memory && "Invalid access!");
162    return Mem.Off;
163  }
164
165  unsigned getMemOffReg() const {
166    assert(Kind == Memory && "Invalid access!");
167    return Mem.OffReg;
168  }
169
170  bool isToken() const { return Kind == Token; }
171  bool isImm() const { return Kind == Immediate; }
172  bool isMem() const { return Kind == Memory; }
173  bool isFsl() const { return Kind == Fsl; }
174  bool isReg() const { return Kind == Register; }
175
176  void addExpr(MCInst &Inst, const MCExpr *Expr) const {
177    // Add as immediates when possible.  Null MCExpr = 0.
178    if (Expr == 0)
179      Inst.addOperand(MCOperand::CreateImm(0));
180    else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
181      Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
182    else
183      Inst.addOperand(MCOperand::CreateExpr(Expr));
184  }
185
186  void addRegOperands(MCInst &Inst, unsigned N) const {
187    assert(N == 1 && "Invalid number of operands!");
188    Inst.addOperand(MCOperand::CreateReg(getReg()));
189  }
190
191  void addImmOperands(MCInst &Inst, unsigned N) const {
192    assert(N == 1 && "Invalid number of operands!");
193    addExpr(Inst, getImm());
194  }
195
196  void addFslOperands(MCInst &Inst, unsigned N) const {
197    assert(N == 1 && "Invalid number of operands!");
198    addExpr(Inst, getFslImm());
199  }
200
201  void addMemOperands(MCInst &Inst, unsigned N) const {
202    assert(N == 2 && "Invalid number of operands!");
203
204    Inst.addOperand(MCOperand::CreateReg(getMemBase()));
205
206    unsigned RegOff = getMemOffReg();
207    if (RegOff)
208      Inst.addOperand(MCOperand::CreateReg(RegOff));
209    else
210      addExpr(Inst, getMemOff());
211  }
212
213  StringRef getToken() const {
214    assert(Kind == Token && "Invalid access!");
215    return StringRef(Tok.Data, Tok.Length);
216  }
217
218  virtual void print(raw_ostream &OS) const;
219
220  static MBlazeOperand *CreateToken(StringRef Str, SMLoc S) {
221    MBlazeOperand *Op = new MBlazeOperand(Token);
222    Op->Tok.Data = Str.data();
223    Op->Tok.Length = Str.size();
224    Op->StartLoc = S;
225    Op->EndLoc = S;
226    return Op;
227  }
228
229  static MBlazeOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) {
230    MBlazeOperand *Op = new MBlazeOperand(Register);
231    Op->Reg.RegNum = RegNum;
232    Op->StartLoc = S;
233    Op->EndLoc = E;
234    return Op;
235  }
236
237  static MBlazeOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
238    MBlazeOperand *Op = new MBlazeOperand(Immediate);
239    Op->Imm.Val = Val;
240    Op->StartLoc = S;
241    Op->EndLoc = E;
242    return Op;
243  }
244
245  static MBlazeOperand *CreateFslImm(const MCExpr *Val, SMLoc S, SMLoc E) {
246    MBlazeOperand *Op = new MBlazeOperand(Fsl);
247    Op->Imm.Val = Val;
248    Op->StartLoc = S;
249    Op->EndLoc = E;
250    return Op;
251  }
252
253  static MBlazeOperand *CreateMem(unsigned Base, const MCExpr *Off, SMLoc S,
254                                  SMLoc E) {
255    MBlazeOperand *Op = new MBlazeOperand(Memory);
256    Op->Mem.Base = Base;
257    Op->Mem.Off = Off;
258    Op->Mem.OffReg = 0;
259    Op->StartLoc = S;
260    Op->EndLoc = E;
261    return Op;
262  }
263
264  static MBlazeOperand *CreateMem(unsigned Base, unsigned Off, SMLoc S,
265                                  SMLoc E) {
266    MBlazeOperand *Op = new MBlazeOperand(Memory);
267    Op->Mem.Base = Base;
268    Op->Mem.OffReg = Off;
269    Op->Mem.Off = 0;
270    Op->StartLoc = S;
271    Op->EndLoc = E;
272    return Op;
273  }
274};
275
276} // end anonymous namespace.
277
278void MBlazeOperand::print(raw_ostream &OS) const {
279  switch (Kind) {
280  case Immediate:
281    getImm()->print(OS);
282    break;
283  case Register:
284    OS << "<register R";
285    OS << getMBlazeRegisterNumbering(getReg()) << ">";
286    break;
287  case Token:
288    OS << "'" << getToken() << "'";
289    break;
290  case Memory: {
291    OS << "<memory R";
292    OS << getMBlazeRegisterNumbering(getMemBase());
293    OS << ", ";
294
295    unsigned RegOff = getMemOffReg();
296    if (RegOff)
297      OS << "R" << getMBlazeRegisterNumbering(RegOff);
298    else
299      OS << getMemOff();
300    OS << ">";
301    }
302    break;
303  case Fsl:
304    getFslImm()->print(OS);
305    break;
306  }
307}
308
309/// @name Auto-generated Match Functions
310/// {
311
312static unsigned MatchRegisterName(StringRef Name);
313
314/// }
315//
316bool MBlazeAsmParser::
317MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
318                        SmallVectorImpl<MCParsedAsmOperand*> &Operands,
319                        MCStreamer &Out, unsigned &ErrorInfo,
320                        bool MatchingInlineAsm) {
321  MCInst Inst;
322  switch (MatchInstructionImpl(Operands, Inst, ErrorInfo,
323                               MatchingInlineAsm)) {
324  default: break;
325  case Match_Success:
326    Out.EmitInstruction(Inst);
327    return false;
328  case Match_MissingFeature:
329    return Error(IDLoc, "instruction use requires an option to be enabled");
330  case Match_MnemonicFail:
331      return Error(IDLoc, "unrecognized instruction mnemonic");
332  case Match_InvalidOperand: {
333    SMLoc ErrorLoc = IDLoc;
334    if (ErrorInfo != ~0U) {
335      if (ErrorInfo >= Operands.size())
336        return Error(IDLoc, "too few operands for instruction");
337
338      ErrorLoc = ((MBlazeOperand*)Operands[ErrorInfo])->getStartLoc();
339      if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
340    }
341
342    return Error(ErrorLoc, "invalid operand for instruction");
343  }
344  }
345
346  llvm_unreachable("Implement any new match types added!");
347}
348
349MBlazeOperand *MBlazeAsmParser::
350ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
351  if (Operands.size() != 4)
352    return 0;
353
354  MBlazeOperand &Base = *(MBlazeOperand*)Operands[2];
355  MBlazeOperand &Offset = *(MBlazeOperand*)Operands[3];
356
357  SMLoc S = Base.getStartLoc();
358  SMLoc O = Offset.getStartLoc();
359  SMLoc E = Offset.getEndLoc();
360
361  if (!Base.isReg()) {
362    Error(S, "base address must be a register");
363    return 0;
364  }
365
366  if (!Offset.isReg() && !Offset.isImm()) {
367    Error(O, "offset must be a register or immediate");
368    return 0;
369  }
370
371  MBlazeOperand *Op;
372  if (Offset.isReg())
373    Op = MBlazeOperand::CreateMem(Base.getReg(), Offset.getReg(), S, E);
374  else
375    Op = MBlazeOperand::CreateMem(Base.getReg(), Offset.getImm(), S, E);
376
377  delete Operands.pop_back_val();
378  delete Operands.pop_back_val();
379  Operands.push_back(Op);
380
381  return Op;
382}
383
384bool MBlazeAsmParser::ParseRegister(unsigned &RegNo,
385                                    SMLoc &StartLoc, SMLoc &EndLoc) {
386  return (ParseRegister(RegNo) == 0);
387}
388
389MBlazeOperand *MBlazeAsmParser::ParseRegister(unsigned &RegNo) {
390  SMLoc S = Parser.getTok().getLoc();
391  SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
392
393  switch (getLexer().getKind()) {
394  default: return 0;
395  case AsmToken::Identifier:
396    RegNo = MatchRegisterName(getLexer().getTok().getIdentifier());
397    if (RegNo == 0)
398      return 0;
399
400    getLexer().Lex();
401    return MBlazeOperand::CreateReg(RegNo, S, E);
402  }
403}
404
405static unsigned MatchFslRegister(StringRef String) {
406  if (!String.startswith("rfsl"))
407    return -1;
408
409  unsigned regNum;
410  if (String.substr(4).getAsInteger(10,regNum))
411    return -1;
412
413  return regNum;
414}
415
416MBlazeOperand *MBlazeAsmParser::ParseFsl() {
417  SMLoc S = Parser.getTok().getLoc();
418  SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
419
420  switch (getLexer().getKind()) {
421  default: return 0;
422  case AsmToken::Identifier:
423    unsigned reg = MatchFslRegister(getLexer().getTok().getIdentifier());
424    if (reg >= 16)
425      return 0;
426
427    getLexer().Lex();
428    const MCExpr *EVal = MCConstantExpr::Create(reg,getContext());
429    return MBlazeOperand::CreateFslImm(EVal,S,E);
430  }
431}
432
433MBlazeOperand *MBlazeAsmParser::ParseImmediate() {
434  SMLoc S = Parser.getTok().getLoc();
435  SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
436
437  const MCExpr *EVal;
438  switch (getLexer().getKind()) {
439  default: return 0;
440  case AsmToken::LParen:
441  case AsmToken::Plus:
442  case AsmToken::Minus:
443  case AsmToken::Integer:
444  case AsmToken::Identifier:
445    if (getParser().ParseExpression(EVal))
446      return 0;
447
448    return MBlazeOperand::CreateImm(EVal, S, E);
449  }
450}
451
452MBlazeOperand *MBlazeAsmParser::
453ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
454  MBlazeOperand *Op;
455
456  // Attempt to parse the next token as a register name
457  unsigned RegNo;
458  Op = ParseRegister(RegNo);
459
460  // Attempt to parse the next token as an FSL immediate
461  if (!Op)
462    Op = ParseFsl();
463
464  // Attempt to parse the next token as an immediate
465  if (!Op)
466    Op = ParseImmediate();
467
468  // If the token could not be parsed then fail
469  if (!Op) {
470    Error(Parser.getTok().getLoc(), "unknown operand");
471    return 0;
472  }
473
474  // Push the parsed operand into the list of operands
475  Operands.push_back(Op);
476  return Op;
477}
478
479/// Parse an mblaze instruction mnemonic followed by its operands.
480bool MBlazeAsmParser::
481ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc,
482                 SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
483  // The first operands is the token for the instruction name
484  size_t dotLoc = Name.find('.');
485  Operands.push_back(MBlazeOperand::CreateToken(Name.substr(0,dotLoc),NameLoc));
486  if (dotLoc < Name.size())
487    Operands.push_back(MBlazeOperand::CreateToken(Name.substr(dotLoc),NameLoc));
488
489  // If there are no more operands then finish
490  if (getLexer().is(AsmToken::EndOfStatement))
491    return false;
492
493  // Parse the first operand
494  if (!ParseOperand(Operands))
495    return true;
496
497  while (getLexer().isNot(AsmToken::EndOfStatement) &&
498         getLexer().is(AsmToken::Comma)) {
499    // Consume the comma token
500    getLexer().Lex();
501
502    // Parse the next operand
503    if (!ParseOperand(Operands))
504      return true;
505  }
506
507  // If the instruction requires a memory operand then we need to
508  // replace the last two operands (base+offset) with a single
509  // memory operand.
510  if (Name.startswith("lw") || Name.startswith("sw") ||
511      Name.startswith("lh") || Name.startswith("sh") ||
512      Name.startswith("lb") || Name.startswith("sb"))
513    return (ParseMemory(Operands) == NULL);
514
515  return false;
516}
517
518/// ParseDirective parses the MBlaze specific directives
519bool MBlazeAsmParser::ParseDirective(AsmToken DirectiveID) {
520  StringRef IDVal = DirectiveID.getIdentifier();
521  if (IDVal == ".word")
522    return ParseDirectiveWord(2, DirectiveID.getLoc());
523  return true;
524}
525
526/// ParseDirectiveWord
527///  ::= .word [ expression (, expression)* ]
528bool MBlazeAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
529  if (getLexer().isNot(AsmToken::EndOfStatement)) {
530    for (;;) {
531      const MCExpr *Value;
532      if (getParser().ParseExpression(Value))
533        return true;
534
535      getParser().getStreamer().EmitValue(Value, Size, 0 /*addrspace*/);
536
537      if (getLexer().is(AsmToken::EndOfStatement))
538        break;
539
540      // FIXME: Improve diagnostic.
541      if (getLexer().isNot(AsmToken::Comma))
542        return Error(L, "unexpected token in directive");
543      Parser.Lex();
544    }
545  }
546
547  Parser.Lex();
548  return false;
549}
550
551extern "C" void LLVMInitializeMBlazeAsmLexer();
552
553/// Force static initialization.
554extern "C" void LLVMInitializeMBlazeAsmParser() {
555  RegisterMCAsmParser<MBlazeAsmParser> X(TheMBlazeTarget);
556  LLVMInitializeMBlazeAsmLexer();
557}
558
559#define GET_REGISTER_MATCHER
560#define GET_MATCHER_IMPLEMENTATION
561#include "MBlazeGenAsmMatcher.inc"
562