-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV][Xqccmp] Correctly Parse/Disassemble pushfp #133188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-mc Author: Sam Elliott (lenary) ChangesIn the 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. Full diff: https://github.com/llvm/llvm-project/pull/133188.diff 12 Files Affected:
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 0d40fb5614009..19f28a6287060 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -215,7 +215,10 @@ class RISCVAsmParser : public MCTargetAsmParser {
ParseStatus parseGPRPair(OperandVector &Operands, bool IsRV64Inst);
ParseStatus parseFRMArg(OperandVector &Operands);
ParseStatus parseFenceArg(OperandVector &Operands);
+
+ template <bool MustIncludeS0 = false>
ParseStatus parseReglist(OperandVector &Operands);
+
ParseStatus parseRegReg(OperandVector &Operands);
ParseStatus parseRetval(OperandVector &Operands);
ParseStatus parseZcmpStackAdj(OperandVector &Operands,
@@ -474,6 +477,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
bool isSystemRegister() const { return Kind == KindTy::SystemRegister; }
bool isRegReg() const { return Kind == KindTy::RegReg; }
bool isRlist() const { return Kind == KindTy::Rlist; }
+ bool isRlistS0() const { return Kind == KindTy::Rlist && Rlist.Val != 4; }
bool isSpimm() const { return Kind == KindTy::Spimm; }
bool isGPR() const {
@@ -2794,9 +2798,15 @@ ParseStatus RISCVAsmParser::parseRegReg(OperandVector &Operands) {
return ParseStatus::Success;
}
+template <bool MustIncludeS0>
ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) {
// Rlist: {ra [, s0[-sN]]}
// XRlist: {x1 [, x8[-x9][, x18[-xN]]]}
+
+ // When MustIncludeS0 = true (not the default) (used for `qc.cm.pushfp`) which
+ // must include `fp`/`s0` in the list:
+ // Rlist: {ra, s0[-sN]}
+ // XRlist: {x1, x8[-x9][, x18[-xN]]}
SMLoc S = getLoc();
if (parseToken(AsmToken::LCurly, "register list must start with '{'"))
@@ -2814,8 +2824,19 @@ ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) {
return Error(getLoc(), "register list must start from 'ra' or 'x1'");
getLexer().Lex();
- // parse case like ,s0
- if (parseOptionalToken(AsmToken::Comma)) {
+ bool SeenComma = false;
+
+ // If you must include S0, then you need the comma. Fail now if it isn't there
+ if constexpr (MustIncludeS0) {
+ if (parseToken(AsmToken::Comma, "register list must include 's0' or 'x8'"))
+ return ParseStatus::Failure;
+ SeenComma = true;
+ } else {
+ SeenComma = parseOptionalToken(AsmToken::Comma);
+ }
+
+ // parse case like ,s0 - we may have already seen the comma in which case skip
+ if (SeenComma) {
if (getLexer().isNot(AsmToken::Identifier))
return Error(getLoc(), "invalid register");
StringRef RegName = getLexer().getTok().getIdentifier();
@@ -2884,6 +2905,8 @@ ParseStatus RISCVAsmParser::parseReglist(OperandVector &Operands) {
auto Encode = RISCVZC::encodeRlist(RegEnd, IsEABI);
assert(Encode != RISCVZC::INVALID_RLIST);
+ if constexpr (MustIncludeS0)
+ assert(Encode != RISCVZC::RA);
Operands.push_back(RISCVOperand::createRlist(Encode, S));
return ParseStatus::Success;
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 93cbf662bfa32..d03351db5473b 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -507,6 +507,9 @@ static DecodeStatus decodeXTHeadMemPair(MCInst &Inst, uint32_t Insn,
static DecodeStatus decodeZcmpRlist(MCInst &Inst, uint32_t Imm,
uint64_t Address, const void *Decoder);
+static DecodeStatus decodeXqccmpRlistS0(MCInst &Inst, uint32_t Imm,
+ uint64_t Address, const void *Decoder);
+
static DecodeStatus decodeRegReg(MCInst &Inst, uint32_t Insn, uint64_t Address,
const MCDisassembler *Decoder);
@@ -621,6 +624,14 @@ static DecodeStatus decodeZcmpRlist(MCInst &Inst, uint32_t Imm,
return MCDisassembler::Success;
}
+static DecodeStatus decodeXqccmpRlistS0(MCInst &Inst, uint32_t Imm,
+ uint64_t Address, const void *Decoder) {
+ if (Imm <= 4)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus decodeRegReg(MCInst &Inst, uint32_t Insn, uint64_t Address,
const MCDisassembler *Decoder) {
uint32_t Rs1 = fieldFromInstruction(Insn, 0, 5);
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index db305b0083415..0ede9ba7cf712 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -343,6 +343,8 @@ enum OperandType : unsigned {
OPERAND_RVKRNUM_0_7,
OPERAND_RVKRNUM_1_10,
OPERAND_RVKRNUM_2_14,
+ OPERAND_RLIST,
+ OPERAND_RLIST_S0,
OPERAND_SPIMM,
// Operand is a 3-bit rounding mode, '111' indicates FRM register.
// Represents 'frm' argument passing to floating-point operations.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index e589e6171d010..6163175347ca0 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -104,6 +104,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ unsigned getRlistS0OpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
unsigned getRegReg(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -621,6 +625,17 @@ unsigned RISCVMCCodeEmitter::getRlistOpValue(const MCInst &MI, unsigned OpNo,
return Imm;
}
+unsigned
+RISCVMCCodeEmitter::getRlistS0OpValue(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 >= 5 && "EABI is currently not implemented");
+ return Imm;
+}
+
unsigned RISCVMCCodeEmitter::getRegReg(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 4fb11f278df97..7867fd7d516cc 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2642,6 +2642,12 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
case RISCVOp::OPERAND_RVKRNUM_2_14:
Ok = Imm >= 2 && Imm <= 14;
break;
+ case RISCVOp::OPERAND_RLIST:
+ Ok = Imm >= RISCVZC::RA && Imm <= RISCVZC::RA_S0_S11;
+ break;
+ case RISCVOp::OPERAND_RLIST_S0:
+ Ok = Imm >= RISCVZC::RA_S0 && Imm <= RISCVZC::RA_S0_S11;
+ break;
case RISCVOp::OPERAND_SPIMM:
Ok = (Imm & 0xf) == 0;
break;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
index 5bb9c1e4b228b..8cb1cf151f1ad 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
@@ -25,6 +25,30 @@
// Operand and SDNode transformation definitions.
//===----------------------------------------------------------------------===//
+def RlistS0AsmOperand : AsmOperandClass {
+ let Name = "RlistS0";
+ let ParserMethod = "parseReglist<true>";
+ let RenderMethod = "addRlistOperands";
+ let DiagnosticType = "InvalidRlistS0";
+ let DiagnosticString = "operand must be {ra, s0[-sN]} or {x1, x8[-x9][, x18[-xN]]}";
+}
+
+def rlist_s0 : RISCVOp<OtherVT> {
+ let ParserMatchClass = RlistS0AsmOperand;
+ let PrintMethod = "printRlist";
+ let DecoderMethod = "decodeXqccmpRlistS0";
+ let EncoderMethod = "getRlistS0OpValue";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ // 0~4 invalid for `qc.cm.pushfp`
+ return isUInt<4>(Imm) && Imm >= 5;
+ }];
+
+ string OperandType = "OPERAND_RLIST_S0";
+}
+
//===----------------------------------------------------------------------===//
// Instruction Formats
//===----------------------------------------------------------------------===//
@@ -33,6 +57,20 @@
// Instruction Class Templates
//===----------------------------------------------------------------------===//
+class RVInstXqccmpCPPPFP<bits<5> funct5, string opcodestr,
+ DAGOperand immtype = stackadj>
+ : RVInst16<(outs), (ins rlist_s0:$rlist, immtype:$stackadj),
+ opcodestr, "$rlist, $stackadj", [], InstFormatOther> {
+ bits<4> rlist;
+ bits<16> stackadj;
+
+ let Inst{1-0} = 0b10;
+ let Inst{3-2} = stackadj{5-4};
+ let Inst{7-4} = rlist;
+ let Inst{12-8} = funct5;
+ let Inst{15-13} = 0b101;
+}
+
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
@@ -59,7 +97,7 @@ def QC_CM_PUSH : RVInstZcCPPP<0b11000, "qc.cm.push", negstackadj>,
ReadStoreData, ReadStoreData, ReadStoreData]>;
let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2, X8] in
-def QC_CM_PUSHFP : RVInstZcCPPP<0b11001, "qc.cm.pushfp", negstackadj>,
+def QC_CM_PUSHFP : RVInstXqccmpCPPPFP<0b11001, "qc.cm.pushfp", negstackadj>,
Sched<[WriteIALU, WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
index efed74ca8c870..04c10220f5bf1 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
@@ -58,7 +58,7 @@ def NegStackAdjAsmOperand : AsmOperandClass {
let RenderMethod = "addSpimmOperands";
}
-def rlist : Operand<OtherVT> {
+def rlist : RISCVOp<OtherVT> {
let ParserMatchClass = RlistAsmOperand;
let PrintMethod = "printRlist";
let DecoderMethod = "decodeZcmpRlist";
@@ -70,6 +70,8 @@ def rlist : Operand<OtherVT> {
// 0~3 Reserved for EABI
return isUInt<4>(Imm) && Imm >= 4;
}];
+
+ let OperandType = "OPERAND_RLIST";
}
def stackadj : RISCVOp<OtherVT> {
diff --git a/llvm/test/MC/Disassembler/RISCV/xqccmp-invalid-rlist.txt b/llvm/test/MC/Disassembler/RISCV/xqccmp-invalid-rlist.txt
new file mode 100644
index 0000000000000..fe81c01a037af
--- /dev/null
+++ b/llvm/test/MC/Disassembler/RISCV/xqccmp-invalid-rlist.txt
@@ -0,0 +1,11 @@
+# RUN: not llvm-mc -disassemble -triple=riscv32 -mattr=+experimental-xqccmp %s \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-XQCCMP %s
+
+[0x00,0x00]
+# CHECK: unimp
+
+[0x42,0xb9]
+# CHECK-XQCCMP-NOT: qc.cm.pushfp {ra}, -{{[0-9]+}}
+
+[0x00,0x00]
+# CHECK: unimp
diff --git a/llvm/test/MC/RISCV/rv32xqccmp-invalid.s b/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
index 74f96f076756c..059009de3d830 100644
--- a/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
+++ b/llvm/test/MC/RISCV/rv32xqccmp-invalid.s
@@ -33,3 +33,7 @@ qc.cm.pushfp {ra, s0}, -12
# CHECK-ERROR: error: stack adjustment for register list must be a multiple of 16 bytes in the range [16, 64]
qc.cm.pop {ra, s0-s1}, -40
+
+# CHECK-ERROR: error: register list must include 's0' or 'x8'
+qc.cm.pushfp {ra}, -16
+
diff --git a/llvm/test/MC/RISCV/rv32xqccmp-valid.s b/llvm/test/MC/RISCV/rv32xqccmp-valid.s
index 5827777e524ca..b1f373ede247d 100644
--- a/llvm/test/MC/RISCV/rv32xqccmp-valid.s
+++ b/llvm/test/MC/RISCV/rv32xqccmp-valid.s
@@ -288,14 +288,6 @@ qc.cm.push {ra, s0-s11}, -112
# CHECK-ASM: encoding: [0xfe,0xb8]
qc.cm.push {x1, x8-x9, x18-x27}, -112
-# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
-# CHECK-ASM: encoding: [0x42,0xb9]
-qc.cm.pushfp {ra}, -16
-
-# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
-# CHECK-ASM: encoding: [0x42,0xb9]
-qc.cm.pushfp {x1}, -16
-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
# CHECK-ASM: encoding: [0x56,0xb9]
qc.cm.pushfp {ra, s0}, -32
diff --git a/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s b/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s
index 8f9e3ce7ee533..003f9852b184a 100644
--- a/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s
+++ b/llvm/test/MC/RISCV/rv64e-xqccmp-valid.s
@@ -72,10 +72,6 @@ qc.cm.push {ra, s0}, -32
# CHECK-ASM: encoding: [0x62,0xb8]
qc.cm.push {ra, s0-s1}, -32
-# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
-# CHECK-ASM: encoding: [0x42,0xb9]
-qc.cm.pushfp {ra}, -16
-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
# CHECK-ASM: encoding: [0x56,0xb9]
qc.cm.pushfp {ra, s0}, -32
diff --git a/llvm/test/MC/RISCV/rv64xqccmp-valid.s b/llvm/test/MC/RISCV/rv64xqccmp-valid.s
index 06ba33fe8a495..29cf6f0dfbdac 100644
--- a/llvm/test/MC/RISCV/rv64xqccmp-valid.s
+++ b/llvm/test/MC/RISCV/rv64xqccmp-valid.s
@@ -148,10 +148,6 @@ qc.cm.push {ra, s0-s11}, -112
# CHECK-ASM: encoding: [0xf6,0xb8]
qc.cm.push {ra, s0-s11}, -128
-# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra}, -16
-# CHECK-ASM: encoding: [0x42,0xb9]
-qc.cm.pushfp {ra}, -16
-
# CHECK-ASM-AND-OBJ: qc.cm.pushfp {ra, s0}, -32
# CHECK-ASM: encoding: [0x56,0xb9]
qc.cm.pushfp {ra, s0}, -32
|
I templated I may need a declaration somewhere that the |
Can we have an untemplated |
const MCOperand &MO = MI.getOperand(OpNo); | ||
assert(MO.isImm() && "Rlist operand must be immediate"); | ||
auto Imm = MO.getImm(); | ||
assert(Imm >= 5 && "EABI is currently not implemented"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should split this assert so the error makes sense. The Zcmp has some note that encodings 0-3 are reserved for future EABI version which is why this assert mentions EABI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Sure, I guess the size savings of this are better than any savings from |
✅ With the latest revision this PR passed the C/C++ code formatter. |
OS << "-s11"; | ||
else if (SlistEncode > 5 && SlistEncode <= 14) | ||
else if (SlistEncode > RISCVZC::RA_S0 && SlistEncode <= RISCVZC::RA_S0_S11) | ||
OS << "-s" << (SlistEncode - 5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SlistEncode - RISCVZC::RA_S0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
In the
qc.cm.pushfp
instruction, it is likecm.pushfp
except in one important way -qc.cm.pushfp {ra}, -N*16
is not a valid encoding, because this would updates0
/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.