Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
// LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=// | // LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=// | ||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#include "MCTargetDesc/LoongArchInstPrinter.h" | #include "MCTargetDesc/LoongArchInstPrinter.h" | ||||
#include "MCTargetDesc/LoongArchMCExpr.h" | |||||
#include "MCTargetDesc/LoongArchMCTargetDesc.h" | #include "MCTargetDesc/LoongArchMCTargetDesc.h" | ||||
#include "TargetInfo/LoongArchTargetInfo.h" | #include "TargetInfo/LoongArchTargetInfo.h" | ||||
#include "llvm/MC/MCContext.h" | #include "llvm/MC/MCContext.h" | ||||
#include "llvm/MC/MCInstrInfo.h" | #include "llvm/MC/MCInstrInfo.h" | ||||
#include "llvm/MC/MCParser/MCAsmLexer.h" | #include "llvm/MC/MCParser/MCAsmLexer.h" | ||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h" | #include "llvm/MC/MCParser/MCParsedAsmOperand.h" | ||||
#include "llvm/MC/MCParser/MCTargetAsmParser.h" | #include "llvm/MC/MCParser/MCTargetAsmParser.h" | ||||
#include "llvm/MC/MCRegisterInfo.h" | #include "llvm/MC/MCRegisterInfo.h" | ||||
#include "llvm/MC/MCStreamer.h" | #include "llvm/MC/MCStreamer.h" | ||||
#include "llvm/MC/MCSubtargetInfo.h" | #include "llvm/MC/MCSubtargetInfo.h" | ||||
#include "llvm/MC/MCValue.h" | |||||
#include "llvm/MC/TargetRegistry.h" | #include "llvm/MC/TargetRegistry.h" | ||||
#include "llvm/Support/Casting.h" | #include "llvm/Support/Casting.h" | ||||
using namespace llvm; | using namespace llvm; | ||||
#define DEBUG_TYPE "loongarch-asm-parser" | #define DEBUG_TYPE "loongarch-asm-parser" | ||||
namespace { | namespace { | ||||
Show All 29 Lines | bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, | ||||
MCStreamer &Out); | MCStreamer &Out); | ||||
// Auto-generated instruction matching functions. | // Auto-generated instruction matching functions. | ||||
#define GET_ASSEMBLER_HEADER | #define GET_ASSEMBLER_HEADER | ||||
#include "LoongArchGenAsmMatcher.inc" | #include "LoongArchGenAsmMatcher.inc" | ||||
OperandMatchResultTy parseRegister(OperandVector &Operands); | OperandMatchResultTy parseRegister(OperandVector &Operands); | ||||
OperandMatchResultTy parseImmediate(OperandVector &Operands); | OperandMatchResultTy parseImmediate(OperandVector &Operands); | ||||
OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); | |||||
OperandMatchResultTy parseSImm26Operand(OperandVector &Operands); | |||||
bool parseOperand(OperandVector &Operands, StringRef Mnemonic); | bool parseOperand(OperandVector &Operands, StringRef Mnemonic); | ||||
public: | public: | ||||
enum LoongArchMatchResultTy { | enum LoongArchMatchResultTy { | ||||
Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, | Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, | ||||
Match_RequiresMsbNotLessThanLsb, | Match_RequiresMsbNotLessThanLsb, | ||||
Match_RequiresOpnd2NotR0R1, | Match_RequiresOpnd2NotR0R1, | ||||
#define GET_OPERAND_DIAGNOSTIC_TYPES | #define GET_OPERAND_DIAGNOSTIC_TYPES | ||||
#include "LoongArchGenAsmMatcher.inc" | #include "LoongArchGenAsmMatcher.inc" | ||||
#undef GET_OPERAND_DIAGNOSTIC_TYPES | #undef GET_OPERAND_DIAGNOSTIC_TYPES | ||||
}; | }; | ||||
static bool classifySymbolRef(const MCExpr *Expr, | |||||
LoongArchMCExpr::VariantKind &Kind); | |||||
LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, | LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, | ||||
const MCInstrInfo &MII, const MCTargetOptions &Options) | const MCInstrInfo &MII, const MCTargetOptions &Options) | ||||
: MCTargetAsmParser(Options, STI, MII) { | : MCTargetAsmParser(Options, STI, MII) { | ||||
Parser.addAliasForDirective(".half", ".2byte"); | Parser.addAliasForDirective(".half", ".2byte"); | ||||
Parser.addAliasForDirective(".hword", ".2byte"); | Parser.addAliasForDirective(".hword", ".2byte"); | ||||
Parser.addAliasForDirective(".word", ".4byte"); | Parser.addAliasForDirective(".word", ".4byte"); | ||||
Parser.addAliasForDirective(".dword", ".8byte"); | Parser.addAliasForDirective(".dword", ".8byte"); | ||||
Show All 29 Lines | public: | ||||
LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} | LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} | ||||
bool isToken() const override { return Kind == KindTy::Token; } | bool isToken() const override { return Kind == KindTy::Token; } | ||||
bool isReg() const override { return Kind == KindTy::Register; } | bool isReg() const override { return Kind == KindTy::Register; } | ||||
bool isImm() const override { return Kind == KindTy::Immediate; } | bool isImm() const override { return Kind == KindTy::Immediate; } | ||||
bool isMem() const override { return false; } | bool isMem() const override { return false; } | ||||
void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; } | void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; } | ||||
static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) { | static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm, | ||||
LoongArchMCExpr::VariantKind &VK) { | |||||
if (auto *LE = dyn_cast<LoongArchMCExpr>(Expr)) { | |||||
VK = LE->getKind(); | |||||
return false; | |||||
} | |||||
if (auto CE = dyn_cast<MCConstantExpr>(Expr)) { | if (auto CE = dyn_cast<MCConstantExpr>(Expr)) { | ||||
Imm = CE->getValue(); | Imm = CE->getValue(); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
template <unsigned N, int P = 0> bool isUImm() const { | template <unsigned N, int P = 0> bool isUImm() const { | ||||
if (!isImm()) | if (!isImm()) | ||||
return false; | return false; | ||||
int64_t Imm; | int64_t Imm; | ||||
bool IsConstantImm = evaluateConstantImm(getImm(), Imm); | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; | ||||
return IsConstantImm && isUInt<N>(Imm - P); | bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); | ||||
return IsConstantImm && isUInt<N>(Imm - P) && | |||||
VK == LoongArchMCExpr::VK_LoongArch_None; | |||||
} | } | ||||
template <unsigned N, unsigned S = 0> bool isSImm() const { | template <unsigned N, unsigned S = 0> bool isSImm() const { | ||||
if (!isImm()) | if (!isImm()) | ||||
return false; | return false; | ||||
int64_t Imm; | int64_t Imm; | ||||
bool IsConstantImm = evaluateConstantImm(getImm(), Imm); | LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; | ||||
return IsConstantImm && isShiftedInt<N, S>(Imm); | bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); | ||||
return IsConstantImm && isShiftedInt<N, S>(Imm) && | |||||
VK == LoongArchMCExpr::VK_LoongArch_None; | |||||
} | } | ||||
bool isUImm2() const { return isUImm<2>(); } | bool isUImm2() const { return isUImm<2>(); } | ||||
bool isUImm2plus1() const { return isUImm<2, 1>(); } | bool isUImm2plus1() const { return isUImm<2, 1>(); } | ||||
bool isUImm3() const { return isUImm<3>(); } | bool isUImm3() const { return isUImm<3>(); } | ||||
bool isUImm5() const { return isUImm<5>(); } | bool isUImm5() const { return isUImm<5>(); } | ||||
bool isUImm6() const { return isUImm<6>(); } | bool isUImm6() const { return isUImm<6>(); } | ||||
bool isUImm8() const { return isUImm<8>(); } | bool isUImm8() const { return isUImm<8>(); } | ||||
bool isUImm12() const { return isUImm<12>(); } | bool isUImm12() const { return isUImm<12>(); } | ||||
bool isUImm14() const { return isUImm<14>(); } | bool isUImm14() const { return isUImm<14>(); } | ||||
bool isUImm15() const { return isUImm<15>(); } | bool isUImm15() const { return isUImm<15>(); } | ||||
bool isSImm12() const { return isSImm<12>(); } | |||||
bool isSImm12() const { | |||||
if (!isImm()) | |||||
return false; | |||||
int64_t Imm; | |||||
LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; | |||||
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); | |||||
bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_PCREL_LO; | |||||
return IsConstantImm | |||||
? (isInt<12>(Imm) && | |||||
(VK == LoongArchMCExpr::VK_LoongArch_None || IsValidKind)) | |||||
: (LoongArchAsmParser::classifySymbolRef(getImm(), VK) && | |||||
IsValidKind); | |||||
} | |||||
bool isSImm14lsl2() const { return isSImm<14, 2>(); } | bool isSImm14lsl2() const { return isSImm<14, 2>(); } | ||||
bool isSImm16() const { return isSImm<16>(); } | bool isSImm16() const { return isSImm<16>(); } | ||||
bool isSImm16lsl2() const { return isSImm<16, 2>(); } | bool isSImm16lsl2() const { return isSImm<16, 2>(); } | ||||
bool isSImm20() const { return isSImm<20>(); } | bool isSImm20() const { return isSImm<20>(); } | ||||
bool isSImm20pcalau12i() const { | |||||
if (!isImm()) | |||||
return false; | |||||
int64_t Imm; | |||||
LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; | |||||
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); | |||||
bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_PCREL_HI; | |||||
return IsConstantImm | |||||
? (isInt<20>(Imm) && | |||||
(VK == LoongArchMCExpr::VK_LoongArch_None || IsValidKind)) | |||||
: (LoongArchAsmParser::classifySymbolRef(getImm(), VK) && | |||||
IsValidKind); | |||||
} | |||||
bool isSImm21lsl2() const { return isSImm<21, 2>(); } | bool isSImm21lsl2() const { return isSImm<21, 2>(); } | ||||
bool isSImm26lsl2() const { return isSImm<26, 2>(); } | |||||
bool isSImm26Operand() const { | |||||
int64_t Imm; | |||||
LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; | |||||
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); | |||||
bool IsValidKind = (VK == LoongArchMCExpr::VK_LoongArch_CALL || | |||||
VK == LoongArchMCExpr::VK_LoongArch_CALL_PLT); | |||||
return IsConstantImm | |||||
? (isShiftedInt<26, 2>(Imm) && | |||||
(VK == LoongArchMCExpr::VK_LoongArch_None || IsValidKind)) | |||||
: (LoongArchAsmParser::classifySymbolRef(getImm(), VK) && | |||||
IsValidKind); | |||||
} | |||||
/// Gets location of the first token of this operand. | /// Gets location of the first token of this operand. | ||||
SMLoc getStartLoc() const override { return StartLoc; } | SMLoc getStartLoc() const override { return StartLoc; } | ||||
/// Gets location of the last token of this operand. | /// Gets location of the last token of this operand. | ||||
SMLoc getEndLoc() const override { return EndLoc; } | SMLoc getEndLoc() const override { return EndLoc; } | ||||
unsigned getReg() const override { | unsigned getReg() const override { | ||||
assert(Kind == KindTy::Register && "Invalid type access!"); | assert(Kind == KindTy::Register && "Invalid type access!"); | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo, | OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo, | ||||
SMLoc &StartLoc, | SMLoc &StartLoc, | ||||
SMLoc &EndLoc) { | SMLoc &EndLoc) { | ||||
llvm_unreachable("Unimplemented function."); | llvm_unreachable("Unimplemented function."); | ||||
} | } | ||||
bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr, | |||||
LoongArchMCExpr::VariantKind &Kind) { | |||||
Kind = LoongArchMCExpr::VK_LoongArch_None; | |||||
if (const LoongArchMCExpr *RE = dyn_cast<LoongArchMCExpr>(Expr)) { | |||||
Kind = RE->getKind(); | |||||
Expr = RE->getSubExpr(); | |||||
} | |||||
MCValue Res; | |||||
if (Expr->evaluateAsRelocatable(Res, nullptr, nullptr)) | |||||
return Res.getRefKind() == LoongArchMCExpr::VK_LoongArch_None; | |||||
return false; | |||||
} | |||||
OperandMatchResultTy | OperandMatchResultTy | ||||
LoongArchAsmParser::parseRegister(OperandVector &Operands) { | LoongArchAsmParser::parseRegister(OperandVector &Operands) { | ||||
if (getLexer().getTok().isNot(AsmToken::Dollar)) | if (getLexer().getTok().isNot(AsmToken::Dollar)) | ||||
return MatchOperand_NoMatch; | return MatchOperand_NoMatch; | ||||
// Eat the $ prefix. | // Eat the $ prefix. | ||||
getLexer().Lex(); | getLexer().Lex(); | ||||
if (getLexer().getKind() != AsmToken::Identifier) | if (getLexer().getKind() != AsmToken::Identifier) | ||||
Show All 14 Lines | |||||
} | } | ||||
OperandMatchResultTy | OperandMatchResultTy | ||||
LoongArchAsmParser::parseImmediate(OperandVector &Operands) { | LoongArchAsmParser::parseImmediate(OperandVector &Operands) { | ||||
SMLoc S = getLoc(); | SMLoc S = getLoc(); | ||||
SMLoc E; | SMLoc E; | ||||
const MCExpr *Res; | const MCExpr *Res; | ||||
switch (getLexer().getKind()) { | |||||
default: | |||||
return MatchOperand_NoMatch; | |||||
case AsmToken::LParen: | |||||
case AsmToken::Dot: | |||||
case AsmToken::Minus: | |||||
case AsmToken::Plus: | |||||
case AsmToken::Exclaim: | |||||
case AsmToken::Tilde: | |||||
case AsmToken::Integer: | |||||
case AsmToken::String: | |||||
case AsmToken::Identifier: | |||||
if (getParser().parseExpression(Res, E)) | if (getParser().parseExpression(Res, E)) | ||||
return MatchOperand_ParseFail; | return MatchOperand_ParseFail; | ||||
break; | |||||
case AsmToken::Percent: | |||||
return parseOperandWithModifier(Operands); | |||||
} | |||||
Operands.push_back(LoongArchOperand::createImm(Res, S, E)); | Operands.push_back(LoongArchOperand::createImm(Res, S, E)); | ||||
return MatchOperand_Success; | return MatchOperand_Success; | ||||
} | } | ||||
OperandMatchResultTy | |||||
LoongArchAsmParser::parseOperandWithModifier(OperandVector &Operands) { | |||||
SMLoc S = getLoc(); | |||||
SMLoc E; | |||||
if (getLexer().getKind() != AsmToken::Percent) { | |||||
Error(getLoc(), "expected '%' for operand modifier"); | |||||
return MatchOperand_ParseFail; | |||||
} | |||||
getParser().Lex(); // Eat '%' | |||||
if (getLexer().getKind() != AsmToken::Identifier) { | |||||
Error(getLoc(), "expected valid identifier for operand modifier"); | |||||
return MatchOperand_ParseFail; | |||||
} | |||||
StringRef Identifier = getParser().getTok().getIdentifier(); | |||||
LoongArchMCExpr::VariantKind VK = | |||||
LoongArchMCExpr::getVariantKindForName(Identifier); | |||||
if (VK == LoongArchMCExpr::VK_LoongArch_Invalid) { | |||||
Error(getLoc(), "unrecognized operand modifier"); | |||||
return MatchOperand_ParseFail; | |||||
} | |||||
getParser().Lex(); // Eat the identifier | |||||
if (getLexer().getKind() != AsmToken::LParen) { | |||||
Error(getLoc(), "expected '('"); | |||||
return MatchOperand_ParseFail; | |||||
} | |||||
getParser().Lex(); // Eat '(' | |||||
const MCExpr *SubExpr; | |||||
if (getParser().parseParenExpression(SubExpr, E)) { | |||||
return MatchOperand_ParseFail; | |||||
} | |||||
const MCExpr *ModExpr = LoongArchMCExpr::create(SubExpr, VK, getContext()); | |||||
Operands.push_back(LoongArchOperand::createImm(ModExpr, S, E)); | |||||
return MatchOperand_Success; | |||||
} | |||||
OperandMatchResultTy | |||||
LoongArchAsmParser::parseSImm26Operand(OperandVector &Operands) { | |||||
SMLoc S = getLoc(); | |||||
const MCExpr *Res; | |||||
if (getLexer().getKind() == AsmToken::Percent) | |||||
return parseOperandWithModifier(Operands); | |||||
if (getLexer().getKind() != AsmToken::Identifier) | |||||
return MatchOperand_NoMatch; | |||||
StringRef Identifier; | |||||
if (getParser().parseIdentifier(Identifier)) | |||||
return MatchOperand_ParseFail; | |||||
SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size()); | |||||
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); | |||||
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); | |||||
Res = LoongArchMCExpr::create(Res, LoongArchMCExpr::VK_LoongArch_CALL, | |||||
getContext()); | |||||
Operands.push_back(LoongArchOperand::createImm(Res, S, E)); | |||||
return MatchOperand_Success; | |||||
} | |||||
/// Looks at a token type and creates the relevant operand from this | /// Looks at a token type and creates the relevant operand from this | ||||
/// information, adding to Operands. Return true upon an error. | /// information, adding to Operands. Return true upon an error. | ||||
bool LoongArchAsmParser::parseOperand(OperandVector &Operands, | bool LoongArchAsmParser::parseOperand(OperandVector &Operands, | ||||
StringRef Mnemonic) { | StringRef Mnemonic) { | ||||
// Check if the current operand has a custom associated parser, if so, try to | |||||
// custom parse the operand, or fallback to the general approach. | |||||
OperandMatchResultTy Result = | |||||
MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true); | |||||
if (Result == MatchOperand_Success) | |||||
return false; | |||||
if (Result == MatchOperand_ParseFail) | |||||
return true; | |||||
if (parseRegister(Operands) == MatchOperand_Success || | if (parseRegister(Operands) == MatchOperand_Success || | ||||
parseImmediate(Operands) == MatchOperand_Success) | parseImmediate(Operands) == MatchOperand_Success) | ||||
return false; | return false; | ||||
// Finally we have exhausted all options and must declare defeat. | // Finally we have exhausted all options and must declare defeat. | ||||
Error(getLoc(), "unknown operand"); | Error(getLoc(), "unknown operand"); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, | ||||
/*Upper=*/(1 << 6) - 1); | /*Upper=*/(1 << 6) - 1); | ||||
case Match_InvalidUImm12: | case Match_InvalidUImm12: | ||||
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, | ||||
/*Upper=*/(1 << 12) - 1); | /*Upper=*/(1 << 12) - 1); | ||||
case Match_InvalidUImm15: | case Match_InvalidUImm15: | ||||
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, | ||||
/*Upper=*/(1 << 15) - 1); | /*Upper=*/(1 << 15) - 1); | ||||
case Match_InvalidSImm12: | case Match_InvalidSImm12: | ||||
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11), | return generateImmOutOfRangeError( | ||||
/*Upper=*/(1 << 11) - 1); | Operands, ErrorInfo, /*Lower=*/-(1 << 11), | ||||
/*Upper=*/(1 << 11) - 1, | |||||
"operand must be a symbol with modifier (e.g. %pc_lo12) or an integer " | |||||
"in the range"); | |||||
case Match_InvalidSImm14lsl2: | case Match_InvalidSImm14lsl2: | ||||
return generateImmOutOfRangeError( | return generateImmOutOfRangeError( | ||||
Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4, | Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4, | ||||
"immediate must be a multiple of 4 in the range"); | "immediate must be a multiple of 4 in the range"); | ||||
case Match_InvalidSImm16: | case Match_InvalidSImm16: | ||||
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15), | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15), | ||||
/*Upper=*/(1 << 15) - 1); | /*Upper=*/(1 << 15) - 1); | ||||
case Match_InvalidSImm16lsl2: | case Match_InvalidSImm16lsl2: | ||||
return generateImmOutOfRangeError( | return generateImmOutOfRangeError( | ||||
Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4, | Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4, | ||||
"immediate must be a multiple of 4 in the range"); | "immediate must be a multiple of 4 in the range"); | ||||
case Match_InvalidSImm20: | case Match_InvalidSImm20: | ||||
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19), | return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19), | ||||
/*Upper=*/(1 << 19) - 1); | /*Upper=*/(1 << 19) - 1); | ||||
case Match_InvalidSImm20pcalau12i: | |||||
return generateImmOutOfRangeError( | |||||
Operands, ErrorInfo, /*Lower=*/-(1 << 19), | |||||
/*Upper=*/(1 << 19) - 1, | |||||
"operand must be a symbol with modifier (e.g. %pc_hi20) or an integer " | |||||
"in the range"); | |||||
case Match_InvalidSImm21lsl2: | case Match_InvalidSImm21lsl2: | ||||
return generateImmOutOfRangeError( | return generateImmOutOfRangeError( | ||||
Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4, | Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4, | ||||
"immediate must be a multiple of 4 in the range"); | "immediate must be a multiple of 4 in the range"); | ||||
case Match_InvalidSImm26lsl2: | case Match_InvalidSImm26Operand: | ||||
return generateImmOutOfRangeError( | return generateImmOutOfRangeError( | ||||
Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4, | Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4, | ||||
"immediate must be a multiple of 4 in the range"); | "operand must be a bare symbol name or an immediate must be a multiple " | ||||
"of 4 in the range"); | |||||
} | } | ||||
llvm_unreachable("Unknown match type detected!"); | llvm_unreachable("Unknown match type detected!"); | ||||
} | } | ||||
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() { | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() { | ||||
RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target()); | RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target()); | ||||
RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target()); | RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target()); | ||||
} | } |