[llvm] [AMDGPU] Post-RA Peephole for Two-Address Instructions (PR #207731)

Lukas Sommer via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 8 09:28:11 PDT 2026


https://github.com/sommerlukas updated https://github.com/llvm/llvm-project/pull/207731

>From 68fb22987e679478d9d38fb39cd0b6fd24d4f02a Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Fri, 3 Jul 2026 11:19:06 -0500
Subject: [PATCH 1/5] Initial implementation of post-RA peephole

Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
 llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp | 179 ++++++++++++++++++-
 1 file changed, 175 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
index a496c9a4daa71..22c6aeec437f8 100644
--- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
@@ -26,6 +26,7 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineLoopInfo.h"
 #include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/CodeGen/ReachingDefAnalysis.h"
 #include "llvm/CodeGen/TargetSchedule.h"
 #include "llvm/Support/BranchProbability.h"
 using namespace llvm;
@@ -39,6 +40,7 @@ class SIPreEmitPeephole {
   const SIInstrInfo *TII = nullptr;
   const SIRegisterInfo *TRI = nullptr;
   MachineLoopInfo *MLI = nullptr;
+  const ReachingDefInfo *RDI = nullptr;
 
   bool optimizeVccBranch(MachineInstr &MI) const;
   void updateMLIBeforeRemovingEdge(MachineBasicBlock *From,
@@ -81,8 +83,34 @@ class SIPreEmitPeephole {
   void addOperandAndMods(MachineInstrBuilder &NewMI, unsigned SrcMods,
                          bool IsHiBits, const MachineOperand &SrcMO);
 
+  // Delayed post-RA conversion from a two-address instruction to a
+  // three-address instruction. The copy instructions become redundant after
+  // retargeting the converted instruction to NewDst.
+  struct ThreeAddressCandidate {
+    MachineInstr *TwoAddrMI;
+    Register NewDst;
+    SmallVector<MachineInstr *, 2> CopiesToRemove;
+
+    ThreeAddressCandidate(MachineInstr &TwoAddrMI, Register NewDst,
+                          ArrayRef<MachineInstr *> Copies)
+        : TwoAddrMI(&TwoAddrMI), NewDst(NewDst), CopiesToRemove(Copies) {}
+  };
+  // Check if \p MaybeCopy is a simple copy of \p Src. If it is a supported
+  // copy, return the destination register of the copy.
+  std::optional<Register> checkCopy(MachineInstr &TwoAddress,
+                                    MachineInstr &MaybeCopy, Register Src);
+  // Check whether the two-address instruction should be replaced with a
+  // three-address instruction to avoid copies of the output registers. If the
+  // replacement should take place, returns the destination register for the
+  // replacement and fills \p Copies with the copy instructions to remove after
+  // the replacement.
+  Register
+  shouldReplaceWithThreeAddress(MachineInstr &MI,
+                                SmallVectorImpl<MachineInstr *> &Copies);
+
 public:
-  bool run(MachineFunction &MF, MachineLoopInfo *MLI);
+  bool run(MachineFunction &MF, MachineLoopInfo *MLI,
+           const ReachingDefInfo *RDI);
 };
 
 class SIPreEmitPeepholeLegacy : public MachineFunctionPass {
@@ -94,13 +122,16 @@ class SIPreEmitPeepholeLegacy : public MachineFunctionPass {
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.addUsedIfAvailable<MachineLoopInfoWrapperPass>();
     AU.addPreserved<MachineLoopInfoWrapperPass>();
+    AU.addRequired<ReachingDefInfoWrapperPass>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
 
   bool runOnMachineFunction(MachineFunction &MF) override {
     auto *MLIWrapper = getAnalysisIfAvailable<MachineLoopInfoWrapperPass>();
     MachineLoopInfo *MLI = MLIWrapper ? &MLIWrapper->getLI() : nullptr;
-    return SIPreEmitPeephole().run(MF, MLI);
+    const ReachingDefInfo *RDI =
+        &getAnalysis<ReachingDefInfoWrapperPass>().getRDI();
+    return SIPreEmitPeephole().run(MF, MLI, RDI);
   }
 };
 
@@ -763,13 +794,99 @@ MachineInstrBuilder SIPreEmitPeephole::createUnpackedMI(MachineInstr &I,
   return NewMI;
 }
 
+std::optional<Register> SIPreEmitPeephole::checkCopy(MachineInstr &TwoAddress,
+                                                     MachineInstr &MaybeCopy,
+                                                     Register Src) {
+  if (MaybeCopy.isBundle())
+    return std::nullopt;
+
+  switch (MaybeCopy.getOpcode()) {
+  case AMDGPU::COPY:
+  case AMDGPU::V_MOV_B32_e32:
+    break;
+  default:
+    return std::nullopt;
+  }
+
+  MachineOperand CopySrc = MaybeCopy.getOperand(1);
+  if (!CopySrc.isReg() || CopySrc.getReg() != Src)
+    return std::nullopt;
+
+  MachineOperand Dst = MaybeCopy.getOperand(0);
+  if (!Dst.isReg())
+    return std::nullopt;
+
+  Register Reg = Dst.getReg();
+  SmallPtrSet<MachineInstr *, 1> Ignore{&TwoAddress, &MaybeCopy};
+  if (!RDI->isSafeToDefRegAt(&TwoAddress, Reg, Ignore))
+    return std::nullopt;
+
+  if (!RDI->hasSameReachingDef(&TwoAddress, &MaybeCopy, AMDGPU::EXEC))
+    return std::nullopt;
+
+  return Reg;
+}
+
+Register SIPreEmitPeephole::shouldReplaceWithThreeAddress(
+    MachineInstr &MI, SmallVectorImpl<MachineInstr *> &Copies) {
+  MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
+  if (!Dst || !Dst->isReg())
+    return Register();
+
+  SmallVector<Register, 2> DestRegs;
+  Register Sub0 = TRI->getSubReg(Dst->getReg(), AMDGPU::sub0);
+  Register Sub1 = TRI->getSubReg(Dst->getReg(), AMDGPU::sub1);
+  if (Sub0 && Sub1) {
+    DestRegs.push_back(Sub0);
+    DestRegs.push_back(Sub1);
+  } else
+    DestRegs.push_back(Dst->getReg());
+
+  SmallVector<Register, 2> Replacements;
+  for (Register SubReg : DestRegs) {
+    if (!SubReg.isPhysical())
+      return Register();
+    if (RDI->isReachingDefLiveOut(&MI, SubReg))
+      return Register();
+
+    SmallPtrSet<MachineInstr *, 1> Uses;
+    RDI->getReachingLocalUses(&MI, SubReg, Uses);
+    if (Uses.size() != 1)
+      return Register();
+
+    MachineInstr &Use = **Uses.begin();
+    std::optional<Register> MaybeRegister = checkCopy(MI, Use, SubReg);
+
+    if (!MaybeRegister)
+      return Register();
+    Replacements.push_back(*MaybeRegister);
+    Copies.push_back(&Use);
+  }
+
+  if (Replacements.size() > 2)
+    return Register();
+
+  if (Replacements.size() == 1)
+    return Replacements.front();
+
+  Register Tuple = TRI->getMatchingSuperReg(Replacements.front(), AMDGPU::sub0,
+                                            TRI->getVGPR64Class());
+  if (!Tuple)
+    return Register();
+
+  if (TRI->getSubReg(Tuple, AMDGPU::sub1) != Replacements[1].asMCReg())
+    return Register();
+  return Tuple;
+}
+
 PreservedAnalyses
 llvm::SIPreEmitPeepholePass::run(MachineFunction &MF,
                                  MachineFunctionAnalysisManager &MFAM) {
   auto *MLI = MFAM.getCachedResult<MachineLoopAnalysis>(MF);
+  const ReachingDefInfo &RDI = MFAM.getResult<ReachingDefAnalysis>(MF);
   SIPreEmitPeephole Impl;
 
-  if (Impl.run(MF, MLI)) {
+  if (Impl.run(MF, MLI, &RDI)) {
     auto PA = getMachineFunctionPassPreservedAnalyses();
     PA.preserve<MachineLoopAnalysis>();
     return PA;
@@ -778,11 +895,13 @@ llvm::SIPreEmitPeepholePass::run(MachineFunction &MF,
   return PreservedAnalyses::all();
 }
 
-bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo) {
+bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo,
+                            const ReachingDefInfo *ReachingDefInfo) {
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   TII = ST.getInstrInfo();
   TRI = &TII->getRegisterInfo();
   MLI = LoopInfo;
+  RDI = ReachingDefInfo;
   bool Changed = false;
 
   MF.RenumberBlocks();
@@ -803,6 +922,58 @@ bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo) {
       }
     }
 
+    // Delayed optimization to replace two-address instructions followed by
+    // copies with a three-address instruction that directly writes to the
+    // copied registers instead. The pattern we seek to optimize is:
+    // $vgpr2_vgpr3 = V_FMAC_F64 ..., $vgpr_2_vgpr3
+    // $vgpr0 = V_MOV_B32 $vgrp2
+    // $vgpr1 = V_MOV_B32 $vgrp3
+    //
+    // This can be optimized to:
+    // $vgpr0_vgpr1 = V_FMA_F64 ..., $vgpr2_vgpr3
+    //
+    // The TwoAddressInstruction pass handles some cases, but bails in more
+    // complex cases.
+    SmallVector<ThreeAddressCandidate> Candidates;
+    // First, collect the candidates. We can't perform the transformation right
+    // away, it would invalidate the iterator.
+    for (auto &MI : make_early_inc_range(MBB.instrs())) {
+      if (MI.isBundle())
+        continue;
+
+      unsigned Opc = MI.getOpcode();
+      if (Opc != AMDGPU::V_FMAC_F64_e64 && Opc != AMDGPU::V_FMAC_F32_e64 &&
+          Opc != AMDGPU::V_FMAC_F64_e32 && Opc != AMDGPU::V_FMAC_F32_e32)
+        continue;
+
+      SmallVector<MachineInstr *, 2> Copies;
+      if (Register Dst = shouldReplaceWithThreeAddress(MI, Copies))
+        Candidates.emplace_back(MI, Dst, Copies);
+    }
+
+    for (ThreeAddressCandidate &Cand : Candidates) {
+      MachineInstr *ThreeAddrsInst =
+          TII->convertToThreeAddress(*Cand.TwoAddrMI, nullptr, nullptr);
+      if (!ThreeAddrsInst)
+        continue;
+      MachineOperand &NewDst = ThreeAddrsInst->getOperand(0);
+      assert(NewDst.isReg());
+
+      const TargetRegisterClass *DstRC =
+          TII->getRegClass(ThreeAddrsInst->getDesc(), NewDst.getOperandNo());
+      if (DstRC && !DstRC->contains(Cand.NewDst.asMCReg())) {
+        ThreeAddrsInst->eraseFromParent();
+        continue;
+      }
+
+      NewDst.setReg(Cand.NewDst);
+      NewDst.setIsRenamable(false);
+      Cand.TwoAddrMI->eraseFromParent();
+      llvm::for_each(Cand.CopiesToRemove,
+                     [](MachineInstr *Copy) { Copy->eraseFromParent(); });
+      Changed = true;
+    }
+
     if (!ST.hasVGPRIndexMode())
       continue;
 

>From 6c8e3f9d29d9c9929ce3fdaf3ce337b5dee66d15 Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Mon, 6 Jul 2026 07:00:27 -0500
Subject: [PATCH 2/5] Add and update tests

Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
 .../CodeGen/AMDGPU/hazard-pass-ordering.mir   |   3 +
 .../AMDGPU/insert-handle-flat-vmem-ds.mir     |   3 +
 .../CodeGen/AMDGPU/insert-skip-from-vcc.mir   |  49 ++++++
 .../CodeGen/AMDGPU/insert-skips-gfx10.mir     |   7 +
 .../CodeGen/AMDGPU/insert-skips-gfx12.mir     |  20 +++
 .../CodeGen/AMDGPU/insert-skips-gfx1250.mir   |   2 +
 llvm/test/CodeGen/AMDGPU/insert-skips-gws.mir |   2 +
 .../AMDGPU/insert-skips-ignored-insts.mir     |   1 +
 llvm/test/CodeGen/AMDGPU/llc-pipeline.ll      |   4 +
 ...hort-exec-branch-on-unconditional-jump.mir |   1 +
 ...emove-short-exec-branches-gpr-idx-mode.mir |   4 +
 ...ort-exec-branches-special-instructions.mir |  10 ++
 .../CodeGen/AMDGPU/set-gpr-idx-peephole.mir   | 164 +++++++++++++++---
 .../AMDGPU/si-pre-emit-peephole-fmac.mir      |  38 ++++
 ...i-pre-emit-peephole-preserve-loop-info.mir |   9 +
 .../AMDGPU/skip-branch-taildup-ret.mir        |   2 +
 16 files changed, 295 insertions(+), 24 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir

diff --git a/llvm/test/CodeGen/AMDGPU/hazard-pass-ordering.mir b/llvm/test/CodeGen/AMDGPU/hazard-pass-ordering.mir
index 093a8e02e0ab1..e4a99f04e3537 100644
--- a/llvm/test/CodeGen/AMDGPU/hazard-pass-ordering.mir
+++ b/llvm/test/CodeGen/AMDGPU/hazard-pass-ordering.mir
@@ -10,8 +10,11 @@
 # GCN-NEXT: s_nop
 # GCN-NEXT: flat_load_dword
 name:            mai_hazard_pass_ordering_optimize_vcc_branch
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $agpr0, $vgpr1
+
     $vgpr0 = V_MOV_B32_e32 1, implicit $exec
     $vgpr2 = V_ACCVGPR_READ_B32_e64 killed $agpr0, implicit $exec
     $sgpr8_sgpr9 = S_MOV_B64 -1
diff --git a/llvm/test/CodeGen/AMDGPU/insert-handle-flat-vmem-ds.mir b/llvm/test/CodeGen/AMDGPU/insert-handle-flat-vmem-ds.mir
index 785f5bed97904..b7b3354afa086 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-handle-flat-vmem-ds.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-handle-flat-vmem-ds.mir
@@ -5,6 +5,7 @@
 ---
 
 name: skip_execz_flat
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_execz_flat
   ; CHECK: bb.0:
@@ -34,6 +35,7 @@ body: |
 ---
 
 name: skip_execz_mubuf
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_execz_mubuf
   ; CHECK: bb.0:
@@ -63,6 +65,7 @@ body: |
 ---
 
 name: skip_execz_ds
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_execz_ds
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/insert-skip-from-vcc.mir b/llvm/test/CodeGen/AMDGPU/insert-skip-from-vcc.mir
index 0004989d42408..0ff5efe8f2f6e 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-skip-from-vcc.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-skip-from-vcc.mir
@@ -8,6 +8,7 @@
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -26,6 +27,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_imm_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -43,6 +45,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_EXECNZ %bb.1, implicit $exec
 name:            and_execnz_imm_vccnz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -60,6 +63,7 @@ body:             |
 # GCN: $vcc = S_AND_B64 $exec, -1, implicit-def $scc
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_imm_vccz_live_scc
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -78,6 +82,7 @@ body:             |
 # GCN: $vcc = S_AND_B64 $exec, -1, implicit-def $scc
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_live_scc
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -96,6 +101,7 @@ body:             |
 # GCN:      $sgpr0_sgpr1 = S_MOV_B64 -1
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_live_sreg
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -114,6 +120,7 @@ body:             |
 # GCN:      $sgpr0_sgpr1 = S_MOV_B64 -1
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_live_sreg_commute
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -133,6 +140,7 @@ body:             |
 # GCN: $vcc = S_AND_B64 $exec, -1, implicit-def $scc
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_live_scc_commute
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -152,6 +160,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_commute
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -170,6 +179,7 @@ body:             |
 # GCN:      $exec = S_MOV_B64 -1
 # GCN-NEXT: S_ENDPGM 0
 name:            and_execz_mov_exec_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -188,6 +198,7 @@ body:             |
 # GCN:      $exec = S_MOV_B64 -1
 # GCN-NEXT: S_BRANCH %bb.1{{$}}
 name:            and_execz_mov_exec_vccnz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -207,6 +218,7 @@ body:             |
 # GCN-NEXT: $sgpr2 = S_MOV_B32 $sgpr1
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_reads_sreg_early
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -227,6 +239,7 @@ body:             |
 # GCN-NEXT: $sgpr2 = S_MOV_B32 $sgpr1
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_reads_sreg_late
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -247,6 +260,7 @@ body:             |
 # GCN-NEXT: $vcc = S_AND_B64 $exec, killed $sgpr0_sgpr1, implicit-def dead $scc
 # GCN-NEXT: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            and_execz_mov_vccz_reads_writes_sreg_early
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -267,6 +281,7 @@ body:             |
 # GCN-NEXT: $sgpr2 = S_MOV_B32 $vcc_lo
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_reads_cond
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -288,6 +303,7 @@ body:             |
 # GCN-NEXT: $vcc = S_AND_B64 $exec, killed $sgpr0_sgpr1, implicit-def dead $scc
 # GCN-NEXT: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            and_execz_mov_vccz_modifies_sreg
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -308,6 +324,7 @@ body:             |
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 # GCN-NEXT: S_ENDPGM 0, implicit $scc
 name:            and_execz_imm_vccz_liveout_scc
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -326,6 +343,7 @@ body:             |
 # W32-NOT: S_AND_
 # W32: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_execz_mov_vccz_w32
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -345,6 +363,7 @@ body:             |
 # GCN-NOT: S_ANDN2_
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            andn2_execz_mov_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -364,6 +383,7 @@ body:             |
 # GCN-NOT: S_ANDN2_
 # GCN: S_BRANCH %bb.1
 name:            andn2_branch_mov_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -383,6 +403,7 @@ body:             |
 # GCN-NOT: S_ANDN2_
 # GCN: S_CBRANCH_EXECNZ %bb.1, implicit $exec
 name:            andn2_execnz_mov_vccnz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -403,6 +424,7 @@ body:             |
 # GCN-NOT: S_CBRANCH
 # GCN-NOT: S_BRANCH
 name:            andn2_no_branch_mov_vccnz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -423,6 +445,7 @@ body:             |
 # GCN: $vcc = S_MOV_B64 0
 # GCN-NEXT: S_BRANCH %bb.1
 name:            and_0_mov
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -443,6 +466,7 @@ body:             |
 # GCN: $vcc = S_MOV_B64 0
 # GCN-NEXT: S_BRANCH %bb.1
 name:            andn2_m1_mov
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -463,6 +487,7 @@ body:             |
 # GCN: $vcc = S_MOV_B64 $exec
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            and_m1_mov
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -483,6 +508,7 @@ body:             |
 # GCN: $vcc = S_MOV_B64 $exec
 # GCN-NEXT: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            andn2_0_mov
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -503,6 +529,7 @@ body:             |
 # GCN: S_AND_
 # GCN-NEXT: S_BRANCH %bb.1
 name:            and_0_scc_req
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -523,6 +550,7 @@ body:             |
 # GCN: S_ANDN2_
 # GCN-NEXT: S_BRANCH %bb.1
 name:            andn2_m1_scc_req
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -542,6 +570,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            and_cmp_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -550,6 +579,8 @@ body:             |
     S_NOP 0
 
   bb.2:
+    liveins: $vgpr0, $sgpr0, $sgpr0_sgpr1
+
     V_CMP_EQ_U32_e32 0, killed $vgpr0, implicit-def $vcc, implicit $exec
     $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
     S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
@@ -561,6 +592,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_VCCNZ %bb.1, implicit killed $vcc
 name:            and_cmp_vccnz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -569,6 +601,8 @@ body:             |
     S_NOP 0
 
   bb.2:
+    liveins: $vgpr0, $sgpr0, $sgpr0_sgpr1
+
     V_CMP_EQ_U32_e32 0, killed $vgpr0, implicit-def $vcc, implicit $exec
     $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
     S_CBRANCH_VCCNZ %bb.1, implicit killed $vcc
@@ -580,6 +614,7 @@ body:             |
 # GCN: $vcc = S_ANDN2_B64 $exec, $vcc, implicit-def dead $scc
 # GCN: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            andn2_cmp_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -588,6 +623,8 @@ body:             |
     S_NOP 0
 
   bb.2:
+    liveins: $vgpr0, $sgpr0, $sgpr0_sgpr1
+
     V_CMP_EQ_U32_e32 0, killed $vgpr0, implicit-def $vcc, implicit $exec
     $vcc = S_ANDN2_B64 $exec, $vcc, implicit-def dead $scc
     S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
@@ -599,6 +636,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            and_cmpclass_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -607,6 +645,8 @@ body:             |
     S_NOP 0
 
   bb.2:
+    liveins: $vgpr0, $sgpr0, $sgpr0_sgpr1
+
     V_CMP_CLASS_F32_e32 killed $sgpr0, killed $vgpr0, implicit-def $vcc, implicit $exec
     $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
     S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
@@ -618,6 +658,7 @@ body:             |
 # GCN-NOT: S_AND_
 # GCN: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            and_cmpx_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -626,6 +667,8 @@ body:             |
     S_NOP 0
 
   bb.2:
+    liveins: $vgpr0, $sgpr0, $sgpr0_sgpr1
+
     V_CMPX_EQ_U32_e32 0, killed $vgpr0, implicit-def $vcc, implicit-def $exec, implicit $exec
     $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
     S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
@@ -638,6 +681,7 @@ body:             |
 # GCN: $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
 # GCN: S_CBRANCH_VCCZ %bb.1, implicit killed $vcc
 name:            and_or_cmp_vccz
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -646,6 +690,8 @@ body:             |
     S_NOP 0
 
   bb.2:
+    liveins: $vgpr0, $sgpr0, $sgpr0_sgpr1
+
     V_CMP_EQ_U32_e32 0, killed $vgpr0, implicit-def $vcc, implicit $exec
     $exec = S_OR_B64 $exec, $sgpr0_sgpr1, implicit-def dead $scc
     $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
@@ -659,6 +705,7 @@ body:             |
 # GCN-NOT: S_
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            issue176578_src0_nonreg
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -678,6 +725,7 @@ body:             |
 # GCN-NOT: S_
 # GCN: S_CBRANCH_EXECZ %bb.1, implicit $exec
 name:            issue176578_src1_nonreg
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
@@ -696,6 +744,7 @@ body:             |
 # GCN: $vcc = S_AND_B64
 # GCN-NEXT: S_CBRANCH_VCCZ %bb.1
 name:            issue176578_nonregs
+tracksRegLiveness: true
 body:             |
   bb.0:
     S_NOP 0
diff --git a/llvm/test/CodeGen/AMDGPU/insert-skips-gfx10.mir b/llvm/test/CodeGen/AMDGPU/insert-skips-gfx10.mir
index 0bf74d96e134e..9f5fc74de2bd6 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-skips-gfx10.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-skips-gfx10.mir
@@ -3,6 +3,7 @@
 
 ---
 name: skip_waitcnt_vscnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_waitcnt_vscnt
   ; CHECK: bb.0:
@@ -33,6 +34,7 @@ body: |
 
 ---
 name: skip_waitcnt_expcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_waitcnt_expcnt
   ; CHECK: bb.0:
@@ -63,6 +65,7 @@ body: |
 
 ---
 name: skip_waitcnt_vmcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_waitcnt_vmcnt
   ; CHECK: bb.0:
@@ -93,6 +96,7 @@ body: |
 
 ---
 name: skip_waitcnt_lgkmcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_waitcnt_lgkmcnt
   ; CHECK: bb.0:
@@ -123,6 +127,7 @@ body: |
 
 ---
 name: skip_wait_idle
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_idle
   ; CHECK: bb.0:
@@ -153,6 +158,7 @@ body: |
 
 ---
 name: skip_bvh
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_bvh
   ; CHECK: bb.0:
@@ -187,6 +193,7 @@ body: |
 
 ---
 name: skip_barrier
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/insert-skips-gfx12.mir b/llvm/test/CodeGen/AMDGPU/insert-skips-gfx12.mir
index bac167fbb1570..cb7c4021787ff 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-skips-gfx12.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-skips-gfx12.mir
@@ -3,6 +3,7 @@
 
 ---
 name: skip_wait_loadcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_loadcnt
   ; CHECK: bb.0:
@@ -33,6 +34,7 @@ body: |
 
 ---
 name: skip_wait_loadcnt_dscnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_loadcnt_dscnt
   ; CHECK: bb.0:
@@ -63,6 +65,7 @@ body: |
 
 ---
 name: skip_wait_storecnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_storecnt
   ; CHECK: bb.0:
@@ -93,6 +96,7 @@ body: |
 
 ---
 name: skip_wait_storecnt_dscnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_storecnt_dscnt
   ; CHECK: bb.0:
@@ -123,6 +127,7 @@ body: |
 
 ---
 name: skip_wait_samplecnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_samplecnt
   ; CHECK: bb.0:
@@ -153,6 +158,7 @@ body: |
 
 ---
 name: skip_wait_bvhcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_bvhcnt
   ; CHECK: bb.0:
@@ -183,6 +189,7 @@ body: |
 
 ---
 name: skip_wait_expcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_expcnt
   ; CHECK: bb.0:
@@ -213,6 +220,7 @@ body: |
 
 ---
 name: skip_wait_dscnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_dscnt
   ; CHECK: bb.0:
@@ -243,6 +251,7 @@ body: |
 
 ---
 name: skip_wait_kmcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_kmcnt
   ; CHECK: bb.0:
@@ -273,6 +282,7 @@ body: |
 
 ---
 name: skip_wait_idle
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_idle
   ; CHECK: bb.0:
@@ -303,6 +313,7 @@ body: |
 
 ---
 name: skip_wait_event
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_event
   ; CHECK: bb.0:
@@ -333,6 +344,7 @@ body: |
 
 ---
 name: skip_barrier_signal_imm
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_signal_imm
   ; CHECK: bb.0:
@@ -363,6 +375,7 @@ body: |
 
 ---
 name: skip_barrier_signal_isfirst_imm
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_signal_isfirst_imm
   ; CHECK: bb.0:
@@ -395,6 +408,7 @@ body: |
 
 ---
 name: skip_barrier_signal_m0
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_signal_m0
   ; CHECK: bb.0:
@@ -427,6 +441,7 @@ body: |
 
 ---
 name: skip_barrier_signal_isfirst_m0
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_signal_isfirst_m0
   ; CHECK: bb.0:
@@ -461,6 +476,7 @@ body: |
 
 ---
 name: skip_barrier_wait
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_wait
   ; CHECK: bb.0:
@@ -491,6 +507,7 @@ body: |
 
 ---
 name: skip_barrier_init_imm
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_init_imm
   ; CHECK: bb.0:
@@ -523,6 +540,7 @@ body: |
 
 ---
 name: skip_barrier_init_m0
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_init_m0
   ; CHECK: bb.0:
@@ -555,6 +573,7 @@ body: |
 
 ---
 name: skip_barrier_join_imm
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_join_imm
   ; CHECK: bb.0:
@@ -585,6 +604,7 @@ body: |
 
 ---
 name: skip_barrier_leave
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_barrier_leave
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/insert-skips-gfx1250.mir b/llvm/test/CodeGen/AMDGPU/insert-skips-gfx1250.mir
index 8a5d9cb6c5632..3854357f5a9ca 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-skips-gfx1250.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-skips-gfx1250.mir
@@ -3,6 +3,7 @@
 
 ---
 name: skip_wait_xcnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_xcnt
   ; CHECK: bb.0:
@@ -33,6 +34,7 @@ body: |
 
 ---
 name: skip_wait_asynccnt
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_wait_asynccnt
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/insert-skips-gws.mir b/llvm/test/CodeGen/AMDGPU/insert-skips-gws.mir
index 3281e4ccda7ab..1c94a1f9b737a 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-skips-gws.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-skips-gws.mir
@@ -5,6 +5,7 @@
 ---
 
 name: skip_gws_init
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_gws_init
   ; CHECK: bb.0:
@@ -36,6 +37,7 @@ body: |
 ---
 
 name: skip_gws_barrier
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: skip_gws_barrier
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/insert-skips-ignored-insts.mir b/llvm/test/CodeGen/AMDGPU/insert-skips-ignored-insts.mir
index 372f22019aefb..3cc1e6e19510d 100644
--- a/llvm/test/CodeGen/AMDGPU/insert-skips-ignored-insts.mir
+++ b/llvm/test/CodeGen/AMDGPU/insert-skips-ignored-insts.mir
@@ -4,6 +4,7 @@
 ---
 
 name: no_count_dbg_value
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: no_count_dbg_value
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll b/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
index 070c873798647..93ff015f27b41 100644
--- a/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
+++ b/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
@@ -435,6 +435,7 @@
 ; GCN-O1-NEXT:        Insert required mode register values
 ; GCN-O1-NEXT:        SI Insert Hard Clauses
 ; GCN-O1-NEXT:        SI Final Branch Preparation
+; GCN-O1-NEXT:        Reaching Definitions Analysis
 ; GCN-O1-NEXT:        SI peephole optimizations
 ; GCN-O1-NEXT:        Post RA hazard recognizer
 ; GCN-O1-NEXT:        AMDGPU Insert waits for SGPR read hazards
@@ -753,6 +754,7 @@
 ; GCN-O1-OPTS-NEXT:        Insert required mode register values
 ; GCN-O1-OPTS-NEXT:        SI Insert Hard Clauses
 ; GCN-O1-OPTS-NEXT:        SI Final Branch Preparation
+; GCN-O1-OPTS-NEXT:        Reaching Definitions Analysis
 ; GCN-O1-OPTS-NEXT:        SI peephole optimizations
 ; GCN-O1-OPTS-NEXT:        Post RA hazard recognizer
 ; GCN-O1-OPTS-NEXT:        AMDGPU Insert waits for SGPR read hazards
@@ -1076,6 +1078,7 @@
 ; GCN-O2-NEXT:        Insert required mode register values
 ; GCN-O2-NEXT:        SI Insert Hard Clauses
 ; GCN-O2-NEXT:        SI Final Branch Preparation
+; GCN-O2-NEXT:        Reaching Definitions Analysis
 ; GCN-O2-NEXT:        SI peephole optimizations
 ; GCN-O2-NEXT:        Post RA hazard recognizer
 ; GCN-O2-NEXT:        AMDGPU Insert waits for SGPR read hazards
@@ -1412,6 +1415,7 @@
 ; GCN-O3-NEXT:        Insert required mode register values
 ; GCN-O3-NEXT:        SI Insert Hard Clauses
 ; GCN-O3-NEXT:        SI Final Branch Preparation
+; GCN-O3-NEXT:        Reaching Definitions Analysis
 ; GCN-O3-NEXT:        SI peephole optimizations
 ; GCN-O3-NEXT:        Post RA hazard recognizer
 ; GCN-O3-NEXT:        AMDGPU Insert waits for SGPR read hazards
diff --git a/llvm/test/CodeGen/AMDGPU/remove-not-short-exec-branch-on-unconditional-jump.mir b/llvm/test/CodeGen/AMDGPU/remove-not-short-exec-branch-on-unconditional-jump.mir
index f45f48434fa23..e96e9acd7f09f 100644
--- a/llvm/test/CodeGen/AMDGPU/remove-not-short-exec-branch-on-unconditional-jump.mir
+++ b/llvm/test/CodeGen/AMDGPU/remove-not-short-exec-branch-on-unconditional-jump.mir
@@ -5,6 +5,7 @@
 
 ---
 name:            test
+tracksRegLiveness: true
 body:             |
   ; CHECK-LABEL: name: test
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-gpr-idx-mode.mir b/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-gpr-idx-mode.mir
index ee5546befd12d..90dd9f2e83157 100644
--- a/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-gpr-idx-mode.mir
+++ b/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-gpr-idx-mode.mir
@@ -5,6 +5,7 @@
 ---
 
 name: need_skip_gpr_idx_mode
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_gpr_idx_mode
   ; CHECK: bb.0:
@@ -34,6 +35,7 @@ body: |
 ---
 
 name: need_skip_gpr_idx_on
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_gpr_idx_on
   ; CHECK: bb.0:
@@ -67,6 +69,7 @@ body: |
 ---
 
 name: need_skip_gpr_idx_off
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_gpr_idx_off
   ; CHECK: bb.0:
@@ -96,6 +99,7 @@ body: |
 ---
 
 name: need_skip_gpr_idx_idx
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_gpr_idx_idx
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-special-instructions.mir b/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-special-instructions.mir
index 2c8739a87626e..b959d4f36f82e 100644
--- a/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-special-instructions.mir
+++ b/llvm/test/CodeGen/AMDGPU/remove-short-exec-branches-special-instructions.mir
@@ -6,6 +6,7 @@
 ---
 
 name: need_skip_setreg_imm32_b32
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_setreg_imm32_b32
   ; CHECK: bb.0:
@@ -37,6 +38,7 @@ body: |
 ---
 
 name: need_skip_setreg_b32
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_setreg_b32
   ; CHECK: bb.0:
@@ -71,6 +73,7 @@ body: |
 ---
 
 name: need_skip_denorm_mode
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_denorm_mode
   ; CHECK: bb.0:
@@ -101,6 +104,7 @@ body: |
 ---
 
 name: need_skip_round_mode
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_round_mode
   ; CHECK: bb.0:
@@ -131,15 +135,18 @@ body: |
 ---
 
 name: need_skip_writelane_b32
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_writelane_b32
   ; CHECK: bb.0:
   ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT:   liveins: $vgpr0
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   S_CBRANCH_EXECZ %bb.2, implicit $exec
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT: bb.1:
   ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $vgpr0
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   $sgpr0 = IMPLICIT_DEF
   ; CHECK-NEXT:   $vgpr0 = V_WRITELANE_B32 $sgpr0, 0, $vgpr0
@@ -147,10 +154,12 @@ body: |
   ; CHECK-NEXT: bb.2:
   ; CHECK-NEXT:   S_ENDPGM 0
   bb.0:
+    liveins: $vgpr0
     successors: %bb.1, %bb.2
     S_CBRANCH_EXECZ %bb.2, implicit $exec
 
   bb.1:
+    liveins: $vgpr0
     successors: %bb.2
     $sgpr0 = IMPLICIT_DEF
     $vgpr0 = V_WRITELANE_B32 $sgpr0, 0, $vgpr0
@@ -161,6 +170,7 @@ body: |
 
 ---
 name: need_skip_readlane_b32
+tracksRegLiveness: true
 body: |
   ; CHECK-LABEL: name: need_skip_readlane_b32
   ; CHECK: bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/set-gpr-idx-peephole.mir b/llvm/test/CodeGen/AMDGPU/set-gpr-idx-peephole.mir
index 131656975ec40..29db2860be152 100644
--- a/llvm/test/CodeGen/AMDGPU/set-gpr-idx-peephole.mir
+++ b/llvm/test/CodeGen/AMDGPU/set-gpr-idx-peephole.mir
@@ -5,11 +5,16 @@
 
 ---
 name:            simple
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: simple
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: $vgpr15 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
@@ -23,11 +28,16 @@ body:             |
 
 ---
 name:            salu_in_between
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: salu_in_between
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: $sgpr0 = S_MOV_B32 $sgpr2
     ; GCN-NEXT: $vgpr15 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
@@ -43,10 +53,15 @@ body:             |
 
 ---
 name:            meta_in_between
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
     ; GCN-LABEL: name: meta_in_between
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: KILL $sgpr0
     ; GCN-NEXT: $sgpr0 = IMPLICIT_DEF
@@ -64,11 +79,16 @@ body:             |
 
 ---
 name:            valu_write_in_between
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: valu_write_in_between
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: $vgpr20 = V_MOV_B32_indirect_read 1, implicit $exec, implicit $m0
@@ -86,11 +106,16 @@ body:             |
 
 ---
 name:            valu_read_in_between
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: valu_read_in_between
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: V_NOP_e32 implicit $exec, implicit $vgpr0
@@ -108,11 +133,16 @@ body:             |
 
 ---
 name:            changed_index
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: changed_index
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: $sgpr2 = S_MOV_B32 1
@@ -130,11 +160,16 @@ body:             |
 
 ---
 name:            implicitly_changed_index
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: implicitly_changed_index
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: S_NOP 0, implicit-def $sgpr2
@@ -152,11 +187,16 @@ body:             |
 
 ---
 name:            changed_m0
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: changed_m0
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: $m0 = S_MOV_B32 1
@@ -174,11 +214,16 @@ body:             |
 
 ---
 name:            implicitly_changed_m0
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: implicitly_changed_m0
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: S_NOP 0, implicit-def $m0
@@ -196,11 +241,16 @@ body:             |
 
 ---
 name:            same_imm_index
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: same_imm_index
-    ; GCN: S_SET_GPR_IDX_ON 1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON 1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: $vgpr15 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
@@ -214,11 +264,16 @@ body:             |
 
 ---
 name:            different_imm_index
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: different_imm_index
-    ; GCN: S_SET_GPR_IDX_ON 1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON 1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: S_SET_GPR_IDX_ON 2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
@@ -234,11 +289,16 @@ body:             |
 
 ---
 name:            different_gpr_index
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: different_gpr_index
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: S_SET_GPR_IDX_ON killed $sgpr1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
@@ -254,11 +314,16 @@ body:             |
 
 ---
 name:            different_gpr_index_then_same_index
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: different_gpr_index_then_same_index
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
@@ -280,11 +345,16 @@ body:             |
 
 ---
 name:            use_m0_with_idx_off
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: use_m0_with_idx_off
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_ON killed $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
@@ -300,20 +370,23 @@ body:             |
 
 ---
 name:            three_in_a_row
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: three_in_a_row
     ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
-    ; GCN-NEXT: $vgpr17 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
+    ; GCN-NEXT: $vgpr17 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: $vgpr18 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
   S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
-  S_SET_GPR_IDX_ON killed $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
-  $vgpr17 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
+  S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+  $vgpr17 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
   S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
   S_SET_GPR_IDX_ON killed $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
   $vgpr18 = V_MOV_B32_indirect_read undef $vgpr0, implicit $exec, implicit $m0, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
@@ -322,11 +395,16 @@ body:             |
 
 ---
 name:            different_gpr_index_then_two_same_indexes
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: different_gpr_index_then_two_same_indexes
-    ; GCN: S_SET_GPR_IDX_ON $sgpr1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr1, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
     ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
@@ -346,11 +424,16 @@ body:             |
 
 ---
 name:            two_same_indexes_then_different
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: two_same_indexes_then_different
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
@@ -370,11 +453,16 @@ body:             |
 
 ---
 name:            indirect_mov
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
 
     ; GCN-LABEL: name: indirect_mov
-    ; GCN: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $m0, implicit-def $mode, implicit undef $m0, implicit $mode
     ; GCN-NEXT: $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: V_MOV_B32_indirect_write undef $vgpr0, undef $vgpr3, implicit $exec, implicit $m0, implicit-def $vgpr0_vgpr1_vgpr2_vgpr3, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3(tied-def 4)
     ; GCN-NEXT: V_MOV_B32_indirect_write undef $vgpr0, undef $vgpr3, implicit $exec, implicit $m0, implicit-def $vgpr0_vgpr1_vgpr2_vgpr3, implicit killed $vgpr0_vgpr1_vgpr2_vgpr3(tied-def 4)
@@ -390,10 +478,15 @@ body:             |
 
 ---
 name:            simple_bundle
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
     ; GCN-LABEL: name: simple_bundle
-    ; GCN: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
     ; GCN-NEXT:   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
     ; GCN-NEXT:   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: }
@@ -415,10 +508,15 @@ body:             |
 
 ---
 name:            salu_in_between_bundle
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
     ; GCN-LABEL: name: salu_in_between_bundle
-    ; GCN: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
     ; GCN-NEXT:   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
     ; GCN-NEXT:   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT: }
@@ -442,10 +540,15 @@ body:             |
 
 ---
 name:            valu_in_between_bundle
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
     ; GCN-LABEL: name: valu_in_between_bundle
-    ; GCN: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
     ; GCN-NEXT:   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
     ; GCN-NEXT:   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT:   S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
@@ -471,10 +574,15 @@ body:             |
 
 ---
 name:            changed_index_bundle
+tracksRegLiveness: true
 body:             |
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
     ; GCN-LABEL: name: changed_index_bundle
-    ; GCN: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: BUNDLE implicit-def $m0, implicit-def $m0_lo16, implicit-def $m0_hi16, implicit-def $mode, implicit-def $vgpr16, implicit-def $vgpr16_lo16, implicit-def $vgpr16_hi16, implicit $sgpr2, implicit $m0, implicit $mode, implicit undef $vgpr1, implicit $exec, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15 {
     ; GCN-NEXT:   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
     ; GCN-NEXT:   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
     ; GCN-NEXT:   S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
@@ -500,10 +608,12 @@ body:             |
 
 ---
 name:            simple_cbranch_vccz
+tracksRegLiveness: true
 body:             |
   ; GCN-LABEL: name: simple_cbranch_vccz
   ; GCN: bb.0:
   ; GCN-NEXT:   successors: %bb.1(0x80000000)
+  ; GCN-NEXT:   liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
   ; GCN-NEXT: {{  $}}
   ; GCN-NEXT:   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
   ; GCN-NEXT:   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
@@ -513,6 +623,8 @@ body:             |
   ; GCN-NEXT: {{  $}}
   ; GCN-NEXT: bb.1:
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
   S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
@@ -525,10 +637,12 @@ body:             |
 
 ---
 name:            simple_cbranch_execz
+tracksRegLiveness: true
 body:             |
   ; GCN-LABEL: name: simple_cbranch_execz
   ; GCN: bb.0:
   ; GCN-NEXT:   successors:
+  ; GCN-NEXT:   liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
   ; GCN-NEXT: {{  $}}
   ; GCN-NEXT:   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
   ; GCN-NEXT:   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
@@ -537,6 +651,8 @@ body:             |
   ; GCN-NEXT: {{  $}}
   ; GCN-NEXT: bb.1:
   bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0, $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15, $vcc
+
   S_SET_GPR_IDX_ON $sgpr2, 1, implicit-def $mode, implicit-def $m0, implicit $mode, implicit undef $m0
   $vgpr16 = V_MOV_B32_indirect_read undef $vgpr1, implicit $exec, implicit $m0, implicit $vgpr0_vgpr1_vgpr2_vgpr3_vgpr4_vgpr5_vgpr6_vgpr7_vgpr8_vgpr9_vgpr10_vgpr11_vgpr12_vgpr13_vgpr14_vgpr15
   S_SET_GPR_IDX_OFF implicit-def $mode, implicit $mode
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
new file mode 100644
index 0000000000000..7f94f55237621
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
@@ -0,0 +1,38 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -run-pass=si-pre-emit-peephole -verify-machineinstrs -o - %s | FileCheck %s
+
+---
+name: fmac_f64_e32_return_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr0, $vgpr1
+
+    ; CHECK-LABEL: name: fmac_f64_e32_return_copy
+    ; CHECK: $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr4_vgpr5, 0, killed $vgpr0_vgpr1, 0, killed $vgpr2_vgpr3, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: SI_RETURN implicit killed $vgpr0, implicit killed $vgpr1
+    renamable $vgpr2_vgpr3 = nofpexcept V_RSQ_F64_e32 $vgpr0_vgpr1, implicit $mode, implicit $exec
+    renamable $vgpr4_vgpr5 = nofpexcept V_MUL_F64_e64 0, $vgpr2_vgpr3, 0, $vgpr0_vgpr1, 0, 0, implicit $mode, implicit $exec
+    renamable $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr0_vgpr1, 0, $vgpr2_vgpr3, 0, 4602678819172646912, 0, 0, implicit $mode, implicit $exec
+    renamable $vgpr2_vgpr3 = nofpexcept V_FMAC_F64_e32 killed renamable $vgpr4_vgpr5, killed renamable $vgpr0_vgpr1, killed renamable $vgpr2_vgpr3, implicit $mode, implicit $exec
+    $vgpr0 = V_MOV_B32_e32 killed $vgpr2, implicit $exec, implicit $exec
+    $vgpr1 = V_MOV_B32_e32 killed $vgpr3, implicit $exec, implicit $exec
+    SI_RETURN implicit killed $vgpr0, implicit killed $vgpr1
+...
+
+---
+name: fmac_f32_e32_return_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr0
+
+    ; CHECK-LABEL: name: fmac_f32_e32_return_copy
+    ; CHECK: $vgpr0 = nofpexcept V_FMA_F32_e64 0, killed $vgpr4, 0, killed $vgpr0, 0, killed $vgpr2, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: SI_RETURN implicit killed $vgpr0
+    renamable $vgpr2 = nofpexcept V_RSQ_F32_e32 $vgpr0, implicit $exec, implicit $mode
+    renamable $vgpr4 = nofpexcept V_MUL_F32_e64 0, $vgpr2, 0, $vgpr0, 0, 0, implicit $mode, implicit $exec
+    renamable $vgpr0 = nofpexcept V_FMA_F32_e64 0, killed $vgpr0, 0, $vgpr2, 0, 1056964608, 0, 0, implicit $mode, implicit $exec
+    renamable $vgpr2 = nofpexcept V_FMAC_F32_e32 killed renamable $vgpr4, killed renamable $vgpr0, killed renamable $vgpr2, implicit $mode, implicit $exec
+    $vgpr0 = V_MOV_B32_e32 killed $vgpr2, implicit $exec, implicit $exec
+    SI_RETURN implicit killed $vgpr0
+...
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-preserve-loop-info.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-preserve-loop-info.mir
index e3ac9f70a50a0..e225933aee734 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-preserve-loop-info.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-preserve-loop-info.mir
@@ -3,7 +3,9 @@
 # CHECK: Running analysis: MachineLoopAnalysis on vcc_and_removal_preserves_mli
 # CHECK-NEXT: Running analysis: MachineDominatorTreeAnalysis on vcc_and_removal_preserves_mli
 # CHECK-NEXT: Running pass: SIPreEmitPeepholePass on vcc_and_removal_preserves_mli
+# CHECK-NEXT: Running analysis: ReachingDefAnalysis on vcc_and_removal_preserves_mli
 # CHECK-NEXT: Invalidating analysis: MachineDominatorTreeAnalysis on vcc_and_removal_preserves_mli
+# CHECK-NEXT: Invalidating analysis: ReachingDefAnalysis on vcc_and_removal_preserves_mli
 # CHECK-NEXT: Running pass: MachineLoopPrinterPass on vcc_and_removal_preserves_mli
 # CHECK-NEXT: Machine loop info for machine function 'vcc_and_removal_preserves_mli':
 # CHECK-NOT: Running analysis: MachineLoopAnalysis on vcc_and_removal_preserves_mli
@@ -11,12 +13,17 @@
 
 ---
 name: vcc_and_removal_preserves_mli
+tracksRegLiveness: true
 body: |
   bb.0:
+    liveins: $vgpr0
+
     S_BRANCH %bb.1
 
   ; S_AND gets removed
   bb.1:
+    liveins: $vgpr0
+
     V_CMP_EQ_U32_e32 0, $vgpr0, implicit-def $vcc, implicit $exec
     $vcc = S_AND_B64 $exec, $vcc, implicit-def dead $scc
     S_CBRANCH_VCCNZ %bb.1, implicit $vcc
@@ -27,12 +34,14 @@ body: |
 ...
 
 # CHECK-LABEL: Running pass: SIPreEmitPeepholePass on vcc_branch_destroys_loop
+# CHECK-NEXT: Running analysis: ReachingDefAnalysis on vcc_branch_destroys_loop
 # CHECK-NOT: Running analysis: MachineLoopAnalysis on vcc_branch_destroys_loop
 # CHECK: Machine loop info for machine function 'vcc_branch_destroys_loop':
 # CHECK-NOT: Loop at depth
 
 ---
 name: vcc_branch_destroys_loop
+tracksRegLiveness: true
 body: |
   bb.0:
     S_BRANCH %bb.1
diff --git a/llvm/test/CodeGen/AMDGPU/skip-branch-taildup-ret.mir b/llvm/test/CodeGen/AMDGPU/skip-branch-taildup-ret.mir
index 4b5d05167d53a..306a5e56df2f8 100644
--- a/llvm/test/CodeGen/AMDGPU/skip-branch-taildup-ret.mir
+++ b/llvm/test/CodeGen/AMDGPU/skip-branch-taildup-ret.mir
@@ -3,6 +3,7 @@
 
 ---
 name: skip_branch_taildup_endpgm
+tracksRegLiveness: true
 machineFunctionInfo:
   isEntryFunction: true
 body:             |
@@ -124,6 +125,7 @@ body:             |
 
 ---
 name: skip_branch_taildup_ret
+tracksRegLiveness: true
 body:             |
   ; CHECK-LABEL: name: skip_branch_taildup_ret
   ; CHECK: bb.0:

>From eb1d7da1a5058069340c42562b0bf271cdb0497a Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Mon, 6 Jul 2026 08:07:42 -0500
Subject: [PATCH 3/5] Add documentation

Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
 llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp  | 15 ++++++++---
 .../AMDGPU/si-pre-emit-peephole-fmac.mir      | 25 +++++++++++++++++++
 2 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
index 22c6aeec437f8..734ccbad4eb35 100644
--- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
@@ -83,9 +83,10 @@ class SIPreEmitPeephole {
   void addOperandAndMods(MachineInstrBuilder &NewMI, unsigned SrcMods,
                          bool IsHiBits, const MachineOperand &SrcMO);
 
-  // Delayed post-RA conversion from a two-address instruction to a
-  // three-address instruction. The copy instructions become redundant after
-  // retargeting the converted instruction to NewDst.
+  // Hold information about a candidate for delayed post-RA conversion from a
+  // two-address instruction to a three-address instruction. The copy
+  // instructions become redundant after retargeting the converted instruction
+  // to NewDst.
   struct ThreeAddressCandidate {
     MachineInstr *TwoAddrMI;
     Register NewDst;
@@ -817,10 +818,14 @@ std::optional<Register> SIPreEmitPeephole::checkCopy(MachineInstr &TwoAddress,
     return std::nullopt;
 
   Register Reg = Dst.getReg();
+  // Check that it is safe to define the copy destination register at the
+  // current position of the two-address instruction.
   SmallPtrSet<MachineInstr *, 1> Ignore{&TwoAddress, &MaybeCopy};
   if (!RDI->isSafeToDefRegAt(&TwoAddress, Reg, Ignore))
     return std::nullopt;
 
+  // Check that the two-address instruction and the copy have the same exec
+  // mask.
   if (!RDI->hasSameReachingDef(&TwoAddress, &MaybeCopy, AMDGPU::EXEC))
     return std::nullopt;
 
@@ -846,7 +851,7 @@ Register SIPreEmitPeephole::shouldReplaceWithThreeAddress(
   for (Register SubReg : DestRegs) {
     if (!SubReg.isPhysical())
       return Register();
-    if (RDI->isReachingDefLiveOut(&MI, SubReg))
+    if (RDI->getLocalLiveOutMIDef(MI.getParent(), SubReg) == &MI)
       return Register();
 
     SmallPtrSet<MachineInstr *, 1> Uses;
@@ -869,6 +874,8 @@ Register SIPreEmitPeephole::shouldReplaceWithThreeAddress(
   if (Replacements.size() == 1)
     return Replacements.front();
 
+  // Try to identify a matching super-register/tuple for the f64 case and abort
+  // the transformation if there is none.
   Register Tuple = TRI->getMatchingSuperReg(Replacements.front(), AMDGPU::sub0,
                                             TRI->getVGPR64Class());
   if (!Tuple)
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
index 7f94f55237621..fc8e9552bbf18 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
@@ -36,3 +36,28 @@ body: |
     $vgpr0 = V_MOV_B32_e32 killed $vgpr2, implicit $exec, implicit $exec
     SI_RETURN implicit killed $vgpr0
 ...
+
+---
+name: fmac_f32_e32_copy_live_out
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr0, $vgpr2, $vgpr4
+    successors: %bb.1
+
+    ; CHECK-LABEL: name: fmac_f32_e32_copy_live_out
+    ; CHECK: renamable $vgpr2 = nofpexcept V_FMAC_F32_e32 killed $vgpr4, killed $vgpr0, killed $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr0 = V_MOV_B32_e32 $vgpr2, implicit $exec, implicit $exec
+    ; CHECK-NEXT: S_BRANCH %bb.1
+    renamable $vgpr2 = nofpexcept V_FMAC_F32_e32 killed renamable $vgpr4, killed renamable $vgpr0, killed renamable $vgpr2, implicit $mode, implicit $exec
+    $vgpr0 = V_MOV_B32_e32 $vgpr2, implicit $exec, implicit $exec
+    S_BRANCH %bb.1
+
+  bb.1:
+    liveins: $vgpr2
+
+    ; CHECK: bb.1:
+    ; CHECK-NEXT: liveins: $vgpr2
+    ; CHECK: SI_RETURN implicit killed $vgpr2
+    SI_RETURN implicit killed $vgpr2
+...

>From 11d03a7a0dc961c7c0b5fd0a846e2532d12f75ea Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Tue, 7 Jul 2026 07:56:44 -0500
Subject: [PATCH 4/5] Auto-generate test checks

Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
 .../AMDGPU/si-pre-emit-peephole-fmac.mir      | 39 ++++++++++++++-----
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
index fc8e9552bbf18..d3391e2cda4e3 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
@@ -1,4 +1,5 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -run-pass=si-pre-emit-peephole -verify-machineinstrs -o - %s | FileCheck %s
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -run-pass=si-pre-emit-peephole -o - %s | FileCheck %s
 
 ---
 name: fmac_f64_e32_return_copy
@@ -8,7 +9,12 @@ body: |
     liveins: $vgpr0, $vgpr1
 
     ; CHECK-LABEL: name: fmac_f64_e32_return_copy
-    ; CHECK: $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr4_vgpr5, 0, killed $vgpr0_vgpr1, 0, killed $vgpr2_vgpr3, 0, 0, implicit $mode, implicit $exec
+    ; CHECK: liveins: $vgpr0, $vgpr1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: renamable $vgpr2_vgpr3 = nofpexcept V_RSQ_F64_e32 $vgpr0_vgpr1, implicit $mode, implicit $exec
+    ; CHECK-NEXT: renamable $vgpr4_vgpr5 = nofpexcept V_MUL_F64_e64 0, $vgpr2_vgpr3, 0, $vgpr0_vgpr1, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: renamable $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr0_vgpr1, 0, $vgpr2_vgpr3, 0, 4602678819172646912, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr4_vgpr5, 0, killed $vgpr0_vgpr1, 0, killed $vgpr2_vgpr3, 0, 0, implicit $mode, implicit $exec
     ; CHECK-NEXT: SI_RETURN implicit killed $vgpr0, implicit killed $vgpr1
     renamable $vgpr2_vgpr3 = nofpexcept V_RSQ_F64_e32 $vgpr0_vgpr1, implicit $mode, implicit $exec
     renamable $vgpr4_vgpr5 = nofpexcept V_MUL_F64_e64 0, $vgpr2_vgpr3, 0, $vgpr0_vgpr1, 0, 0, implicit $mode, implicit $exec
@@ -27,7 +33,12 @@ body: |
     liveins: $vgpr0
 
     ; CHECK-LABEL: name: fmac_f32_e32_return_copy
-    ; CHECK: $vgpr0 = nofpexcept V_FMA_F32_e64 0, killed $vgpr4, 0, killed $vgpr0, 0, killed $vgpr2, 0, 0, implicit $mode, implicit $exec
+    ; CHECK: liveins: $vgpr0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: renamable $vgpr2 = nofpexcept V_RSQ_F32_e32 $vgpr0, implicit $exec, implicit $mode
+    ; CHECK-NEXT: renamable $vgpr4 = nofpexcept V_MUL_F32_e64 0, $vgpr2, 0, $vgpr0, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: renamable $vgpr0 = nofpexcept V_FMA_F32_e64 0, killed $vgpr0, 0, $vgpr2, 0, 1056964608, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr0 = nofpexcept V_FMA_F32_e64 0, killed $vgpr4, 0, killed $vgpr0, 0, killed $vgpr2, 0, 0, implicit $mode, implicit $exec
     ; CHECK-NEXT: SI_RETURN implicit killed $vgpr0
     renamable $vgpr2 = nofpexcept V_RSQ_F32_e32 $vgpr0, implicit $exec, implicit $mode
     renamable $vgpr4 = nofpexcept V_MUL_F32_e64 0, $vgpr2, 0, $vgpr0, 0, 0, implicit $mode, implicit $exec
@@ -41,14 +52,25 @@ body: |
 name: fmac_f32_e32_copy_live_out
 tracksRegLiveness: true
 body: |
+  ; CHECK-LABEL: name: fmac_f32_e32_copy_live_out
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr2, $vgpr4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   renamable $vgpr2 = nofpexcept V_FMAC_F32_e32 killed $vgpr4, killed $vgpr0, killed $vgpr2, implicit $mode, implicit $exec
+  ; CHECK-NEXT:   $vgpr0 = V_MOV_B32_e32 $vgpr2, implicit $exec, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   liveins: $vgpr2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   SI_RETURN implicit killed $vgpr2
+  ; Negative test to check the peephole doesn't apply if the original
+  ; destination register is live out of the block.
   bb.0:
     liveins: $vgpr0, $vgpr2, $vgpr4
     successors: %bb.1
 
-    ; CHECK-LABEL: name: fmac_f32_e32_copy_live_out
-    ; CHECK: renamable $vgpr2 = nofpexcept V_FMAC_F32_e32 killed $vgpr4, killed $vgpr0, killed $vgpr2, implicit $mode, implicit $exec
-    ; CHECK-NEXT: $vgpr0 = V_MOV_B32_e32 $vgpr2, implicit $exec, implicit $exec
-    ; CHECK-NEXT: S_BRANCH %bb.1
     renamable $vgpr2 = nofpexcept V_FMAC_F32_e32 killed renamable $vgpr4, killed renamable $vgpr0, killed renamable $vgpr2, implicit $mode, implicit $exec
     $vgpr0 = V_MOV_B32_e32 $vgpr2, implicit $exec, implicit $exec
     S_BRANCH %bb.1
@@ -56,8 +78,5 @@ body: |
   bb.1:
     liveins: $vgpr2
 
-    ; CHECK: bb.1:
-    ; CHECK-NEXT: liveins: $vgpr2
-    ; CHECK: SI_RETURN implicit killed $vgpr2
     SI_RETURN implicit killed $vgpr2
 ...

>From afbbf3d1319d3a0cc2ca6d7ab8e2c3c4d6a82fe9 Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Wed, 8 Jul 2026 11:22:02 -0500
Subject: [PATCH 5/5] Extend to more copies and opcodes

Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
 llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp  | 213 ++++++++++++------
 llvm/test/CodeGen/AMDGPU/mad-mix.ll           |   9 +-
 .../AMDGPU/si-pre-emit-peephole-fmac-f16.mir  |  41 ++++
 .../AMDGPU/si-pre-emit-peephole-fmac.mir      |  42 ++++
 4 files changed, 225 insertions(+), 80 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac-f16.mir

diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
index 734ccbad4eb35..ebd5b89e3154f 100644
--- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
@@ -96,19 +96,26 @@ class SIPreEmitPeephole {
                           ArrayRef<MachineInstr *> Copies)
         : TwoAddrMI(&TwoAddrMI), NewDst(NewDst), CopiesToRemove(Copies) {}
   };
-  // Check if \p MaybeCopy is a simple copy of \p Src. If it is a supported
+  // Return true if MI is a candidate for late conversion to a three-address
+  // instruction to avoid copies.
+  bool isLateThreeAddrPeepholeCandidate(const MachineInstr &MI) const;
+  // Check if MaybeCopy is a simple copy of Src. If it is a supported
   // copy, return the destination register of the copy.
-  std::optional<Register> checkCopy(MachineInstr &TwoAddress,
-                                    MachineInstr &MaybeCopy, Register Src);
+  Register checkCopy(MachineInstr &TwoAddress, MachineInstr &MaybeCopy,
+                     Register Src, const TargetRegisterClass *NewDstRC);
   // Check whether the two-address instruction should be replaced with a
   // three-address instruction to avoid copies of the output registers. If the
   // replacement should take place, returns the destination register for the
-  // replacement and fills \p Copies with the copy instructions to remove after
+  // replacement and fills Copies with the copy instructions to remove after
   // the replacement.
   Register
   shouldReplaceWithThreeAddress(MachineInstr &MI,
                                 SmallVectorImpl<MachineInstr *> &Copies);
 
+  // Convert two-adress instruction in Cand to its three-address equivalent,
+  // targeting the register given in Cand.
+  bool convertToThreeAddressInstr(ThreeAddressCandidate &Cand);
+
 public:
   bool run(MachineFunction &MF, MachineLoopInfo *MLI,
            const ReachingDefInfo *RDI);
@@ -795,41 +802,79 @@ MachineInstrBuilder SIPreEmitPeephole::createUnpackedMI(MachineInstr &I,
   return NewMI;
 }
 
-std::optional<Register> SIPreEmitPeephole::checkCopy(MachineInstr &TwoAddress,
-                                                     MachineInstr &MaybeCopy,
-                                                     Register Src) {
-  if (MaybeCopy.isBundle())
-    return std::nullopt;
-
-  switch (MaybeCopy.getOpcode()) {
-  case AMDGPU::COPY:
-  case AMDGPU::V_MOV_B32_e32:
-    break;
+bool SIPreEmitPeephole::isLateThreeAddrPeepholeCandidate(
+    const MachineInstr &MI) const {
+  // This is a subset of the opcodes that are convertible to three-address
+  // instructions according to . This is intended. For some cases,
+  // convertToThreeAddress could early-clobber, which would require us to roll
+  // back the transformation. However, rollback is not side-effect free for some
+  // cases in convertToThreeAddress that fold immediates. Therefore, we limit
+  // this peephole to only the instructions for which rollback will not be
+  // necessary.
+  switch (MI.getOpcode()) {
+  case AMDGPU::V_MAC_F16_e32:
+  case AMDGPU::V_MAC_F16_e64:
+  case AMDGPU::V_MAC_F32_e32:
+  case AMDGPU::V_MAC_F32_e64:
+  case AMDGPU::V_MAC_LEGACY_F32_e32:
+  case AMDGPU::V_MAC_LEGACY_F32_e64:
+  case AMDGPU::V_FMAC_F16_e32:
+  case AMDGPU::V_FMAC_F16_e64:
+  case AMDGPU::V_FMAC_F16_t16_e64:
+  case AMDGPU::V_FMAC_F16_fake16_e64:
+  case AMDGPU::V_FMAC_F32_e32:
+  case AMDGPU::V_FMAC_F32_e64:
+  case AMDGPU::V_FMAC_LEGACY_F32_e32:
+  case AMDGPU::V_FMAC_LEGACY_F32_e64:
+  case AMDGPU::V_FMAC_F64_e32:
+  case AMDGPU::V_FMAC_F64_e64:
+    return true;
   default:
-    return std::nullopt;
+    return false;
   }
+}
+
+Register SIPreEmitPeephole::checkCopy(MachineInstr &TwoAddress,
+                                      MachineInstr &MaybeCopy, Register Src,
+                                      const TargetRegisterClass *NewDstRC) {
+  if (MaybeCopy.isBundle())
+    return Register();
+
+  if (!TII->isFoldableCopy(MaybeCopy) ||
+      MaybeCopy.getOpcode() == AMDGPU::WWM_COPY)
+    return Register();
 
-  MachineOperand CopySrc = MaybeCopy.getOperand(1);
-  if (!CopySrc.isReg() || CopySrc.getReg() != Src)
-    return std::nullopt;
+  if (TII->hasAnyModifiersSet(MaybeCopy))
+    return Register();
+
+  auto CopySrc = MaybeCopy.getOperand(TII->getFoldableCopySrcIdx(MaybeCopy));
+  if (!CopySrc.isReg() || CopySrc.getReg() != Src ||
+      CopySrc.getSubReg() != AMDGPU::NoSubRegister)
+    return Register();
 
   MachineOperand Dst = MaybeCopy.getOperand(0);
-  if (!Dst.isReg())
-    return std::nullopt;
+  if (!Dst.isReg() || Dst.getSubReg() != AMDGPU::NoSubRegister)
+    return Register();
+
+  Register DstReg = Dst.getReg();
+  if (TRI->getPhysRegBaseClass(DstReg) != TRI->getPhysRegBaseClass(Src))
+    return Register();
+
+  if (NewDstRC && !NewDstRC->contains(DstReg.asMCReg()))
+    return Register();
 
-  Register Reg = Dst.getReg();
   // Check that it is safe to define the copy destination register at the
   // current position of the two-address instruction.
   SmallPtrSet<MachineInstr *, 1> Ignore{&TwoAddress, &MaybeCopy};
-  if (!RDI->isSafeToDefRegAt(&TwoAddress, Reg, Ignore))
-    return std::nullopt;
+  if (!RDI->isSafeToDefRegAt(&TwoAddress, DstReg, Ignore))
+    return Register();
 
   // Check that the two-address instruction and the copy have the same exec
   // mask.
   if (!RDI->hasSameReachingDef(&TwoAddress, &MaybeCopy, AMDGPU::EXEC))
-    return std::nullopt;
+    return Register();
 
-  return Reg;
+  return DstReg;
 }
 
 Register SIPreEmitPeephole::shouldReplaceWithThreeAddress(
@@ -838,54 +883,96 @@ Register SIPreEmitPeephole::shouldReplaceWithThreeAddress(
   if (!Dst || !Dst->isReg())
     return Register();
 
-  SmallVector<Register, 2> DestRegs;
-  Register Sub0 = TRI->getSubReg(Dst->getReg(), AMDGPU::sub0);
-  Register Sub1 = TRI->getSubReg(Dst->getReg(), AMDGPU::sub1);
-  if (Sub0 && Sub1) {
-    DestRegs.push_back(Sub0);
-    DestRegs.push_back(Sub1);
-  } else
-    DestRegs.push_back(Dst->getReg());
-
-  SmallVector<Register, 2> Replacements;
-  for (Register SubReg : DestRegs) {
-    if (!SubReg.isPhysical())
+  const TargetRegisterClass *NewDstRC =
+      TII->getRegClass(MI.getDesc(), Dst->getOperandNo());
+
+  auto CheckRegisterCopies =
+      [&](Register Reg, const TargetRegisterClass *ReplacementRC) -> Register {
+    if (!Reg.isPhysical())
       return Register();
-    if (RDI->getLocalLiveOutMIDef(MI.getParent(), SubReg) == &MI)
+    if (RDI->getLocalLiveOutMIDef(MI.getParent(), Reg) == &MI)
       return Register();
 
     SmallPtrSet<MachineInstr *, 1> Uses;
-    RDI->getReachingLocalUses(&MI, SubReg, Uses);
+    RDI->getReachingLocalUses(&MI, Reg, Uses);
     if (Uses.size() != 1)
       return Register();
 
     MachineInstr &Use = **Uses.begin();
-    std::optional<Register> MaybeRegister = checkCopy(MI, Use, SubReg);
+    Register ReplacementReg = checkCopy(MI, Use, Reg, ReplacementRC);
 
-    if (!MaybeRegister)
+    if (!ReplacementReg)
       return Register();
-    Replacements.push_back(*MaybeRegister);
+
     Copies.push_back(&Use);
-  }
+    return ReplacementReg;
+  };
+
+  Register DstReg = Dst->getReg();
+  if (Register Replacement = CheckRegisterCopies(DstReg, NewDstRC))
+    return Replacement;
 
-  if (Replacements.size() > 2)
+  // If we didn't find a copy for the full register, we might be dealing with a
+  // 64-bit register and copies for the individual parts. Check both
+  // subregisters for matching copies.
+  Register Sub0 = TRI->getSubReg(Dst->getReg(), AMDGPU::sub0);
+  Register Sub1 = TRI->getSubReg(Dst->getReg(), AMDGPU::sub1);
+  if (!Sub0 || !Sub1)
     return Register();
 
-  if (Replacements.size() == 1)
-    return Replacements.front();
+  auto Sub0Replacment = CheckRegisterCopies(Sub0, nullptr);
+  auto Sub1Replacement = CheckRegisterCopies(Sub1, nullptr);
+  if (!Sub0Replacment || !Sub1Replacement)
+    return Register();
 
   // Try to identify a matching super-register/tuple for the f64 case and abort
   // the transformation if there is none.
-  Register Tuple = TRI->getMatchingSuperReg(Replacements.front(), AMDGPU::sub0,
-                                            TRI->getVGPR64Class());
+  if (!NewDstRC)
+    return Register();
+  Register Tuple =
+      TRI->getMatchingSuperReg(Sub0Replacment, AMDGPU::sub0, NewDstRC);
   if (!Tuple)
     return Register();
 
-  if (TRI->getSubReg(Tuple, AMDGPU::sub1) != Replacements[1].asMCReg())
+  if (TRI->getSubReg(Tuple, AMDGPU::sub1) != Sub1Replacement.asMCReg())
     return Register();
   return Tuple;
 }
 
+bool SIPreEmitPeephole::convertToThreeAddressInstr(
+    ThreeAddressCandidate &Cand) {
+  MachineInstr *ThreeAddrsInst =
+      TII->convertToThreeAddress(*Cand.TwoAddrMI, nullptr, nullptr);
+  if (!ThreeAddrsInst)
+    return false;
+  MachineOperand &NewDst = ThreeAddrsInst->getOperand(0);
+  assert(NewDst.isReg());
+
+  // The two asserts are defensive for the case that the implementation of
+  // convertToThreeAddress changes in a manner incompatible with this peephole.
+  const TargetRegisterClass *DstRC =
+      TII->getRegClass(ThreeAddrsInst->getDesc(), NewDst.getOperandNo());
+  assert((!DstRC || DstRC->contains(Cand.NewDst.asMCReg())) &&
+         "candidate prechecks should guarantee a legal destination class");
+
+  auto RegistersOverlap = [&](MachineOperand &MO) {
+    if (!MO.isReg())
+      return false;
+    return TRI->regsOverlap(Cand.NewDst, MO.getReg());
+  };
+  assert((!NewDst.isEarlyClobber() ||
+          llvm::none_of(ThreeAddrsInst->uses(), RegistersOverlap)) &&
+         "three-address instruction must not early-clobber the new destination "
+         "register");
+
+  NewDst.setReg(Cand.NewDst);
+  NewDst.setIsRenamable(false);
+  Cand.TwoAddrMI->eraseFromParent();
+  llvm::for_each(Cand.CopiesToRemove,
+                 [](MachineInstr *Copy) { Copy->eraseFromParent(); });
+  return true;
+}
+
 PreservedAnalyses
 llvm::SIPreEmitPeepholePass::run(MachineFunction &MF,
                                  MachineFunctionAnalysisManager &MFAM) {
@@ -948,9 +1035,7 @@ bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo,
       if (MI.isBundle())
         continue;
 
-      unsigned Opc = MI.getOpcode();
-      if (Opc != AMDGPU::V_FMAC_F64_e64 && Opc != AMDGPU::V_FMAC_F32_e64 &&
-          Opc != AMDGPU::V_FMAC_F64_e32 && Opc != AMDGPU::V_FMAC_F32_e32)
+      if (!isLateThreeAddrPeepholeCandidate(MI))
         continue;
 
       SmallVector<MachineInstr *, 2> Copies;
@@ -958,28 +1043,8 @@ bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo,
         Candidates.emplace_back(MI, Dst, Copies);
     }
 
-    for (ThreeAddressCandidate &Cand : Candidates) {
-      MachineInstr *ThreeAddrsInst =
-          TII->convertToThreeAddress(*Cand.TwoAddrMI, nullptr, nullptr);
-      if (!ThreeAddrsInst)
-        continue;
-      MachineOperand &NewDst = ThreeAddrsInst->getOperand(0);
-      assert(NewDst.isReg());
-
-      const TargetRegisterClass *DstRC =
-          TII->getRegClass(ThreeAddrsInst->getDesc(), NewDst.getOperandNo());
-      if (DstRC && !DstRC->contains(Cand.NewDst.asMCReg())) {
-        ThreeAddrsInst->eraseFromParent();
-        continue;
-      }
-
-      NewDst.setReg(Cand.NewDst);
-      NewDst.setIsRenamable(false);
-      Cand.TwoAddrMI->eraseFromParent();
-      llvm::for_each(Cand.CopiesToRemove,
-                     [](MachineInstr *Copy) { Copy->eraseFromParent(); });
-      Changed = true;
-    }
+    for (ThreeAddressCandidate &Cand : Candidates)
+      Changed |= convertToThreeAddressInstr(Cand);
 
     if (!ST.hasVGPRIndexMode())
       continue;
diff --git a/llvm/test/CodeGen/AMDGPU/mad-mix.ll b/llvm/test/CodeGen/AMDGPU/mad-mix.ll
index ee5de5fb697a8..e5dc34c6bda81 100644
--- a/llvm/test/CodeGen/AMDGPU/mad-mix.ll
+++ b/llvm/test/CodeGen/AMDGPU/mad-mix.ll
@@ -353,8 +353,7 @@ define <2 x float> @v_mad_mix_v2f32_shuffle(<2 x half> %src0, <2 x half> %src1,
 ; GFX9GEN-NEXT:    v_cvt_f32_f16_sdwa v2, v2 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
 ; GFX9GEN-NEXT:    v_cvt_f32_f16_sdwa v1, v1 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
 ; GFX9GEN-NEXT:    v_mad_f32 v0, v3, v0, v2
-; GFX9GEN-NEXT:    v_mac_f32_e32 v2, v4, v1
-; GFX9GEN-NEXT:    v_mov_b32_e32 v1, v2
+; GFX9GEN-NEXT:    v_mad_f32 v1, v4, v1, v2
 ; GFX9GEN-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; VI-LABEL: v_mad_mix_v2f32_shuffle:
@@ -366,8 +365,7 @@ define <2 x float> @v_mad_mix_v2f32_shuffle(<2 x half> %src0, <2 x half> %src1,
 ; VI-NEXT:    v_cvt_f32_f16_sdwa v2, v2 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
 ; VI-NEXT:    v_cvt_f32_f16_sdwa v1, v1 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
 ; VI-NEXT:    v_mad_f32 v0, v3, v0, v2
-; VI-NEXT:    v_mac_f32_e32 v2, v4, v1
-; VI-NEXT:    v_mov_b32_e32 v1, v2
+; VI-NEXT:    v_mad_f32 v1, v4, v1, v2
 ; VI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; SDAG-CI-LABEL: v_mad_mix_v2f32_shuffle:
@@ -532,8 +530,7 @@ define float @v_mad_mix_f32_absf16lo_f16lo_f16lo(half %src0, half %src1, half %s
 ; SDAG-CI-NEXT:    v_cvt_f32_f16_e32 v3, v1
 ; SDAG-CI-NEXT:    v_cvt_f32_f16_e32 v1, v2
 ; SDAG-CI-NEXT:    v_cvt_f32_f16_e64 v0, |v0|
-; SDAG-CI-NEXT:    v_mac_f32_e32 v1, v0, v3
-; SDAG-CI-NEXT:    v_mov_b32_e32 v0, v1
+; SDAG-CI-NEXT:    v_mad_f32 v0, v0, v3, v1
 ; SDAG-CI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GISEL-CI-LABEL: v_mad_mix_f32_absf16lo_f16lo_f16lo:
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac-f16.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac-f16.mir
new file mode 100644
index 0000000000000..6d49eefb14c32
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac-f16.mir
@@ -0,0 +1,41 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 -run-pass=si-pre-emit-peephole -o - %s | FileCheck %s
+
+---
+name: fmac_f16_t16_e64_return_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr1_lo16, $vgpr2_lo16, $vgpr4_lo16
+
+    ; CHECK-LABEL: name: fmac_f16_t16_e64_return_copy
+    ; CHECK: liveins: $vgpr1_lo16, $vgpr2_lo16, $vgpr4_lo16
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $vgpr0_lo16 = V_MOV_B16_t16_e64 0, $vgpr1_lo16, 0, implicit $exec
+    ; CHECK-NEXT: $vgpr0_lo16 = nofpexcept V_FMA_F16_gfx9_t16_e64 0, $vgpr4_lo16, 0, $vgpr1_lo16, 0, killed $vgpr2_lo16, 0, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0, implicit killed $vgpr0_lo16
+    $vgpr0_lo16 = V_MOV_B16_t16_e64 0, $vgpr1_lo16, 0, implicit $exec
+    $vgpr2_lo16 = nofpexcept V_FMAC_F16_t16_e64 0, $vgpr4_lo16, 0, $vgpr1_lo16, 0, killed $vgpr2_lo16, 0, 0, 0, implicit $mode, implicit $exec
+    $vgpr0_lo16 = V_MOV_B16_t16_e64 0, killed $vgpr2_lo16, 0, implicit $exec
+    S_ENDPGM 0, implicit killed $vgpr0_lo16
+...
+
+---
+name: fmac_f16_t16_e64_return_copy_with_modifier
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr1_lo16, $vgpr2_lo16, $vgpr4_lo16
+
+    ; CHECK-LABEL: name: fmac_f16_t16_e64_return_copy_with_modifier
+    ; CHECK: liveins: $vgpr1_lo16, $vgpr2_lo16, $vgpr4_lo16
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $vgpr0_lo16 = V_MOV_B16_t16_e64 0, $vgpr1_lo16, 0, implicit $exec
+    ; CHECK-NEXT: $vgpr2_lo16 = nofpexcept V_FMAC_F16_t16_e64 0, $vgpr4_lo16, 0, $vgpr1_lo16, 0, killed $vgpr2_lo16, 0, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr0_lo16 = V_MOV_B16_t16_e64 1, killed $vgpr2_lo16, 0, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0, implicit killed $vgpr0_lo16
+    $vgpr0_lo16 = V_MOV_B16_t16_e64 0, $vgpr1_lo16, 0, implicit $exec
+    $vgpr2_lo16 = nofpexcept V_FMAC_F16_t16_e64 0, $vgpr4_lo16, 0, $vgpr1_lo16, 0, killed $vgpr2_lo16, 0, 0, 0, implicit $mode, implicit $exec
+    $vgpr0_lo16 = V_MOV_B16_t16_e64 1, killed $vgpr2_lo16, 0, implicit $exec
+    S_ENDPGM 0, implicit killed $vgpr0_lo16
+...
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
index d3391e2cda4e3..d900d3f1fa8e1 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-fmac.mir
@@ -25,6 +25,29 @@ body: |
     SI_RETURN implicit killed $vgpr0, implicit killed $vgpr1
 ...
 
+---
+name: fmac_f64_e32_return_full_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr0, $vgpr1
+
+    ; CHECK-LABEL: name: fmac_f64_e32_return_full_copy
+    ; CHECK: liveins: $vgpr0, $vgpr1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: renamable $vgpr2_vgpr3 = nofpexcept V_RSQ_F64_e32 $vgpr0_vgpr1, implicit $mode, implicit $exec
+    ; CHECK-NEXT: renamable $vgpr4_vgpr5 = nofpexcept V_MUL_F64_e64 0, $vgpr2_vgpr3, 0, $vgpr0_vgpr1, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: renamable $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr0_vgpr1, 0, $vgpr2_vgpr3, 0, 4602678819172646912, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr4_vgpr5, 0, killed $vgpr0_vgpr1, 0, killed $vgpr2_vgpr3, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: SI_RETURN implicit killed $vgpr0, implicit killed $vgpr1
+    renamable $vgpr2_vgpr3 = nofpexcept V_RSQ_F64_e32 $vgpr0_vgpr1, implicit $mode, implicit $exec
+    renamable $vgpr4_vgpr5 = nofpexcept V_MUL_F64_e64 0, $vgpr2_vgpr3, 0, $vgpr0_vgpr1, 0, 0, implicit $mode, implicit $exec
+    renamable $vgpr0_vgpr1 = nofpexcept V_FMA_F64_e64 0, killed $vgpr0_vgpr1, 0, $vgpr2_vgpr3, 0, 4602678819172646912, 0, 0, implicit $mode, implicit $exec
+    renamable $vgpr2_vgpr3 = nofpexcept V_FMAC_F64_e32 killed renamable $vgpr4_vgpr5, killed renamable $vgpr0_vgpr1, killed renamable $vgpr2_vgpr3, implicit $mode, implicit $exec
+    $vgpr0_vgpr1 = V_MOV_B64_e32 killed $vgpr2_vgpr3, implicit $exec, implicit $exec
+    SI_RETURN implicit killed $vgpr0, implicit killed $vgpr1
+...
+
 ---
 name: fmac_f32_e32_return_copy
 tracksRegLiveness: true
@@ -48,6 +71,25 @@ body: |
     SI_RETURN implicit killed $vgpr0
 ...
 
+---
+name: mac_f32_e32_return_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr0, $vgpr2, $vgpr4
+
+    ; CHECK-LABEL: name: mac_f32_e32_return_copy
+    ; CHECK: liveins: $vgpr0, $vgpr2, $vgpr4
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $vgpr1 = V_MOV_B32_e32 $vgpr0, implicit $exec
+    ; CHECK-NEXT: $vgpr1 = nofpexcept V_MAD_F32_e64 0, killed $vgpr4, 0, killed $vgpr0, 0, killed $vgpr2, 0, 0, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0, implicit killed $vgpr1
+    $vgpr1 = V_MOV_B32_e32 $vgpr0, implicit $exec
+    $vgpr2 = nofpexcept V_MAC_F32_e32 killed $vgpr4, killed $vgpr0, killed $vgpr2, implicit $mode, implicit $exec
+    $vgpr1 = V_MOV_B32_e32 killed $vgpr2, implicit $exec
+    S_ENDPGM 0, implicit killed $vgpr1
+...
+
 ---
 name: fmac_f32_e32_copy_live_out
 tracksRegLiveness: true



More information about the llvm-commits mailing list