[llvm] [MIR] Save internal VirtRegMap state in MIR (PR #197361)

Quentin Colombet via llvm-commits llvm-commits at lists.llvm.org
Wed May 13 21:34:01 PDT 2026


https://github.com/qcolombet updated https://github.com/llvm/llvm-project/pull/197361

>From ad8352f17b241058debca6d11d2a9fab4698f331 Mon Sep 17 00:00:00 2001
From: Quentin Colombet <quentin.colombet at gmail.com>
Date: Fri, 24 Apr 2026 15:37:47 -0700
Subject: [PATCH] [MIR] Save internal VirtRegMap state in MIR

Adds two optional fields to the per-vreg YAML record so MIR tests can
express VirtRegMap state that previously had no representation:

  registers:
    - { id: 1, class: vgpr_32, split-from: '%0', assigned-phys: '$vgpr5' }

Testing passes that consume sibling-register information (e.g.
InlineSpiller) requires constructing a VirtRegMap with split
relationships from a MIR test, which implies triggering live-range
splitting at minimum and make reproducers unnecessarily complicated.

So this change introduces a mechanism to serialize/deserialize the state
of the VirtRegMap pass.

Mechanism:
- For serialization:
  - MIRPrinter emits the new fields only when the VirtRegMap is available.
- For deserialization:
  - MIRParser stashes parsed entries on the generic MachineFunctionInfo
    base (PendingVRegMappings), using the existing
    parseVirtualRegisterReference / parseRegisterReference helpers.
  - VirtRegMap::init() drains the stash via assignVirt2Phys and
    setIsSplitFromReg, then clears it.

Validation at parse time:
  - 'assigned-phys' must be a physical register.
  - 'split-from' must reference a different vreg than 'id'.
  - 'split-from' physregs / named-vreg references already rejected
    by parseStandaloneVirtualRegister.

I'm not super happy about stashing the VRM info in the MFI, but that's
a small price to pay.
---
 llvm/include/llvm/CodeGen/MIRPrinter.h        | 11 ++++-
 llvm/include/llvm/CodeGen/MIRYamlMapping.h    | 18 ++++++-
 llvm/include/llvm/CodeGen/MachineFunction.h   | 10 ++++
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      | 48 +++++++++++++++++++
 llvm/lib/CodeGen/MIRPrinter.cpp               | 33 +++++++++----
 llvm/lib/CodeGen/MIRPrintingPass.cpp          | 11 ++++-
 llvm/lib/CodeGen/VirtRegMap.cpp               | 15 ++++++
 .../MIR/AMDGPU/virtregmap-stash-bad-phys.mir  | 18 +++++++
 .../MIR/AMDGPU/virtregmap-stash-bad-split.mir | 16 +++++++
 .../AMDGPU/virtregmap-stash-self-split.mir    | 17 +++++++
 .../CodeGen/MIR/AMDGPU/virtregmap-stash.mir   | 32 +++++++++++++
 11 files changed, 216 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-phys.mir
 create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-split.mir
 create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-self-split.mir
 create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash.mir

diff --git a/llvm/include/llvm/CodeGen/MIRPrinter.h b/llvm/include/llvm/CodeGen/MIRPrinter.h
index 829d16823d721..7956193c556a4 100644
--- a/llvm/include/llvm/CodeGen/MIRPrinter.h
+++ b/llvm/include/llvm/CodeGen/MIRPrinter.h
@@ -24,6 +24,7 @@ class MachineBasicBlock;
 class MachineFunction;
 class MachineModuleInfo;
 class Module;
+class VirtRegMap;
 template <typename T> class SmallVectorImpl;
 
 class PrintMIRPreparePass : public RequiredPassInfoMixin<PrintMIRPreparePass> {
@@ -47,12 +48,18 @@ class PrintMIRPass : public RequiredPassInfoMixin<PrintMIRPass> {
 LLVM_ABI void printMIR(raw_ostream &OS, const Module &M);
 
 /// Print MIR using Legacy Pass Manager (uses MachineModuleInfo).
+/// If \p VRM is non-null and -mir-emit-vrm is enabled, the printer will
+/// serialize VirtRegMap state (split-from, assigned-phys).
 LLVM_ABI void printMIR(raw_ostream &OS, const MachineModuleInfo &MMI,
-                       const MachineFunction &MF);
+                       const MachineFunction &MF,
+                       const VirtRegMap *VRM = nullptr);
 
 /// Print MIR using New Pass Manager (uses FunctionAnalysisManager).
+/// If \p VRM is non-null and -mir-emit-vrm is enabled, the printer will
+/// serialize VirtRegMap state (split-from, assigned-phys).
 LLVM_ABI void printMIR(raw_ostream &OS, FunctionAnalysisManager &FAM,
-                       const MachineFunction &MF);
+                       const MachineFunction &MF,
+                       const VirtRegMap *VRM = nullptr);
 
 /// Determine a possible list of successors of a basic block based on the
 /// basic block machine operand being used inside the block. This should give
diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 295ee296f78ab..de495f1d6ef82 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -203,12 +203,20 @@ struct VirtualRegisterDefinition {
   StringValue Class;
   StringValue PreferredRegister;
   std::vector<FlowStringValue> RegisterFlags;
+  // VirtRegMap state.
+  // SplitFrom: id-form virtual register only (e.g. '%0'); physregs and named
+  //            vregs are rejected by the parser.
+  // AssignedPhys: physical register only (e.g. '$r5'); virtregs are rejected.
+  StringValue SplitFrom;
+  StringValue AssignedPhys;
 
   // TODO: Serialize the target specific register hints.
 
   bool operator==(const VirtualRegisterDefinition &Other) const {
     return ID == Other.ID && Class == Other.Class &&
-           PreferredRegister == Other.PreferredRegister;
+           PreferredRegister == Other.PreferredRegister &&
+           SplitFrom == Other.SplitFrom &&
+           AssignedPhys == Other.AssignedPhys;
   }
 };
 
@@ -220,6 +228,14 @@ template <> struct MappingTraits<VirtualRegisterDefinition> {
                        StringValue()); // Don't print out when it's empty.
     YamlIO.mapOptional("flags", Reg.RegisterFlags,
                        std::vector<FlowStringValue>());
+    // MIRPrinter sets WriteDefaultValues=true unless -simplify-mir is passed,
+    // so a plain mapOptional with an empty default would still emit the keys
+    // and change every existing test's output.
+    // Skip the call on output when empty to keep them off entirely.
+    if (!YamlIO.outputting() || !Reg.SplitFrom.Value.empty())
+      YamlIO.mapOptional("split-from", Reg.SplitFrom, StringValue());
+    if (!YamlIO.outputting() || !Reg.AssignedPhys.Value.empty())
+      YamlIO.mapOptional("assigned-phys", Reg.AssignedPhys, StringValue());
   }
 
   static const bool flow = true;
diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h
index d620ae5137eba..ff6024c1e9b8e 100644
--- a/llvm/include/llvm/CodeGen/MachineFunction.h
+++ b/llvm/include/llvm/CodeGen/MachineFunction.h
@@ -129,6 +129,16 @@ struct LLVM_ABI MachineFunctionInfo {
       const {
     return nullptr;
   }
+
+  // Placeholder for deserialization of the VirtRegMap object.
+  // This gets populuated by the MIRParser when the information is present
+  // and is used in VirtRegMap::init() to initialize its state.
+  struct PendingVRegMapping {
+    Register VReg;
+    Register SplitFrom;       // NoReg if absent.
+    MCRegister AssignedPhys;  // NoReg if absent.
+  };
+  SmallVector<PendingVRegMapping, 0> PendingVRegMappings;
 };
 
 /// Properties which a MachineFunction may have at a given point in time.
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 00967e1de43cc..140de1dc7ef56 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -804,6 +804,54 @@ bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS,
     RegInfo.setCalleeSavedRegs(CalleeSavedRegisters);
   }
 
+  // Stash any VirtRegMap state on the generic MachineFunctionInfo base.
+  // VirtRegMap::init() will use that information to get pre-populated
+  // on the first analysis run.
+  for (const auto &VReg : YamlMF.VirtualRegisters) {
+    if (VReg.SplitFrom.Value.empty() && VReg.AssignedPhys.Value.empty())
+      continue;
+
+    auto *MFI = MF.getInfo<MachineFunctionInfo>();
+    if (!MFI)
+      return error(VReg.SplitFrom.Value.empty() ? VReg.AssignedPhys.SourceRange
+                                                       .Start
+                                                : VReg.SplitFrom.SourceRange
+                                                       .Start,
+                   "'split-from' / 'assigned-phys' require the target to "
+                   "implement TargetMachine::createMachineFunctionInfo");
+
+    auto It = PFS.VRegInfos.find(VReg.ID.Value);
+    if (It == PFS.VRegInfos.end())
+      continue;
+    Register ChildReg = It->second->VReg;
+
+    MachineFunctionInfo::PendingVRegMapping Pending;
+    Pending.VReg = ChildReg;
+
+    if (!VReg.SplitFrom.Value.empty()) {
+      VRegInfo *Parent = nullptr;
+      if (parseVirtualRegisterReference(PFS, Parent, VReg.SplitFrom.Value,
+                                        Error))
+        return error(Error, VReg.SplitFrom.SourceRange);
+      if (Parent->VReg == ChildReg)
+        return error(VReg.SplitFrom.SourceRange.Start,
+                     Twine("'split-from' references the same vreg as 'id' (%") +
+                         Twine(VReg.ID.Value) + ")");
+      Pending.SplitFrom = Parent->VReg;
+    }
+    if (!VReg.AssignedPhys.Value.empty()) {
+      Register Phys;
+      if (parseRegisterReference(PFS, Phys, VReg.AssignedPhys.Value, Error))
+        return error(Error, VReg.AssignedPhys.SourceRange);
+      if (!Phys.isPhysical())
+        return error(VReg.AssignedPhys.SourceRange.Start,
+                     Twine("'assigned-phys' must be a physical register, got '") +
+                         VReg.AssignedPhys.Value + "'");
+      Pending.AssignedPhys = Phys.asMCReg();
+    }
+    MFI->PendingVRegMappings.push_back(Pending);
+  }
+
   return false;
 }
 
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 679304c43af02..f51c0f241a443 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -37,6 +37,7 @@
 #include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/CodeGen/VirtRegMap.h"
 #include "llvm/CodeGenTypes/LowLevelType.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DebugLoc.h"
@@ -143,7 +144,8 @@ static void printMBB(raw_ostream &OS, MFPrintState &State,
                      const MachineBasicBlock &MBB);
 static void convertMRI(yaml::MachineFunction &YamlMF, const MachineFunction &MF,
                        const MachineRegisterInfo &RegInfo,
-                       const TargetRegisterInfo *TRI);
+                       const TargetRegisterInfo *TRI,
+                       const VirtRegMap *VRM);
 static void convertMCP(yaml::MachineFunction &MF,
                        const MachineConstantPool &ConstantPool);
 static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
@@ -175,7 +177,7 @@ static void convertPrefetchTargets(yaml::MachineFunction &YMF,
                                    const MachineFunction &MF);
 
 static void printMF(raw_ostream &OS, MFGetterFnT Fn,
-                    const MachineFunction &MF) {
+                    const MachineFunction &MF, const VirtRegMap *VRM) {
   MFPrintState State(std::move(Fn), MF);
 
   State.RegisterMaskIds = initRegisterMaskIds(MF);
@@ -206,7 +208,8 @@ static void printMF(raw_ostream &OS, MFGetterFnT Fn,
   YamlMF.IsSSA = Props.hasIsSSA();
   YamlMF.NoVRegs = Props.hasNoVRegs();
 
-  convertMRI(YamlMF, MF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
+  convertMRI(YamlMF, MF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo(),
+             VRM);
   MachineModuleSlotTracker &MST = State.MST;
   MST.incorporateFunction(MF.getFunction());
   convertMFI(MST, YamlMF.FrameInfo, MF.getFrameInfo(),
@@ -306,7 +309,8 @@ static void printRegFlags(Register Reg,
 
 static void convertMRI(yaml::MachineFunction &YamlMF, const MachineFunction &MF,
                        const MachineRegisterInfo &RegInfo,
-                       const TargetRegisterInfo *TRI) {
+                       const TargetRegisterInfo *TRI,
+                       const VirtRegMap *VRM) {
   YamlMF.TracksRegLiveness = RegInfo.tracksLiveness();
 
   // Print the virtual register definitions.
@@ -321,6 +325,17 @@ static void convertMRI(yaml::MachineFunction &YamlMF, const MachineFunction &MF,
     if (PreferredReg)
       printRegMIR(PreferredReg, VReg.PreferredRegister, TRI);
     printRegFlags(Reg, VReg.RegisterFlags, MF, TRI);
+    if (VRM) {
+      Register Orig = VRM->getPreSplitReg(Reg);
+      if (Orig && Orig != Reg) {
+        raw_string_ostream OS(VReg.SplitFrom.Value);
+        OS << printReg(Orig, TRI);
+      }
+      if (VRM->hasPhys(Reg)) {
+        raw_string_ostream OS(VReg.AssignedPhys.Value);
+        OS << printReg(VRM->getPhys(Reg), TRI);
+      }
+    }
     YamlMF.VirtualRegisters.push_back(std::move(VReg));
   }
 
@@ -1070,12 +1085,14 @@ void llvm::printMIR(raw_ostream &OS, const Module &M) {
 }
 
 void llvm::printMIR(raw_ostream &OS, const MachineModuleInfo &MMI,
-                    const MachineFunction &MF) {
-  printMF(OS, [&](const Function &F) { return MMI.getMachineFunction(F); }, MF);
+                    const MachineFunction &MF, const VirtRegMap *VRM) {
+  printMF(
+      OS, [&](const Function &F) { return MMI.getMachineFunction(F); }, MF,
+      VRM);
 }
 
 void llvm::printMIR(raw_ostream &OS, FunctionAnalysisManager &FAM,
-                    const MachineFunction &MF) {
+                    const MachineFunction &MF, const VirtRegMap *VRM) {
   printMF(
       OS,
       [&](const Function &F) {
@@ -1083,5 +1100,5 @@ void llvm::printMIR(raw_ostream &OS, FunctionAnalysisManager &FAM,
                        const_cast<Function &>(F))
                     .getMF();
       },
-      MF);
+      MF, VRM);
 }
diff --git a/llvm/lib/CodeGen/MIRPrintingPass.cpp b/llvm/lib/CodeGen/MIRPrintingPass.cpp
index a6fdaa6ab9c50..f5e455a520151 100644
--- a/llvm/lib/CodeGen/MIRPrintingPass.cpp
+++ b/llvm/lib/CodeGen/MIRPrintingPass.cpp
@@ -15,6 +15,7 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/VirtRegMap.h"
 #include "llvm/IR/Function.h"
 #include "llvm/InitializePasses.h"
 
@@ -30,7 +31,8 @@ PreservedAnalyses PrintMIRPass::run(MachineFunction &MF,
   auto &FAM = MFAM.getResult<FunctionAnalysisManagerMachineFunctionProxy>(MF)
                   .getManager();
 
-  printMIR(OS, FAM, MF);
+  const VirtRegMap *VRM = MFAM.getCachedResult<VirtRegMapAnalysis>(MF);
+  printMIR(OS, FAM, MF, VRM);
   return PreservedAnalyses::all();
 }
 
@@ -50,6 +52,7 @@ struct MIRPrintingPass : public MachineFunctionPass {
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.setPreservesAll();
+    AU.addUsedIfAvailable<VirtRegMapWrapperLegacy>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
 
@@ -60,7 +63,11 @@ struct MIRPrintingPass : public MachineFunctionPass {
     MachineModuleInfo *MMI =
         &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
 
-    printMIR(StrOS, *MMI, MF);
+    const VirtRegMap *VRM = nullptr;
+    if (auto *W = getAnalysisIfAvailable<VirtRegMapWrapperLegacy>())
+      VRM = &W->getVRM();
+
+    printMIR(StrOS, *MMI, MF, VRM);
     MachineFunctions.append(Str);
     return false;
   }
diff --git a/llvm/lib/CodeGen/VirtRegMap.cpp b/llvm/lib/CodeGen/VirtRegMap.cpp
index 972bd8f550e8b..3d625e8032111 100644
--- a/llvm/lib/CodeGen/VirtRegMap.cpp
+++ b/llvm/lib/CodeGen/VirtRegMap.cpp
@@ -74,6 +74,21 @@ void VirtRegMap::init(MachineFunction &mf) {
   Virt2ShapeMap.clear();
 
   grow();
+
+  // Drain any VirtRegMap state stashed by MIRParser on the generic
+  // MachineFunctionInfo base. Must run after grow() so that Virt2*Map have
+  // capacity for every vreg referenced by the stash.
+  if (auto *MFI = mf.getInfo<MachineFunctionInfo>()) {
+    for (const auto &P : MFI->PendingVRegMappings) {
+      if (P.AssignedPhys)
+        assignVirt2Phys(P.VReg, P.AssignedPhys);
+      // Guard against self-reference; the parser also rejects this, but a
+      // belt-and-braces check keeps Virt2SplitMap meaningful.
+      if (P.SplitFrom && P.SplitFrom != P.VReg)
+        setIsSplitFromReg(P.VReg, P.SplitFrom);
+    }
+    MFI->PendingVRegMappings.clear();
+  }
 }
 
 void VirtRegMap::grow() {
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-phys.mir b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-phys.mir
new file mode 100644
index 0000000000000..9dddfbf4fb6ca
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-phys.mir
@@ -0,0 +1,18 @@
+# RUN: not llc -mtriple=amdgcn -mcpu=gfx1100 -run-pass=virtregmap \
+# RUN:     -filetype=null %s 2>&1 | FileCheck %s
+#
+# 'assigned-phys' must be a physical register; passing a vreg should error.
+
+# CHECK: 'assigned-phys' must be a physical register, got '%0'
+---
+name: bad_phys
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: vgpr_32 }
+  - { id: 1, class: vgpr_32, assigned-phys: '%0' }
+body: |
+  bb.0:
+    %0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    %1:vgpr_32 = V_MOV_B32_e32 1, implicit $exec
+    S_ENDPGM 0, implicit %0, implicit %1
+...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-split.mir b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-split.mir
new file mode 100644
index 0000000000000..494677f23f7d1
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-bad-split.mir
@@ -0,0 +1,16 @@
+# RUN: not llc -mtriple=amdgcn -mcpu=gfx1100 -run-pass=virtregmap \
+# RUN:     -filetype=null %s 2>&1 | FileCheck %s
+#
+# 'split-from' must reference a virtual register; physregs are rejected.
+
+# CHECK: expected a virtual register
+---
+name: bad_split
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: vgpr_32, split-from: '$vgpr5' }
+body: |
+  bb.0:
+    %0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    S_ENDPGM 0, implicit %0
+...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-self-split.mir b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-self-split.mir
new file mode 100644
index 0000000000000..a14c37e01b2e7
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash-self-split.mir
@@ -0,0 +1,17 @@
+# RUN: not llc -mtriple=amdgcn -mcpu=gfx1100 -run-pass=virtregmap \
+# RUN:     -filetype=null %s 2>&1 | FileCheck %s
+#
+# 'split-from' must reference a different vreg than 'id'.
+# I.e., disallow self-references
+
+# CHECK: 'split-from' references the same vreg as 'id' (%0)
+---
+name: self_split
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: vgpr_32, split-from: '%0' }
+body: |
+  bb.0:
+    %0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    S_ENDPGM 0, implicit %0
+...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash.mir b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash.mir
new file mode 100644
index 0000000000000..a9272c92775a6
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/virtregmap-stash.mir
@@ -0,0 +1,32 @@
+# RUN: llc -mtriple=amdgcn -mcpu=gfx1100 -run-pass=virtregmap \
+# RUN:     -o - %s | FileCheck %s
+#
+# Verify that VirtRegMap state (split-from, assigned-phys) round-trips through
+# MIR.
+
+# CHECK-LABEL: name: test_vrm_roundtrip
+# CHECK:      registers:
+# CHECK:      id: 0,
+# CHECK-NOT:  split-from:
+# CHECK:      assigned-phys: '$vgpr5'
+# CHECK:      id: 1,
+# CHECK:      split-from: '%0'
+# CHECK:      assigned-phys: '$vgpr6'
+# CHECK:      id: 2,
+# CHECK:      split-from: '%0'
+# CHECK:      assigned-phys: '$vgpr7'
+---
+name: test_vrm_roundtrip
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: vgpr_32, assigned-phys: '$vgpr5' }
+  - { id: 1, class: vgpr_32, assigned-phys: '$vgpr6', split-from: '%0' }
+  - { id: 2, class: vgpr_32, assigned-phys: '$vgpr7', split-from: '%0' }
+body: |
+  bb.0:
+    liveins: $vgpr0
+    %0:vgpr_32 = COPY $vgpr0
+    %1:vgpr_32 = V_ADD_U32_e32 1, %0:vgpr_32, implicit $exec
+    %2:vgpr_32 = V_ADD_U32_e32 2, %0:vgpr_32, implicit $exec
+    S_ENDPGM 0, implicit %0, implicit %1, implicit %2
+...



More information about the llvm-commits mailing list