diff --git a/llvm/lib/Target/LoongArch/AsmParser/CMakeLists.txt b/llvm/lib/Target/LoongArch/AsmParser/CMakeLists.txt
new file mode 100644
--- /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
--- /dev/null
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -0,0 +1,482 @@
+// 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<MCConstantExpr>(Expr)) {
+      Imm = CE->getValue();
+      return true;
+    }
+
+    return false;
+  }
+
+  template <unsigned N, int P = 0> bool isUImm() const {
+    if (!isImm())
+      return false;
+
+    int64_t Imm;
+    bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
+    return IsConstantImm && isUInt<N>(Imm - P);
+  }
+
+  template <unsigned N, unsigned S = 0> bool isSImm() const {
+    if (!isImm())
+      return false;
+
+    int64_t Imm;
+    bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
+    return IsConstantImm && isShiftedInt<N, S>(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 << "<register " << RegName(getReg()) << ">";
+      break;
+    case KindTy::Token:
+      OS << "'" << getToken() << "'";
+      break;
+    }
+  }
+
+  static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
+    auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
+    Op->Tok = Str;
+    Op->StartLoc = S;
+    Op->EndLoc = S;
+    return Op;
+  }
+
+  static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
+                                                     SMLoc E) {
+    auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
+    Op->Reg.RegNum = RegNo;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
+  static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
+                                                     SMLoc E) {
+    auto Op = std::make_unique<LoongArchOperand>(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<MCConstantExpr>(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 (getLexer().is(AsmToken::EndOfStatement)) {
+    getParser().Lex(); // Consume the EndOfStatement.
+    return false;
+  }
+
+  // Parse first operand.
+  if (parseOperand(Operands, Name))
+    return true;
+
+  // Parse until end of statement, consuming commas between operands.
+  while (getLexer().is(AsmToken::Comma)) {
+    getLexer().Lex();
+    if (parseOperand(Operands, Name))
+      return true;
+  }
+
+  if (getLexer().isNot(AsmToken::EndOfStatement)) {
+    SMLoc Loc = getLexer().getLoc();
+    getParser().eatToEndOfStatement();
+    return Error(Loc, "unexpected token");
+  }
+
+  getParser().Lex(); // Consume the EndOfStatement.
+  return false;
+}
+
+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<LoongArchAsmParser> X(getTheLoongArch32Target());
+  RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
+}
diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt
--- a/llvm/lib/Target/LoongArch/CMakeLists.txt
+++ b/llvm/lib/Target/LoongArch/CMakeLists.txt
@@ -4,11 +4,11 @@
 
 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 @@
   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
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -22,6 +22,7 @@
 class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
   let Name = prefix # "Imm" # width # suffix;
   let DiagnosticType = !strconcat("Invalid", Name);
+  let RenderMethod = "addImmOperands";
 }
 
 class SImmAsmOperand<int width, string suffix = "">
@@ -32,29 +33,64 @@
     : ImmAsmOperand<"U", width, suffix> {
 }
 
-def uimm2 : Operand<GRLenVT>;
+def uimm2 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<2>;
+}
+
 def uimm2_plus1 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<2, "plus1">;
   let EncoderMethod = "getImmOpValueSub1";
 }
-def uimm3 : Operand<GRLenVT>;
-def uimm5 : Operand<GRLenVT>;
-def uimm6 : Operand<GRLenVT>;
-def uimm12 : Operand<GRLenVT>;
-def uimm15 : Operand<GRLenVT>;
-def simm12 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isInt<12>(Imm);}]>;
-def simm14 : Operand<GRLenVT>;
+
+def uimm3 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<3>;
+}
+
+def uimm5 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<5>;
+}
+
+def uimm6 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<6>;
+}
+
+def uimm12 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<12>;
+}
+
+def uimm15 : Operand<GRLenVT> {
+  let ParserMatchClass = UImmAsmOperand<15>;
+}
+
+def simm12 : Operand<GRLenVT>, ImmLeaf<GRLenVT, [{return isInt<12>(Imm);}]> {
+  let ParserMatchClass = SImmAsmOperand<12>;
+}
+
 def simm14_lsl2 : Operand<GRLenVT> {
+  let ParserMatchClass = SImmAsmOperand<14, "lsl2">;
   let EncoderMethod = "getImmOpValueAsr2";
 }
-def simm16 : Operand<GRLenVT>;
+
+def simm16 : Operand<GRLenVT> {
+  let ParserMatchClass = SImmAsmOperand<16>;
+}
+
 def simm16_lsl2 : Operand<GRLenVT> {
+  let ParserMatchClass = SImmAsmOperand<16, "lsl2">;
   let EncoderMethod = "getImmOpValueAsr2";
 }
-def simm20 : Operand<GRLenVT>;
+
+def simm20 : Operand<GRLenVT> {
+  let ParserMatchClass = SImmAsmOperand<20>;
+}
+
 def simm21_lsl2 : Operand<GRLenVT> {
+  let ParserMatchClass = SImmAsmOperand<21, "lsl2">;
   let EncoderMethod = "getImmOpValueAsr2";
 }
+
 def simm26_lsl2 : Operand<GRLenVT> {
+  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
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp
@@ -29,5 +29,6 @@
   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
--- 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 @@
   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()}) {
     // Register the MC register info.
@@ -95,5 +121,6 @@
 
     // Register the MCInstPrinter.
     TargetRegistry::RegisterMCInstPrinter(*T, createLoongArchMCInstPrinter);
+    TargetRegistry::RegisterMCInstrAnalysis(*T, createLoongArchInstrAnalysis);
   }
 }
diff --git a/llvm/test/MC/LoongArch/Directives/cfi.s b/llvm/test/MC/LoongArch/Directives/cfi.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Directives/cfi.s
@@ -0,0 +1,39 @@
+.ifndef ERR
+
+## Test valid cfi directives.
+# RUN: llvm-mc %s --triple=loongarch32 | FileCheck %s
+# RUN: llvm-mc %s --triple=loongarch64 | FileCheck %s
+
+# 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
+
+.else
+
+## Test invalid cfi directives.
+# 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
+
+.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
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Directives/data.s
@@ -0,0 +1,88 @@
+.ifndef ERR
+
+## Test valid data directives.
+# RUN: llvm-mc --triple=loongarch32 < %s | FileCheck %s
+# RUN: llvm-mc --triple=loongarch64 < %s | FileCheck %s
+
+.data
+
+# CHECK:      .byte 1
+# CHECK-NEXT: .byte 255
+.byte 1
+.byte 0xff
+
+# CHECK:      .half 1
+# CHECK-NEXT: .half 65535
+.half 0x1
+.half 0xffff
+
+# CHECK:      .half 1
+# CHECK-NEXT: .half 65535
+.2byte 0x1
+.2byte 0xffff
+
+# CHECK:      .half 1
+# CHECK-NEXT: .half 65535
+.short 0x1
+.short 0xffff
+
+# CHECK:      .half 1
+# CHECK-NEXT: .half 65535
+.hword 0x1
+.hword 0xffff
+
+# CHECK:      .word 1
+# CHECK-NEXT: .word 4294967295
+.word 0x1
+.word 0xffffffff
+
+# CHECK:      .word 1
+# CHECK-NEXT: .word 4294967295
+.long 0x1
+.long 0xffffffff
+
+# CHECK:      .word 1
+# CHECK-NEXT: .word 4294967295
+.4byte 0x1
+.4byte 0xffffffff
+
+# CHECK:      .dword 1
+# CHECK-NEXT: .dword 1234605616436508552
+.dword 0x1
+.dword 0x1122334455667788
+
+# CHECK:      .dword 1
+# CHECK-NEXT: .dword 1234605616436508552
+.8byte 0x1
+.8byte 0x1122334455667788
+
+.else
+
+## Test invalid data directives.
+# 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-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/ISA/Basic/Integer/arith.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/arith.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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=CHECK32-ASM %s
+# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \
+# RUN:     | FileCheck --check-prefixes=CHECK32-ASM,CHECK64-ASM %s
+
+#############################################################
+## Instructions for both loongarch32 and loongarch64
+#############################################################
+
+# CHECK32-ASM: add.w $a5, $ra, $s8
+# CHECK32-ASM: encoding: [0x29,0x7c,0x10,0x00]
+add.w $a5, $ra, $s8
+
+# CHECK32-ASM: sub.w $r21, $s2, $t7
+# CHECK32-ASM: encoding: [0x35,0x4f,0x11,0x00]
+sub.w $r21, $s2, $t7
+
+# CHECK32-ASM: addi.w $a1, $a3, 246
+# CHECK32-ASM: encoding: [0xe5,0xd8,0x83,0x02]
+addi.w $a1, $a3, 246
+
+# CHECK32-ASM: alsl.w $tp, $t5, $tp, 4
+# CHECK32-ASM: encoding: [0x22,0x8a,0x05,0x00]
+alsl.w $tp, $t5, $tp, 4
+
+# CHECK32-ASM: lu12i.w $t4, 49
+# CHECK32-ASM: encoding: [0x30,0x06,0x00,0x14]
+lu12i.w $t4, 49
+
+# CHECK32-ASM: lu12i.w $a0, -1
+# CHECK32-ASM: encoding: [0xe4,0xff,0xff,0x15]
+lu12i.w $a0, -1
+
+# CHECK32-ASM: slt $s6, $s3, $tp
+# CHECK32-ASM: encoding: [0x5d,0x0b,0x12,0x00]
+slt $s6, $s3, $tp
+
+# CHECK32-ASM: sltu $a7, $r21, $s6
+# CHECK32-ASM: encoding: [0xab,0xf6,0x12,0x00]
+sltu $a7, $r21, $s6
+
+# CHECK32-ASM: slti $s4, $ra, 235
+# CHECK32-ASM: encoding: [0x3b,0xac,0x03,0x02]
+slti $s4, $ra, 235
+
+# CHECK32-ASM: sltui $zero, $a4, 162
+# CHECK32-ASM: encoding: [0x00,0x89,0x42,0x02]
+sltui $zero, $a4, 162
+
+# CHECK32-ASM: pcaddi $a5, 187
+# CHECK32-ASM: encoding: [0x69,0x17,0x00,0x18]
+pcaddi $a5, 187
+
+# CHECK32-ASM: pcaddu12i $zero, 37
+# CHECK32-ASM: encoding: [0xa0,0x04,0x00,0x1c]
+pcaddu12i $zero, 37
+
+# CHECK32-ASM: pcalau12i $a6, 89
+# CHECK32-ASM: encoding: [0x2a,0x0b,0x00,0x1a]
+pcalau12i $a6, 89
+
+# CHECK32-ASM: and $t7, $s8, $ra
+# CHECK32-ASM: encoding: [0xf3,0x87,0x14,0x00]
+and $t7, $s8, $ra
+
+# CHECK32-ASM: or $t5, $t4, $s7
+# CHECK32-ASM: encoding: [0x11,0x7a,0x15,0x00]
+or $t5, $t4, $s7
+
+# CHECK32-ASM: nor $a1, $t6, $a1
+# CHECK32-ASM: encoding: [0x45,0x16,0x14,0x00]
+nor $a1, $t6, $a1
+
+# CHECK32-ASM: xor $t3, $t7, $a4
+# CHECK32-ASM: encoding: [0x6f,0xa2,0x15,0x00]
+xor $t3, $t7, $a4
+
+# CHECK32-ASM: andn $s5, $s2, $a1
+# CHECK32-ASM: encoding: [0x3c,0x97,0x16,0x00]
+andn $s5, $s2, $a1
+
+# CHECK32-ASM: orn $tp, $sp, $s2
+# CHECK32-ASM: encoding: [0x62,0x64,0x16,0x00]
+orn $tp, $sp, $s2
+
+# CHECK32-ASM: andi $s2, $zero, 106
+# CHECK32-ASM: encoding: [0x19,0xa8,0x41,0x03]
+andi $s2, $zero, 106
+
+# CHECK32-ASM: ori $t5, $a1, 47
+# CHECK32-ASM: encoding: [0xb1,0xbc,0x80,0x03]
+ori $t5, $a1, 47
+
+# CHECK32-ASM: xori $t6, $s0, 99
+# CHECK32-ASM: encoding: [0xf2,0x8e,0xc1,0x03]
+xori $t6, $s0, 99
+
+# CHECK32-ASM: mul.w $a0, $t6, $sp
+# CHECK32-ASM: encoding: [0x44,0x0e,0x1c,0x00]
+mul.w $a0, $t6, $sp
+
+# CHECK32-ASM: mulh.w $s4, $s0, $zero
+# CHECK32-ASM: encoding: [0xfb,0x82,0x1c,0x00]
+mulh.w $s4, $s0, $zero
+
+# CHECK32-ASM: mulh.wu $a6, $t5, $s1
+# CHECK32-ASM: encoding: [0x2a,0x62,0x1d,0x00]
+mulh.wu $a6, $t5, $s1
+
+# CHECK32-ASM: div.w $s7, $t1, $s2
+# CHECK32-ASM: encoding: [0xbe,0x65,0x20,0x00]
+div.w $s7, $t1, $s2
+
+# CHECK32-ASM: mod.w $ra, $s3, $a6
+# CHECK32-ASM: encoding: [0x41,0xab,0x20,0x00]
+mod.w $ra, $s3, $a6
+
+# CHECK32-ASM: div.wu $t7, $s0, $zero
+# CHECK32-ASM: encoding: [0xf3,0x02,0x21,0x00]
+div.wu $t7, $s0, $zero
+
+# CHECK32-ASM: mod.wu $s4, $a5, $t5
+# CHECK32-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/ISA/Basic/Integer/atomic.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/atomic.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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=CHECK32-ASM %s
+# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \
+# RUN:     | FileCheck --check-prefixes=CHECK32-ASM,CHECK64-ASM %s
+
+#############################################################
+## Instructions for both loongarch32 and loongarch64
+#############################################################
+
+# CHECK32-ASM: ll.w $tp, $s4, 220
+# CHECK32-ASM: encoding: [0x62,0xdf,0x00,0x20]
+ll.w $tp, $s4, 220
+
+# CHECK32-ASM: sc.w $t7, $t2, 56
+# CHECK32-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/ISA/Basic/Integer/barrier.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/barrier.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/ISA/Basic/Integer/bit-manipu.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/bit-manipu.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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=CHECK32-ASM %s
+# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \
+# RUN:     | FileCheck --check-prefixes=CHECK32-ASM,CHECK64-ASM %s
+
+#############################################################
+## Instructions for both loongarch32 and loongarch64
+#############################################################
+
+# CHECK32-ASM: ext.w.b $t8, $t6
+# CHECK32-ASM: encoding: [0x54,0x5e,0x00,0x00]
+ext.w.b $t8, $t6
+
+# CHECK32-ASM: ext.w.h $s0, $s0
+# CHECK32-ASM: encoding: [0xf7,0x5a,0x00,0x00]
+ext.w.h $s0, $s0
+
+# CHECK32-ASM: clo.w $ra, $sp
+# CHECK32-ASM: encoding: [0x61,0x10,0x00,0x00]
+clo.w $ra, $sp
+
+# CHECK32-ASM: clz.w $a3, $a6
+# CHECK32-ASM: encoding: [0x47,0x15,0x00,0x00]
+clz.w $a3, $a6
+
+# CHECK32-ASM: cto.w $tp, $a2
+# CHECK32-ASM: encoding: [0xc2,0x18,0x00,0x00]
+cto.w $tp, $a2
+
+# CHECK32-ASM: ctz.w $a1, $fp
+# CHECK32-ASM: encoding: [0xc5,0x1e,0x00,0x00]
+ctz.w $a1, $fp
+
+# CHECK32-ASM: bytepick.w $s6, $zero, $t4, 0
+# CHECK32-ASM: encoding: [0x1d,0x40,0x08,0x00]
+bytepick.w $s6, $zero, $t4, 0
+
+# CHECK32-ASM: revb.2h $t8, $a7
+# CHECK32-ASM: encoding: [0x74,0x31,0x00,0x00]
+revb.2h $t8, $a7
+
+# CHECK32-ASM: bitrev.4b $r21, $s4
+# CHECK32-ASM: encoding: [0x75,0x4b,0x00,0x00]
+bitrev.4b $r21, $s4
+
+# CHECK32-ASM: bitrev.w $s2, $a1
+# CHECK32-ASM: encoding: [0xb9,0x50,0x00,0x00]
+bitrev.w $s2, $a1
+
+# CHECK32-ASM: bstrins.w $a4, $a7, 7, 2
+# CHECK32-ASM: encoding: [0x68,0x09,0x67,0x00]
+bstrins.w $a4, $a7, 7, 2
+
+# CHECK32-ASM: bstrpick.w $ra, $a5, 10, 4
+# CHECK32-ASM: encoding: [0x21,0x91,0x6a,0x00]
+bstrpick.w $ra, $a5, 10, 4
+
+# CHECK32-ASM: maskeqz $t8, $a7, $t6
+# CHECK32-ASM: encoding: [0x74,0x49,0x13,0x00]
+maskeqz $t8, $a7, $t6
+
+# CHECK32-ASM: masknez $t8, $t1, $s3
+# CHECK32-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/ISA/Basic/Integer/bit-shift.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/bit-shift.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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=CHECK32-ASM %s
+# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \
+# RUN:     | FileCheck --check-prefixes=CHECK32-ASM,CHECK64-ASM %s
+
+#############################################################
+## Instructions for both loongarch32 and loongarch64
+#############################################################
+
+# CHECK32-ASM: sll.w $s1, $s4, $s0
+# CHECK32-ASM: encoding: [0x78,0x5f,0x17,0x00]
+sll.w $s1, $s4, $s0
+
+# CHECK32-ASM: srl.w $s8, $t5, $a3
+# CHECK32-ASM: encoding: [0x3f,0x9e,0x17,0x00]
+srl.w $s8, $t5, $a3
+
+# CHECK32-ASM: sra.w $t0, $s5, $a6
+# CHECK32-ASM: encoding: [0x8c,0x2b,0x18,0x00]
+sra.w $t0, $s5, $a6
+
+# CHECK32-ASM: rotr.w $ra, $s3, $t6
+# CHECK32-ASM: encoding: [0x41,0x4b,0x1b,0x00]
+rotr.w $ra, $s3, $t6
+
+# CHECK32-ASM: slli.w $s3, $t6, 0
+# CHECK32-ASM: encoding: [0x5a,0x82,0x40,0x00]
+slli.w $s3, $t6, 0
+
+# CHECK32-ASM: srli.w $a6, $t2, 30
+# CHECK32-ASM: encoding: [0xca,0xf9,0x44,0x00]
+srli.w $a6, $t2, 30
+
+# CHECK32-ASM: srai.w $a4, $t5, 24
+# CHECK32-ASM: encoding: [0x28,0xe2,0x48,0x00]
+srai.w $a4, $t5, 24
+
+# CHECK32-ASM: rotri.w $s0, $t8, 23
+# CHECK32-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/ISA/Basic/Integer/bound-check.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/bound-check.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/ISA/Basic/Integer/branch.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/branch.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/ISA/Basic/Integer/crc.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/crc.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/ISA/Basic/Integer/invalid.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/invalid.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/ISA/Basic/Integer/invalid64.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/invalid64.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/ISA/Basic/Integer/memory.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/memory.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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=CHECK32-ASM %s
+# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \
+# RUN:     | FileCheck --check-prefixes=CHECK32-ASM,CHECK64-ASM %s
+
+#############################################################
+## Instructions for both loongarch32 and loongarch64
+#############################################################
+
+# CHECK32-ASM: ld.b $s1, $a4, 21
+# CHECK32-ASM: encoding: [0x18,0x55,0x00,0x28]
+ld.b $s1, $a4, 21
+
+# CHECK32-ASM: ld.h $a3, $t6, 80
+# CHECK32-ASM: encoding: [0x47,0x42,0x41,0x28]
+ld.h $a3, $t6, 80
+
+# CHECK32-ASM: ld.w $t6, $s3, 92
+# CHECK32-ASM: encoding: [0x52,0x73,0x81,0x28]
+ld.w $t6, $s3, 92
+
+# CHECK32-ASM: ld.bu $t1, $t1, 150
+# CHECK32-ASM: encoding: [0xad,0x59,0x02,0x2a]
+ld.bu $t1, $t1, 150
+
+# CHECK32-ASM: ld.hu $t6, $s6, 198
+# CHECK32-ASM: encoding: [0xb2,0x1b,0x43,0x2a]
+ld.hu $t6, $s6, 198
+
+# CHECK32-ASM: st.b $sp, $a3, 95
+# CHECK32-ASM: encoding: [0xe3,0x7c,0x01,0x29]
+st.b $sp, $a3, 95
+
+# CHECK32-ASM: st.h $s2, $t4, 122
+# CHECK32-ASM: encoding: [0x19,0xea,0x41,0x29]
+st.h $s2, $t4, 122
+
+# CHECK32-ASM: st.w $t1, $t1, 175
+# CHECK32-ASM: encoding: [0xad,0xbd,0x82,0x29]
+st.w $t1, $t1, 175
+
+# CHECK32-ASM: preld 10, $zero, 23
+# CHECK32-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/ISA/Basic/Integer/misc.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/misc.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/Basic/Integer/misc.s
@@ -0,0 +1,52 @@
+## Test valid misc instructions.
+
+# RUN: llvm-mc %s --triple=loongarch32 -show-encoding \
+# RUN:     | FileCheck --check-prefix=CHECK32-ASM %s
+# RUN: llvm-mc %s --triple=loongarch64 -show-encoding --defsym=LA64=1 \
+# RUN:     | FileCheck --check-prefixes=CHECK32-ASM,CHECK64-ASM %s
+
+#############################################################
+## Instructions for both loongarch32 and loongarch64
+#############################################################
+
+# CHECK32-ASM: syscall 100
+# CHECK32-ASM: encoding: [0x64,0x00,0x2b,0x00]
+syscall 100
+
+# CHECK32-ASM: break 199
+# CHECK32-ASM: encoding: [0xc7,0x00,0x2a,0x00]
+break 199
+
+# CHECK32-ASM: rdtimel.w $s1, $a0
+# CHECK32-ASM: encoding: [0x98,0x60,0x00,0x00]
+rdtimel.w $s1, $a0
+
+# CHECK32-ASM: rdtimeh.w $a7, $a1
+# CHECK32-ASM: encoding: [0xab,0x64,0x00,0x00]
+rdtimeh.w $a7, $a1
+
+# CHECK32-ASM: cpucfg $sp, $a4
+# CHECK32-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/ISA/Basic/Integer/pseudos.s b/llvm/test/MC/LoongArch/ISA/Basic/Integer/pseudos.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/ISA/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/lit.local.cfg b/llvm/test/MC/LoongArch/lit.local.cfg
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/LoongArch/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'LoongArch' in config.root.targets:
+    config.unsupported = True