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, 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: 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 92 void addImmOperands(MCInst &Inst, unsigned N) const { 93 Inst.addOperand(MCOperand::CreateImm(getImm())); 94 } 95 void addRegOperands(MCInst &Inst, unsigned N) const { 96 llvm_unreachable("addRegOperands"); 97 } 98 StringRef getToken() const { 99 return StringRef(Tok.Data, Tok.Length); 100 } 101 bool isToken() const override { 102 return Kind == Token; 103 } 104 105 bool isImm() const override { 106 return Kind == Immediate; 107 } 108 109 int64_t getImm() const { 110 return Imm.Val; 111 } 112 113 bool isReg() const override { 114 return false; 115 } 116 117 unsigned getReg() const override { 118 return 0; 119 } 120 121 bool isMem() const override { 122 return false; 123 } 124 125 SMLoc getStartLoc() const override { 126 return SMLoc(); 127 } 128 129 SMLoc getEndLoc() const override { 130 return SMLoc(); 131 } 132 133 void print(raw_ostream &OS) const override { } 134 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 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 153 bool AMDGPUAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { 154 return true; 155 } 156 157 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 186 bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) { 187 return true; 188 } 189 190 AMDGPUAsmParser::OperandMatchResultTy 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 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 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 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 307 bool AMDGPUOperand::isSWaitCnt() const { 308 return isImm(); 309 } 310 311 /// Force static initialization. 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