49f0f23a6c91e4a736fe5b51a7144a66d3a546d1
[oota-llvm.git] / lib / Target / R600 / AsmParser / AMDGPUAsmParser.cpp
1 //===-- AMDGPUAsmParser.cpp - Parse SI 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/AMDGPUMCTargetDesc.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/ADT/Twine.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCExpr.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstrInfo.h"
20 #include "llvm/MC/MCParser/MCAsmLexer.h"
21 #include "llvm/MC/MCParser/MCAsmParser.h"
22 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
23 #include "llvm/MC/MCRegisterInfo.h"
24 #include "llvm/MC/MCStreamer.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/MC/MCTargetAsmParser.h"
27 #include "llvm/Support/SourceMgr.h"
28 #include "llvm/Support/TargetRegistry.h"
29 #include "llvm/Support/raw_ostream.h"
30
31 using namespace llvm;
32
33 namespace {
34
35 class AMDGPUAsmParser : public MCTargetAsmParser {
36   MCSubtargetInfo &STI;
37   MCAsmParser &Parser;
38
39
40   /// @name Auto-generated Match Functions
41   /// {
42
43 #define GET_ASSEMBLER_HEADER
44 #include "AMDGPUGenAsmMatcher.inc"
45
46   /// }
47
48 public:
49   AMDGPUAsmParser(MCSubtargetInfo &STI, MCAsmParser &Parser,
50                   const MCInstrInfo &MII, const MCTargetOptions &Options)
51       : MCTargetAsmParser(), STI(STI), Parser(Parser) {
52     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
53   }
54   bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
55   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
56                                OperandVector &Operands, MCStreamer &Out,
57                                uint64_t &ErrorInfo,
58                                bool MatchingInlineAsm) override;
59   bool ParseDirective(AsmToken DirectiveID) override;
60   OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Mnemonic);
61   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
62                         SMLoc NameLoc, OperandVector &Operands) override;
63
64   bool parseCnt(int64_t &IntVal);
65   OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands);
66 };
67
68 class AMDGPUOperand : public MCParsedAsmOperand {
69   enum KindTy {
70     Token,
71     Immediate
72   } Kind;
73
74 public:
75   AMDGPUOperand(enum KindTy K) : MCParsedAsmOperand(), Kind(K) {}
76
77   struct TokOp {
78     const char *Data;
79     unsigned Length;
80   };
81
82   struct ImmOp {
83     int64_t Val;
84   };
85
86   union {
87     TokOp Tok;
88     ImmOp Imm;
89   };
90
91   void addImmOperands(MCInst &Inst, unsigned N) const {
92     Inst.addOperand(MCOperand::CreateImm(getImm()));
93   }
94   void addRegOperands(MCInst &Inst, unsigned N) const {
95     llvm_unreachable("addRegOperands");
96   }
97   StringRef getToken() const {
98     return StringRef(Tok.Data, Tok.Length);
99   }
100   bool isToken() const override {
101     return Kind == Token;
102   }
103
104   bool isImm() const override {
105     return Kind == Immediate;
106   }
107
108   int64_t getImm() const {
109     return Imm.Val;
110   }
111
112   bool isReg() const override {
113     return false;
114   }
115
116   unsigned getReg() const override {
117     return 0;
118   }
119
120   bool isMem() const override {
121     return false;
122   }
123
124   SMLoc getStartLoc() const override {
125     return SMLoc();
126   }
127
128   SMLoc getEndLoc() const override {
129     return SMLoc();
130   }
131
132   void print(raw_ostream &OS) const override { }
133
134   static std::unique_ptr<AMDGPUOperand> CreateImm(int64_t Val) {
135     auto Op = llvm::make_unique<AMDGPUOperand>(Immediate);
136     Op->Imm.Val = Val;
137     return Op;
138   }
139
140   static std::unique_ptr<AMDGPUOperand> CreateToken(StringRef Str, SMLoc Loc) {
141     auto Res = llvm::make_unique<AMDGPUOperand>(Token);
142     Res->Tok.Data = Str.data();
143     Res->Tok.Length = Str.size();
144     return Res;
145   }
146
147   bool isSWaitCnt() const;
148 };
149
150 }
151
152 bool AMDGPUAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) {
153   return true;
154 }
155
156
157 bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
158                                               OperandVector &Operands,
159                                               MCStreamer &Out,
160                                               uint64_t &ErrorInfo,
161                                               bool MatchingInlineAsm) {
162   MCInst Inst;
163
164   switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
165   case Match_Success:
166     Inst.setLoc(IDLoc);
167     Out.EmitInstruction(Inst, STI);
168     return false;
169   case Match_MissingFeature:
170     return Error(IDLoc, "instruction use requires an option to be enabled");
171   case Match_MnemonicFail:
172     return Error(IDLoc, "unrecognized instruction mnemonic");
173   case Match_InvalidOperand: {
174     if (ErrorInfo != ~0ULL) {
175       if (ErrorInfo >= Operands.size())
176         return Error(IDLoc, "too few operands for instruction");
177
178     }
179     return Error(IDLoc, "invalid operand for instruction");
180   }
181   }
182   llvm_unreachable("Implement any new match types added!");
183 }
184
185 bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) {
186   return true;
187 }
188
189 AMDGPUAsmParser::OperandMatchResultTy
190 AMDGPUAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
191
192   // Try to parse with a custom parser
193   OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
194
195   // If we successfully parsed the operand or if there as an error parsing,
196   // we are done.
197   if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail)
198     return ResTy;
199
200   switch(getLexer().getKind()) {
201     case AsmToken::Integer: {
202       int64_t IntVal;
203       if (getParser().parseAbsoluteExpression(IntVal))
204         return MatchOperand_ParseFail;
205       Operands.push_back(AMDGPUOperand::CreateImm(IntVal));
206       return MatchOperand_Success;
207     }
208     default:
209       return MatchOperand_NoMatch;
210   }
211 }
212
213 bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info,
214                                        StringRef Name,
215                                        SMLoc NameLoc, OperandVector &Operands) {
216   // Add the instruction mnemonic
217   Operands.push_back(AMDGPUOperand::CreateToken(Name, NameLoc));
218
219   if (getLexer().is(AsmToken::EndOfStatement))
220     return false;
221
222   AMDGPUAsmParser::OperandMatchResultTy Res = parseOperand(Operands, Name);
223   switch (Res) {
224     case MatchOperand_Success: return false;
225     case MatchOperand_ParseFail: return Error(NameLoc,
226                                               "Failed parsing operand");
227     case MatchOperand_NoMatch: return Error(NameLoc, "Not a valid operand");
228   }
229   return true;
230 }
231
232 //===----------------------------------------------------------------------===//
233 // s_waitcnt
234 //===----------------------------------------------------------------------===//
235
236 bool AMDGPUAsmParser::parseCnt(int64_t &IntVal) {
237   StringRef CntName = Parser.getTok().getString();
238   int64_t CntVal;
239
240   Parser.Lex();
241   if (getLexer().isNot(AsmToken::LParen))
242     return true;
243
244   Parser.Lex();
245   if (getLexer().isNot(AsmToken::Integer))
246     return true;
247
248   if (getParser().parseAbsoluteExpression(CntVal))
249     return true;
250
251   if (getLexer().isNot(AsmToken::RParen))
252     return true;
253
254   Parser.Lex();
255   if (getLexer().is(AsmToken::Amp) || getLexer().is(AsmToken::Comma))
256     Parser.Lex();
257
258   int CntShift;
259   int CntMask;
260
261   if (CntName == "vmcnt") {
262     CntMask = 0xf;
263     CntShift = 0;
264   } else if (CntName == "expcnt") {
265     CntMask = 0x7;
266     CntShift = 4;
267   } else if (CntName == "lgkmcnt") {
268     CntMask = 0x7;
269     CntShift = 8;
270   } else {
271     return true;
272   }
273
274   IntVal &= ~(CntMask << CntShift);
275   IntVal |= (CntVal << CntShift);
276   return false;
277 }
278
279 AMDGPUAsmParser::OperandMatchResultTy
280 AMDGPUAsmParser::parseSWaitCntOps(OperandVector &Operands) {
281   // Disable all counters by default.
282   // vmcnt   [3:0]
283   // expcnt  [6:4]
284   // lgkmcnt [10:8]
285   int64_t CntVal = 0x77f;
286
287   switch(getLexer().getKind()) {
288     default: return MatchOperand_ParseFail;
289     case AsmToken::Integer:
290       // The operand can be an integer value.
291       if (getParser().parseAbsoluteExpression(CntVal))
292         return MatchOperand_ParseFail;
293       break;
294
295     case AsmToken::Identifier:
296       do {
297         if (parseCnt(CntVal))
298           return MatchOperand_ParseFail;
299       } while(getLexer().isNot(AsmToken::EndOfStatement));
300       break;
301   }
302   Operands.push_back(AMDGPUOperand::CreateImm(CntVal));
303   return MatchOperand_Success;
304 }
305
306 bool AMDGPUOperand::isSWaitCnt() const {
307   return isImm();
308 }
309
310 /// Force static initialization.
311 extern "C" void LLVMInitializeR600AsmParser() {
312   RegisterMCAsmParser<AMDGPUAsmParser> A(TheAMDGPUTarget);
313   RegisterMCAsmParser<AMDGPUAsmParser> B(TheGCNTarget);
314 }
315
316 #define GET_REGISTER_MATCHER
317 #define GET_MATCHER_IMPLEMENTATION
318 #include "AMDGPUGenAsmMatcher.inc"
319