diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c --- 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 --- a/llvm/docs/RISCVUsage.rst +++ b/llvm/docs/RISCVUsage.rst @@ -195,6 +195,9 @@ ``experimental-zcf`` LLVM implements the `1.0.1 draft specification `__. +``experimental-zcmp`` + LLVM implements the `1.0.1 draft specification `__. + ``experimental-zcmt`` LLVM implements the `1.0.1 draft specification `_. diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -144,6 +144,7 @@ {"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}}, @@ -935,6 +936,7 @@ 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"}; @@ -993,6 +995,7 @@ {{"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 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -183,6 +183,9 @@ 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 @@ VType, FRM, Fence, + Rlist, + Spimm, } Kind; struct RegOp { @@ -329,6 +334,14 @@ unsigned Val; }; + struct RlistOp { + unsigned Val; + }; + + struct SpimmOp { + unsigned Val; + }; + SMLoc StartLoc, EndLoc; union { StringRef Tok; @@ -339,6 +352,8 @@ struct VTypeOp VType; struct FRMOp FRM; struct FenceOp Fence; + struct RlistOp Rlist; + struct SpimmOp Spimm; }; RISCVOperand(KindTy K) : Kind(K) {} @@ -373,6 +388,12 @@ 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 @@ 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 @@ OS << getFence(); OS << '>'; break; + case KindTy::Rlist: + OS << "'; + break; + case KindTy::Spimm: + OS << "'; + break; } } @@ -1024,6 +1057,21 @@ return Op; } + static std::unique_ptr createRlist(unsigned RlistEncode, + SMLoc S) { + auto Op = std::make_unique(KindTy::Rlist); + Op->Rlist.Val = RlistEncode; + Op->StartLoc = S; + return Op; + } + + static std::unique_ptr createSpimm(unsigned Spimm, SMLoc S) { + auto Op = std::make_unique(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 @@ 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 @@ (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 @@ 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(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 @@ } } + 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 different."); + } + } + bool IsTHeadMemPair32 = (Opcode == RISCV::TH_LWD || Opcode == RISCV::TH_LWUD || Opcode == RISCV::TH_SWD); bool IsTHeadMemPair64 = (Opcode == RISCV::TH_LDD || Opcode == RISCV::TH_SDD); @@ -3161,7 +3382,6 @@ .addImm(Imm - 1) .addOperand(Inst.getOperand(3))); } - return false; } } diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -168,6 +168,17 @@ 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 @@ 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 @@ 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 Bytes, uint64_t Address, @@ -612,6 +645,14 @@ if (Result != MCDisassembler::Fail) return Result; } + if (STI.hasFeature(RISCV::FeatureStdExtZcmp)) { + LLVM_DEBUG( + dbgs() << "Trying Zcmp table (16-bit Table Jump 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.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -493,6 +493,124 @@ 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/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp @@ -295,4 +295,18 @@ return bit_cast(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/RISCVInstPrinter.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h @@ -48,6 +48,10 @@ 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 getMnemonic(const MCInst *MI) override; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp @@ -202,6 +202,60 @@ 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/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -88,6 +88,10 @@ unsigned getVMaskReg(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + unsigned getRlistOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // end anonymous namespace @@ -483,4 +487,14 @@ } } +unsigned RISCVMCCodeEmitter::getRlistOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &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 --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -361,6 +361,14 @@ "'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 --- 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 @@ 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 { + 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 { + 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 @@ let Constraints = "$rd = $rd_wb"; } +class RVInstZcCPPP + : RVInst16 { + + let Inst{1-0} = 0b10; + let Inst{15-13} = 0b101; +} + //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// @@ -132,6 +178,62 @@ 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">; +} + +let 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 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -175,6 +175,14 @@ 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 --- 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 --- /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 different +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 --- /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 --- /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 different +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 --- /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