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