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