[llvm] [MIRParser] Accept sub-register for implicit operand verification (PR #180707)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 10 01:08:10 PST 2026


https://github.com/tyb0807 updated https://github.com/llvm/llvm-project/pull/180707

>From d2f2f0cf8c92e1fcd435719451e2f30eedf37790 Mon Sep 17 00:00:00 2001
From: tyb0807 <sontuan.vu at amd.com>
Date: Tue, 10 Feb 2026 00:02:05 +0000
Subject: [PATCH] [MIRParser] Accept sub-register for implicit operand
 verification

The MIR parser's implicit operand verification rejects sub-registers
that the MIR printer itself emits, breaking MIR round-tripping.

On AMDGPU wave32 targets, S_CBRANCH_VCCNZ is defined with
`Uses = [VCC]` (64-bit super-register), but the target uses $vcc_lo
(32-bit) as the condition register.  The MIR printer correctly emits
`implicit $vcc_lo`, but the parser's `verifyImplicitOperands` uses
`MachineOperand::isIdenticalTo` which requires an exact register
match against the MCInstrDesc's implicit uses, causing:

  error: missing implicit register operand 'implicit $vcc'

Fix `isImplicitOperandIn` to also accept a sub-register when it is
covered by the expected super-register, using
`TRI->isSubRegisterEq`.
---
 llvm/lib/CodeGen/MIRParser/MIParser.cpp       | 14 ++++-
 .../MIR/AMDGPU/parse-implicit-vcc-subreg.mir  | 54 +++++++++++++++++++
 2 files changed, 66 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/parse-implicit-vcc-subreg.mir

diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 9329adcb995b8..1aa87befa3ea0 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -1446,10 +1446,20 @@ static std::string getRegisterName(const TargetRegisterInfo *TRI,
 
 /// Return true if the parsed machine operands contain a given machine operand.
 static bool isImplicitOperandIn(const MachineOperand &ImplicitOperand,
-                                ArrayRef<ParsedMachineOperand> Operands) {
+                                ArrayRef<ParsedMachineOperand> Operands,
+                                const TargetRegisterInfo *TRI) {
   for (const auto &I : Operands) {
     if (ImplicitOperand.isIdenticalTo(I.Operand))
       return true;
+    // Accept a sub-register in place of the expected super-register.  On
+    // targets that narrow physical registers for specific subtargets (e.g.,
+    // AMDGPU wave32 uses $vcc_lo instead of $vcc), the MIR printer emits the
+    // narrow register while the MCInstrDesc still references the wide
+    // super-register.
+    if (I.Operand.isReg() && I.Operand.isImplicit() &&
+        ImplicitOperand.isDef() == I.Operand.isDef() &&
+        TRI->isSubRegisterEq(ImplicitOperand.getReg(), I.Operand.getReg()))
+      return true;
   }
   return false;
 }
@@ -1471,7 +1481,7 @@ bool MIParser::verifyImplicitOperands(ArrayRef<ParsedMachineOperand> Operands,
   const auto *TRI = MF.getSubtarget().getRegisterInfo();
   assert(TRI && "Expected target register info");
   for (const auto &I : ImplicitOperands) {
-    if (isImplicitOperandIn(I, Operands))
+    if (isImplicitOperandIn(I, Operands, TRI))
       continue;
     return error(Operands.empty() ? Token.location() : Operands.back().End,
                  Twine("missing implicit register operand '") +
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/parse-implicit-vcc-subreg.mir b/llvm/test/CodeGen/MIR/AMDGPU/parse-implicit-vcc-subreg.mir
new file mode 100644
index 0000000000000..e07671c97580c
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/parse-implicit-vcc-subreg.mir
@@ -0,0 +1,54 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1250 -run-pass=none -verify-machineinstrs %s -o - | FileCheck %s
+
+# Verify that the MIR parser accepts $vcc_lo as the implicit operand for
+# S_CBRANCH_VCCNZ on wave32 targets.
+
+# CHECK-LABEL: name: parse_implicit_vcc_lo
+# CHECK:       S_CBRANCH_VCCNZ %bb.1, implicit killed $vcc_lo
+---
+name:            parse_implicit_vcc_lo
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $sgpr0, $exec_lo
+    successors: %bb.1
+
+    $vcc_lo = S_AND_B32 $exec_lo, $sgpr0, implicit-def dead $scc
+    S_CBRANCH_VCCNZ %bb.1, implicit killed $vcc_lo
+
+  bb.1:
+    S_ENDPGM 0
+...
+
+# Also verify that S_CBRANCH_VCCZ works with $vcc_lo.
+# CHECK-LABEL: name: parse_implicit_vcc_lo_vccz
+# CHECK:       S_CBRANCH_VCCZ %bb.1, implicit killed $vcc_lo
+---
+name:            parse_implicit_vcc_lo_vccz
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $sgpr0, $exec_lo
+    successors: %bb.1
+
+    $vcc_lo = S_AND_B32 $exec_lo, $sgpr0, implicit-def dead $scc
+    S_CBRANCH_VCCZ %bb.1, implicit killed $vcc_lo
+
+  bb.1:
+    S_ENDPGM 0
+...
+
+# Verify that implicit-def sub-registers are also accepted.  V_ADD_CO_U32_e32
+# has 'Defs = [VCC]', but on wave32 the printer emits implicit-def $vcc_lo.
+# CHECK-LABEL: name: parse_implicit_def_vcc_lo
+# CHECK:       $vgpr0 = V_ADD_CO_U32_e32 $vgpr0, $vgpr1, implicit-def $vcc_lo, implicit $exec
+---
+name:            parse_implicit_def_vcc_lo
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $vgpr0, $vgpr1
+
+    $vgpr0 = V_ADD_CO_U32_e32 $vgpr0, $vgpr1, implicit-def $vcc_lo, implicit $exec
+    S_ENDPGM 0
+...



More information about the llvm-commits mailing list