[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