Skip to content
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

Merged
merged 2 commits into from
Nov 30, 2023

Conversation

arsenm
Copy link
Contributor

@arsenm arsenm commented Nov 29, 2023

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.

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.
@llvmbot
Copy link
Collaborator

llvmbot commented Nov 29, 2023

@llvm/pr-subscribers-backend-msp430

@llvm/pr-subscribers-backend-amdgpu

Author: Matt Arsenault (arsenm)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/73758.diff

7 Files Affected:

  • (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+3-12)
  • (modified) llvm/lib/CodeGen/MachineInstr.cpp (-4)
  • (modified) llvm/lib/CodeGen/MachineVerifier.cpp (+2-2)
  • (modified) llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp (+1)
  • (removed) llvm/test/CodeGen/MIR/AMDGPU/extra-imm-operand.mir (-13)
  • (removed) llvm/test/CodeGen/MIR/AMDGPU/extra-reg-operand.mir (-13)
  • (added) llvm/test/MachineVerifier/verify-implicit-def.mir (+30)
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
+...
+
+

Copy link
Contributor

@kparzysz kparzysz left a 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
Copy link
Contributor

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.

Copy link
Contributor

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".

Copy link
Contributor

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. :)

Copy link
Collaborator

@qcolombet qcolombet left a 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

llvm/lib/CodeGen/MachineInstr.cpp Show resolved Hide resolved
llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp Show resolved Hide resolved
Copy link
Collaborator

@asl asl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@arsenm
Copy link
Contributor Author

arsenm commented Nov 30, 2023

Does the verifier run even when it's not explicitly enabled?

For MIR parsing it does. The enable option only changes whether it runs between passes

@arsenm arsenm merged commit c44dca1 into llvm:main Nov 30, 2023
2 of 3 checks passed
@arsenm arsenm deleted the machine-verifier-implicit-operands-nonreg branch November 30, 2023 13:33
arsenm added a commit that referenced this pull request Dec 4, 2023
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants