-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
MachineVerifier: Reject extra non-register operands on instructions #73758
MachineVerifier: Reject extra non-register operands on instructions #73758
Conversation
We were allowing extra immediate arguments, and only bothering to check if registers were implicit or not. Also consolidate extra operand checks in verifier, to make this testable. We had 3 different places checking if you were trying to build an instruction with more operands than allowed by the definition. We had an assertion in addOperand, a direct check in the MIRParser to avoid the assertion, and the machine verifier checks. Remove the assert and parser check so the verifier can provide a consistent verification experience, which will also handle instructions modified in place.
@llvm/pr-subscribers-backend-msp430 @llvm/pr-subscribers-backend-amdgpu Author: Matt Arsenault (arsenm) ChangesWe were allowing extra immediate arguments, and only bothering to check if registers were implicit or not. Also consolidate extra operand checks in verifier, to make this testable. We had 3 different places checking if you were trying to build an instruction with more operands than allowed by the definition. We had an assertion in addOperand, a direct check in the MIRParser to avoid the assertion, and the machine verifier checks. Remove the assert and parser check so the verifier can provide a consistent verification experience, which will also handle instructions modified in place. Full diff: https://github.com/llvm/llvm-project/pull/73758.diff 7 Files Affected:
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index f5d80b2ae27c233..f300b05727f7905 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -1175,19 +1175,10 @@ bool MIParser::parse(MachineInstr *&MI) {
MI = MF.CreateMachineInstr(MCID, DebugLocation, /*NoImplicit=*/true);
MI->setFlags(Flags);
- unsigned NumExplicitOps = 0;
- for (const auto &Operand : Operands) {
- bool IsImplicitOp = Operand.Operand.isReg() && Operand.Operand.isImplicit();
- if (!IsImplicitOp) {
- if (!MCID.isVariadic() && NumExplicitOps >= MCID.getNumOperands() &&
- !Operand.Operand.isValidExcessOperand())
- return error(Operand.Begin, "too many operands for instruction");
-
- ++NumExplicitOps;
- }
-
+ // Don't check the operands make sense, let the verifier catch any
+ // improprieties.
+ for (const auto &Operand : Operands)
MI->addOperand(MF, Operand.Operand);
- }
if (assignRegisterTies(*MI, Operands))
return true;
diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp
index 9e7b4df2576feee..27eae372f8ad764 100644
--- a/llvm/lib/CodeGen/MachineInstr.cpp
+++ b/llvm/lib/CodeGen/MachineInstr.cpp
@@ -231,10 +231,6 @@ void MachineInstr::addOperand(MachineFunction &MF, const MachineOperand &Op) {
// OpNo now points as the desired insertion point. Unless this is a variadic
// instruction, only implicit regs are allowed beyond MCID->getNumOperands().
// RegMask operands go between the explicit and implicit operands.
- assert((MCID->isVariadic() || OpNo < MCID->getNumOperands() ||
- Op.isValidExcessOperand()) &&
- "Trying to add an operand to a machine instr that is already done!");
-
MachineRegisterInfo *MRI = getRegInfo();
// Determine if the Operands array needs to be reallocated.
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 729dfc67491ee14..aaf9bd740d1379d 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -2126,9 +2126,9 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) {
}
} else if (MO->isReg() && MO->isTied())
report("Explicit operand should not be tied", MO, MONum);
- } else {
+ } else if (!MI->isVariadic()) {
// ARM adds %reg0 operands to indicate predicates. We'll allow that.
- if (MO->isReg() && !MO->isImplicit() && !MI->isVariadic() && MO->getReg())
+ if (!MO->isValidExcessOperand())
report("Extra explicit operand on non-variadic instruction", MO, MONum);
}
diff --git a/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp b/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp
index 4ee40f47b8c19ec..f3900c990469ffc 100644
--- a/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp
+++ b/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp
@@ -134,6 +134,7 @@ MSP430RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
MI.setDesc(TII.get(MSP430::MOV16rr));
MI.getOperand(FIOperandNum).ChangeToRegister(BasePtr, false);
+ MI.removeOperand(FIOperandNum + 1);
if (Offset == 0)
return false;
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/extra-imm-operand.mir b/llvm/test/CodeGen/MIR/AMDGPU/extra-imm-operand.mir
deleted file mode 100644
index 65cb32cdd9aebfe..000000000000000
--- a/llvm/test/CodeGen/MIR/AMDGPU/extra-imm-operand.mir
+++ /dev/null
@@ -1,13 +0,0 @@
-# RUN: not llc -march=amdgcn -run-pass=none -o /dev/null %s 2>&1 | \
-# RUN: FileCheck --strict-whitespace %s
-
----
-name: extra_imm_operand
-body: |
- bb.0:
- ; CHECK: [[@LINE+3]]:17: too many operands for instruction
- ; CHECK-NEXT: {{^}} S_ENDPGM 0, 0
- ; CHECK-NEXT: {{^}} ^
- S_ENDPGM 0, 0
-
-...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/extra-reg-operand.mir b/llvm/test/CodeGen/MIR/AMDGPU/extra-reg-operand.mir
deleted file mode 100644
index d6b2522542a82dd..000000000000000
--- a/llvm/test/CodeGen/MIR/AMDGPU/extra-reg-operand.mir
+++ /dev/null
@@ -1,13 +0,0 @@
-# RUN: not llc -march=amdgcn -run-pass=none -o /dev/null %s 2>&1 | \
-# RUN: FileCheck --strict-whitespace %s
-
----
-name: extra_reg_operand
-body: |
- bb.0:
- ; CHECK: [[@LINE+3]]:17: too many operands for instruction
- ; CHECK-NEXT: {{^}} S_ENDPGM 0, undef $vgpr0
- ; CHECK-NEXT: {{^}} ^
- S_ENDPGM 0, undef $vgpr0
-
-...
diff --git a/llvm/test/MachineVerifier/verify-implicit-def.mir b/llvm/test/MachineVerifier/verify-implicit-def.mir
new file mode 100644
index 000000000000000..8ca6f2dc75c01de
--- /dev/null
+++ b/llvm/test/MachineVerifier/verify-implicit-def.mir
@@ -0,0 +1,30 @@
+# REQUIRES: amdgpu-registered-target
+# RUN: not --crash llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=none -o /dev/null %s 2>&1 | FileCheck %s
+
+---
+name: invalid_reg_sequence
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK: *** Bad machine code: Too few operands ***
+ IMPLICIT_DEF
+
+ ; FIXME: Error message misleading
+ ; CHECK: *** Bad machine code: Explicit definition must be a register ***
+ IMPLICIT_DEF 0
+
+ ; CHECK: *** Bad machine code: Extra explicit operand on non-variadic instruction ***
+ %1:vgpr_32 = IMPLICIT_DEF 0
+
+ ; CHECK: *** Bad machine code: Extra explicit operand on non-variadic instruction ***
+ ; CHECK: *** Bad machine code: Extra explicit operand on non-variadic instruction ***
+ %2:vgpr_32 = IMPLICIT_DEF 0, 1
+
+ ; CHECK: *** Bad machine code: Extra explicit operand on non-variadic instruction ***
+ %3:vgpr_32 = IMPLICIT_DEF %1
+
+ ; CHECK-NOT: Bad machine code
+ %4:vgpr_32 = IMPLICIT_DEF implicit %1
+...
+
+
|
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.
Does the verifier run even when it's not explicitly enabled?
Otherwise this makes sense to me.
++NumExplicitOps; | ||
} | ||
|
||
// Don't check the operands make sense, let the verifier catch any |
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.
I think there is "if" missing in the 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.
It reads OK to me. "Don't check the operands make sense" is a shorter way of saying "Don't check that the operands make sense".
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.
I somewhat misparsed it the first time I read it, and then it looked weird to me every time I looked at it. :)
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, nits and suggestions below
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, thanks!
For MIR parsing it does. The enable option only changes whether it runs between passes |
If this was coalescing a SUBREG_TO_REG as a copy, the resulting instruction would be an IMPLICIT_DEF with an unexpected 2 immediate operands, which need to be dropped. Until recently the verifier did not catch this error, and an assert would fire if later the broken IMPLICIT_DEF was rematerialized P #73758 is related, it changes the failure mode to a verifier error.
We were allowing extra immediate arguments, and only bothering to check if registers were implicit or not.
Also consolidate extra operand checks in verifier, to make this testable. We had 3 different places checking if you were trying to build an instruction with more operands than allowed by the definition. We had an assertion in addOperand, a direct check in the MIRParser to avoid the assertion, and the machine verifier checks. Remove the assert and parser check so the verifier can provide a consistent verification experience, which will also handle instructions modified in place.