Skip to content

Commit 6b55e91

Browse files
committed
[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
1 parent 173b8fe commit 6b55e91

18 files changed

+1075
-1
lines changed

clang/test/Preprocessor/riscv-target-features.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
// CHECK-NOT: __riscv_zcb {{.*$}}
4949
// CHECK-NOT: __riscv_zcd {{.*$}}
5050
// CHECK-NOT: __riscv_zcf {{.*$}}
51+
// CHECK-NOT: __riscv_zcmp {{.*$}}
5152
// CHECK-NOT: __riscv_zcmt {{.*$}}
5253
// CHECK-NOT: __riscv_h {{.*$}}
5354
// CHECK-NOT: __riscv_zvbb {{.*$}}
@@ -512,6 +513,13 @@
512513
// RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCF-EXT %s
513514
// CHECK-ZCF-EXT: __riscv_zcf 1000000{{$}}
514515

516+
// RUN: %clang -target riscv32 -march=rv32izcmp1p0 -menable-experimental-extensions \
517+
// RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCMP-EXT %s
518+
// RUN: %clang -target riscv64 -march=rv64izcmp1p0 -menable-experimental-extensions \
519+
// RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCMP-EXT %s
520+
// CHECK-ZCMP-EXT: __riscv_zca 1000000{{$}}
521+
// CHECK-ZCMP-EXT: __riscv_zcmp 1000000{{$}}
522+
515523
// RUN: %clang -target riscv32 -march=rv32izcmt1p0 -menable-experimental-extensions \
516524
// RUN: -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-ZCMT-EXT %s
517525
// RUN: %clang -target riscv64 -march=rv64izcmt1p0 -menable-experimental-extensions \

llvm/docs/RISCVUsage.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ The primary goal of experimental support is to assist in the process of ratifica
195195
``experimental-zcf``
196196
LLVM implements the `1.0.1 draft specification <https://github.com/riscv/riscv-code-size-reduction/releases/tag/v1.0.1>`__.
197197

198+
``experimental-zcmp``
199+
LLVM implements the `1.0.1 draft specification <https://github.com/riscv/riscv-code-size-reduction/releases/tag/v1.0.1>`__.
200+
198201
``experimental-zcmt``
199202
LLVM implements the `1.0.1 draft specification <https://github.com/riscv/riscv-code-size-reduction/releases/tag/v1.0.1>`_.
200203

llvm/lib/Support/RISCVISAInfo.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
144144
{"zcb", RISCVExtensionVersion{1, 0}},
145145
{"zcd", RISCVExtensionVersion{1, 0}},
146146
{"zcf", RISCVExtensionVersion{1, 0}},
147+
{"zcmp", RISCVExtensionVersion{1, 0}},
147148
{"zcmt", RISCVExtensionVersion{1, 0}},
148149
{"zfa", RISCVExtensionVersion{0, 2}},
149150
{"zicond", RISCVExtensionVersion{1, 0}},
@@ -920,6 +921,7 @@ static const char *ImpliedExtsV[] = {"zvl128b", "zve64d", "f", "d"};
920921
static const char *ImpliedExtsXTHeadVdot[] = {"v"};
921922
static const char *ImpliedExtsXsfvcp[] = {"zve32x"};
922923
static const char *ImpliedExtsZcb[] = {"zca"};
924+
static const char *ImpliedExtsZcmp[] = {"zca"};
923925
static const char *ImpliedExtsZcmt[] = {"zca"};
924926
static const char *ImpliedExtsZdinx[] = {"zfinx"};
925927
static const char *ImpliedExtsZfa[] = {"f"};
@@ -978,6 +980,7 @@ static constexpr ImpliedExtsEntry ImpliedExts[] = {
978980
{{"xsfvcp"}, {ImpliedExtsXsfvcp}},
979981
{{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
980982
{{"zcb"}, {ImpliedExtsZcb}},
983+
{{"zcmp"}, {ImpliedExtsZcmp}},
981984
{{"zcmt"}, {ImpliedExtsZcmt}},
982985
{{"zdinx"}, {ImpliedExtsZdinx}},
983986
{{"zfa"}, {ImpliedExtsZfa}},

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ class RISCVAsmParser : public MCTargetAsmParser {
183183
OperandMatchResultTy parseGPRAsFPR(OperandVector &Operands);
184184
OperandMatchResultTy parseFRMArg(OperandVector &Operands);
185185
OperandMatchResultTy parseFenceArg(OperandVector &Operands);
186+
OperandMatchResultTy parseReglist(OperandVector &Operands);
187+
OperandMatchResultTy parseRetval(OperandVector &Operands);
188+
OperandMatchResultTy parseZcmpSpimm(OperandVector &Operands);
186189

187190
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
188191

@@ -293,6 +296,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
293296
VType,
294297
FRM,
295298
Fence,
299+
Rlist,
300+
Spimm,
296301
} Kind;
297302

298303
struct RegOp {
@@ -329,6 +334,14 @@ struct RISCVOperand final : public MCParsedAsmOperand {
329334
unsigned Val;
330335
};
331336

337+
struct RlistOp {
338+
unsigned Val;
339+
};
340+
341+
struct SpimmOp {
342+
unsigned Val;
343+
};
344+
332345
SMLoc StartLoc, EndLoc;
333346
union {
334347
StringRef Tok;
@@ -339,6 +352,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
339352
struct VTypeOp VType;
340353
struct FRMOp FRM;
341354
struct FenceOp Fence;
355+
struct RlistOp Rlist;
356+
struct SpimmOp Spimm;
342357
};
343358

344359
RISCVOperand(KindTy K) : Kind(K) {}
@@ -373,6 +388,12 @@ struct RISCVOperand final : public MCParsedAsmOperand {
373388
case KindTy::Fence:
374389
Fence = o.Fence;
375390
break;
391+
case KindTy::Rlist:
392+
Rlist = o.Rlist;
393+
break;
394+
case KindTy::Spimm:
395+
Spimm = o.Spimm;
396+
break;
376397
}
377398
}
378399

@@ -397,6 +418,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
397418
bool isImm() const override { return Kind == KindTy::Immediate; }
398419
bool isMem() const override { return false; }
399420
bool isSystemRegister() const { return Kind == KindTy::SystemRegister; }
421+
bool isRlist() const { return Kind == KindTy::Rlist; }
422+
bool isSpimm() const { return Kind == KindTy::Spimm; }
400423

401424
bool isGPR() const {
402425
return Kind == KindTy::Register &&
@@ -949,6 +972,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
949972
OS << getFence();
950973
OS << '>';
951974
break;
975+
case KindTy::Rlist:
976+
OS << "<rlist: ";
977+
RISCVZC::printRlist(Rlist.Val, OS);
978+
OS << '>';
979+
break;
980+
case KindTy::Spimm:
981+
OS << "<Spimm: ";
982+
RISCVZC::printSpimm(Spimm.Val, OS);
983+
OS << '>';
984+
break;
952985
}
953986
}
954987

@@ -1024,6 +1057,21 @@ struct RISCVOperand final : public MCParsedAsmOperand {
10241057
return Op;
10251058
}
10261059

1060+
static std::unique_ptr<RISCVOperand> createRlist(unsigned RlistEncode,
1061+
SMLoc S) {
1062+
auto Op = std::make_unique<RISCVOperand>(KindTy::Rlist);
1063+
Op->Rlist.Val = RlistEncode;
1064+
Op->StartLoc = S;
1065+
return Op;
1066+
}
1067+
1068+
static std::unique_ptr<RISCVOperand> createSpimm(unsigned Spimm, SMLoc S) {
1069+
auto Op = std::make_unique<RISCVOperand>(KindTy::Spimm);
1070+
Op->Spimm.Val = Spimm;
1071+
Op->StartLoc = S;
1072+
return Op;
1073+
}
1074+
10271075
static void addExpr(MCInst &Inst, const MCExpr *Expr, bool IsRV64Imm) {
10281076
assert(Expr && "Expr shouldn't be null!");
10291077
int64_t Imm = 0;
@@ -1087,6 +1135,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
10871135
Inst.addOperand(MCOperand::createImm(Imm));
10881136
}
10891137

1138+
void addRlistOperands(MCInst &Inst, unsigned N) const {
1139+
assert(N == 1 && "Invalid number of operands!");
1140+
Inst.addOperand(MCOperand::createImm(Rlist.Val));
1141+
}
1142+
1143+
void addSpimmOperands(MCInst &Inst, unsigned N) const {
1144+
assert(N == 1 && "Invalid number of operands!");
1145+
Inst.addOperand(MCOperand::createImm(Spimm.Val));
1146+
}
1147+
10901148
void addFRMArgOperands(MCInst &Inst, unsigned N) const {
10911149
assert(N == 1 && "Invalid number of operands!");
10921150
Inst.addOperand(MCOperand::createImm(getFRM()));
@@ -1422,6 +1480,19 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
14221480
(1 << 4),
14231481
"immediate must be in the range");
14241482
}
1483+
case Match_InvalidRlist: {
1484+
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
1485+
return Error(
1486+
ErrorLoc,
1487+
"operand must be {ra [, s0[-sN]]} or {x1 [, x8[-x9][, x18[-xN]]]}");
1488+
}
1489+
case Match_InvalidSpimm: {
1490+
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
1491+
return Error(
1492+
ErrorLoc,
1493+
"stack adjustment is invalid for this instruction and register list; "
1494+
"refer to Zc spec for a detailed range of stack adjustment");
1495+
}
14251496
case Match_InvalidRnumArg: {
14261497
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, 10);
14271498
}
@@ -2243,6 +2314,147 @@ RISCVAsmParser::parseZeroOffsetMemOp(OperandVector &Operands) {
22432314
return MatchOperand_Success;
22442315
}
22452316

2317+
OperandMatchResultTy RISCVAsmParser::parseReglist(OperandVector &Operands) {
2318+
// Rlist: {ra [, s0[-sN]]}
2319+
// XRlist: {x1 [, x8[-x9][, x18[-xN]]]}
2320+
SMLoc S = getLoc();
2321+
if (getLexer().isNot(AsmToken::LCurly)) {
2322+
Error(getLoc(), "register list must start with '{'");
2323+
return MatchOperand_ParseFail;
2324+
}
2325+
getLexer().Lex(); // eat '{'
2326+
bool IsEABI = isRVE();
2327+
2328+
MCRegister RegStart = RISCV::NoRegister;
2329+
MCRegister RegEnd = RISCV::NoRegister;
2330+
StringRef RegName = getLexer().getTok().getIdentifier();
2331+
matchRegisterNameHelper(IsEABI, RegStart, RegName);
2332+
if (RegStart != RISCV::X1) {
2333+
Error(getLoc(), "register list must start from 'ra' or 'x1'");
2334+
return MatchOperand_ParseFail;
2335+
}
2336+
getLexer().Lex();
2337+
2338+
// parse case like ,s0
2339+
if (getLexer().is(AsmToken::Comma)) {
2340+
getLexer().Lex();
2341+
if (getLexer().isNot(AsmToken::Identifier)) {
2342+
Error(getLoc(), "invalid register");
2343+
return MatchOperand_ParseFail;
2344+
}
2345+
StringRef RegName = getLexer().getTok().getIdentifier();
2346+
if (matchRegisterNameHelper(IsEABI, RegStart, RegName)) {
2347+
Error(getLoc(), "invalid register");
2348+
return MatchOperand_ParseFail;
2349+
}
2350+
if (RegStart != RISCV::X8) {
2351+
Error(getLoc(), "continuous register list must start from 's0' or 'x8'");
2352+
return MatchOperand_ParseFail;
2353+
}
2354+
getLexer().Lex(); // eat reg
2355+
}
2356+
2357+
// parse case like -s1
2358+
if (getLexer().is(AsmToken::Minus)) {
2359+
getLexer().Lex();
2360+
StringRef EndName = getLexer().getTok().getIdentifier();
2361+
// FIXME: the register mapping and checks of EABI is wrong
2362+
if (matchRegisterNameHelper(IsEABI, RegEnd, EndName)) {
2363+
Error(getLoc(), "invalid register");
2364+
return MatchOperand_ParseFail;
2365+
}
2366+
if (IsEABI && RegEnd != RISCV::X9) {
2367+
Error(getLoc(), "contiguous register list of EABI can only be 's0-s1' or "
2368+
"'x8-x9' pair");
2369+
return MatchOperand_ParseFail;
2370+
}
2371+
getLexer().Lex();
2372+
}
2373+
2374+
if (!IsEABI) {
2375+
// parse extra part like ', x18[-x20]' for XRegList
2376+
if (getLexer().is(AsmToken::Comma)) {
2377+
if (RegEnd != RISCV::X9) {
2378+
Error(
2379+
getLoc(),
2380+
"first contiguous registers pair of register list must be 'x8-x9'");
2381+
return MatchOperand_ParseFail;
2382+
}
2383+
2384+
// parse ', x18' for extra part
2385+
getLexer().Lex();
2386+
if (getLexer().isNot(AsmToken::Identifier)) {
2387+
Error(getLoc(), "invalid register");
2388+
return MatchOperand_ParseFail;
2389+
}
2390+
StringRef EndName = getLexer().getTok().getIdentifier();
2391+
if (MatchRegisterName(EndName) != RISCV::X18) {
2392+
Error(getLoc(), "second contiguous registers pair of register list "
2393+
"must start from 'x18'");
2394+
return MatchOperand_ParseFail;
2395+
}
2396+
getLexer().Lex();
2397+
2398+
// parse '-x20' for extra part
2399+
if (getLexer().is(AsmToken::Minus)) {
2400+
getLexer().Lex();
2401+
if (getLexer().isNot(AsmToken::Identifier)) {
2402+
Error(getLoc(), "invalid register");
2403+
return MatchOperand_ParseFail;
2404+
}
2405+
EndName = getLexer().getTok().getIdentifier();
2406+
if (MatchRegisterName(EndName) == RISCV::NoRegister) {
2407+
Error(getLoc(), "invalid register");
2408+
return MatchOperand_ParseFail;
2409+
}
2410+
getLexer().Lex();
2411+
}
2412+
RegEnd = MatchRegisterName(EndName);
2413+
}
2414+
}
2415+
2416+
if (RegEnd == RISCV::X26) {
2417+
Error(getLoc(), "invalid register list, {ra, s0-s10} or {x1, x8-x9, "
2418+
"x18-x26} is not supported");
2419+
return MatchOperand_ParseFail;
2420+
}
2421+
2422+
if (getLexer().isNot(AsmToken::RCurly)) {
2423+
Error(getLoc(), "register list must end with '}'");
2424+
return MatchOperand_ParseFail;
2425+
}
2426+
getLexer().Lex(); // eat '}'
2427+
2428+
if (RegEnd == RISCV::NoRegister)
2429+
RegEnd = RegStart;
2430+
2431+
auto Encode = RISCVZC::encodeRlist(RegEnd, IsEABI);
2432+
if (Encode == 16) {
2433+
Error(S, "invalid register list");
2434+
return MatchOperand_ParseFail;
2435+
}
2436+
Operands.push_back(RISCVOperand::createRlist(Encode, S));
2437+
2438+
return MatchOperand_Success;
2439+
}
2440+
2441+
OperandMatchResultTy RISCVAsmParser::parseZcmpSpimm(OperandVector &Operands) {
2442+
if (getLexer().is(AsmToken::Minus))
2443+
getLexer().Lex();
2444+
2445+
SMLoc S = getLoc();
2446+
int64_t StackAdjustment = getLexer().getTok().getIntVal();
2447+
unsigned Spimm = 0;
2448+
unsigned RlistVal = static_cast<RISCVOperand *>(Operands[1].get())->Rlist.Val;
2449+
2450+
bool IsEABI = isRVE();
2451+
if (!RISCVZC::getSpimm(RlistVal, Spimm, StackAdjustment, isRV64(), IsEABI))
2452+
return MatchOperand_NoMatch;
2453+
Operands.push_back(RISCVOperand::createSpimm(Spimm << 4, S));
2454+
getLexer().Lex();
2455+
return MatchOperand_Success;
2456+
}
2457+
22462458
/// Looks at a token type and creates the relevant operand from this
22472459
/// information, adding to Operands. If operand was parsed, returns false, else
22482460
/// true.
@@ -2925,6 +3137,15 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
29253137
}
29263138
}
29273139

3140+
if (Opcode == RISCV::CM_MVSA01) {
3141+
unsigned Rd1 = Inst.getOperand(0).getReg();
3142+
unsigned Rd2 = Inst.getOperand(1).getReg();
3143+
if (Rd1 == Rd2) {
3144+
SMLoc Loc = Operands[1]->getStartLoc();
3145+
return Error(Loc, "'rs1' and 'rs2' must be different.");
3146+
}
3147+
}
3148+
29283149
bool IsTHeadMemPair32 = (Opcode == RISCV::TH_LWD ||
29293150
Opcode == RISCV::TH_LWUD || Opcode == RISCV::TH_SWD);
29303151
bool IsTHeadMemPair64 = (Opcode == RISCV::TH_LDD || Opcode == RISCV::TH_SDD);

0 commit comments

Comments
 (0)