-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[RISC-V][MC] Validate instructions prior to emission in AsmParser #171739
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
base: main
Are you sure you want to change the base?
[RISC-V][MC] Validate instructions prior to emission in AsmParser #171739
Conversation
Created using spr 1.3.8-beta.1
|
@llvm/pr-subscribers-backend-risc-v Author: Alexander Richardson (arichardson) ChangesThis ensures that broken AsmParser pseudo expansions trigger an error. Ideally we would do this in a target-independent way, but for now this Full diff: https://github.com/llvm/llvm-project/pull/171739.diff 1 Files Affected:
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 9bb3724c96c11..483d0a36966fe 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -128,6 +128,8 @@ class RISCVAsmParser : public MCTargetAsmParser {
// Helper to actually emit an instruction to the MCStreamer. Also, when
// possible, compression of the instruction is performed.
void emitToStreamer(MCStreamer &S, const MCInst &Inst);
+ void validateInstructionPreEmit(const MCInst &Inst,
+ const MCSubtargetInfo &STI);
// Helper to emit a combination of LUI, ADDI(W), and SLLI instructions that
// synthesize the desired immediate value into the destination register.
@@ -3471,6 +3473,34 @@ bool RISCVAsmParser::parseDirectiveVariantCC() {
return false;
}
+void RISCVAsmParser::validateInstructionPreEmit(const MCInst &Inst, const MCSubtargetInfo &STI) {
+ // Ensure that we don't emit instructions with missing predicates or invalid
+ // register classes.
+ // TODO: ideally this code should be shared between targets.
+ RISCV_MC::verifyInstructionPredicates(Inst.getOpcode(), STI.getFeatureBits());
+ const MCRegisterInfo *MRI = getContext().getRegisterInfo();
+ unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
+ const MCInstrDesc &Desc = MII.get(Inst.getOpcode());
+ for (auto [I, Op] : enumerate(Inst.getOperands())) {
+ if (Op.isReg() && Op.getReg().isValid()) {
+ auto RCID = MII.getOpRegClassID(Desc.operands()[I], HwMode);
+ // Some instructions don't have a valid regclass, e.g. .insn_*
+ if (RCID == -1)
+ continue;
+ const MCRegisterClass &RegClass = MRI->getRegClass(RCID);
+ if (!RegClass.contains(Op.getReg())) {
+ getParser().printError(getLoc(), MII.getName(Inst.getOpcode()) + " operand " +
+ Twine(I + 1) + " register " +
+ MRI->getName(Op.getReg()) +
+ " is not a member of register class " +
+ MRI->getRegClassName(&RegClass));
+ reportFatalInternalError("Attempting to emit invalid instruction. "
+ "Incorrect pseudo expansion?");
+ }
+ }
+ }
+}
+
void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
MCInst CInst;
bool Res = false;
@@ -3479,6 +3509,7 @@ void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
Res = RISCVRVC::compress(CInst, Inst, STI);
if (Res)
++RISCVNumInstrsCompressed;
+ validateInstructionPreEmit((Res ? CInst : Inst), STI);
S.emitInstruction((Res ? CInst : Inst), STI);
}
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
Found the following reg class mismatch: #171738 and has been very helpful for my RVY work. |
Created using spr 1.3.8-beta.1
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
|
I believe this should be stacked on top of #171738 ? |
Created using spr 1.3.8-beta.1
Yes I accidentally used |
lenary
left a comment
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.
IMO this should be behind a developer-oriented flag, like -verify-machineinstrs is for llc today.
The logic looks right, and yes sharing between targets would be good but can come later.
Thanks, that's a good suggestion. How about only doing it for assertions builds or EXPENSIVE_CHECKS? I haven't measured the performance impact here but since it's only for assembly inputs it shouldn't be on the critical path for most projects. |
I would have a command-line option that defaults to true when in |
This ensures that broken AsmParser pseudo expansions trigger an error. Noticed this while adding Y extension support where expanding pseudos generated instructions that were failing predicates and/or using the wrong register class, but since the encoded .o bit pattern as well as the assembly output are the same for mode-dependent instructions, this was not immediately obvious and only shows up with --show-inst. Verify predicates and operand register classes prior to emission. Ideally we would do this in a target-independent way, but for now this only checks RISC-V outputs. Pull Request: llvm#171739
This ensures that broken AsmParser pseudo expansions trigger an error.
Noticed this while adding Y extension support where expanding pseudos
generated instructions that were failing predicates and/or using the
wrong register class, but since the encoded .o bit pattern as well as
the assembly output are the same for mode-dependent instructions, this
was not immediately obvious and only shows up with --show-inst.
Verify predicates and operand register classes prior to emission.
Ideally we would do this in a target-independent way, but for now this
only checks RISC-V outputs.