diff --git a/llvm/lib/Target/LoongArch/AsmParser/CMakeLists.txt b/llvm/lib/Target/LoongArch/AsmParser/CMakeLists.txt new file mode 100644 index 00000000000000..29616053118f27 --- /dev/null +++ b/llvm/lib/Target/LoongArch/AsmParser/CMakeLists.txt @@ -0,0 +1,13 @@ +add_llvm_component_library(LLVMLoongArchAsmParser + LoongArchAsmParser.cpp + + LINK_COMPONENTS + LoongArchDesc + LoongArchInfo + MC + MCParser + Support + + ADD_TO_COMPONENT + LoongArch + ) diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp new file mode 100644 index 00000000000000..5f9eae2ff589ee --- /dev/null +++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp @@ -0,0 +1,477 @@ +// LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/LoongArchInstPrinter.h" +#include "MCTargetDesc/LoongArchMCTargetDesc.h" +#include "TargetInfo/LoongArchTargetInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; + +#define DEBUG_TYPE "loongarch-asm-parser" + +namespace { +struct LoongArchOperand; + +class LoongArchAsmParser : public MCTargetAsmParser { + SMLoc getLoc() const { return getParser().getTok().getLoc(); } + + /// Parse a register as used in CFI directives. + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) override; + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseDirective(AsmToken DirectiveID) override { return true; } + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + + bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, + int64_t Lower, int64_t Upper, Twine Msg); + + /// Helper for processing MC instructions that have been successfully matched + /// by MatchAndEmitInstruction. + bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, + MCStreamer &Out); + +// Auto-generated instruction matching functions. +#define GET_ASSEMBLER_HEADER +#include "LoongArchGenAsmMatcher.inc" + + OperandMatchResultTy parseRegister(OperandVector &Operands); + OperandMatchResultTy parseImmediate(OperandVector &Operands); + + bool parseOperand(OperandVector &Operands, StringRef Mnemonic); + +public: + enum LoongArchMatchResultTy { + Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "LoongArchGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + }; + + LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, STI, MII) { + Parser.addAliasForDirective(".half", ".2byte"); + Parser.addAliasForDirective(".hword", ".2byte"); + Parser.addAliasForDirective(".word", ".4byte"); + Parser.addAliasForDirective(".dword", ".8byte"); + + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } +}; + +/// LoongArchOperand - Instances of this class represent a parsed LoongArch +/// machine instruction. +class LoongArchOperand : public MCParsedAsmOperand { + enum class KindTy { + Token, + Register, + Immediate, + } Kind; + + struct RegOp { + MCRegister RegNum; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + SMLoc StartLoc, EndLoc; + union { + StringRef Tok; + struct RegOp Reg; + struct ImmOp Imm; + }; + +public: + LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + + bool isToken() const override { return Kind == KindTy::Token; } + bool isReg() const override { return Kind == KindTy::Register; } + bool isImm() const override { return Kind == KindTy::Immediate; } + bool isMem() const override { return false; } + + static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) { + if (auto CE = dyn_cast(Expr)) { + Imm = CE->getValue(); + return true; + } + + return false; + } + + template bool isUImm() const { + if (!isImm()) + return false; + + int64_t Imm; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm); + return IsConstantImm && isUInt(Imm - P); + } + + template bool isSImm() const { + if (!isImm()) + return false; + + int64_t Imm; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm); + return IsConstantImm && isShiftedInt(Imm); + } + + bool isUImm2() const { return isUImm<2>(); } + bool isUImm2plus1() const { return isUImm<2, 1>(); } + bool isUImm3() const { return isUImm<3>(); } + bool isUImm5() const { return isUImm<5>(); } + bool isUImm6() const { return isUImm<6>(); } + bool isUImm12() const { return isUImm<12>(); } + bool isUImm15() const { return isUImm<15>(); } + bool isSImm12() const { return isSImm<12>(); } + bool isSImm14lsl2() const { return isSImm<14, 2>(); } + bool isSImm16() const { return isSImm<16>(); } + bool isSImm16lsl2() const { return isSImm<16, 2>(); } + bool isSImm20() const { return isSImm<20>(); } + bool isSImm21lsl2() const { return isSImm<21, 2>(); } + bool isSImm26lsl2() const { return isSImm<26, 2>(); } + + /// Gets location of the first token of this operand. + SMLoc getStartLoc() const override { return StartLoc; } + /// Gets location of the last token of this operand. + SMLoc getEndLoc() const override { return EndLoc; } + + unsigned getReg() const override { + assert(Kind == KindTy::Register && "Invalid type access!"); + return Reg.RegNum.id(); + } + + const MCExpr *getImm() const { + assert(Kind == KindTy::Immediate && "Invalid type access!"); + return Imm.Val; + } + + StringRef getToken() const { + assert(Kind == KindTy::Token && "Invalid type access!"); + return Tok; + } + + void print(raw_ostream &OS) const override { + auto RegName = [](unsigned Reg) { + if (Reg) + return LoongArchInstPrinter::getRegisterName(Reg); + else + return "noreg"; + }; + + switch (Kind) { + case KindTy::Immediate: + OS << *getImm(); + break; + case KindTy::Register: + OS << ""; + break; + case KindTy::Token: + OS << "'" << getToken() << "'"; + break; + } + } + + static std::unique_ptr createToken(StringRef Str, SMLoc S) { + auto Op = std::make_unique(KindTy::Token); + Op->Tok = Str; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr createReg(unsigned RegNo, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(KindTy::Register); + Op->Reg.RegNum = RegNo; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(KindTy::Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + if (auto CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::createImm(CE->getValue())); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + // Used by the TableGen Code. + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg())); + } + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } +}; +} // end anonymous namespace + +#define GET_REGISTER_MATCHER +#define GET_SUBTARGET_FEATURE_NAME +#define GET_MATCHER_IMPLEMENTATION +#define GET_MNEMONIC_SPELL_CHECKER +#include "LoongArchGenAsmMatcher.inc" + +static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) { + RegNo = MatchRegisterName(Name); + + if (RegNo == LoongArch::NoRegister) + RegNo = MatchRegisterAltName(Name); + + return RegNo == LoongArch::NoRegister; +} + +bool LoongArchAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + return Error(getParser().getTok().getLoc(), "invalid register number"); +} + +OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo, + SMLoc &StartLoc, + SMLoc &EndLoc) { + llvm_unreachable("Unimplemented function."); +} + +OperandMatchResultTy +LoongArchAsmParser::parseRegister(OperandVector &Operands) { + if (getLexer().getTok().isNot(AsmToken::Dollar)) + return MatchOperand_NoMatch; + + // Eat the $ prefix. + getLexer().Lex(); + if (getLexer().getKind() != AsmToken::Identifier) + return MatchOperand_NoMatch; + + StringRef Name = getLexer().getTok().getIdentifier(); + MCRegister RegNo; + matchRegisterNameHelper(RegNo, Name); + if (RegNo == LoongArch::NoRegister) + return MatchOperand_NoMatch; + + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); + getLexer().Lex(); + Operands.push_back(LoongArchOperand::createReg(RegNo, S, E)); + + return MatchOperand_Success; +} + +OperandMatchResultTy +LoongArchAsmParser::parseImmediate(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E; + const MCExpr *Res; + + if (getParser().parseExpression(Res, E)) + return MatchOperand_ParseFail; + + Operands.push_back(LoongArchOperand::createImm(Res, S, E)); + return MatchOperand_Success; +} + +/// Looks at a token type and creates the relevant operand from this +/// information, adding to Operands. Return true upon an error. +bool LoongArchAsmParser::parseOperand(OperandVector &Operands, + StringRef Mnemonic) { + if (parseRegister(Operands) == MatchOperand_Success || + parseImmediate(Operands) == MatchOperand_Success) + return false; + + // Finally we have exhausted all options and must declare defeat. + Error(getLoc(), "unknown operand"); + return true; +} + +bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info, + StringRef Name, SMLoc NameLoc, + OperandVector &Operands) { + // First operand in MCInst is instruction mnemonic. + Operands.push_back(LoongArchOperand::createToken(Name, NameLoc)); + + // If there are no more operands, then finish. + if (parseOptionalToken(AsmToken::EndOfStatement)) + return false; + + // Parse first operand. + if (parseOperand(Operands, Name)) + return true; + + // Parse until end of statement, consuming commas between operands. + while (parseOptionalToken(AsmToken::Comma)) + if (parseOperand(Operands, Name)) + return true; + + // Parse end of statement and return successfully. + if (parseOptionalToken(AsmToken::EndOfStatement)) + return false; + + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); +} + +bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + OperandVector &Operands, + MCStreamer &Out) { + Inst.setLoc(IDLoc); + Out.emitInstruction(Inst, getSTI()); + return false; +} + +bool LoongArchAsmParser::generateImmOutOfRangeError( + OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, + Twine Msg = "immediate must be an integer in the range") { + SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); +} + +bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + FeatureBitset MissingFeatures; + + auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures, + MatchingInlineAsm); + switch (Result) { + default: + break; + case Match_Success: + return processInstruction(Inst, IDLoc, Operands, Out); + case Match_MissingFeature: { + assert(MissingFeatures.any() && "Unknown missing features!"); + bool FirstFeature = true; + std::string Msg = "instruction requires the following:"; + for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) { + if (MissingFeatures[i]) { + Msg += FirstFeature ? " " : ", "; + Msg += getSubtargetFeatureName(i); + FirstFeature = false; + } + } + return Error(IDLoc, Msg); + } + case Match_MnemonicFail: { + FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); + std::string Suggestion = LoongArchMnemonicSpellCheck( + ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0); + return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion); + } + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0ULL) { + if (ErrorInfo >= Operands.size()) + return Error(ErrorLoc, "too few operands for instruction"); + + ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + return Error(ErrorLoc, "invalid operand for instruction"); + } + } + + // Handle the case when the error message is of specific type + // other than the generic Match_InvalidOperand, and the + // corresponding operand is missing. + if (Result > FIRST_TARGET_MATCH_RESULT_TY) { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size()) + return Error(ErrorLoc, "too few operands for instruction"); + } + + switch (Result) { + default: + break; + case Match_InvalidUImm2: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, + /*Upper=*/(1 << 2) - 1); + case Match_InvalidUImm2plus1: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1, + /*Upper=*/(1 << 2)); + case Match_InvalidUImm3: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, + /*Upper=*/(1 << 3) - 1); + case Match_InvalidUImm5: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, + /*Upper=*/(1 << 5) - 1); + case Match_InvalidUImm6: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, + /*Upper=*/(1 << 6) - 1); + case Match_InvalidUImm12: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, + /*Upper=*/(1 << 12) - 1); + case Match_InvalidUImm15: + return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, + /*Upper=*/(1 << 15) - 1); + case Match_InvalidSImm12: + return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 11), + (1 << 11) - 1); + case Match_InvalidSImm14lsl2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4, + "immediate must be a multiple of 4 in the range"); + case Match_InvalidSImm16: + return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 15), + (1 << 15) - 1); + case Match_InvalidSImm16lsl2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4, + "immediate must be a multiple of 4 in the range"); + case Match_InvalidSImm20: + return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 19), + (1 << 19) - 1); + case Match_InvalidSImm21lsl2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4, + "immediate must be a multiple of 4 in the range"); + case Match_InvalidSImm26lsl2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4, + "immediate must be a multiple of 4 in the range"); + } + llvm_unreachable("Unknown match type detected!"); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() { + RegisterMCAsmParser X(getTheLoongArch32Target()); + RegisterMCAsmParser Y(getTheLoongArch64Target()); +} diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt index ecd6af701316ab..4eebfb713b61cd 100644 --- a/llvm/lib/Target/LoongArch/CMakeLists.txt +++ b/llvm/lib/Target/LoongArch/CMakeLists.txt @@ -4,11 +4,11 @@ set(LLVM_TARGET_DEFINITIONS LoongArch.td) tablegen(LLVM LoongArchGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM LoongArchGenAsmWriter.inc -gen-asm-writer) -tablegen(LLVM LoongArchGenRegisterInfo.inc -gen-register-info) -tablegen(LLVM LoongArchGenInstrInfo.inc -gen-instr-info) tablegen(LLVM LoongArchGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM LoongArchGenInstrInfo.inc -gen-instr-info) tablegen(LLVM LoongArchGenMCPseudoLowering.inc -gen-pseudo-lowering) tablegen(LLVM LoongArchGenMCCodeEmitter.inc -gen-emitter) +tablegen(LLVM LoongArchGenRegisterInfo.inc -gen-register-info) tablegen(LLVM LoongArchGenSubtargetInfo.inc -gen-subtarget) add_public_tablegen_target(LoongArchCommonTableGen) @@ -41,5 +41,6 @@ add_llvm_target(LoongArchCodeGen LoongArch ) +add_subdirectory(AsmParser) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td index 4b452b28314c24..48a68b5bd3a705 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -22,6 +22,7 @@ class ImmAsmOperand : AsmOperandClass { let Name = prefix # "Imm" # width # suffix; let DiagnosticType = !strconcat("Invalid", Name); + let RenderMethod = "addImmOperands"; } class SImmAsmOperand @@ -32,29 +33,64 @@ class UImmAsmOperand : ImmAsmOperand<"U", width, suffix> { } -def uimm2 : Operand; +def uimm2 : Operand { + let ParserMatchClass = UImmAsmOperand<2>; +} + def uimm2_plus1 : Operand { + let ParserMatchClass = UImmAsmOperand<2, "plus1">; let EncoderMethod = "getImmOpValueSub1"; } -def uimm3 : Operand; -def uimm5 : Operand; -def uimm6 : Operand; -def uimm12 : Operand; -def uimm15 : Operand; -def simm12 : Operand, ImmLeaf(Imm);}]>; -def simm14 : Operand; + +def uimm3 : Operand { + let ParserMatchClass = UImmAsmOperand<3>; +} + +def uimm5 : Operand { + let ParserMatchClass = UImmAsmOperand<5>; +} + +def uimm6 : Operand { + let ParserMatchClass = UImmAsmOperand<6>; +} + +def uimm12 : Operand { + let ParserMatchClass = UImmAsmOperand<12>; +} + +def uimm15 : Operand { + let ParserMatchClass = UImmAsmOperand<15>; +} + +def simm12 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = SImmAsmOperand<12>; +} + def simm14_lsl2 : Operand { + let ParserMatchClass = SImmAsmOperand<14, "lsl2">; let EncoderMethod = "getImmOpValueAsr2"; } -def simm16 : Operand; + +def simm16 : Operand { + let ParserMatchClass = SImmAsmOperand<16>; +} + def simm16_lsl2 : Operand { + let ParserMatchClass = SImmAsmOperand<16, "lsl2">; let EncoderMethod = "getImmOpValueAsr2"; } -def simm20 : Operand; + +def simm20 : Operand { + let ParserMatchClass = SImmAsmOperand<20>; +} + def simm21_lsl2 : Operand { + let ParserMatchClass = SImmAsmOperand<21, "lsl2">; let EncoderMethod = "getImmOpValueAsr2"; } + def simm26_lsl2 : Operand { + let ParserMatchClass = SImmAsmOperand<26, "lsl2">; let EncoderMethod = "getImmOpValueAsr2"; } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp index 01993f93e7507f..bc946db2f4495a 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp @@ -29,5 +29,6 @@ LoongArchMCAsmInfo::LoongArchMCAsmInfo(const Triple &TT) { ZeroDirective = "\t.space\t"; CommentString = "#"; SupportsDebugInformation = true; + DwarfRegNumForCFI = true; ExceptionsType = ExceptionHandling::DwarfCFI; } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp index 6b78b31c9b33cd..aa576abff97577 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp @@ -17,6 +17,7 @@ #include "TargetInfo/LoongArchTargetInfo.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -73,6 +74,31 @@ static MCInstPrinter *createLoongArchMCInstPrinter(const Triple &T, return new LoongArchInstPrinter(MAI, MII, MRI); } +namespace { + +class LoongArchMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit LoongArchMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} + + bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target) const override { + unsigned NumOps = Inst.getNumOperands(); + if (isBranch(Inst) || Inst.getOpcode() == LoongArch::BL) { + Target = Addr + Inst.getOperand(NumOps - 1).getImm(); + return true; + } + + return false; + } +}; + +} // end anonymous namespace + +static MCInstrAnalysis *createLoongArchInstrAnalysis(const MCInstrInfo *Info) { + return new LoongArchMCInstrAnalysis(Info); +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTargetMC() { for (Target *T : {&getTheLoongArch32Target(), &getTheLoongArch64Target()}) { TargetRegistry::RegisterMCRegInfo(*T, createLoongArchMCRegisterInfo); @@ -82,5 +108,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTargetMC() { TargetRegistry::RegisterMCCodeEmitter(*T, createLoongArchMCCodeEmitter); TargetRegistry::RegisterMCAsmBackend(*T, createLoongArchAsmBackend); TargetRegistry::RegisterMCInstPrinter(*T, createLoongArchMCInstPrinter); + TargetRegistry::RegisterMCInstrAnalysis(*T, createLoongArchInstrAnalysis); } } diff --git a/llvm/test/MC/LoongArch/Basic/Integer/arith.s b/llvm/test/MC/LoongArch/Basic/Integer/arith.s new file mode 100644 index 00000000000000..104b01fba19a0f --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/arith.s @@ -0,0 +1,208 @@ +## Test valid arithmetic operation instructions + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK64-ASM %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM: add.w $a5, $ra, $s8 +# CHECK-ASM: encoding: [0x29,0x7c,0x10,0x00] +add.w $a5, $ra, $s8 + +# CHECK-ASM: sub.w $r21, $s2, $t7 +# CHECK-ASM: encoding: [0x35,0x4f,0x11,0x00] +sub.w $r21, $s2, $t7 + +# CHECK-ASM: addi.w $a1, $a3, 246 +# CHECK-ASM: encoding: [0xe5,0xd8,0x83,0x02] +addi.w $a1, $a3, 246 + +# CHECK-ASM: alsl.w $tp, $t5, $tp, 4 +# CHECK-ASM: encoding: [0x22,0x8a,0x05,0x00] +alsl.w $tp, $t5, $tp, 4 + +# CHECK-ASM: lu12i.w $t4, 49 +# CHECK-ASM: encoding: [0x30,0x06,0x00,0x14] +lu12i.w $t4, 49 + +# CHECK-ASM: lu12i.w $a0, -1 +# CHECK-ASM: encoding: [0xe4,0xff,0xff,0x15] +lu12i.w $a0, -1 + +# CHECK-ASM: slt $s6, $s3, $tp +# CHECK-ASM: encoding: [0x5d,0x0b,0x12,0x00] +slt $s6, $s3, $tp + +# CHECK-ASM: sltu $a7, $r21, $s6 +# CHECK-ASM: encoding: [0xab,0xf6,0x12,0x00] +sltu $a7, $r21, $s6 + +# CHECK-ASM: slti $s4, $ra, 235 +# CHECK-ASM: encoding: [0x3b,0xac,0x03,0x02] +slti $s4, $ra, 235 + +# CHECK-ASM: sltui $zero, $a4, 162 +# CHECK-ASM: encoding: [0x00,0x89,0x42,0x02] +sltui $zero, $a4, 162 + +# CHECK-ASM: pcaddi $a5, 187 +# CHECK-ASM: encoding: [0x69,0x17,0x00,0x18] +pcaddi $a5, 187 + +# CHECK-ASM: pcaddu12i $zero, 37 +# CHECK-ASM: encoding: [0xa0,0x04,0x00,0x1c] +pcaddu12i $zero, 37 + +# CHECK-ASM: pcalau12i $a6, 89 +# CHECK-ASM: encoding: [0x2a,0x0b,0x00,0x1a] +pcalau12i $a6, 89 + +# CHECK-ASM: and $t7, $s8, $ra +# CHECK-ASM: encoding: [0xf3,0x87,0x14,0x00] +and $t7, $s8, $ra + +# CHECK-ASM: or $t5, $t4, $s7 +# CHECK-ASM: encoding: [0x11,0x7a,0x15,0x00] +or $t5, $t4, $s7 + +# CHECK-ASM: nor $a1, $t6, $a1 +# CHECK-ASM: encoding: [0x45,0x16,0x14,0x00] +nor $a1, $t6, $a1 + +# CHECK-ASM: xor $t3, $t7, $a4 +# CHECK-ASM: encoding: [0x6f,0xa2,0x15,0x00] +xor $t3, $t7, $a4 + +# CHECK-ASM: andn $s5, $s2, $a1 +# CHECK-ASM: encoding: [0x3c,0x97,0x16,0x00] +andn $s5, $s2, $a1 + +# CHECK-ASM: orn $tp, $sp, $s2 +# CHECK-ASM: encoding: [0x62,0x64,0x16,0x00] +orn $tp, $sp, $s2 + +# CHECK-ASM: andi $s2, $zero, 106 +# CHECK-ASM: encoding: [0x19,0xa8,0x41,0x03] +andi $s2, $zero, 106 + +# CHECK-ASM: ori $t5, $a1, 47 +# CHECK-ASM: encoding: [0xb1,0xbc,0x80,0x03] +ori $t5, $a1, 47 + +# CHECK-ASM: xori $t6, $s0, 99 +# CHECK-ASM: encoding: [0xf2,0x8e,0xc1,0x03] +xori $t6, $s0, 99 + +# CHECK-ASM: mul.w $a0, $t6, $sp +# CHECK-ASM: encoding: [0x44,0x0e,0x1c,0x00] +mul.w $a0, $t6, $sp + +# CHECK-ASM: mulh.w $s4, $s0, $zero +# CHECK-ASM: encoding: [0xfb,0x82,0x1c,0x00] +mulh.w $s4, $s0, $zero + +# CHECK-ASM: mulh.wu $a6, $t5, $s1 +# CHECK-ASM: encoding: [0x2a,0x62,0x1d,0x00] +mulh.wu $a6, $t5, $s1 + +# CHECK-ASM: div.w $s7, $t1, $s2 +# CHECK-ASM: encoding: [0xbe,0x65,0x20,0x00] +div.w $s7, $t1, $s2 + +# CHECK-ASM: mod.w $ra, $s3, $a6 +# CHECK-ASM: encoding: [0x41,0xab,0x20,0x00] +mod.w $ra, $s3, $a6 + +# CHECK-ASM: div.wu $t7, $s0, $zero +# CHECK-ASM: encoding: [0xf3,0x02,0x21,0x00] +div.wu $t7, $s0, $zero + +# CHECK-ASM: mod.wu $s4, $a5, $t5 +# CHECK-ASM: encoding: [0x3b,0xc5,0x21,0x00] +mod.wu $s4, $a5, $t5 + + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM: add.d $tp, $t6, $s4 +# CHECK64-ASM: encoding: [0x42,0xee,0x10,0x00] +add.d $tp, $t6, $s4 + +# CHECK64-ASM: sub.d $a3, $t0, $a3 +# CHECK64-ASM: encoding: [0x87,0x9d,0x11,0x00] +sub.d $a3, $t0, $a3 + +# CHECK64-ASM: addi.d $s5, $a2, 75 +# CHECK64-ASM: encoding: [0xdc,0x2c,0xc1,0x02] +addi.d $s5, $a2, 75 + +# CHECK64-ASM: addu16i.d $a5, $s0, 23 +# CHECK64-ASM: encoding: [0xe9,0x5e,0x00,0x10] +addu16i.d $a5, $s0, 23 + +# CHECK64-ASM: alsl.wu $t7, $a4, $s2, 1 +# CHECK64-ASM: encoding: [0x13,0x65,0x06,0x00] +alsl.wu $t7, $a4, $s2, 1 + +# CHECK64-ASM: alsl.d $t5, $a7, $a1, 3 +# CHECK64-ASM: encoding: [0x71,0x15,0x2d,0x00] +alsl.d $t5, $a7, $a1, 3 + +# CHECK64-ASM: lu32i.d $sp, 196 +# CHECK64-ASM: encoding: [0x83,0x18,0x00,0x16] +lu32i.d $sp, 196 + +# CHECK64-ASM: lu52i.d $t1, $a0, 195 +# CHECK64-ASM: encoding: [0x8d,0x0c,0x03,0x03] +lu52i.d $t1, $a0, 195 + +# CHECK64-ASM: pcaddu18i $t0, 26 +# CHECK64-ASM: encoding: [0x4c,0x03,0x00,0x1e] +pcaddu18i $t0, 26 + +# CHECK64-ASM: mul.d $ra, $t2, $s1 +# CHECK64-ASM: encoding: [0xc1,0xe1,0x1d,0x00] +mul.d $ra, $t2, $s1 + +# CHECK64-ASM: mulh.d $s5, $ra, $s4 +# CHECK64-ASM: encoding: [0x3c,0x6c,0x1e,0x00] +mulh.d $s5, $ra, $s4 + +# CHECK64-ASM: mulh.du $t1, $s4, $s6 +# CHECK64-ASM: encoding: [0x6d,0xf7,0x1e,0x00] +mulh.du $t1, $s4, $s6 + +# CHECK64-ASM: mulw.d.w $s4, $a2, $t5 +# CHECK64-ASM: encoding: [0xdb,0x44,0x1f,0x00] +mulw.d.w $s4, $a2, $t5 + +# CHECK64-ASM: mulw.d.wu $t5, $fp, $s7 +# CHECK64-ASM: encoding: [0xd1,0xfa,0x1f,0x00] +mulw.d.wu $t5, $fp, $s7 + +# CHECK64-ASM: div.d $s0, $a2, $r21 +# CHECK64-ASM: encoding: [0xd7,0x54,0x22,0x00] +div.d $s0, $a2, $r21 + +# CHECK64-ASM: mod.d $t4, $sp, $t3 +# CHECK64-ASM: encoding: [0x70,0xbc,0x22,0x00] +mod.d $t4, $sp, $t3 + +# CHECK64-ASM: div.du $s8, $s1, $t2 +# CHECK64-ASM: encoding: [0x1f,0x3b,0x23,0x00] +div.du $s8, $s1, $t2 + +# CHECK64-ASM: mod.du $s2, $s0, $s1 +# CHECK64-ASM: encoding: [0xf9,0xe2,0x23,0x00] +mod.du $s2, $s0, $s1 + +.endif + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/atomic.s b/llvm/test/MC/LoongArch/Basic/Integer/atomic.s new file mode 100644 index 00000000000000..5a3671ec9cd31c --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/atomic.s @@ -0,0 +1,181 @@ +## Test valid atomic memory access instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK64-ASM %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM: ll.w $tp, $s4, 220 +# CHECK-ASM: encoding: [0x62,0xdf,0x00,0x20] +ll.w $tp, $s4, 220 + +# CHECK-ASM: sc.w $t7, $t2, 56 +# CHECK-ASM: encoding: [0xd3,0x39,0x00,0x21] +sc.w $t7, $t2, 56 + + + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM: amswap.w $a2, $t0, $s1 +# CHECK64-ASM: encoding: [0x06,0x33,0x60,0x38] +amswap.w $a2, $t0, $s1 + +# CHECK64-ASM: amswap.d $tp, $t2, $fp +# CHECK64-ASM: encoding: [0xc2,0xba,0x60,0x38] +amswap.d $tp, $t2, $fp + +# CHECK64-ASM: amadd.w $a4, $t0, $r21 +# CHECK64-ASM: encoding: [0xa8,0x32,0x61,0x38] +amadd.w $a4, $t0, $r21 + +# CHECK64-ASM: amadd.d $a1, $t5, $s6 +# CHECK64-ASM: encoding: [0xa5,0xc7,0x61,0x38] +amadd.d $a1, $t5, $s6 + +# CHECK64-ASM: amand.w $a0, $t7, $fp +# CHECK64-ASM: encoding: [0xc4,0x4e,0x62,0x38] +amand.w $a0, $t7, $fp + +# CHECK64-ASM: amand.d $a6, $t6, $s6 +# CHECK64-ASM: encoding: [0xaa,0xcb,0x62,0x38] +amand.d $a6, $t6, $s6 + +# CHECK64-ASM: amor.w $a2, $t4, $s0 +# CHECK64-ASM: encoding: [0xe6,0x42,0x63,0x38] +amor.w $a2, $t4, $s0 + +# CHECK64-ASM: amor.d $sp, $t4, $s1 +# CHECK64-ASM: encoding: [0x03,0xc3,0x63,0x38] +amor.d $sp, $t4, $s1 + +# CHECK64-ASM: amxor.w $tp, $t3, $s0 +# CHECK64-ASM: encoding: [0xe2,0x3e,0x64,0x38] +amxor.w $tp, $t3, $s0 + +# CHECK64-ASM: amxor.d $a4, $t8, $s5 +# CHECK64-ASM: encoding: [0x88,0xd3,0x64,0x38] +amxor.d $a4, $t8, $s5 + +# CHECK64-ASM: ammax.w $ra, $a7, $s0 +# CHECK64-ASM: encoding: [0xe1,0x2e,0x65,0x38] +ammax.w $ra, $a7, $s0 + +# CHECK64-ASM: ammax.d $a5, $t8, $s4 +# CHECK64-ASM: encoding: [0x69,0xd3,0x65,0x38] +ammax.d $a5, $t8, $s4 + +# CHECK64-ASM: ammin.w $a5, $t2, $s0 +# CHECK64-ASM: encoding: [0xe9,0x3a,0x66,0x38] +ammin.w $a5, $t2, $s0 + +# CHECK64-ASM: ammin.d $a5, $t1, $fp +# CHECK64-ASM: encoding: [0xc9,0xb6,0x66,0x38] +ammin.d $a5, $t1, $fp + +# CHECK64-ASM: ammax.wu $a5, $a7, $fp +# CHECK64-ASM: encoding: [0xc9,0x2e,0x67,0x38] +ammax.wu $a5, $a7, $fp + +# CHECK64-ASM: ammax.du $a2, $t4, $s2 +# CHECK64-ASM: encoding: [0x26,0xc3,0x67,0x38] +ammax.du $a2, $t4, $s2 + +# CHECK64-ASM: ammin.wu $a4, $t6, $s7 +# CHECK64-ASM: encoding: [0xc8,0x4b,0x68,0x38] +ammin.wu $a4, $t6, $s7 + +# CHECK64-ASM: ammin.du $a3, $t4, $s2 +# CHECK64-ASM: encoding: [0x27,0xc3,0x68,0x38] +ammin.du $a3, $t4, $s2 + +# CHECK64-ASM: amswap_db.w $a2, $t0, $s1 +# CHECK64-ASM: encoding: [0x06,0x33,0x69,0x38] +amswap_db.w $a2, $t0, $s1 + +# CHECK64-ASM: amswap_db.d $tp, $t2, $fp +# CHECK64-ASM: encoding: [0xc2,0xba,0x69,0x38] +amswap_db.d $tp, $t2, $fp + +# CHECK64-ASM: amadd_db.w $a4, $t0, $r21 +# CHECK64-ASM: encoding: [0xa8,0x32,0x6a,0x38] +amadd_db.w $a4, $t0, $r21 + +# CHECK64-ASM: amadd_db.d $a1, $t5, $s6 +# CHECK64-ASM: encoding: [0xa5,0xc7,0x6a,0x38] +amadd_db.d $a1, $t5, $s6 + +# CHECK64-ASM: amand_db.w $a0, $t7, $fp +# CHECK64-ASM: encoding: [0xc4,0x4e,0x6b,0x38] +amand_db.w $a0, $t7, $fp + +# CHECK64-ASM: amand_db.d $a6, $t6, $s6 +# CHECK64-ASM: encoding: [0xaa,0xcb,0x6b,0x38] +amand_db.d $a6, $t6, $s6 + +# CHECK64-ASM: amor_db.w $a2, $t4, $s0 +# CHECK64-ASM: encoding: [0xe6,0x42,0x6c,0x38] +amor_db.w $a2, $t4, $s0 + +# CHECK64-ASM: amor_db.d $sp, $t4, $s1 +# CHECK64-ASM: encoding: [0x03,0xc3,0x6c,0x38] +amor_db.d $sp, $t4, $s1 + +# CHECK64-ASM: amxor_db.w $tp, $t3, $s0 +# CHECK64-ASM: encoding: [0xe2,0x3e,0x6d,0x38] +amxor_db.w $tp, $t3, $s0 + +# CHECK64-ASM: amxor_db.d $a4, $t8, $s5 +# CHECK64-ASM: encoding: [0x88,0xd3,0x6d,0x38] +amxor_db.d $a4, $t8, $s5 + +# CHECK64-ASM: ammax_db.w $ra, $a7, $s0 +# CHECK64-ASM: encoding: [0xe1,0x2e,0x6e,0x38] +ammax_db.w $ra, $a7, $s0 + +# CHECK64-ASM: ammax_db.d $a5, $t8, $s4 +# CHECK64-ASM: encoding: [0x69,0xd3,0x6e,0x38] +ammax_db.d $a5, $t8, $s4 + +# CHECK64-ASM: ammin_db.w $a5, $t2, $s0 +# CHECK64-ASM: encoding: [0xe9,0x3a,0x6f,0x38] +ammin_db.w $a5, $t2, $s0 + +# CHECK64-ASM: ammin_db.d $a5, $t1, $fp +# CHECK64-ASM: encoding: [0xc9,0xb6,0x6f,0x38] +ammin_db.d $a5, $t1, $fp + +# CHECK64-ASM: ammax_db.wu $a5, $a7, $fp +# CHECK64-ASM: encoding: [0xc9,0x2e,0x70,0x38] +ammax_db.wu $a5, $a7, $fp + +# CHECK64-ASM: ammax_db.du $a2, $t4, $s2 +# CHECK64-ASM: encoding: [0x26,0xc3,0x70,0x38] +ammax_db.du $a2, $t4, $s2 + +# CHECK64-ASM: ammin_db.wu $a4, $t6, $s7 +# CHECK64-ASM: encoding: [0xc8,0x4b,0x71,0x38] +ammin_db.wu $a4, $t6, $s7 + +# CHECK64-ASM: ammin_db.du $a3, $t4, $s2 +# CHECK64-ASM: encoding: [0x27,0xc3,0x71,0x38] +ammin_db.du $a3, $t4, $s2 + +# CHECK64-ASM: ll.d $s2, $s4, 16 +# CHECK64-ASM: encoding: [0x79,0x13,0x00,0x22] +ll.d $s2, $s4, 16 + +# CHECK64-ASM: sc.d $t5, $t5, 244 +# CHECK64-ASM: encoding: [0x31,0xf6,0x00,0x23] +sc.d $t5, $t5, 244 + +.endif + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/barrier.s b/llvm/test/MC/LoongArch/Basic/Integer/barrier.s new file mode 100644 index 00000000000000..077ada583b70f1 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/barrier.s @@ -0,0 +1,15 @@ +## Test valid barrier instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s + +# CHECK-ASM: dbar 0 +# CHECK-ASM: encoding: [0x00,0x00,0x72,0x38] +dbar 0 + +# CHECK-ASM: ibar 0 +# CHECK-ASM: encoding: [0x00,0x80,0x72,0x38] +ibar 0 + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/bit-manipu.s b/llvm/test/MC/LoongArch/Basic/Integer/bit-manipu.s new file mode 100644 index 00000000000000..d3604b4d8676e0 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/bit-manipu.s @@ -0,0 +1,132 @@ +## Test valid bit manipulation instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK64-ASM %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM: ext.w.b $t8, $t6 +# CHECK-ASM: encoding: [0x54,0x5e,0x00,0x00] +ext.w.b $t8, $t6 + +# CHECK-ASM: ext.w.h $s0, $s0 +# CHECK-ASM: encoding: [0xf7,0x5a,0x00,0x00] +ext.w.h $s0, $s0 + +# CHECK-ASM: clo.w $ra, $sp +# CHECK-ASM: encoding: [0x61,0x10,0x00,0x00] +clo.w $ra, $sp + +# CHECK-ASM: clz.w $a3, $a6 +# CHECK-ASM: encoding: [0x47,0x15,0x00,0x00] +clz.w $a3, $a6 + +# CHECK-ASM: cto.w $tp, $a2 +# CHECK-ASM: encoding: [0xc2,0x18,0x00,0x00] +cto.w $tp, $a2 + +# CHECK-ASM: ctz.w $a1, $fp +# CHECK-ASM: encoding: [0xc5,0x1e,0x00,0x00] +ctz.w $a1, $fp + +# CHECK-ASM: bytepick.w $s6, $zero, $t4, 0 +# CHECK-ASM: encoding: [0x1d,0x40,0x08,0x00] +bytepick.w $s6, $zero, $t4, 0 + +# CHECK-ASM: revb.2h $t8, $a7 +# CHECK-ASM: encoding: [0x74,0x31,0x00,0x00] +revb.2h $t8, $a7 + +# CHECK-ASM: bitrev.4b $r21, $s4 +# CHECK-ASM: encoding: [0x75,0x4b,0x00,0x00] +bitrev.4b $r21, $s4 + +# CHECK-ASM: bitrev.w $s2, $a1 +# CHECK-ASM: encoding: [0xb9,0x50,0x00,0x00] +bitrev.w $s2, $a1 + +# CHECK-ASM: bstrins.w $a4, $a7, 7, 2 +# CHECK-ASM: encoding: [0x68,0x09,0x67,0x00] +bstrins.w $a4, $a7, 7, 2 + +# CHECK-ASM: bstrpick.w $ra, $a5, 10, 4 +# CHECK-ASM: encoding: [0x21,0x91,0x6a,0x00] +bstrpick.w $ra, $a5, 10, 4 + +# CHECK-ASM: maskeqz $t8, $a7, $t6 +# CHECK-ASM: encoding: [0x74,0x49,0x13,0x00] +maskeqz $t8, $a7, $t6 + +# CHECK-ASM: masknez $t8, $t1, $s3 +# CHECK-ASM: encoding: [0xb4,0xe9,0x13,0x00] +masknez $t8, $t1, $s3 + + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM: clo.d $s6, $ra +# CHECK64-ASM: encoding: [0x3d,0x20,0x00,0x00] +clo.d $s6, $ra + +# CHECK64-ASM: clz.d $s3, $s3 +# CHECK64-ASM: encoding: [0x5a,0x27,0x00,0x00] +clz.d $s3, $s3 + +# CHECK64-ASM: cto.d $t6, $t8 +# CHECK64-ASM: encoding: [0x92,0x2a,0x00,0x00] +cto.d $t6, $t8 + +# CHECK64-ASM: ctz.d $t5, $a6 +# CHECK64-ASM: encoding: [0x51,0x2d,0x00,0x00] +ctz.d $t5, $a6 + +# CHECK64-ASM: bytepick.d $t3, $t5, $t8, 4 +# CHECK64-ASM: encoding: [0x2f,0x52,0x0e,0x00] +bytepick.d $t3, $t5, $t8, 4 + +# CHECK64-ASM: revb.4h $t1, $t7 +# CHECK64-ASM: encoding: [0x6d,0x36,0x00,0x00] +revb.4h $t1, $t7 + +# CHECK64-ASM: revb.2w $s5, $s4 +# CHECK64-ASM: encoding: [0x7c,0x3b,0x00,0x00] +revb.2w $s5, $s4 + +# CHECK64-ASM: revb.d $zero, $s0 +# CHECK64-ASM: encoding: [0xe0,0x3e,0x00,0x00] +revb.d $zero, $s0 + +# CHECK64-ASM: revh.2w $s5, $a6 +# CHECK64-ASM: encoding: [0x5c,0x41,0x00,0x00] +revh.2w $s5, $a6 + +# CHECK64-ASM: revh.d $a5, $a3 +# CHECK64-ASM: encoding: [0xe9,0x44,0x00,0x00] +revh.d $a5, $a3 + +# CHECK64-ASM: bitrev.8b $t1, $s2 +# CHECK64-ASM: encoding: [0x2d,0x4f,0x00,0x00] +bitrev.8b $t1, $s2 + +# CHECK64-ASM: bitrev.d $t7, $s0 +# CHECK64-ASM: encoding: [0xf3,0x56,0x00,0x00] +bitrev.d $t7, $s0 + +# CHECK64-ASM: bstrins.d $a4, $a7, 7, 2 +# CHECK64-ASM: encoding: [0x68,0x09,0x87,0x00] +bstrins.d $a4, $a7, 7, 2 + +# CHECK64-ASM: bstrpick.d $s8, $s4, 39, 22 +# CHECK64-ASM: encoding: [0x7f,0x5b,0xe7,0x00] +bstrpick.d $s8, $s4, 39, 22 + +.endif + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/bit-shift.s b/llvm/test/MC/LoongArch/Basic/Integer/bit-shift.s new file mode 100644 index 00000000000000..2646245bcd7405 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/bit-shift.s @@ -0,0 +1,84 @@ +## Test valid bit shift instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK64-ASM %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM: sll.w $s1, $s4, $s0 +# CHECK-ASM: encoding: [0x78,0x5f,0x17,0x00] +sll.w $s1, $s4, $s0 + +# CHECK-ASM: srl.w $s8, $t5, $a3 +# CHECK-ASM: encoding: [0x3f,0x9e,0x17,0x00] +srl.w $s8, $t5, $a3 + +# CHECK-ASM: sra.w $t0, $s5, $a6 +# CHECK-ASM: encoding: [0x8c,0x2b,0x18,0x00] +sra.w $t0, $s5, $a6 + +# CHECK-ASM: rotr.w $ra, $s3, $t6 +# CHECK-ASM: encoding: [0x41,0x4b,0x1b,0x00] +rotr.w $ra, $s3, $t6 + +# CHECK-ASM: slli.w $s3, $t6, 0 +# CHECK-ASM: encoding: [0x5a,0x82,0x40,0x00] +slli.w $s3, $t6, 0 + +# CHECK-ASM: srli.w $a6, $t2, 30 +# CHECK-ASM: encoding: [0xca,0xf9,0x44,0x00] +srli.w $a6, $t2, 30 + +# CHECK-ASM: srai.w $a4, $t5, 24 +# CHECK-ASM: encoding: [0x28,0xe2,0x48,0x00] +srai.w $a4, $t5, 24 + +# CHECK-ASM: rotri.w $s0, $t8, 23 +# CHECK-ASM: encoding: [0x97,0xde,0x4c,0x00] +rotri.w $s0, $t8, 23 + + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM: sll.d $t8, $t3, $sp +# CHECK64-ASM: encoding: [0xf4,0x8d,0x18,0x00] +sll.d $t8, $t3, $sp + +# CHECK64-ASM: srl.d $t2, $s2, $zero +# CHECK64-ASM: encoding: [0x2e,0x03,0x19,0x00] +srl.d $t2, $s2, $zero + +# CHECK64-ASM: sra.d $a3, $fp, $s8 +# CHECK64-ASM: encoding: [0xc7,0xfe,0x19,0x00] +sra.d $a3, $fp, $s8 + +# CHECK64-ASM: rotr.d $s8, $sp, $ra +# CHECK64-ASM: encoding: [0x7f,0x84,0x1b,0x00] +rotr.d $s8, $sp, $ra + +# CHECK64-ASM: slli.d $a6, $s8, 39 +# CHECK64-ASM: encoding: [0xea,0x9f,0x41,0x00] +slli.d $a6, $s8, 39 + +# CHECK64-ASM: srli.d $s8, $fp, 38 +# CHECK64-ASM: encoding: [0xdf,0x9a,0x45,0x00] +srli.d $s8, $fp, 38 + +# CHECK64-ASM: srai.d $a5, $r21, 27 +# CHECK64-ASM: encoding: [0xa9,0x6e,0x49,0x00] +srai.d $a5, $r21, 27 + +# CHECK64-ASM: rotri.d $s6, $zero, 7 +# CHECK64-ASM: encoding: [0x1d,0x1c,0x4d,0x00] +rotri.d $s6, $zero, 7 + +.endif + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/bound-check.s b/llvm/test/MC/LoongArch/Basic/Integer/bound-check.s new file mode 100644 index 00000000000000..0d914dd737e7ec --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/bound-check.s @@ -0,0 +1,69 @@ +## Test valid boundary check memory access instructions. + +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s + +# CHECK-ASM: ldgt.b $a2, $a2, $s6 +# CHECK-ASM: encoding: [0xc6,0x74,0x78,0x38] +ldgt.b $a2, $a2, $s6 + +# CHECK-ASM: ldgt.h $a1, $s8, $ra +# CHECK-ASM: encoding: [0xe5,0x87,0x78,0x38] +ldgt.h $a1, $s8, $ra + +# CHECK-ASM: ldgt.w $t3, $s3, $a4 +# CHECK-ASM: encoding: [0x4f,0x23,0x79,0x38] +ldgt.w $t3, $s3, $a4 + +# CHECK-ASM: ldgt.d $s0, $s2, $s8 +# CHECK-ASM: encoding: [0x37,0xff,0x79,0x38] +ldgt.d $s0, $s2, $s8 + +# CHECK-ASM: ldle.b $a5, $t0, $t3 +# CHECK-ASM: encoding: [0x89,0x3d,0x7a,0x38] +ldle.b $a5, $t0, $t3 + +# CHECK-ASM: ldle.h $a7, $a7, $s0 +# CHECK-ASM: encoding: [0x6b,0xdd,0x7a,0x38] +ldle.h $a7, $a7, $s0 + +# CHECK-ASM: ldle.w $s1, $tp, $tp +# CHECK-ASM: encoding: [0x58,0x08,0x7b,0x38] +ldle.w $s1, $tp, $tp + +# CHECK-ASM: ldle.d $t8, $t3, $t4 +# CHECK-ASM: encoding: [0xf4,0xc1,0x7b,0x38] +ldle.d $t8, $t3, $t4 + +# CHECK-ASM: stgt.b $s4, $t7, $t8 +# CHECK-ASM: encoding: [0x7b,0x52,0x7c,0x38] +stgt.b $s4, $t7, $t8 + +# CHECK-ASM: stgt.h $t4, $a0, $a2 +# CHECK-ASM: encoding: [0x90,0x98,0x7c,0x38] +stgt.h $t4, $a0, $a2 + +# CHECK-ASM: stgt.w $s8, $s5, $t2 +# CHECK-ASM: encoding: [0x9f,0x3b,0x7d,0x38] +stgt.w $s8, $s5, $t2 + +# CHECK-ASM: stgt.d $s7, $r21, $s1 +# CHECK-ASM: encoding: [0xbe,0xe2,0x7d,0x38] +stgt.d $s7, $r21, $s1 + +# CHECK-ASM: stle.b $a6, $a0, $t4 +# CHECK-ASM: encoding: [0x8a,0x40,0x7e,0x38] +stle.b $a6, $a0, $t4 + +# CHECK-ASM: stle.h $t5, $t5, $r21 +# CHECK-ASM: encoding: [0x31,0xd6,0x7e,0x38] +stle.h $t5, $t5, $r21 + +# CHECK-ASM: stle.w $s0, $s5, $s6 +# CHECK-ASM: encoding: [0x97,0x77,0x7f,0x38] +stle.w $s0, $s5, $s6 + +# CHECK-ASM: stle.d $s2, $s1, $s6 +# CHECK-ASM: encoding: [0x19,0xf7,0x7f,0x38] +stle.d $s2, $s1, $s6 + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/branch.s b/llvm/test/MC/LoongArch/Basic/Integer/branch.s new file mode 100644 index 00000000000000..8e4fb3d11fe798 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/branch.s @@ -0,0 +1,51 @@ +## Test valid branch instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s + +# CHECK-ASM: beq $a6, $a3, 176 +# CHECK-ASM: encoding: [0x47,0xb1,0x00,0x58] +beq $a6, $a3, 176 + +# CHECK-ASM: bne $s2, $ra, 136 +# CHECK-ASM: encoding: [0x21,0x8b,0x00,0x5c] +bne $s2, $ra, 136 + +# CHECK-ASM: blt $t3, $s7, 168 +# CHECK-ASM: encoding: [0xfe,0xa9,0x00,0x60] +blt $t3, $s7, 168 + +# CHECK-ASM: bge $t0, $t3, 148 +# CHECK-ASM: encoding: [0x8f,0x95,0x00,0x64] +bge $t0, $t3, 148 + +# CHECK-ASM: bltu $t5, $a1, 4 +# CHECK-ASM: encoding: [0x25,0x06,0x00,0x68] +bltu $t5, $a1, 4 + +# CHECK-ASM: bgeu $a2, $s0, 140 +# CHECK-ASM: encoding: [0xd7,0x8c,0x00,0x6c] +bgeu $a2, $s0, 140 + +# CHECK-ASM: beqz $a5, 96 +# CHECK-ASM: encoding: [0x20,0x61,0x00,0x40] +beqz $a5, 96 + +# CHECK-ASM: bnez $sp, 212 +# CHECK-ASM: encoding: [0x60,0xd4,0x00,0x44] +bnez $sp, 212 + +# CHECK-ASM: b 248 +# CHECK-ASM: encoding: [0x00,0xf8,0x00,0x50] +b 248 + +# CHECK-ASM: bl 236 +# CHECK-ASM: encoding: [0x00,0xec,0x00,0x54] +bl 236 + +# CHECK-ASM: jirl $ra, $a0, 4 +# CHECK-ASM: encoding: [0x81,0x04,0x00,0x4c] +jirl $ra, $a0, 4 + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/crc.s b/llvm/test/MC/LoongArch/Basic/Integer/crc.s new file mode 100644 index 00000000000000..06ccdd93ee31c4 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/crc.s @@ -0,0 +1,37 @@ +## Test valid CRC check instructions. + +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s + +# CHECK-ASM: crc.w.b.w $s1, $a3, $tp +# CHECK-ASM: encoding: [0xf8,0x08,0x24,0x00] +crc.w.b.w $s1, $a3, $tp + +# CHECK-ASM: crc.w.h.w $s8, $a6, $t6 +# CHECK-ASM: encoding: [0x5f,0xc9,0x24,0x00] +crc.w.h.w $s8, $a6, $t6 + +# CHECK-ASM: crc.w.w.w $s5, $a2, $a6 +# CHECK-ASM: encoding: [0xdc,0x28,0x25,0x00] +crc.w.w.w $s5, $a2, $a6 + +# CHECK-ASM: crc.w.d.w $s5, $a7, $s8 +# CHECK-ASM: encoding: [0x7c,0xfd,0x25,0x00] +crc.w.d.w $s5, $a7, $s8 + +# CHECK-ASM: crcc.w.b.w $t3, $t6, $sp +# CHECK-ASM: encoding: [0x4f,0x0e,0x26,0x00] +crcc.w.b.w $t3, $t6, $sp + +# CHECK-ASM: crcc.w.h.w $r21, $s6, $t6 +# CHECK-ASM: encoding: [0xb5,0xcb,0x26,0x00] +crcc.w.h.w $r21, $s6, $t6 + +# CHECK-ASM: crcc.w.w.w $t5, $t2, $t1 +# CHECK-ASM: encoding: [0xd1,0x35,0x27,0x00] +crcc.w.w.w $t5, $t2, $t1 + +# CHECK-ASM: crcc.w.d.w $s7, $r21, $s4 +# CHECK-ASM: encoding: [0xbe,0xee,0x27,0x00] +crcc.w.d.w $s7, $r21, $s4 + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/invalid.s b/llvm/test/MC/LoongArch/Basic/Integer/invalid.s new file mode 100644 index 00000000000000..cb6b2ba1beddf0 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/invalid.s @@ -0,0 +1,176 @@ +## Test invalid instructions on both loongarch32 and loongarch64 target. + +# RUN: not llvm-mc --triple=loongarch32 %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK64 +# RUN: not llvm-mc --triple=loongarch64 %s 2>&1 --defsym=LA64=1 | FileCheck %s + +## Out of range immediates +## uimm2 +bytepick.w $a0, $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:27: error: immediate must be an integer in the range [0, 3] +bytepick.w $a0, $a0, $a0, 4 +# CHECK: :[[#@LINE-1]]:27: error: immediate must be an integer in the range [0, 3] + +## uimm2_plus1 +alsl.w $a0, $a0, $a0, 0 +# CHECK: :[[#@LINE-1]]:23: error: immediate must be an integer in the range [1, 4] +alsl.w $a0, $a0, $a0, 5 +# CHECK: :[[#@LINE-1]]:23: error: immediate must be an integer in the range [1, 4] + +## uimm5 +slli.w $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [0, 31] +srli.w $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [0, 31] +srai.w $a0, $a0, 32 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [0, 31] +rotri.w $a0, $a0, 32 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be an integer in the range [0, 31] +bstrins.w $a0, $a0, 31, -1 +# CHECK: :[[#@LINE-1]]:25: error: immediate must be an integer in the range [0, 31] +bstrpick.w $a0, $a0, 32, 0 +# CHECK: :[[#@LINE-1]]:22: error: immediate must be an integer in the range [0, 31] +preld -1, $a0, 0 +# CHECK: :[[#@LINE-1]]:7: error: immediate must be an integer in the range [0, 31] +preld 32, $a0, 0 +# CHECK: :[[#@LINE-1]]:7: error: immediate must be an integer in the range [0, 31] + +## uimm12 +andi $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [0, 4095] +ori $a0, $a0, 4096 +# CHECK: :[[#@LINE-1]]:15: error: immediate must be an integer in the range [0, 4095] +xori $a0, $a0, 4096 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [0, 4095] + +## simm12 +addi.w $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [-2048, 2047] +slti $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] +sltui $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047] +preld 0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:15: error: immediate must be an integer in the range [-2048, 2047] +ld.b $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] +ld.h $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] +ld.w $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] +ld.bu $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047] +ld.hu $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047] +st.b $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] +st.h $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] +st.w $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] + +## simm14_lsl2 +ll.w $a0, $a0, -32772 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-32768, 32764] +ll.w $a0, $a0, -32769 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-32768, 32764] +sc.w $a0, $a0, 32767 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-32768, 32764] +sc.w $a0, $a0, 32768 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-32768, 32764] + +## simm16_lsl2 +beq $a0, $a0, -0x20004 +# CHECK: :[[#@LINE-1]]:15: error: immediate must be a multiple of 4 in the range [-131072, 131068] +bne $a0, $a0, -0x20004 +# CHECK: :[[#@LINE-1]]:15: error: immediate must be a multiple of 4 in the range [-131072, 131068] +blt $a0, $a0, -0x1FFFF +# CHECK: :[[#@LINE-1]]:15: error: immediate must be a multiple of 4 in the range [-131072, 131068] +bge $a0, $a0, -0x1FFFF +# CHECK: :[[#@LINE-1]]:15: error: immediate must be a multiple of 4 in the range [-131072, 131068] +bltu $a0, $a0, 0x1FFFF +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-131072, 131068] +bgeu $a0, $a0, 0x1FFFF +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-131072, 131068] +jirl $a0, $a0, 0x20000 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-131072, 131068] + +## simm20 +lu12i.w $a0, -0x80001 +# CHECK: :[[#@LINE-1]]:14: error: immediate must be an integer in the range [-524288, 524287] +pcaddi $a0, -0x80001 +# CHECK: :[[#@LINE-1]]:13: error: immediate must be an integer in the range [-524288, 524287] +pcaddu12i $a0, 0x80000 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287] +pcalau12i $a0, 0x80000 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287] + +## simm21_lsl2 +beqz $a0, -0x400001 +# CHECK: :[[#@LINE-1]]:11: error: immediate must be a multiple of 4 in the range [-4194304, 4194300] +bnez $a0, -0x3FFFFF +# CHECK: :[[#@LINE-1]]:11: error: immediate must be a multiple of 4 in the range [-4194304, 4194300] +beqz $a0, 0x3FFFFF +# CHECK: :[[#@LINE-1]]:11: error: immediate must be a multiple of 4 in the range [-4194304, 4194300] +bnez $a0, 0x400000 +# CHECK: :[[#@LINE-1]]:11: error: immediate must be a multiple of 4 in the range [-4194304, 4194300] + +## simm26_lsl2 +b -0x8000001 +# CHECK: :[[#@LINE-1]]:3: error: immediate must be a multiple of 4 in the range [-134217728, 134217724] +b 0x1 +# CHECK: :[[#@LINE-1]]:3: error: immediate must be a multiple of 4 in the range [-134217728, 134217724] +bl 0x7FFFFFF +# CHECK: :[[#@LINE-1]]:4: error: immediate must be a multiple of 4 in the range [-134217728, 134217724] +bl 0x8000000 +# CHECK: :[[#@LINE-1]]:4: error: immediate must be a multiple of 4 in the range [-134217728, 134217724] + +## Invalid mnemonics +nori $a0, $a0, 0 +# CHECK: :[[#@LINE-1]]:1: error: unrecognized instruction mnemonic +andni $a0, $a0, 0 +# CHECK: :[[#@LINE-1]]:1: error: unrecognized instruction mnemonic +orni $a0, $a0, 0 +# CHECK: :[[#@LINE-1]]:1: error: unrecognized instruction mnemonic + +## Invalid register names +add.w $foo, $a0, $a0 +# CHECK: :[[#@LINE-1]]:8: error: invalid operand for instruction +sub.w $a8, $a0, $a0 +# CHECK: :[[#@LINE-1]]:8: error: invalid operand for instruction +addi.w $x0, $a0, 0 +# CHECK: :[[#@LINE-1]]:9: error: invalid operand for instruction +alsl.w $t9, $a0, $a0, 1 +# CHECK: :[[#@LINE-1]]:9: error: invalid operand for instruction +lu12i.w $s10, 0 +# CHECK: :[[#@LINE-1]]:10: error: invalid operand for instruction + +.ifndef LA64 +## LoongArch64 mnemonics +add.d $a0, $a0, $a0 +# CHECK64: :[[#@LINE-1]]:1: error: instruction requires the following: LA64 Basic Integer and Privilege Instruction Set +addi.d $a0, $a0, 0 +# CHECK64: :[[#@LINE-1]]:1: error: instruction requires the following: LA64 Basic Integer and Privilege Instruction Set +.endif + +## Invalid operand types +slt $a0, $a0, 0 +# CHECK: :[[#@LINE-1]]:15: error: invalid operand for instruction +slti $a0, 0, 0 +# CHECK: :[[#@LINE-1]]:11: error: invalid operand for instruction + +## Too many operands +andi $a0, $a0, 0, 0 +# CHECK: :[[#@LINE-1]]:19: error: invalid operand for instruction + +## Too few operands +and $a0, $a0 +# CHECK: :[[#@LINE-1]]:1: error: too few operands for instruction +andi $a0, $a0 +# CHECK: :[[#@LINE-1]]:1: error: too few operands for instruction + +## Instructions outside the base ISA +## TODO: Test instructions in LSX/LASX/LBT/LVZ after their introduction. + +## Using floating point registers when integer registers are expected +sll.w $a0, $a0, $fa0 +# CHECK: :[[#@LINE-1]]:18: error: invalid operand for instruction diff --git a/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s b/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s new file mode 100644 index 00000000000000..e5249f04f4920a --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s @@ -0,0 +1,66 @@ +## Test invalid instructions on loongarch64 target. + +# RUN: not llvm-mc --triple=loongarch64 %s 2>&1 | FileCheck %s + +## Out of range immediates +## uimm2_plus1 +alsl.wu $a0, $a0, $a0, 0 +# CHECK: :[[#@LINE-1]]:24: error: immediate must be an integer in the range [1, 4] +alsl.d $a0, $a0, $a0, 5 +# CHECK: :[[#@LINE-1]]:23: error: immediate must be an integer in the range [1, 4] + +## uimm3 +bytepick.d $a0, $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:27: error: immediate must be an integer in the range [0, 7] +bytepick.d $a0, $a0, $a0, 8 +# CHECK: :[[#@LINE-1]]:27: error: immediate must be an integer in the range [0, 7] + +## uimm6 +slli.d $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [0, 63] +srli.d $a0, $a0, -1 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [0, 63] +srai.d $a0, $a0, 64 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [0, 63] +rotri.d $a0, $a0, 64 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be an integer in the range [0, 63] +bstrins.d $a0, $a0, 63, -1 +# CHECK: :[[#@LINE-1]]:25: error: immediate must be an integer in the range [0, 63] +bstrpick.d $a0, $a0, 64, 0 +# CHECK: :[[#@LINE-1]]:22: error: immediate must be an integer in the range [0, 63] + +## simm12 +addi.d $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:18: error: immediate must be an integer in the range [-2048, 2047] +lu52i.d $a0, $a0, -2049 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be an integer in the range [-2048, 2047] +ld.wu $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:17: error: immediate must be an integer in the range [-2048, 2047] +st.d $a0, $a0, 2048 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-2048, 2047] + +## simm14_lsl2 +ldptr.w $a0, $a0, -32772 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be a multiple of 4 in the range [-32768, 32764] +ldptr.d $a0, $a0, -32772 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be a multiple of 4 in the range [-32768, 32764] +stptr.w $a0, $a0, -32769 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be a multiple of 4 in the range [-32768, 32764] +stptr.d $a0, $a0, -32769 +# CHECK: :[[#@LINE-1]]:19: error: immediate must be a multiple of 4 in the range [-32768, 32764] +ll.w $a0, $a0, 32767 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-32768, 32764] +sc.w $a0, $a0, 32768 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be a multiple of 4 in the range [-32768, 32764] + +## simm16 +addu16i.d $a0, $a0, -32769 +# CHECK: :[[#@LINE-1]]:21: error: immediate must be an integer in the range [-32768, 32767] +addu16i.d $a0, $a0, 32768 +# CHECK: :[[#@LINE-1]]:21: error: immediate must be an integer in the range [-32768, 32767] + +## simm20 +lu32i.d $a0, -0x80001 +# CHECK: :[[#@LINE-1]]:14: error: immediate must be an integer in the range [-524288, 524287] +pcaddu18i $a0, 0x80000 +# CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287] diff --git a/llvm/test/MC/LoongArch/Basic/Integer/memory.s b/llvm/test/MC/LoongArch/Basic/Integer/memory.s new file mode 100644 index 00000000000000..75225f7ac9a2d2 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/memory.s @@ -0,0 +1,124 @@ +## Test valid memory access instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK64-ASM %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM: ld.b $s1, $a4, 21 +# CHECK-ASM: encoding: [0x18,0x55,0x00,0x28] +ld.b $s1, $a4, 21 + +# CHECK-ASM: ld.h $a3, $t6, 80 +# CHECK-ASM: encoding: [0x47,0x42,0x41,0x28] +ld.h $a3, $t6, 80 + +# CHECK-ASM: ld.w $t6, $s3, 92 +# CHECK-ASM: encoding: [0x52,0x73,0x81,0x28] +ld.w $t6, $s3, 92 + +# CHECK-ASM: ld.bu $t1, $t1, 150 +# CHECK-ASM: encoding: [0xad,0x59,0x02,0x2a] +ld.bu $t1, $t1, 150 + +# CHECK-ASM: ld.hu $t6, $s6, 198 +# CHECK-ASM: encoding: [0xb2,0x1b,0x43,0x2a] +ld.hu $t6, $s6, 198 + +# CHECK-ASM: st.b $sp, $a3, 95 +# CHECK-ASM: encoding: [0xe3,0x7c,0x01,0x29] +st.b $sp, $a3, 95 + +# CHECK-ASM: st.h $s2, $t4, 122 +# CHECK-ASM: encoding: [0x19,0xea,0x41,0x29] +st.h $s2, $t4, 122 + +# CHECK-ASM: st.w $t1, $t1, 175 +# CHECK-ASM: encoding: [0xad,0xbd,0x82,0x29] +st.w $t1, $t1, 175 + +# CHECK-ASM: preld 10, $zero, 23 +# CHECK-ASM: encoding: [0x0a,0x5c,0xc0,0x2a] +preld 10, $zero, 23 + + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM: ld.wu $t2, $t7, 31 +# CHECK64-ASM: encoding: [0x6e,0x7e,0x80,0x2a] +ld.wu $t2, $t7, 31 + +# CHECK64-ASM: st.d $s7, $s7, 60 +# CHECK64-ASM: encoding: [0xde,0xf3,0xc0,0x29] +st.d $s7, $s7, 60 + +# CHECK64-ASM: ldx.b $s1, $ra, $tp +# CHECK64-ASM: encoding: [0x38,0x08,0x00,0x38] +ldx.b $s1, $ra, $tp + +# CHECK64-ASM: ldx.h $fp, $fp, $t5 +# CHECK64-ASM: encoding: [0xd6,0x46,0x04,0x38] +ldx.h $fp, $fp, $t5 + +# CHECK64-ASM: ldx.w $s2, $a7, $s0 +# CHECK64-ASM: encoding: [0x79,0x5d,0x08,0x38] +ldx.w $s2, $a7, $s0 + +# CHECK64-ASM: ldx.d $t6, $s0, $t8 +# CHECK64-ASM: encoding: [0xf2,0x52,0x0c,0x38] +ldx.d $t6, $s0, $t8 + +# CHECK64-ASM: ldx.bu $a7, $a5, $a5 +# CHECK64-ASM: encoding: [0x2b,0x25,0x20,0x38] +ldx.bu $a7, $a5, $a5 + +# CHECK64-ASM: ldx.hu $fp, $s0, $s4 +# CHECK64-ASM: encoding: [0xf6,0x6e,0x24,0x38] +ldx.hu $fp, $s0, $s4 + +# CHECK64-ASM: ldx.wu $a4, $s1, $s5 +# CHECK64-ASM: encoding: [0x08,0x73,0x28,0x38] +ldx.wu $a4, $s1, $s5 + +# CHECK64-ASM: stx.b $t7, $ra, $sp +# CHECK64-ASM: encoding: [0x33,0x0c,0x10,0x38] +stx.b $t7, $ra, $sp + +# CHECK64-ASM: stx.h $zero, $s5, $s3 +# CHECK64-ASM: encoding: [0x80,0x6b,0x14,0x38] +stx.h $zero, $s5, $s3 + +# CHECK64-ASM: stx.w $a3, $a0, $s8 +# CHECK64-ASM: encoding: [0x87,0x7c,0x18,0x38] +stx.w $a3, $a0, $s8 + +# CHECK64-ASM: stx.d $a3, $s8, $a6 +# CHECK64-ASM: encoding: [0xe7,0x2b,0x1c,0x38] +stx.d $a3, $s8, $a6 + +# CHECK64-ASM: ldptr.w $s3, $a2, 60 +# CHECK64-ASM: encoding: [0xda,0x3c,0x00,0x24] +ldptr.w $s3, $a2, 60 + +# CHECK64-ASM: ldptr.d $a1, $s6, 244 +# CHECK64-ASM: encoding: [0xa5,0xf7,0x00,0x26] +ldptr.d $a1, $s6, 244 + +# CHECK64-ASM: stptr.w $s5, $a1, 216 +# CHECK64-ASM: encoding: [0xbc,0xd8,0x00,0x25] +stptr.w $s5, $a1, 216 + +# CHECK64-ASM: stptr.d $t2, $s1, 196 +# CHECK64-ASM: encoding: [0x0e,0xc7,0x00,0x27] +stptr.d $t2, $s1, 196 + +.endif + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/misc.s b/llvm/test/MC/LoongArch/Basic/Integer/misc.s new file mode 100644 index 00000000000000..7ed934bd04d665 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/misc.s @@ -0,0 +1,52 @@ +## Test valid misc instructions. + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK64-ASM %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM: syscall 100 +# CHECK-ASM: encoding: [0x64,0x00,0x2b,0x00] +syscall 100 + +# CHECK-ASM: break 199 +# CHECK-ASM: encoding: [0xc7,0x00,0x2a,0x00] +break 199 + +# CHECK-ASM: rdtimel.w $s1, $a0 +# CHECK-ASM: encoding: [0x98,0x60,0x00,0x00] +rdtimel.w $s1, $a0 + +# CHECK-ASM: rdtimeh.w $a7, $a1 +# CHECK-ASM: encoding: [0xab,0x64,0x00,0x00] +rdtimeh.w $a7, $a1 + +# CHECK-ASM: cpucfg $sp, $a4 +# CHECK-ASM: encoding: [0x03,0x6d,0x00,0x00] +cpucfg $sp, $a4 + + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM: asrtle.d $t0, $t5 +# CHECK64-ASM: encoding: [0x80,0x45,0x01,0x00] +asrtle.d $t0, $t5 + +# CHECK64-ASM: asrtgt.d $t8, $t8 +# CHECK64-ASM: encoding: [0x80,0xd2,0x01,0x00] +asrtgt.d $t8, $t8 + +# CHECK64-ASM: rdtime.d $tp, $t3 +# CHECK64-ASM: encoding: [0xe2,0x69,0x00,0x00] +rdtime.d $tp, $t3 + +.endif + diff --git a/llvm/test/MC/LoongArch/Basic/Integer/pseudos.s b/llvm/test/MC/LoongArch/Basic/Integer/pseudos.s new file mode 100644 index 00000000000000..1ace33f7131aec --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Integer/pseudos.s @@ -0,0 +1,14 @@ +## Test valid pseudo instructions + +# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s --triple=loongarch64 -show-encoding \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s + +# CHECK-ASM: nop +# CHECK-ASM: encoding: [0x00,0x00,0x40,0x03] +nop + +# CHECK-ASM: move $a4, $a5 +# CHECK-ASM: encoding: [0x28,0x01,0x15,0x00] +move $a4, $a5 diff --git a/llvm/test/MC/LoongArch/Directives/cfi.s b/llvm/test/MC/LoongArch/Directives/cfi.s new file mode 100644 index 00000000000000..7101fc90729067 --- /dev/null +++ b/llvm/test/MC/LoongArch/Directives/cfi.s @@ -0,0 +1,34 @@ +## Test cfi directives. + +# RUN: llvm-mc %s --triple=loongarch32 | FileCheck %s +# RUN: llvm-mc %s --triple=loongarch64 | FileCheck %s +# RUN: not llvm-mc --triple=loongarch32 --defsym=ERR=1 < %s 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-ERR +# RUN: not llvm-mc --triple=loongarch64 --defsym=ERR=1 < %s 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-ERR + +# CHECK: .cfi_startproc +.cfi_startproc +# CHECK-NEXT: .cfi_offset 0, 0 +.cfi_offset 0, 0 +# CHECK-NEXT: .cfi_offset 9, 8 +.cfi_offset 9, 8 +# CHECK-NEXT: .cfi_offset 31, 16 +.cfi_offset 31, 16 +# CHECK-NEXT: .cfi_endproc +.cfi_endproc + +.ifdef ERR +.cfi_startproc +# CHECK-ERR: :[[#@LINE+1]]:13: error: invalid register number +.cfi_offset -22, -8 +# CHECK-ERR: :[[#@LINE+1]]:13: error: invalid register number +.cfi_offset fp, -8 +# CHECK-ERR: :[[#@LINE+1]]:13: error: invalid register number +.cfi_offset $22, -8 +# CHECK-ERR: :[[#@LINE+1]]:13: error: invalid register number +.cfi_offset $r22, -8 +# CHECK-ERR: :[[#@LINE+1]]:13: error: invalid register number +.cfi_offset $fp, -8 +.cfi_endproc +.endif diff --git a/llvm/test/MC/LoongArch/Directives/data.s b/llvm/test/MC/LoongArch/Directives/data.s new file mode 100644 index 00000000000000..e3c66d10b18a05 --- /dev/null +++ b/llvm/test/MC/LoongArch/Directives/data.s @@ -0,0 +1,102 @@ +## Test data directives. +# RUN: llvm-mc --triple=loongarch32 < %s \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc --triple=loongarch64 < %s \ +# RUN: | FileCheck --check-prefix=CHECK-ASM %s +# RUN: llvm-mc --triple=loongarch32 --filetype=obj < %s | llvm-objdump -s - \ +# RUN: | FileCheck --check-prefix=CHECK-DATA %s +# RUN: llvm-mc --triple=loongarch64 --filetype=obj < %s | llvm-objdump -s - \ +# RUN: | FileCheck --check-prefix=CHECK-DATA %s +# RUN: not llvm-mc --triple=loongarch32 --defsym=ERR=1 < %s 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-ERR +# RUN: not llvm-mc --triple=loongarch64 --defsym=ERR=1 < %s 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-ERR + +.data + +# CHECK-ASM: .byte 0 +# CHECK-ASM-NEXT: .byte 1 +# CHECK-ASM-NEXT: .byte 171 +# CHECK-ASM-NEXT: .byte 255 +# CHECK-DATA: Contents of section .data: +# CHECK-DATA-NEXT: 0000 0001abff 0100ffff 0100ffff 0100ffff +.byte 0 +.byte 1 +.byte 0xab +.byte 0xff + +# CHECK-ASM: .half 1 +# CHECK-ASM-NEXT: .half 65535 +.half 0x1 +.half 0xffff + +# CHECK-ASM: .half 1 +# CHECK-ASM-NEXT: .half 65535 +.2byte 0x1 +.2byte 0xffff + +# CHECK-ASM: .half 1 +# CHECK-ASM-NEXT: .half 65535 +.short 0x1 +.short 0xffff + +# CHECK-ASM: .half 0 +# CHECK-ASM-NEXT: .half 1 +# CHECK-ASM-NEXT: .half 4660 +# CHECK-ASM-NEXT: .half 65535 +# CHECK-DATA-NEXT: 0010 00000100 3412ffff 01000000 ffffffff +.hword 0 +.hword 0x1 +.hword 0x1234 +.hword 0xffff + +# CHECK-ASM: .word 1 +# CHECK-ASM-NEXT: .word 4294967295 +.word 0x1 +.word 0xffffffff + +# CHECK-ASM: .word 1 +# CHECK-ASM-NEXT: .word 4294967295 +# CHECK-DATA-NEXT: 0020 01000000 ffffffff 01000000 ffffffff +.long 0x1 +.long 0xffffffff + +# CHECK-ASM: .word 1 +# CHECK-ASM-NEXT: .word 4294967295 +.4byte 0x1 +.4byte 0xffffffff + +# CHECK-ASM: .dword 1 +# CHECK-ASM-NEXT: .dword 1234605616436508552 +# CHECK-DATA-NEXT: 0030 01000000 00000000 88776655 44332211 +.dword 0x1 +.dword 0x1122334455667788 + +# CHECK-ASM: .dword 1 +# CHECK-ASM-NEXT: .dword 1234605616436508552 +# CHECK-DATA-NEXT: 0040 01000000 00000000 88776655 44332211 +.8byte 0x1 +.8byte 0x1122334455667788 + +.ifdef ERR +# CHECK-ERR: :[[#@LINE+1]]:7: error: out of range literal value +.byte 0xffa +# CHECK-ERR: :[[#@LINE+1]]:7: error: out of range literal value +.half 0xffffa +# CHECK-ERR: :[[#@LINE+1]]:8: error: out of range literal value +.short 0xffffa +# CHECK-ERR: :[[#@LINE+1]]:8: error: out of range literal value +.hword 0xffffa +# CHECK-ERR: :[[#@LINE+1]]:8: error: out of range literal value +.2byte 0xffffa +# CHECK-ERR: :[[#@LINE+1]]:7: error: out of range literal value +.word 0xffffffffa +# CHECK-ERR: :[[#@LINE+1]]:7: error: out of range literal value +.long 0xffffffffa +# CHECK-ERR: :[[#@LINE+1]]:8: error: out of range literal value +.4byte 0xffffffffa +# CHECK-ERR: :[[#@LINE+1]]:8: error: literal value out of range for directive +.dword 0xffffffffffffffffa +# CHECK-ERR: :[[#@LINE+1]]:8: error: literal value out of range for directive +.8byte 0xffffffffffffffffa +.endif diff --git a/llvm/test/MC/LoongArch/lit.local.cfg b/llvm/test/MC/LoongArch/lit.local.cfg new file mode 100644 index 00000000000000..2b5a4893e686ff --- /dev/null +++ b/llvm/test/MC/LoongArch/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'LoongArch' in config.root.targets: + config.unsupported = True