1 // LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MCTargetDesc/LoongArchInstPrinter.h" 10 #include "MCTargetDesc/LoongArchMCTargetDesc.h" 11 #include "TargetInfo/LoongArchTargetInfo.h" 12 #include "llvm/MC/MCContext.h" 13 #include "llvm/MC/MCInstrInfo.h" 14 #include "llvm/MC/MCParser/MCAsmLexer.h" 15 #include "llvm/MC/MCParser/MCParsedAsmOperand.h" 16 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 17 #include "llvm/MC/MCStreamer.h" 18 #include "llvm/MC/MCSubtargetInfo.h" 19 #include "llvm/MC/TargetRegistry.h" 20 #include "llvm/Support/Casting.h" 21 22 using namespace llvm; 23 24 #define DEBUG_TYPE "loongarch-asm-parser" 25 26 namespace { 27 struct LoongArchOperand; 28 29 class LoongArchAsmParser : public MCTargetAsmParser { 30 SMLoc getLoc() const { return getParser().getTok().getLoc(); } 31 32 /// Parse a register as used in CFI directives. 33 bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; 34 OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, 35 SMLoc &EndLoc) override; 36 37 bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, 38 SMLoc NameLoc, OperandVector &Operands) override; 39 40 bool ParseDirective(AsmToken DirectiveID) override { return true; } 41 42 bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, 43 OperandVector &Operands, MCStreamer &Out, 44 uint64_t &ErrorInfo, 45 bool MatchingInlineAsm) override; 46 47 bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, 48 int64_t Lower, int64_t Upper, Twine Msg); 49 50 /// Helper for processing MC instructions that have been successfully matched 51 /// by MatchAndEmitInstruction. 52 bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, 53 MCStreamer &Out); 54 55 // Auto-generated instruction matching functions. 56 #define GET_ASSEMBLER_HEADER 57 #include "LoongArchGenAsmMatcher.inc" 58 59 OperandMatchResultTy parseRegister(OperandVector &Operands); 60 OperandMatchResultTy parseImmediate(OperandVector &Operands); 61 62 bool parseOperand(OperandVector &Operands, StringRef Mnemonic); 63 64 public: 65 enum LoongArchMatchResultTy { 66 Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, 67 #define GET_OPERAND_DIAGNOSTIC_TYPES 68 #include "LoongArchGenAsmMatcher.inc" 69 #undef GET_OPERAND_DIAGNOSTIC_TYPES 70 }; 71 72 LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, 73 const MCInstrInfo &MII, const MCTargetOptions &Options) 74 : MCTargetAsmParser(Options, STI, MII) { 75 Parser.addAliasForDirective(".half", ".2byte"); 76 Parser.addAliasForDirective(".hword", ".2byte"); 77 Parser.addAliasForDirective(".word", ".4byte"); 78 Parser.addAliasForDirective(".dword", ".8byte"); 79 80 // Initialize the set of available features. 81 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); 82 } 83 }; 84 85 /// LoongArchOperand - Instances of this class represent a parsed LoongArch 86 /// machine instruction. 87 class LoongArchOperand : public MCParsedAsmOperand { 88 enum class KindTy { 89 Token, 90 Register, 91 Immediate, 92 } Kind; 93 94 struct RegOp { 95 MCRegister RegNum; 96 }; 97 98 struct ImmOp { 99 const MCExpr *Val; 100 }; 101 102 SMLoc StartLoc, EndLoc; 103 union { 104 StringRef Tok; 105 struct RegOp Reg; 106 struct ImmOp Imm; 107 }; 108 109 public: 110 LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} 111 112 bool isToken() const override { return Kind == KindTy::Token; } 113 bool isReg() const override { return Kind == KindTy::Register; } 114 bool isImm() const override { return Kind == KindTy::Immediate; } 115 bool isMem() const override { return false; } 116 117 static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) { 118 if (auto CE = dyn_cast<MCConstantExpr>(Expr)) { 119 Imm = CE->getValue(); 120 return true; 121 } 122 123 return false; 124 } 125 126 template <unsigned N, int P = 0> bool isUImm() const { 127 if (!isImm()) 128 return false; 129 130 int64_t Imm; 131 bool IsConstantImm = evaluateConstantImm(getImm(), Imm); 132 return IsConstantImm && isUInt<N>(Imm - P); 133 } 134 135 template <unsigned N, unsigned S = 0> bool isSImm() const { 136 if (!isImm()) 137 return false; 138 139 int64_t Imm; 140 bool IsConstantImm = evaluateConstantImm(getImm(), Imm); 141 return IsConstantImm && isShiftedInt<N, S>(Imm); 142 } 143 144 bool isUImm2() const { return isUImm<2>(); } 145 bool isUImm2plus1() const { return isUImm<2, 1>(); } 146 bool isUImm3() const { return isUImm<3>(); } 147 bool isUImm5() const { return isUImm<5>(); } 148 bool isUImm6() const { return isUImm<6>(); } 149 bool isUImm12() const { return isUImm<12>(); } 150 bool isUImm15() const { return isUImm<15>(); } 151 bool isSImm12() const { return isSImm<12>(); } 152 bool isSImm14lsl2() const { return isSImm<14, 2>(); } 153 bool isSImm16() const { return isSImm<16>(); } 154 bool isSImm16lsl2() const { return isSImm<16, 2>(); } 155 bool isSImm20() const { return isSImm<20>(); } 156 bool isSImm21lsl2() const { return isSImm<21, 2>(); } 157 bool isSImm26lsl2() const { return isSImm<26, 2>(); } 158 159 /// Gets location of the first token of this operand. 160 SMLoc getStartLoc() const override { return StartLoc; } 161 /// Gets location of the last token of this operand. 162 SMLoc getEndLoc() const override { return EndLoc; } 163 164 unsigned getReg() const override { 165 assert(Kind == KindTy::Register && "Invalid type access!"); 166 return Reg.RegNum.id(); 167 } 168 169 const MCExpr *getImm() const { 170 assert(Kind == KindTy::Immediate && "Invalid type access!"); 171 return Imm.Val; 172 } 173 174 StringRef getToken() const { 175 assert(Kind == KindTy::Token && "Invalid type access!"); 176 return Tok; 177 } 178 179 void print(raw_ostream &OS) const override { 180 auto RegName = [](unsigned Reg) { 181 if (Reg) 182 return LoongArchInstPrinter::getRegisterName(Reg); 183 else 184 return "noreg"; 185 }; 186 187 switch (Kind) { 188 case KindTy::Immediate: 189 OS << *getImm(); 190 break; 191 case KindTy::Register: 192 OS << "<register " << RegName(getReg()) << ">"; 193 break; 194 case KindTy::Token: 195 OS << "'" << getToken() << "'"; 196 break; 197 } 198 } 199 200 static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) { 201 auto Op = std::make_unique<LoongArchOperand>(KindTy::Token); 202 Op->Tok = Str; 203 Op->StartLoc = S; 204 Op->EndLoc = S; 205 return Op; 206 } 207 208 static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S, 209 SMLoc E) { 210 auto Op = std::make_unique<LoongArchOperand>(KindTy::Register); 211 Op->Reg.RegNum = RegNo; 212 Op->StartLoc = S; 213 Op->EndLoc = E; 214 return Op; 215 } 216 217 static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S, 218 SMLoc E) { 219 auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate); 220 Op->Imm.Val = Val; 221 Op->StartLoc = S; 222 Op->EndLoc = E; 223 return Op; 224 } 225 226 void addExpr(MCInst &Inst, const MCExpr *Expr) const { 227 if (auto CE = dyn_cast<MCConstantExpr>(Expr)) 228 Inst.addOperand(MCOperand::createImm(CE->getValue())); 229 else 230 Inst.addOperand(MCOperand::createExpr(Expr)); 231 } 232 233 // Used by the TableGen Code. 234 void addRegOperands(MCInst &Inst, unsigned N) const { 235 assert(N == 1 && "Invalid number of operands!"); 236 Inst.addOperand(MCOperand::createReg(getReg())); 237 } 238 void addImmOperands(MCInst &Inst, unsigned N) const { 239 assert(N == 1 && "Invalid number of operands!"); 240 addExpr(Inst, getImm()); 241 } 242 }; 243 } // end anonymous namespace 244 245 #define GET_REGISTER_MATCHER 246 #define GET_SUBTARGET_FEATURE_NAME 247 #define GET_MATCHER_IMPLEMENTATION 248 #define GET_MNEMONIC_SPELL_CHECKER 249 #include "LoongArchGenAsmMatcher.inc" 250 251 static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) { 252 RegNo = MatchRegisterName(Name); 253 254 if (RegNo == LoongArch::NoRegister) 255 RegNo = MatchRegisterAltName(Name); 256 257 return RegNo == LoongArch::NoRegister; 258 } 259 260 bool LoongArchAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, 261 SMLoc &EndLoc) { 262 return Error(getLoc(), "invalid register number"); 263 } 264 265 OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo, 266 SMLoc &StartLoc, 267 SMLoc &EndLoc) { 268 llvm_unreachable("Unimplemented function."); 269 } 270 271 OperandMatchResultTy 272 LoongArchAsmParser::parseRegister(OperandVector &Operands) { 273 if (getLexer().getTok().isNot(AsmToken::Dollar)) 274 return MatchOperand_NoMatch; 275 276 // Eat the $ prefix. 277 getLexer().Lex(); 278 if (getLexer().getKind() != AsmToken::Identifier) 279 return MatchOperand_NoMatch; 280 281 StringRef Name = getLexer().getTok().getIdentifier(); 282 MCRegister RegNo; 283 matchRegisterNameHelper(RegNo, Name); 284 if (RegNo == LoongArch::NoRegister) 285 return MatchOperand_NoMatch; 286 287 SMLoc S = getLoc(); 288 SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); 289 getLexer().Lex(); 290 Operands.push_back(LoongArchOperand::createReg(RegNo, S, E)); 291 292 return MatchOperand_Success; 293 } 294 295 OperandMatchResultTy 296 LoongArchAsmParser::parseImmediate(OperandVector &Operands) { 297 SMLoc S = getLoc(); 298 SMLoc E; 299 const MCExpr *Res; 300 301 if (getParser().parseExpression(Res, E)) 302 return MatchOperand_ParseFail; 303 304 Operands.push_back(LoongArchOperand::createImm(Res, S, E)); 305 return MatchOperand_Success; 306 } 307 308 /// Looks at a token type and creates the relevant operand from this 309 /// information, adding to Operands. Return true upon an error. 310 bool LoongArchAsmParser::parseOperand(OperandVector &Operands, 311 StringRef Mnemonic) { 312 if (parseRegister(Operands) == MatchOperand_Success || 313 parseImmediate(Operands) == MatchOperand_Success) 314 return false; 315 316 // Finally we have exhausted all options and must declare defeat. 317 Error(getLoc(), "unknown operand"); 318 return true; 319 } 320 321 bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info, 322 StringRef Name, SMLoc NameLoc, 323 OperandVector &Operands) { 324 // First operand in MCInst is instruction mnemonic. 325 Operands.push_back(LoongArchOperand::createToken(Name, NameLoc)); 326 327 // If there are no more operands, then finish. 328 if (parseOptionalToken(AsmToken::EndOfStatement)) 329 return false; 330 331 // Parse first operand. 332 if (parseOperand(Operands, Name)) 333 return true; 334 335 // Parse until end of statement, consuming commas between operands. 336 while (parseOptionalToken(AsmToken::Comma)) 337 if (parseOperand(Operands, Name)) 338 return true; 339 340 // Parse end of statement and return successfully. 341 if (parseOptionalToken(AsmToken::EndOfStatement)) 342 return false; 343 344 SMLoc Loc = getLexer().getLoc(); 345 getParser().eatToEndOfStatement(); 346 return Error(Loc, "unexpected token"); 347 } 348 349 bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, 350 OperandVector &Operands, 351 MCStreamer &Out) { 352 Inst.setLoc(IDLoc); 353 Out.emitInstruction(Inst, getSTI()); 354 return false; 355 } 356 357 bool LoongArchAsmParser::generateImmOutOfRangeError( 358 OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, 359 Twine Msg = "immediate must be an integer in the range") { 360 SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); 361 return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); 362 } 363 364 bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, 365 OperandVector &Operands, 366 MCStreamer &Out, 367 uint64_t &ErrorInfo, 368 bool MatchingInlineAsm) { 369 MCInst Inst; 370 FeatureBitset MissingFeatures; 371 372 auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures, 373 MatchingInlineAsm); 374 switch (Result) { 375 default: 376 break; 377 case Match_Success: 378 return processInstruction(Inst, IDLoc, Operands, Out); 379 case Match_MissingFeature: { 380 assert(MissingFeatures.any() && "Unknown missing features!"); 381 bool FirstFeature = true; 382 std::string Msg = "instruction requires the following:"; 383 for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) { 384 if (MissingFeatures[i]) { 385 Msg += FirstFeature ? " " : ", "; 386 Msg += getSubtargetFeatureName(i); 387 FirstFeature = false; 388 } 389 } 390 return Error(IDLoc, Msg); 391 } 392 case Match_MnemonicFail: { 393 FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); 394 std::string Suggestion = LoongArchMnemonicSpellCheck( 395 ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0); 396 return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion); 397 } 398 case Match_InvalidOperand: { 399 SMLoc ErrorLoc = IDLoc; 400 if (ErrorInfo != ~0ULL) { 401 if (ErrorInfo >= Operands.size()) 402 return Error(ErrorLoc, "too few operands for instruction"); 403 404 ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); 405 if (ErrorLoc == SMLoc()) 406 ErrorLoc = IDLoc; 407 } 408 return Error(ErrorLoc, "invalid operand for instruction"); 409 } 410 } 411 412 // Handle the case when the error message is of specific type 413 // other than the generic Match_InvalidOperand, and the 414 // corresponding operand is missing. 415 if (Result > FIRST_TARGET_MATCH_RESULT_TY) { 416 SMLoc ErrorLoc = IDLoc; 417 if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size()) 418 return Error(ErrorLoc, "too few operands for instruction"); 419 } 420 421 switch (Result) { 422 default: 423 break; 424 case Match_InvalidUImm2: 425 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 426 /*Upper=*/(1 << 2) - 1); 427 case Match_InvalidUImm2plus1: 428 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1, 429 /*Upper=*/(1 << 2)); 430 case Match_InvalidUImm3: 431 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 432 /*Upper=*/(1 << 3) - 1); 433 case Match_InvalidUImm5: 434 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 435 /*Upper=*/(1 << 5) - 1); 436 case Match_InvalidUImm6: 437 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 438 /*Upper=*/(1 << 6) - 1); 439 case Match_InvalidUImm12: 440 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 441 /*Upper=*/(1 << 12) - 1); 442 case Match_InvalidUImm15: 443 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 444 /*Upper=*/(1 << 15) - 1); 445 case Match_InvalidSImm12: 446 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11), 447 /*Upper=*/(1 << 11) - 1); 448 case Match_InvalidSImm14lsl2: 449 return generateImmOutOfRangeError( 450 Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4, 451 "immediate must be a multiple of 4 in the range"); 452 case Match_InvalidSImm16: 453 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15), 454 /*Upper=*/(1 << 15) - 1); 455 case Match_InvalidSImm16lsl2: 456 return generateImmOutOfRangeError( 457 Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4, 458 "immediate must be a multiple of 4 in the range"); 459 case Match_InvalidSImm20: 460 return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19), 461 /*Upper=*/(1 << 19) - 1); 462 case Match_InvalidSImm21lsl2: 463 return generateImmOutOfRangeError( 464 Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4, 465 "immediate must be a multiple of 4 in the range"); 466 case Match_InvalidSImm26lsl2: 467 return generateImmOutOfRangeError( 468 Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4, 469 "immediate must be a multiple of 4 in the range"); 470 } 471 llvm_unreachable("Unknown match type detected!"); 472 } 473 474 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() { 475 RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target()); 476 RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target()); 477 } 478