[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