Skip to content

Commit 75ca080

Browse files
authored
[RISCV][Xqccmp] Correctly Parse/Disassemble pushfp (#133188)
In the `qc.cm.pushfp` instruction, it is like `cm.pushfp` except in one important way - `qc.cm.pushfp {ra}, -N*16` is not a valid encoding, because this would update `s0`/`fp`/`x8` without saving it. This change now correctly rejects this variant of the instruction, both during parsing and during disassembly. I also implemented validation for immediates that represent register lists (both kinds), which may help to catch bugs in the future.
1 parent d7c53a9 commit 75ca080

File tree

13 files changed

+131
-28
lines changed

13 files changed

+131
-28
lines changed

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

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,14 @@ class RISCVAsmParser : public MCTargetAsmParser {
215215
ParseStatus parseGPRPair(OperandVector &Operands, bool IsRV64Inst);
216216
ParseStatus parseFRMArg(OperandVector &Operands);
217217
ParseStatus parseFenceArg(OperandVector &Operands);
218-
ParseStatus parseReglist(OperandVector &Operands);
218+
ParseStatus parseReglist(OperandVector &Operands) {
219+
return parseRegListCommon(Operands, /*MustIncludeS0=*/false);
220+
}
221+
ParseStatus parseReglistS0(OperandVector &Operands) {
222+
return parseRegListCommon(Operands, /*MustIncludeS0=*/true);
223+
}
224+
ParseStatus parseRegListCommon(OperandVector &Operands, bool MustIncludeS0);
225+
219226
ParseStatus parseRegReg(OperandVector &Operands);
220227
ParseStatus parseRetval(OperandVector &Operands);
221228
ParseStatus parseZcmpStackAdj(OperandVector &Operands,
@@ -474,6 +481,9 @@ struct RISCVOperand final : public MCParsedAsmOperand {
474481
bool isSystemRegister() const { return Kind == KindTy::SystemRegister; }
475482
bool isRegReg() const { return Kind == KindTy::RegReg; }
476483
bool isRlist() const { return Kind == KindTy::Rlist; }
484+
bool isRlistS0() const {
485+
return Kind == KindTy::Rlist && Rlist.Val != RISCVZC::RA;
486+
}
477487
bool isSpimm() const { return Kind == KindTy::Spimm; }
478488

479489
bool isGPR() const {
@@ -2794,9 +2804,15 @@ ParseStatus RISCVAsmParser::parseRegReg(OperandVector &Operands) {
27942804
return ParseStatus::Success;
27952805
}
27962806

2797-
ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) {
2807+
ParseStatus RISCVAsmParser::parseRegListCommon(OperandVector &Operands,
2808+
bool MustIncludeS0) {
27982809
// Rlist: {ra [, s0[-sN]]}
27992810
// XRlist: {x1 [, x8[-x9][, x18[-xN]]]}
2811+
2812+
// When MustIncludeS0 = true (not the default) (used for `qc.cm.pushfp`) which
2813+
// must include `fp`/`s0` in the list:
2814+
// Rlist: {ra, s0[-sN]}
2815+
// XRlist: {x1, x8[-x9][, x18[-xN]]}
28002816
SMLoc S = getLoc();
28012817

28022818
if (parseToken(AsmToken::LCurly, "register list must start with '{'"))
@@ -2814,8 +2830,20 @@ ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) {
28142830
return Error(getLoc(), "register list must start from 'ra' or 'x1'");
28152831
getLexer().Lex();
28162832

2817-
// parse case like ,s0
2818-
if (parseOptionalToken(AsmToken::Comma)) {
2833+
bool SeenComma = parseOptionalToken(AsmToken::Comma);
2834+
2835+
// There are two choices here:
2836+
// - `s0` is not required (usual case), so only try to parse `s0` if there is
2837+
// a comma
2838+
// - `s0` is required (qc.cm.pushfp), and so we must see the comma between
2839+
// `ra` and `s0` and must always try to parse `s0`, below
2840+
if (MustIncludeS0 && !SeenComma) {
2841+
Error(getLoc(), "register list must include 's0' or 'x8'");
2842+
return ParseStatus::Failure;
2843+
}
2844+
2845+
// parse case like ,s0 (knowing the comma must be there if required)
2846+
if (SeenComma) {
28192847
if (getLexer().isNot(AsmToken::Identifier))
28202848
return Error(getLoc(), "invalid register");
28212849
StringRef RegName = getLexer().getTok().getIdentifier();
@@ -2884,6 +2912,8 @@ ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) {
28842912

28852913
auto Encode = RISCVZC::encodeRlist(RegEnd, IsEABI);
28862914
assert(Encode != RISCVZC::INVALID_RLIST);
2915+
if (MustIncludeS0)
2916+
assert(Encode != RISCVZC::RA);
28872917
Operands.push_back(RISCVOperand::createRlist(Encode, S));
28882918

28892919
return ParseStatus::Success;

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,9 @@ static DecodeStatus decodeXTHeadMemPair(MCInst &Inst, uint32_t Insn,
507507
static DecodeStatus decodeZcmpRlist(MCInst &Inst, uint32_t Imm,
508508
uint64_t Address, const void *Decoder);
509509

510+
static DecodeStatus decodeXqccmpRlistS0(MCInst &Inst, uint32_t Imm,
511+
uint64_t Address, const void *Decoder);
512+
510513
static DecodeStatus decodeZcmpSpimm(MCInst &Inst, uint32_t Imm,
511514
uint64_t Address, const void *Decoder);
512515

@@ -612,7 +615,15 @@ static DecodeStatus decodeXTHeadMemPair(MCInst &Inst, uint32_t Insn,
612615

613616
static DecodeStatus decodeZcmpRlist(MCInst &Inst, uint32_t Imm,
614617
uint64_t Address, const void *Decoder) {
615-
if (Imm <= 3)
618+
if (Imm < RISCVZC::RA)
619+
return MCDisassembler::Fail;
620+
Inst.addOperand(MCOperand::createImm(Imm));
621+
return MCDisassembler::Success;
622+
}
623+
624+
static DecodeStatus decodeXqccmpRlistS0(MCInst &Inst, uint32_t Imm,
625+
uint64_t Address, const void *Decoder) {
626+
if (Imm < RISCVZC::RA_S0)
616627
return MCDisassembler::Fail;
617628
Inst.addOperand(MCOperand::createImm(Imm));
618629
return MCDisassembler::Success;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,12 @@ float RISCVLoadFPImm::getFPImm(unsigned Imm) {
242242

243243
void RISCVZC::printRlist(unsigned SlistEncode, raw_ostream &OS) {
244244
OS << "{ra";
245-
if (SlistEncode > 4) {
245+
if (SlistEncode > RISCVZC::RA) {
246246
OS << ", s0";
247-
if (SlistEncode == 15)
247+
if (SlistEncode == RISCVZC::RA_S0_S11)
248248
OS << "-s11";
249-
else if (SlistEncode > 5 && SlistEncode <= 14)
250-
OS << "-s" << (SlistEncode - 5);
249+
else if (SlistEncode > RISCVZC::RA_S0 && SlistEncode <= RISCVZC::RA_S0_S11)
250+
OS << "-s" << (SlistEncode - RISCVZC::RA_S0);
251251
}
252252
OS << "}";
253253
}

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,8 @@ enum OperandType : unsigned {
343343
OPERAND_RVKRNUM_0_7,
344344
OPERAND_RVKRNUM_1_10,
345345
OPERAND_RVKRNUM_2_14,
346+
OPERAND_RLIST,
347+
OPERAND_RLIST_S0,
346348
OPERAND_SPIMM,
347349
// Operand is a 3-bit rounding mode, '111' indicates FRM register.
348350
// Represents 'frm' argument passing to floating-point operations.

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
103103
unsigned getRlistOpValue(const MCInst &MI, unsigned OpNo,
104104
SmallVectorImpl<MCFixup> &Fixups,
105105
const MCSubtargetInfo &STI) const;
106+
107+
unsigned getRlistS0OpValue(const MCInst &MI, unsigned OpNo,
108+
SmallVectorImpl<MCFixup> &Fixups,
109+
const MCSubtargetInfo &STI) const;
106110
};
107111
} // end anonymous namespace
108112

@@ -616,5 +620,16 @@ unsigned RISCVMCCodeEmitter::getRlistOpValue(const MCInst &MI, unsigned OpNo,
616620
assert(Imm >= 4 && "EABI is currently not implemented");
617621
return Imm;
618622
}
623+
unsigned
624+
RISCVMCCodeEmitter::getRlistS0OpValue(const MCInst &MI, unsigned OpNo,
625+
SmallVectorImpl<MCFixup> &Fixups,
626+
const MCSubtargetInfo &STI) const {
627+
const MCOperand &MO = MI.getOperand(OpNo);
628+
assert(MO.isImm() && "Rlist operand must be immediate");
629+
auto Imm = MO.getImm();
630+
assert(Imm >= 4 && "EABI is currently not implemented");
631+
assert(Imm != RISCVZC::RA && "Rlist operand must include s0");
632+
return Imm;
633+
}
619634

620635
#include "RISCVGenMCCodeEmitter.inc"

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,6 +2679,12 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
26792679
case RISCVOp::OPERAND_RVKRNUM_2_14:
26802680
Ok = Imm >= 2 && Imm <= 14;
26812681
break;
2682+
case RISCVOp::OPERAND_RLIST:
2683+
Ok = Imm >= RISCVZC::RA && Imm <= RISCVZC::RA_S0_S11;
2684+
break;
2685+
case RISCVOp::OPERAND_RLIST_S0:
2686+
Ok = Imm >= RISCVZC::RA_S0 && Imm <= RISCVZC::RA_S0_S11;
2687+
break;
26822688
case RISCVOp::OPERAND_SPIMM:
26832689
Ok = (Imm & 0xf) == 0;
26842690
break;

llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,30 @@
2525
// Operand and SDNode transformation definitions.
2626
//===----------------------------------------------------------------------===//
2727

28+
def RlistS0AsmOperand : AsmOperandClass {
29+
let Name = "RlistS0";
30+
let ParserMethod = "parseReglistS0";
31+
let RenderMethod = "addRlistOperands";
32+
let DiagnosticType = "InvalidRlistS0";
33+
let DiagnosticString = "operand must be {ra, s0[-sN]} or {x1, x8[-x9][, x18[-xN]]}";
34+
}
35+
36+
def rlist_s0 : RISCVOp<OtherVT> {
37+
let ParserMatchClass = RlistS0AsmOperand;
38+
let PrintMethod = "printRlist";
39+
let DecoderMethod = "decodeXqccmpRlistS0";
40+
let EncoderMethod = "getRlistS0OpValue";
41+
let MCOperandPredicate = [{
42+
int64_t Imm;
43+
if (!MCOp.evaluateAsConstantImm(Imm))
44+
return false;
45+
// 0~4 invalid for `qc.cm.pushfp`
46+
return isUInt<4>(Imm) && Imm >= RISCVZC::RA_S0;
47+
}];
48+
49+
string OperandType = "OPERAND_RLIST_S0";
50+
}
51+
2852
//===----------------------------------------------------------------------===//
2953
// Instruction Formats
3054
//===----------------------------------------------------------------------===//
@@ -33,6 +57,20 @@
3357
// Instruction Class Templates
3458
//===----------------------------------------------------------------------===//
3559

60+
class RVInstXqccmpCPPPFP<bits<5> funct5, string opcodestr,
61+
DAGOperand immtype = stackadj>
62+
: RVInst16<(outs), (ins rlist_s0:$rlist, immtype:$stackadj),
63+
opcodestr, "$rlist, $stackadj", [], InstFormatOther> {
64+
bits<4> rlist;
65+
bits<16> stackadj;
66+
67+
let Inst{1-0} = 0b10;
68+
let Inst{3-2} = stackadj{5-4};
69+
let Inst{7-4} = rlist;
70+
let Inst{12-8} = funct5;
71+
let Inst{15-13} = 0b101;
72+
}
73+
3674
//===----------------------------------------------------------------------===//
3775
// Instructions
3876
//===----------------------------------------------------------------------===//
@@ -59,7 +97,7 @@ def QC_CM_PUSH : RVInstZcCPPP<0b11000, "qc.cm.push", negstackadj>,
5997
ReadStoreData, ReadStoreData, ReadStoreData]>;
6098

6199
let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2, X8] in
62-
def QC_CM_PUSHFP : RVInstZcCPPP<0b11001, "qc.cm.pushfp", negstackadj>,
100+
def QC_CM_PUSHFP : RVInstXqccmpCPPPFP<0b11001, "qc.cm.pushfp", negstackadj>,
63101
Sched<[WriteIALU, WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
64102
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
65103
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,

llvm/lib/Target/RISCV/RISCVInstrInfoZc.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def NegStackAdjAsmOperand : AsmOperandClass {
5858
let RenderMethod = "addSpimmOperands";
5959
}
6060

61-
def rlist : Operand<OtherVT> {
61+
def rlist : RISCVOp<OtherVT> {
6262
let ParserMatchClass = RlistAsmOperand;
6363
let PrintMethod = "printRlist";
6464
let DecoderMethod = "decodeZcmpRlist";
@@ -68,8 +68,10 @@ def rlist : Operand<OtherVT> {
6868
if (!MCOp.evaluateAsConstantImm(Imm))
6969
return false;
7070
// 0~3 Reserved for EABI
71-
return isUInt<4>(Imm) && Imm >= 4;
71+
return isUInt<4>(Imm) && Imm >= RISCVZC::RA;
7272
}];
73+
74+
let OperandType = "OPERAND_RLIST";
7375
}
7476

7577
def stackadj : RISCVOp<OtherVT> {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# RUN: not llvm-mc -disassemble -triple=riscv32 -mattr=+experimental-xqccmp %s \
2+
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-XQCCMP %s
3+
4+
[0x00,0x00]
5+
# CHECK: unimp
6+
7+
[0x42,0xb9]
8+
# CHECK-XQCCMP-NOT: qc.cm.pushfp {ra}, -{{[0-9]+}}
9+
10+
[0x00,0x00]
11+
# CHECK: unimp

llvm/test/MC/RISCV/rv32xqccmp-invalid.s

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ qc.cm.pushfp {ra, s0}, -12
3333

3434
# CHECK-ERROR: error: stack adjustment for register list must be a multiple of 16 bytes in the range [16, 64]
3535
qc.cm.pop {ra, s0-s1}, -40
36+
37+
# CHECK-ERROR: error: register list must include 's0' or 'x8'
38+
qc.cm.pushfp {ra}, -16
39+

llvm/test/MC/RISCV/rv32xqccmp-valid.s

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -288,14 +288,6 @@ qc.cm.push {ra, s0-s11}, -112
288288
# CHECK-ASM: encoding: [0xfe,0xb8]
289289
qc.cm.push {x1, x8-x9, x18-x27}, -112
290290

291-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
292-
# CHECK-ASM: encoding: [0x42,0xb9]
293-
qc.cm.pushfp {ra}, -16
294-
295-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
296-
# CHECK-ASM: encoding: [0x42,0xb9]
297-
qc.cm.pushfp {x1}, -16
298-
299291
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
300292
# CHECK-ASM: encoding: [0x56,0xb9]
301293
qc.cm.pushfp {ra, s0}, -32

llvm/test/MC/RISCV/rv64e-xqccmp-valid.s

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ qc.cm.push {ra, s0}, -32
7272
# CHECK-ASM: encoding: [0x62,0xb8]
7373
qc.cm.push {ra, s0-s1}, -32
7474

75-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
76-
# CHECK-ASM: encoding: [0x42,0xb9]
77-
qc.cm.pushfp {ra}, -16
78-
7975
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
8076
# CHECK-ASM: encoding: [0x56,0xb9]
8177
qc.cm.pushfp {ra, s0}, -32

llvm/test/MC/RISCV/rv64xqccmp-valid.s

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,6 @@ qc.cm.push {ra, s0-s11}, -112
148148
# CHECK-ASM: encoding: [0xf6,0xb8]
149149
qc.cm.push {ra, s0-s11}, -128
150150

151-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
152-
# CHECK-ASM: encoding: [0x42,0xb9]
153-
qc.cm.pushfp {ra}, -16
154-
155151
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
156152
# CHECK-ASM: encoding: [0x56,0xb9]
157153
qc.cm.pushfp {ra, s0}, -32

0 commit comments

Comments
 (0)