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