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