[clang] 6b55e91 - [RISCV] Add MC support of RISCV zcmp Extension

via cfe-commits cfe-commits at lists.llvm.org
Sun May 7 23:29:56 PDT 2023


Author: WuXinlong
Date: 2023-05-08T14:29:50+08:00
New Revision: 6b55e9117ebbd32d66b6f6ad12326a6b2acaef58

URL: https://github.com/llvm/llvm-project/commit/6b55e9117ebbd32d66b6f6ad12326a6b2acaef58
DIFF: https://github.com/llvm/llvm-project/commit/6b55e9117ebbd32d66b6f6ad12326a6b2acaef58.diff

LOG: [RISCV] Add MC support of RISCV zcmp Extension

This patch add the instructions of zcmp extension.

Instructions in zcmp extension try to optimise `mv` inst and the prologue & epilogue in functions

co-author: @Scott Egerton, @ZirconLiu, @Lukacma, @Heda Chen, @luxufan, @heyiliang, @liaochunyu

Reviewed By: craig.topper

Differential Revision: https://reviews.llvm.org/D132819

Added: 
    llvm/test/MC/RISCV/rv32zcmp-invalid.s
    llvm/test/MC/RISCV/rv32zcmp-valid.s
    llvm/test/MC/RISCV/rv64zcmp-invalid.s
    llvm/test/MC/RISCV/rv64zcmp-valid.s

Modified: 
    clang/test/Preprocessor/riscv-target-features.c
    llvm/docs/RISCVUsage.rst
    llvm/lib/Support/RISCVISAInfo.cpp
    llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
    llvm/lib/Target/RISCV/RISCVFeatures.td
    llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
    llvm/lib/Target/RISCV/RISCVRegisterInfo.td
    llvm/test/MC/RISCV/attribute-arch.s

Removed: 
    


################################################################################
diff  --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c
index 2dadbe2c420db..fe1b487ad09b0 100644
--- a/clang/test/Preprocessor/riscv-target-features.c
+++ b/clang/test/Preprocessor/riscv-target-features.c
@@ -48,6 +48,7 @@
 // CHECK-NOT: __riscv_zcb {{.*$}}
 // CHECK-NOT: __riscv_zcd {{.*$}}
 // CHECK-NOT: __riscv_zcf {{.*$}}
+// CHECK-NOT: __riscv_zcmp {{.*$}}
 // CHECK-NOT: __riscv_zcmt {{.*$}}
 // CHECK-NOT: __riscv_h {{.*$}}
 // CHECK-NOT: __riscv_zvbb {{.*$}}
@@ -512,6 +513,13 @@
 // RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCF-EXT %s
 // CHECK-ZCF-EXT: __riscv_zcf 1000000{{$}}
 
+// RUN: %clang -target riscv32 -march=rv32izcmp1p0 -menable-experimental-extensions \
+// RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCMP-EXT %s
+// RUN: %clang -target riscv64 -march=rv64izcmp1p0 -menable-experimental-extensions \
+// RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCMP-EXT %s
+// CHECK-ZCMP-EXT: __riscv_zca 1000000{{$}}
+// CHECK-ZCMP-EXT: __riscv_zcmp 1000000{{$}}
+
 // RUN: %clang -target riscv32 -march=rv32izcmt1p0 -menable-experimental-extensions \
 // RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCMT-EXT %s
 // RUN: %clang -target riscv64 -march=rv64izcmt1p0 -menable-experimental-extensions \

diff  --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 5c4ae89085f16..d2a296cd35be1 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -195,6 +195,9 @@ The primary goal of experimental support is to assist in the process of ratifica
 ``experimental-zcf``
   LLVM implements the `1.0.1 draft specification <https://github.com/riscv/riscv-code-size-reduction/releases/tag/v1.0.1>`__.
 
+``experimental-zcmp``
+  LLVM implements the `1.0.1 draft specification <https://github.com/riscv/riscv-code-size-reduction/releases/tag/v1.0.1>`__.
+
 ``experimental-zcmt``
   LLVM implements the `1.0.1 draft specification <https://github.com/riscv/riscv-code-size-reduction/releases/tag/v1.0.1>`_.
 

diff  --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index 097dffd78205a..63d84256b87e6 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -144,6 +144,7 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
     {"zcb", RISCVExtensionVersion{1, 0}},
     {"zcd", RISCVExtensionVersion{1, 0}},
     {"zcf", RISCVExtensionVersion{1, 0}},
+    {"zcmp", RISCVExtensionVersion{1, 0}},
     {"zcmt", RISCVExtensionVersion{1, 0}},
     {"zfa", RISCVExtensionVersion{0, 2}},
     {"zicond", RISCVExtensionVersion{1, 0}},
@@ -920,6 +921,7 @@ static const char *ImpliedExtsV[] = {"zvl128b", "zve64d", "f", "d"};
 static const char *ImpliedExtsXTHeadVdot[] = {"v"};
 static const char *ImpliedExtsXsfvcp[] = {"zve32x"};
 static const char *ImpliedExtsZcb[] = {"zca"};
+static const char *ImpliedExtsZcmp[] = {"zca"};
 static const char *ImpliedExtsZcmt[] = {"zca"};
 static const char *ImpliedExtsZdinx[] = {"zfinx"};
 static const char *ImpliedExtsZfa[] = {"f"};
@@ -978,6 +980,7 @@ static constexpr ImpliedExtsEntry ImpliedExts[] = {
     {{"xsfvcp"}, {ImpliedExtsXsfvcp}},
     {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
     {{"zcb"}, {ImpliedExtsZcb}},
+    {{"zcmp"}, {ImpliedExtsZcmp}},
     {{"zcmt"}, {ImpliedExtsZcmt}},
     {{"zdinx"}, {ImpliedExtsZdinx}},
     {{"zfa"}, {ImpliedExtsZfa}},

diff  --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 4731892ca99c0..e676b54597a55 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -183,6 +183,9 @@ class RISCVAsmParser : public MCTargetAsmParser {
   OperandMatchResultTy parseGPRAsFPR(OperandVector &Operands);
   OperandMatchResultTy parseFRMArg(OperandVector &Operands);
   OperandMatchResultTy parseFenceArg(OperandVector &Operands);
+  OperandMatchResultTy parseReglist(OperandVector &Operands);
+  OperandMatchResultTy parseRetval(OperandVector &Operands);
+  OperandMatchResultTy parseZcmpSpimm(OperandVector &Operands);
 
   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
 
@@ -293,6 +296,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
     VType,
     FRM,
     Fence,
+    Rlist,
+    Spimm,
   } Kind;
 
   struct RegOp {
@@ -329,6 +334,14 @@ struct RISCVOperand final : public MCParsedAsmOperand {
     unsigned Val;
   };
 
+  struct RlistOp {
+    unsigned Val;
+  };
+
+  struct SpimmOp {
+    unsigned Val;
+  };
+
   SMLoc StartLoc, EndLoc;
   union {
     StringRef Tok;
@@ -339,6 +352,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
     struct VTypeOp VType;
     struct FRMOp FRM;
     struct FenceOp Fence;
+    struct RlistOp Rlist;
+    struct SpimmOp Spimm;
   };
 
   RISCVOperand(KindTy K) : Kind(K) {}
@@ -373,6 +388,12 @@ struct RISCVOperand final : public MCParsedAsmOperand {
     case KindTy::Fence:
       Fence = o.Fence;
       break;
+    case KindTy::Rlist:
+      Rlist = o.Rlist;
+      break;
+    case KindTy::Spimm:
+      Spimm = o.Spimm;
+      break;
     }
   }
 
@@ -397,6 +418,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
   bool isImm() const override { return Kind == KindTy::Immediate; }
   bool isMem() const override { return false; }
   bool isSystemRegister() const { return Kind == KindTy::SystemRegister; }
+  bool isRlist() const { return Kind == KindTy::Rlist; }
+  bool isSpimm() const { return Kind == KindTy::Spimm; }
 
   bool isGPR() const {
     return Kind == KindTy::Register &&
@@ -949,6 +972,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
       OS << getFence();
       OS << '>';
       break;
+    case KindTy::Rlist:
+      OS << "<rlist: ";
+      RISCVZC::printRlist(Rlist.Val, OS);
+      OS << '>';
+      break;
+    case KindTy::Spimm:
+      OS << "<Spimm: ";
+      RISCVZC::printSpimm(Spimm.Val, OS);
+      OS << '>';
+      break;
     }
   }
 
@@ -1024,6 +1057,21 @@ struct RISCVOperand final : public MCParsedAsmOperand {
     return Op;
   }
 
+  static std::unique_ptr<RISCVOperand> createRlist(unsigned RlistEncode,
+                                                   SMLoc S) {
+    auto Op = std::make_unique<RISCVOperand>(KindTy::Rlist);
+    Op->Rlist.Val = RlistEncode;
+    Op->StartLoc = S;
+    return Op;
+  }
+
+  static std::unique_ptr<RISCVOperand> createSpimm(unsigned Spimm, SMLoc S) {
+    auto Op = std::make_unique<RISCVOperand>(KindTy::Spimm);
+    Op->Spimm.Val = Spimm;
+    Op->StartLoc = S;
+    return Op;
+  }
+
   static void addExpr(MCInst &Inst, const MCExpr *Expr, bool IsRV64Imm) {
     assert(Expr && "Expr shouldn't be null!");
     int64_t Imm = 0;
@@ -1087,6 +1135,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
     Inst.addOperand(MCOperand::createImm(Imm));
   }
 
+  void addRlistOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::createImm(Rlist.Val));
+  }
+
+  void addSpimmOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::createImm(Spimm.Val));
+  }
+
   void addFRMArgOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     Inst.addOperand(MCOperand::createImm(getFRM()));
@@ -1422,6 +1480,19 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
                                       (1 << 4),
                                       "immediate must be in the range");
   }
+  case Match_InvalidRlist: {
+    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+    return Error(
+        ErrorLoc,
+        "operand must be {ra [, s0[-sN]]} or {x1 [, x8[-x9][, x18[-xN]]]}");
+  }
+  case Match_InvalidSpimm: {
+    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+    return Error(
+        ErrorLoc,
+        "stack adjustment is invalid for this instruction and register list; "
+        "refer to Zc spec for a detailed range of stack adjustment");
+  }
   case Match_InvalidRnumArg: {
     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, 10);
   }
@@ -2243,6 +2314,147 @@ RISCVAsmParser::parseZeroOffsetMemOp(OperandVector &Operands) {
   return MatchOperand_Success;
 }
 
+OperandMatchResultTy RISCVAsmParser::parseReglist(OperandVector &Operands) {
+  // Rlist: {ra [, s0[-sN]]}
+  // XRlist: {x1 [, x8[-x9][, x18[-xN]]]}
+  SMLoc S = getLoc();
+  if (getLexer().isNot(AsmToken::LCurly)) {
+    Error(getLoc(), "register list must start with '{'");
+    return MatchOperand_ParseFail;
+  }
+  getLexer().Lex(); // eat '{'
+  bool IsEABI = isRVE();
+
+  MCRegister RegStart = RISCV::NoRegister;
+  MCRegister RegEnd = RISCV::NoRegister;
+  StringRef RegName = getLexer().getTok().getIdentifier();
+  matchRegisterNameHelper(IsEABI, RegStart, RegName);
+  if (RegStart != RISCV::X1) {
+    Error(getLoc(), "register list must start from 'ra' or 'x1'");
+    return MatchOperand_ParseFail;
+  }
+  getLexer().Lex();
+
+  // parse case like ,s0
+  if (getLexer().is(AsmToken::Comma)) {
+    getLexer().Lex();
+    if (getLexer().isNot(AsmToken::Identifier)) {
+      Error(getLoc(), "invalid register");
+      return MatchOperand_ParseFail;
+    }
+    StringRef RegName = getLexer().getTok().getIdentifier();
+    if (matchRegisterNameHelper(IsEABI, RegStart, RegName)) {
+      Error(getLoc(), "invalid register");
+      return MatchOperand_ParseFail;
+    }
+    if (RegStart != RISCV::X8) {
+      Error(getLoc(), "continuous register list must start from 's0' or 'x8'");
+      return MatchOperand_ParseFail;
+    }
+    getLexer().Lex(); // eat reg
+  }
+
+  // parse case like -s1
+  if (getLexer().is(AsmToken::Minus)) {
+    getLexer().Lex();
+    StringRef EndName = getLexer().getTok().getIdentifier();
+    // FIXME: the register mapping and checks of EABI is wrong
+    if (matchRegisterNameHelper(IsEABI, RegEnd, EndName)) {
+      Error(getLoc(), "invalid register");
+      return MatchOperand_ParseFail;
+    }
+    if (IsEABI && RegEnd != RISCV::X9) {
+      Error(getLoc(), "contiguous register list of EABI can only be 's0-s1' or "
+                      "'x8-x9' pair");
+      return MatchOperand_ParseFail;
+    }
+    getLexer().Lex();
+  }
+
+  if (!IsEABI) {
+    // parse extra part like ', x18[-x20]' for XRegList
+    if (getLexer().is(AsmToken::Comma)) {
+      if (RegEnd != RISCV::X9) {
+        Error(
+            getLoc(),
+            "first contiguous registers pair of register list must be 'x8-x9'");
+        return MatchOperand_ParseFail;
+      }
+
+      // parse ', x18' for extra part
+      getLexer().Lex();
+      if (getLexer().isNot(AsmToken::Identifier)) {
+        Error(getLoc(), "invalid register");
+        return MatchOperand_ParseFail;
+      }
+      StringRef EndName = getLexer().getTok().getIdentifier();
+      if (MatchRegisterName(EndName) != RISCV::X18) {
+        Error(getLoc(), "second contiguous registers pair of register list "
+                        "must start from 'x18'");
+        return MatchOperand_ParseFail;
+      }
+      getLexer().Lex();
+
+      // parse '-x20' for extra part
+      if (getLexer().is(AsmToken::Minus)) {
+        getLexer().Lex();
+        if (getLexer().isNot(AsmToken::Identifier)) {
+          Error(getLoc(), "invalid register");
+          return MatchOperand_ParseFail;
+        }
+        EndName = getLexer().getTok().getIdentifier();
+        if (MatchRegisterName(EndName) == RISCV::NoRegister) {
+          Error(getLoc(), "invalid register");
+          return MatchOperand_ParseFail;
+        }
+        getLexer().Lex();
+      }
+      RegEnd = MatchRegisterName(EndName);
+    }
+  }
+
+  if (RegEnd == RISCV::X26) {
+    Error(getLoc(), "invalid register list, {ra, s0-s10} or {x1, x8-x9, "
+                    "x18-x26} is not supported");
+    return MatchOperand_ParseFail;
+  }
+
+  if (getLexer().isNot(AsmToken::RCurly)) {
+    Error(getLoc(), "register list must end with '}'");
+    return MatchOperand_ParseFail;
+  }
+  getLexer().Lex(); // eat '}'
+
+  if (RegEnd == RISCV::NoRegister)
+    RegEnd = RegStart;
+
+  auto Encode = RISCVZC::encodeRlist(RegEnd, IsEABI);
+  if (Encode == 16) {
+    Error(S, "invalid register list");
+    return MatchOperand_ParseFail;
+  }
+  Operands.push_back(RISCVOperand::createRlist(Encode, S));
+
+  return MatchOperand_Success;
+}
+
+OperandMatchResultTy RISCVAsmParser::parseZcmpSpimm(OperandVector &Operands) {
+  if (getLexer().is(AsmToken::Minus))
+    getLexer().Lex();
+
+  SMLoc S = getLoc();
+  int64_t StackAdjustment = getLexer().getTok().getIntVal();
+  unsigned Spimm = 0;
+  unsigned RlistVal = static_cast<RISCVOperand *>(Operands[1].get())->Rlist.Val;
+
+  bool IsEABI = isRVE();
+  if (!RISCVZC::getSpimm(RlistVal, Spimm, StackAdjustment, isRV64(), IsEABI))
+    return MatchOperand_NoMatch;
+  Operands.push_back(RISCVOperand::createSpimm(Spimm << 4, S));
+  getLexer().Lex();
+  return MatchOperand_Success;
+}
+
 /// Looks at a token type and creates the relevant operand from this
 /// information, adding to Operands. If operand was parsed, returns false, else
 /// true.
@@ -2925,6 +3137,15 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
     }
   }
 
+  if (Opcode == RISCV::CM_MVSA01) {
+    unsigned Rd1 = Inst.getOperand(0).getReg();
+    unsigned Rd2 = Inst.getOperand(1).getReg();
+    if (Rd1 == Rd2) {
+      SMLoc Loc = Operands[1]->getStartLoc();
+      return Error(Loc, "'rs1' and 'rs2' must be 
diff erent.");
+    }
+  }
+
   bool IsTHeadMemPair32 = (Opcode == RISCV::TH_LWD ||
                            Opcode == RISCV::TH_LWUD || Opcode == RISCV::TH_SWD);
   bool IsTHeadMemPair64 = (Opcode == RISCV::TH_LDD || Opcode == RISCV::TH_SDD);

diff  --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index b5fc59ee9bacf..03eb101e98917 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -168,6 +168,17 @@ static DecodeStatus DecodeGPRPF64RegisterClass(MCInst &Inst, uint32_t RegNo,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeSR07RegisterClass(MCInst &Inst, uint64_t RegNo,
+                                            uint64_t Address,
+                                            const void *Decoder) {
+  if (RegNo >= 8)
+    return MCDisassembler::Fail;
+
+  MCRegister Reg = (RegNo < 2) ? (RegNo + RISCV::X8) : (RegNo - 2 + RISCV::X18);
+  Inst.addOperand(MCOperand::createReg(Reg));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus DecodeVRRegisterClass(MCInst &Inst, uint32_t RegNo,
                                           uint64_t Address,
                                           const MCDisassembler *Decoder) {
@@ -370,6 +381,12 @@ static DecodeStatus decodeXTHeadMemPair(MCInst &Inst, uint32_t Insn,
                                         uint64_t Address,
                                         const MCDisassembler *Decoder);
 
+static DecodeStatus decodeZcmpRlist(MCInst &Inst, unsigned Imm,
+                                    uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeZcmpSpimm(MCInst &Inst, unsigned Imm,
+                                    uint64_t Address, const void *Decoder);
+
 #include "RISCVGenDisassemblerTables.inc"
 
 static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
@@ -456,6 +473,22 @@ static DecodeStatus decodeXTHeadMemPair(MCInst &Inst, uint32_t Insn,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeZcmpRlist(MCInst &Inst, unsigned Imm,
+                                    uint64_t Address, const void *Decoder) {
+  if (Imm <= 3)
+    return MCDisassembler::Fail;
+  Inst.addOperand(MCOperand::createImm(Imm));
+  return MCDisassembler::Success;
+}
+
+// spimm is based on rlist now.
+static DecodeStatus decodeZcmpSpimm(MCInst &Inst, unsigned Imm,
+                                    uint64_t Address, const void *Decoder) {
+  // TODO: check if spimm matches rlist
+  Inst.addOperand(MCOperand::createImm(Imm));
+  return MCDisassembler::Success;
+}
+
 DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                                                ArrayRef<uint8_t> Bytes,
                                                uint64_t Address,
@@ -612,6 +645,15 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
     if (Result != MCDisassembler::Fail)
       return Result;
   }
+  if (STI.hasFeature(RISCV::FeatureStdExtZcmp)) {
+    LLVM_DEBUG(
+        dbgs()
+        << "Trying Zcmp table (16-bit Push/Pop & Double Move Instructions):\n");
+    Result =
+        decodeInstruction(DecoderTableRVZcmp16, MI, Insn, Address, this, STI);
+    if (Result != MCDisassembler::Fail)
+      return Result;
+  }
 
   LLVM_DEBUG(dbgs() << "Trying RISCV_C table (16-bit Instruction):\n");
   // Calling the auto-generated decoder function.

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index deae80d34593b..2307d4a8e7092 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -295,4 +295,18 @@ float RISCVLoadFPImm::getFPImm(unsigned Imm) {
   return bit_cast<float>(I);
 }
 
+void RISCVZC::printRlist(unsigned SlistEncode, raw_ostream &OS) {
+  OS << "{ra";
+  if (SlistEncode > 4) {
+    OS << ", s0";
+    if (SlistEncode == 15)
+      OS << "-s11";
+    else if (SlistEncode > 5 && SlistEncode <= 14)
+      OS << "-s" << (SlistEncode - 5);
+  }
+  OS << "}";
+}
+
+void RISCVZC::printSpimm(int64_t Spimm, raw_ostream &OS) { OS << Spimm; }
+
 } // namespace llvm

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index c2a1596e0940e..7f84b4b21a5ed 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -493,6 +493,124 @@ bool compress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI);
 bool uncompress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI);
 } // namespace RISCVRVC
 
+namespace RISCVZC {
+enum RLISTENCODE {
+  RA = 4,
+  RA_S0,
+  RA_S0_S1,
+  RA_S0_S2,
+  RA_S0_S3,
+  RA_S0_S4,
+  RA_S0_S5,
+  RA_S0_S6,
+  RA_S0_S7,
+  RA_S0_S8,
+  RA_S0_S9,
+  // note - to include s10, s11 must also be included
+  RA_S0_S11,
+  INVALID_RLIST,
+};
+
+inline unsigned encodeRlist(MCRegister EndReg, bool IsRV32E = false) {
+  assert((!IsRV32E || EndReg <= RISCV::X9) && "Invalid Rlist for RV32E");
+  switch (EndReg) {
+  case RISCV::X1:
+    return RLISTENCODE::RA;
+  case RISCV::X8:
+    return RLISTENCODE::RA_S0;
+  case RISCV::X9:
+    return RLISTENCODE::RA_S0_S1;
+  case RISCV::X18:
+    return RLISTENCODE::RA_S0_S2;
+  case RISCV::X19:
+    return RLISTENCODE::RA_S0_S3;
+  case RISCV::X20:
+    return RLISTENCODE::RA_S0_S4;
+  case RISCV::X21:
+    return RLISTENCODE::RA_S0_S5;
+  case RISCV::X22:
+    return RLISTENCODE::RA_S0_S6;
+  case RISCV::X23:
+    return RLISTENCODE::RA_S0_S7;
+  case RISCV::X24:
+    return RLISTENCODE::RA_S0_S8;
+  case RISCV::X25:
+    return RLISTENCODE::RA_S0_S9;
+  case RISCV::X26:
+    return RLISTENCODE::INVALID_RLIST;
+  case RISCV::X27:
+    return RLISTENCODE::RA_S0_S11;
+  default:
+    llvm_unreachable("Undefined input.");
+  }
+}
+
+inline static unsigned getStackAdjBase(unsigned RlistVal, bool IsRV64,
+                                       bool IsEABI) {
+  assert(RlistVal != RLISTENCODE::INVALID_RLIST &&
+         "{ra, s0-s10} is not supported, s11 must be included.");
+  if (IsEABI)
+    return 16;
+  if (!IsRV64) {
+    switch (RlistVal) {
+    case RLISTENCODE::RA:
+    case RLISTENCODE::RA_S0:
+    case RLISTENCODE::RA_S0_S1:
+    case RLISTENCODE::RA_S0_S2:
+      return 16;
+    case RLISTENCODE::RA_S0_S3:
+    case RLISTENCODE::RA_S0_S4:
+    case RLISTENCODE::RA_S0_S5:
+    case RLISTENCODE::RA_S0_S6:
+      return 32;
+    case RLISTENCODE::RA_S0_S7:
+    case RLISTENCODE::RA_S0_S8:
+    case RLISTENCODE::RA_S0_S9:
+      return 48;
+    case RLISTENCODE::RA_S0_S11:
+      return 64;
+    }
+  } else {
+    switch (RlistVal) {
+    case RLISTENCODE::RA:
+    case RLISTENCODE::RA_S0:
+      return 16;
+    case RLISTENCODE::RA_S0_S1:
+    case RLISTENCODE::RA_S0_S2:
+      return 32;
+    case RLISTENCODE::RA_S0_S3:
+    case RLISTENCODE::RA_S0_S4:
+      return 48;
+    case RLISTENCODE::RA_S0_S5:
+    case RLISTENCODE::RA_S0_S6:
+      return 64;
+    case RLISTENCODE::RA_S0_S7:
+    case RLISTENCODE::RA_S0_S8:
+      return 80;
+    case RLISTENCODE::RA_S0_S9:
+      return 96;
+    case RLISTENCODE::RA_S0_S11:
+      return 112;
+    }
+  }
+  llvm_unreachable("Unexpected RlistVal");
+}
+
+inline static bool getSpimm(unsigned RlistVal, unsigned &SpimmVal,
+                            int64_t StackAdjustment, bool IsRV64, bool IsEABI) {
+  if (RlistVal == RLISTENCODE::INVALID_RLIST)
+    return false;
+  unsigned stackAdj = getStackAdjBase(RlistVal, IsRV64, IsEABI);
+  SpimmVal = (StackAdjustment - stackAdj) / 16;
+  if (SpimmVal > 3)
+    return false;
+  return true;
+}
+
+void printRlist(unsigned SlistEncode, raw_ostream &OS);
+void printSpimm(int64_t Spimm, raw_ostream &OS);
+} // namespace RISCVZC
+
 } // namespace llvm
 
 #endif

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
index 692842928ea4b..e54d288eee7b4 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
@@ -202,6 +202,60 @@ void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
   RISCVVType::printVType(Imm, O);
 }
 
+void RISCVInstPrinter::printRlist(const MCInst *MI, unsigned OpNo,
+                                  const MCSubtargetInfo &STI, raw_ostream &O) {
+  unsigned Imm = MI->getOperand(OpNo).getImm();
+  O << "{";
+  switch (Imm) {
+  case RISCVZC::RLISTENCODE::RA:
+    O << (ArchRegNames ? "x1" : "ra");
+    break;
+  case RISCVZC::RLISTENCODE::RA_S0:
+    O << (ArchRegNames ? "x1, x8" : "ra, s0");
+    break;
+  case RISCVZC::RLISTENCODE::RA_S0_S1:
+    O << (ArchRegNames ? "x1, x8-x9" : "ra, s0-s1");
+    break;
+  case RISCVZC::RLISTENCODE::RA_S0_S2:
+    O << (ArchRegNames ? "x1, x8-x9, x18" : "ra, s0-s2");
+    break;
+  case RISCVZC::RLISTENCODE::RA_S0_S3:
+  case RISCVZC::RLISTENCODE::RA_S0_S4:
+  case RISCVZC::RLISTENCODE::RA_S0_S5:
+  case RISCVZC::RLISTENCODE::RA_S0_S6:
+  case RISCVZC::RLISTENCODE::RA_S0_S7:
+  case RISCVZC::RLISTENCODE::RA_S0_S8:
+  case RISCVZC::RLISTENCODE::RA_S0_S9:
+    O << (ArchRegNames ? "x1, x8-x9, x18-" : "ra, s0-")
+      << getRegisterName(RISCV::X19 + (Imm - RISCVZC::RLISTENCODE::RA_S0_S3));
+    break;
+  case RISCVZC::RLISTENCODE::RA_S0_S11:
+    O << (ArchRegNames ? "x1, x8-x9, x18-x27" : "ra, s0-s11");
+    break;
+  default:
+    llvm_unreachable("invalid register list");
+  }
+  O << "}";
+}
+
+void RISCVInstPrinter::printSpimm(const MCInst *MI, unsigned OpNo,
+                                  const MCSubtargetInfo &STI, raw_ostream &O) {
+  int64_t Imm = MI->getOperand(OpNo).getImm();
+  unsigned Opcode = MI->getOpcode();
+  bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
+  bool IsEABI = STI.hasFeature(RISCV::FeatureRVE);
+  int64_t Spimm = 0;
+  auto RlistVal = MI->getOperand(0).getImm();
+  assert(RlistVal != 16 && "Incorrect rlist.");
+  auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64, IsEABI);
+  Spimm = Imm + Base;
+  assert((Spimm >= Base && Spimm <= Base + 48) && "Incorrect spimm");
+  if (Opcode == RISCV::CM_PUSH)
+    Spimm = -Spimm;
+
+  RISCVZC::printSpimm(Spimm, O);
+}
+
 void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo,
                                      const MCSubtargetInfo &STI,
                                      raw_ostream &O) {

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h
index 8c42ae059eec8..20f12af13008c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h
@@ -48,6 +48,10 @@ class RISCVInstPrinter : public MCInstPrinter {
                    raw_ostream &O);
   void printVMaskReg(const MCInst *MI, unsigned OpNo,
                      const MCSubtargetInfo &STI, raw_ostream &O);
+  void printRlist(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+                  raw_ostream &O);
+  void printSpimm(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+                  raw_ostream &O);
 
   // Autogenerated by tblgen.
   std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override;

diff  --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index b79ed11412e68..831c1e788dd45 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -88,6 +88,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
   unsigned getVMaskReg(const MCInst &MI, unsigned OpNo,
                        SmallVectorImpl<MCFixup> &Fixups,
                        const MCSubtargetInfo &STI) const;
+
+  unsigned getRlistOpValue(const MCInst &MI, unsigned OpNo,
+                           SmallVectorImpl<MCFixup> &Fixups,
+                           const MCSubtargetInfo &STI) const;
 };
 } // end anonymous namespace
 
@@ -483,4 +487,14 @@ unsigned RISCVMCCodeEmitter::getVMaskReg(const MCInst &MI, unsigned OpNo,
   }
 }
 
+unsigned RISCVMCCodeEmitter::getRlistOpValue(const MCInst &MI, unsigned OpNo,
+                                             SmallVectorImpl<MCFixup> &Fixups,
+                                             const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  assert(MO.isImm() && "Rlist operand must be immediate");
+  auto Imm = MO.getImm();
+  assert(Imm >= 4 && "EABI is currently not implemented");
+  return Imm;
+}
+
 #include "RISCVGenMCCodeEmitter.inc"

diff  --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index d4699ee64127e..602ebeaf29b9b 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -361,6 +361,14 @@ def HasStdExtCOrZcf
                                    "'C' (Compressed Instructions) or "
                                    "'Zcf' (Compressed Single-Precision Floating-Point Instructions)">;
 
+def FeatureStdExtZcmp
+    : SubtargetFeature<"experimental-zcmp", "HasStdExtZcmp", "true",
+                       "'Zcmp' (sequenced instuctions for code-size reduction)", 
+                       [FeatureStdExtZca]>;
+def HasStdExtZcmp : Predicate<"Subtarget->hasStdExtZcmp() && !Subtarget->hasStdExtC()">,
+                               AssemblerPredicate<(all_of FeatureStdExtZcmp, (not FeatureStdExtC)),
+                               "'Zcmp' (sequenced instuctions for code-size reduction)">;
+
 def FeatureStdExtZcmt
     : SubtargetFeature<"experimental-zcmt", "HasStdExtZcmt", "true",
                        "'Zcmt' (table jump instuctions for code-size reduction)", 

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
index 962178b8a18e3..5fd323e25479a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 ///
 /// This file describes the RISC-V instructions from the 'Zc*' compressed
-/// instruction extensions, version 1.0.1.
+/// instruction extensions, version 1.0.3.
 /// This version is still experimental as the 'Zc*' extensions haven't been
 /// ratified yet.
 ///
@@ -39,6 +39,45 @@ def uimm8ge32 : Operand<XLenVT> {
   let OperandNamespace = "RISCVOp";
 }
 
+def RlistAsmOperand : AsmOperandClass {
+  let Name = "Rlist";
+  let ParserMethod = "parseReglist";
+  let DiagnosticType = "InvalidRlist";
+}
+
+def SpimmAsmOperand : AsmOperandClass {
+  let Name = "Spimm";
+  let ParserMethod = "parseZcmpSpimm";
+  let DiagnosticType = "InvalidSpimm";
+}
+
+def rlist : Operand<OtherVT> {
+   let ParserMatchClass = RlistAsmOperand;
+   let PrintMethod = "printRlist";
+   let DecoderMethod = "decodeZcmpRlist";
+   let EncoderMethod = "getRlistOpValue";
+   let MCOperandPredicate = [{
+    int64_t Imm;
+    if (!MCOp.evaluateAsConstantImm(Imm))
+      return false;
+    if (!isUInt<4>(Imm)) return false;
+    // 0~3 Reserved for EABI
+    return (Imm >= 4) && (Imm <= 15);
+  }];
+ }
+
+def spimm : Operand<OtherVT> {
+  let ParserMatchClass = SpimmAsmOperand;
+  let PrintMethod = "printSpimm";
+  let DecoderMethod = "decodeZcmpSpimm";
+  let MCOperandPredicate = [{
+    int64_t Imm;
+    if (!MCOp.evaluateAsConstantImm(Imm))
+      return false;
+    return isShiftedUInt<5, 4>(Imm);
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // Instruction Class Templates
 //===----------------------------------------------------------------------===//
@@ -90,6 +129,13 @@ class RVZcArith_r<bits<5> funct5, string OpcodeStr> :
   let Constraints = "$rd = $rd_wb";
 }
 
+class RVInstZcCPPP<dag outs, dag ins, string opcodestr, string argstr>
+    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatOther> {
+
+  let Inst{1-0} = 0b10;
+  let Inst{15-13} = 0b101;
+}
+
 //===----------------------------------------------------------------------===//
 // Instructions
 //===----------------------------------------------------------------------===//
@@ -132,6 +178,62 @@ def C_SH : CStoreH_rri<0b100011, 0b1, "c.sh">,
            Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
 }
 
+// Zcmp
+let DecoderNamespace = "RVZcmp", Predicates = [HasStdExtZcmp],
+    Defs = [X10, X11], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+def CM_MVA01S : RVInst16CA<0b101011, 0b11, 0b10, (outs),
+                            (ins SR07:$rs1, SR07:$rs2), "cm.mva01s", "$rs1, $rs2">;
+
+def CM_MVSA01 : RVInst16CA<0b101011, 0b01, 0b10, (outs SR07:$rs1, SR07:$rs2),
+                            (ins), "cm.mvsa01", "$rs1, $rs2">;
+} // DecoderNamespace = "RVZcmp", Predicates = [HasStdExtZcmp]...
+
+let DecoderNamespace = "RVZcmp", Predicates = [HasStdExtZcmp] in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in 
+def CM_PUSH : RVInstZcCPPP<(outs), (ins rlist:$rlist, spimm:$spimm), 
+    "cm.push", "{$rlist}, $spimm"> {
+  bits<4> rlist;
+  bits<16> spimm;
+
+  let Inst{12-8} = 0b11000;
+  let Inst{7-4} = rlist;
+  let Inst{3-2} = spimm{5-4};
+}
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in 
+def CM_POPRET : RVInstZcCPPP<(outs), (ins rlist:$rlist, spimm:$spimm), 
+    "cm.popret", "{$rlist}, $spimm"> {
+  bits<4> rlist;
+  bits<16> spimm;
+
+  let Inst{12-8} = 0b11110;
+  let Inst{7-4} = rlist;
+  let Inst{3-2} = spimm{5-4};
+}
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in 
+def CM_POPRETZ : RVInstZcCPPP<(outs), (ins rlist:$rlist, spimm:$spimm), 
+    "cm.popretz", "{$rlist}, $spimm"> {
+  bits<4> rlist;
+  bits<16> spimm;
+
+  let Inst{12-8} = 0b11100;
+  let Inst{7-4} = rlist;
+  let Inst{3-2} = spimm{5-4};
+}
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in 
+def CM_POP : RVInstZcCPPP<(outs), (ins rlist:$rlist, spimm:$spimm), 
+    "cm.pop", "{$rlist}, $spimm"> {
+  bits<4> rlist;
+  bits<16> spimm;
+
+  let Inst{12-8} = 0b11010;
+  let Inst{7-4} = rlist;
+  let Inst{3-2} = spimm{5-4};
+}
+} // DecoderNamespace = "RVZcmp", Predicates = [HasStdExtZcmp]...
+
 let DecoderNamespace = "RVZcmt", Predicates = [HasStdExtZcmt],
     hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
 def CM_JT : RVInst16CJ<0b101, 0b10, (outs), (ins uimm5:$index),

diff  --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index a555202db3661..a27a50cb80100 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -175,6 +175,14 @@ def SP : RegisterClass<"RISCV", [XLenVT], 32, (add X2)> {
   let RegInfos = XLenRI;
 }
 
+// Saved Registers from s0 to s7, for C.MVA01S07 instruction in Zcmp extension
+def SR07 : RegisterClass<"RISCV", [XLenVT], 32, (add
+    (sequence "X%u", 8, 9),
+    (sequence "X%u", 18, 23)
+  )> {
+  let RegInfos = XLenRI;
+}
+
 // Floating point registers
 let RegAltNameIndices = [ABIRegAltName] in {
   def F0_H  : RISCVReg16<0, "f0", ["ft0"]>, DwarfRegNum<[32]>;

diff  --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index b22b202af437f..dbad6cce700b2 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -231,6 +231,9 @@
 .attribute arch, "rv32izcb1p0"
 # CHECK: attribute      5, "rv32i2p1_zca1p0_zcb1p0"
 
+.attribute arch, "rv32izcmp1p0"
+# CHECK: attribute      5, "rv32i2p1_zca1p0_zcmp1p0"
+
 .attribute arch, "rv32izcmt1p0"
 # CHECK: attribute      5, "rv32i2p1_zca1p0_zcmt1p0"
 

diff  --git a/llvm/test/MC/RISCV/rv32zcmp-invalid.s b/llvm/test/MC/RISCV/rv32zcmp-invalid.s
new file mode 100644
index 0000000000000..caa7424bb23e9
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zcmp-invalid.s
@@ -0,0 +1,17 @@
+# RUN: not llvm-mc -triple=riscv32 -mattr=experimental-zcmp -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-ERROR %s
+
+# CHECK-ERROR: error: invalid operand for instruction
+cm.mvsa01 a1, a2
+
+# CHECK-ERROR: error: 'rs1' and 'rs2' must be 
diff erent
+cm.mvsa01 s0, s0
+
+# CHECK-ERROR: error: invalid operand for instruction
+cm.mva01s a1, a2
+
+# CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
+cm.popretz {ra, s0-s10}, 112
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+cm.popretz {ra, s0-s1}, 112

diff  --git a/llvm/test/MC/RISCV/rv32zcmp-valid.s b/llvm/test/MC/RISCV/rv32zcmp-valid.s
new file mode 100644
index 0000000000000..e9cfd58578fb8
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zcmp-valid.s
@@ -0,0 +1,289 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=experimental-zcmp -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=experimental-zcmp < %s \
+# RUN:     | llvm-objdump --mattr=-c,experimental-zcmp -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: cm.mvsa01 s1, s0
+# CHECK-ASM: encoding: [0xa2,0xac]
+cm.mvsa01 s1, s0
+
+# CHECK-ASM-AND-OBJ: cm.mva01s s1, s0
+# CHECK-ASM: encoding: [0xe2,0xac]
+cm.mva01s s1, s0
+
+# CHECK-ASM-AND-OBJ: cm.mva01s s0, s0
+# CHECK-ASM: encoding: [0x62,0xac] 
+cm.mva01s s0, s0
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+cm.popret {ra}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+cm.popret {x1}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+cm.popret {ra}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+cm.popret {x1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+cm.popret {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+cm.popret {x1, x8}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbe]
+cm.popret {ra,s0-s1}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbe]
+cm.popret {x1, x8-x9}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbe]
+cm.popret {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbe]
+cm.popret {x1, x8-x9, x18}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbe]
+cm.popret {ra, s0-s3}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbe]
+cm.popret {x1, x8-x9, x18-x19}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbe]
+cm.popret {ra, s0-s5}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbe]
+cm.popret {x1, x8-x9, x18-x21}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbe]
+cm.popret {ra, s0-s7}, 48
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbe]
+cm.popret {x1, x8-x9, x18-x23}, 48
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbe]
+cm.popret {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbe]
+cm.popret {x1, x8-x9, x18-x27}, 112
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+cm.popretz {ra}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+cm.popretz {x1}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+cm.popretz {ra}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+cm.popretz {x1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+cm.popretz {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+cm.popretz {x1, x8}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbc]
+cm.popretz {ra, s0-s1}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s1}, 16
+# CHECK-ASM: encoding: [0x62,0xbc]
+cm.popretz {x1, x8-x9}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbc]
+cm.popretz {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xbc]
+cm.popretz {x1, x8-x9, x18}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbc]
+cm.popretz {ra, s0-s3}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s3}, 32
+# CHECK-ASM: encoding: [0x82,0xbc]
+cm.popretz {x1, x8-x9, x18-x19}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbc]
+cm.popretz {ra, s0-s5}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xbc]
+cm.popretz {x1, x8-x9, x18-x21}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbc]
+cm.popretz {ra, s0-s7}, 48
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xbc]
+cm.popretz {x1, x8-x9, x18-x23}, 48
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbc]
+cm.popretz {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xfe,0xbc]
+cm.popretz {x1, x8-x9, x18-x27}, 112
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+cm.pop {ra}, 16
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+cm.pop {x1}, 16
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+cm.pop {ra}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+cm.pop {x1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+cm.pop {ra, s0}, 16
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+cm.pop {x1, x8}, 16
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x66,0xba]
+cm.pop {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x66,0xba]
+cm.pop {x1, x8-x9}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xba]
+cm.pop {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x76,0xba]
+cm.pop {x1, x8-x9, x18}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xba]
+cm.pop {ra, s0-s5}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s5}, 32
+# CHECK-ASM: encoding: [0xa2,0xba]
+cm.pop {x1, x8-x9, x18-x21}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xba]
+cm.pop {ra, s0-s7}, 48
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s7}, 48
+# CHECK-ASM: encoding: [0xc2,0xba]
+cm.pop {x1, x8-x9, x18-x23}, 48
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s11}, 64
+# CHECK-ASM: encoding: [0xf2,0xba]
+cm.pop {ra, s0-s11}, 64
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s11}, 64
+# CHECK-ASM: encoding: [0xf2,0xba]
+cm.pop {x1, x8-x9, x18-x27}, 64
+
+# CHECK-ASM-AND-OBJ: cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+cm.push {ra}, -16
+
+# CHECK-ASM-AND-OBJ: cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+cm.push {x1}, -16
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+cm.push {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+cm.push {x1, x8}, -32
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s1}, -16
+# CHECK-ASM: encoding: [0x62,0xb8]
+cm.push {ra, s0-s1}, -16
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s1}, -16
+# CHECK-ASM: encoding: [0x62,0xb8]
+cm.push {x1, x8-x9}, -16
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s3}, -32
+# CHECK-ASM: encoding: [0x82,0xb8]
+cm.push {ra, s0-s3}, -32
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s3}, -32
+# CHECK-ASM: encoding: [0x82,0xb8]
+cm.push {x1, x8-x9, x18-x19}, -32
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s7}, -48
+# CHECK-ASM: encoding: [0xc2,0xb8]
+cm.push {ra, s0-s7}, -48
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s7}, -48
+# CHECK-ASM: encoding: [0xc2,0xb8]
+cm.push {x1, x8-x9, x18-x23}, -48
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s7}, -64
+# CHECK-ASM: encoding: [0xc6,0xb8]
+cm.push {ra, s0-s7}, -64
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s7}, -64
+# CHECK-ASM: encoding: [0xc6,0xb8]
+cm.push {x1, x8-x9, x18-x23}, -64
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s11}, -80
+# CHECK-ASM: encoding: [0xf6,0xb8]
+cm.push {ra, s0-s11}, -80
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s11}, -80
+# CHECK-ASM: encoding: [0xf6,0xb8]
+cm.push {x1, x8-x9, x18-x27}, -80
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xfe,0xb8]
+cm.push {ra, s0-s11}, -112
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xfe,0xb8]
+cm.push {x1, x8-x9, x18-x27}, -112

diff  --git a/llvm/test/MC/RISCV/rv64zcmp-invalid.s b/llvm/test/MC/RISCV/rv64zcmp-invalid.s
new file mode 100644
index 0000000000000..61845ba069268
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zcmp-invalid.s
@@ -0,0 +1,17 @@
+# RUN: not llvm-mc -triple=riscv64 -mattr=experimental-zcmp -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-ERROR %s
+
+# CHECK-ERROR: error: invalid operand for instruction
+cm.mvsa01 a1, a2
+
+# CHECK-ERROR: error: 'rs1' and 'rs2' must be 
diff erent
+cm.mvsa01 s0, s0
+
+# CHECK-ERROR: error: invalid operand for instruction
+cm.mva01s a1, a2
+
+# CHECK-ERROR: error: invalid register list, {ra, s0-s10} or {x1, x8-x9, x18-x26} is not supported
+cm.popretz {ra, s0-s10}, 112
+
+# CHECK-ERROR: error: stack adjustment is invalid for this instruction and register list; refer to Zc spec for a detailed range of stack adjustment
+cm.popretz {ra, s0-s1}, 112

diff  --git a/llvm/test/MC/RISCV/rv64zcmp-valid.s b/llvm/test/MC/RISCV/rv64zcmp-valid.s
new file mode 100644
index 0000000000000..227940a7c6955
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zcmp-valid.s
@@ -0,0 +1,149 @@
+# RUN: llvm-mc %s -triple=riscv64 -mattr=experimental-zcmp -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=experimental-zcmp < %s \
+# RUN:     | llvm-objdump --mattr=-c,experimental-zcmp -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: cm.mvsa01 s1, s0
+# CHECK-ASM: encoding: [0xa2,0xac]
+cm.mvsa01 s1, s0
+
+# CHECK-ASM-AND-OBJ: cm.mva01s s1, s0
+# CHECK-ASM: encoding: [0xe2,0xac]
+cm.mva01s s1, s0
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbe]
+cm.popret {ra}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbe]
+cm.popret {ra}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbe]
+cm.popret {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xbe]
+cm.popret {ra,s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x72,0xbe]
+cm.popret {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s3}, 64
+# CHECK-ASM: encoding: [0x86,0xbe]
+cm.popret {ra, s0-s3}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s5}, 64
+# CHECK-ASM: encoding: [0xa2,0xbe]
+cm.popret {ra, s0-s5}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s7}, 80
+# CHECK-ASM: encoding: [0xc2,0xbe]
+cm.popret {ra, s0-s7}, 80
+
+# CHECK-ASM-AND-OBJ: cm.popret   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xf2,0xbe]
+cm.popret {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xbc]
+cm.popretz {ra}, 16
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xbc]
+cm.popretz {ra}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0}, 64
+# CHECK-ASM: encoding: [0x5e,0xbc]
+cm.popretz {ra, s0}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xbc]
+cm.popretz {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x72,0xbc]
+cm.popretz {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s3}, 64
+# CHECK-ASM: encoding: [0x86,0xbc]
+cm.popretz {ra, s0-s3}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s5}, 64
+# CHECK-ASM: encoding: [0xa2,0xbc]
+cm.popretz {ra, s0-s5}, 64
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s7}, 80
+# CHECK-ASM: encoding: [0xc2,0xbc]
+cm.popretz {ra, s0-s7}, 80
+
+# CHECK-ASM-AND-OBJ: cm.popretz   {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xf2,0xbc]
+cm.popretz {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra}, 16
+# CHECK-ASM: encoding: [0x42,0xba]
+cm.pop {ra}, 16
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra}, 32
+# CHECK-ASM: encoding: [0x46,0xba]
+cm.pop {ra}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0}, 16
+# CHECK-ASM: encoding: [0x52,0xba]
+cm.pop {ra, s0}, 16
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s1}, 32
+# CHECK-ASM: encoding: [0x62,0xba]
+cm.pop {ra, s0-s1}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s2}, 32
+# CHECK-ASM: encoding: [0x72,0xba]
+cm.pop {ra, s0-s2}, 32
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s5}, 64
+# CHECK-ASM: encoding: [0xa2,0xba]
+cm.pop {ra, s0-s5}, 64
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s7}, 80
+# CHECK-ASM: encoding: [0xc2,0xba]
+cm.pop {ra, s0-s7}, 80
+
+# CHECK-ASM-AND-OBJ: cm.pop  {ra, s0-s11}, 112
+# CHECK-ASM: encoding: [0xf2,0xba]
+cm.pop {ra, s0-s11}, 112
+
+# CHECK-ASM-AND-OBJ: cm.push {ra}, -16
+# CHECK-ASM: encoding: [0x42,0xb8]
+cm.push {ra}, -16
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0}, -32
+# CHECK-ASM: encoding: [0x56,0xb8]
+cm.push {ra, s0}, -32
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s1}, -32
+# CHECK-ASM: encoding: [0x62,0xb8]
+cm.push {ra, s0-s1}, -32
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s3}, -64
+# CHECK-ASM: encoding: [0x86,0xb8]
+cm.push {ra, s0-s3}, -64
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s7}, -80
+# CHECK-ASM: encoding: [0xc2,0xb8]
+cm.push {ra, s0-s7}, -80
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s7}, -80
+# CHECK-ASM: encoding: [0xc2,0xb8]
+cm.push {ra, s0-s7}, -80
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s11}, -112
+# CHECK-ASM: encoding: [0xf2,0xb8]
+cm.push {ra, s0-s11}, -112
+
+# CHECK-ASM-AND-OBJ: cm.push {ra, s0-s11}, -128
+# CHECK-ASM: encoding: [0xf6,0xb8]
+cm.push {ra, s0-s11}, -128


        


More information about the cfe-commits mailing list