[llvm] [AMDGPU] Do not forward reserved aperture registers into wider copies (PR #220517)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 06:04:41 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/220517

>From 26cdf4980548bc8ad3f5a3c270730f6bfbc0392f Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 2 Sep 2026 10:41:17 +0200
Subject: [PATCH] [AMDGPU] Do not forward reserved aperture registers into
 wider copies

src_shared_base/src_private_base have no addressable high half, so MachineCopyPropagation must not forward them into a copy that later splits into subregisters

SIInstrInfo::copyPhysReg now reports an error instead of asserting if asked to do so anyway
---
 llvm/lib/CodeGen/MachineCopyPropagation.cpp   | 22 +++++++++++++
 llvm/lib/Target/AMDGPU/SIInstrInfo.cpp        |  9 ++++++
 .../AMDGPU/illegal-aperture-reg-copy.mir      | 14 ++++++++
 .../CodeGen/AMDGPU/machine-cp-aperture-reg.ll | 15 +++++++++
 .../CodeGen/AMDGPU/machine-cp-propagation.mir | 32 +++++++++++++++++++
 5 files changed, 92 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/illegal-aperture-reg-copy.mir
 create mode 100644 llvm/test/CodeGen/AMDGPU/machine-cp-aperture-reg.ll

diff --git a/llvm/lib/CodeGen/MachineCopyPropagation.cpp b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
index 0568890583c1d..2d165e7c59a47 100644
--- a/llvm/lib/CodeGen/MachineCopyPropagation.cpp
+++ b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
@@ -821,6 +821,20 @@ bool MachineCopyPropagation::canUpdateSrcUsers(const MachineInstr &Copy,
   return true;
 }
 
+/// Return true if \p NewReg has a non-artificial subregister for every
+/// subregister index where \p OldReg has one.
+static bool hasMatchingSubRegs(MCRegister OldReg, MCRegister NewReg,
+                               const TargetRegisterInfo *TRI) {
+  for (MCSubRegIndexIterator SRI(OldReg, TRI); SRI.isValid(); ++SRI) {
+    if (TRI->isArtificial(SRI.getSubReg()))
+      continue;
+    MCRegister Sub = TRI->getSubReg(NewReg, SRI.getSubRegIndex());
+    if (!Sub || TRI->isArtificial(Sub))
+      return false;
+  }
+  return true;
+}
+
 /// Look for available copies whose destination register is used by \p MI and
 /// replace the use in \p MI with the copy's source register.
 void MachineCopyPropagation::forwardUses(MachineInstr &MI) {
@@ -879,6 +893,14 @@ void MachineCopyPropagation::forwardUses(MachineInstr &MI) {
     if (MRI->isReserved(CopySrc) && !MRI->isConstantPhysReg(CopySrc))
       continue;
 
+    // A reserved source may lack subregs the copy is later split into.
+    if (MRI->isReserved(CopySrc) && isCopyInstr(MI, *TII, UseCopyInstr) &&
+        !hasMatchingSubRegs(MOUse.getReg().asMCReg(), ForwardedReg, TRI)) {
+      LLVM_DEBUG(dbgs() << "MCP: Copy source is missing subregisters of "
+                        << printReg(MOUse.getReg(), TRI) << '\n');
+      continue;
+    }
+
     if (!isForwardableRegClassCopy(*Copy, MI, OpIdx))
       continue;
 
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 3094c1390e9cf..db3fdf0ea8147 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -1189,6 +1189,15 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
 
   ArrayRef<int16_t> SubIndices = RI.getRegSplitParts(RC, EltSize);
 
+  // Report rather than assert if a register is missing a required subreg.
+  for (int16_t SubIdx : SubIndices) {
+    if (!RI.getSubReg(DestReg, SubIdx) || !RI.getSubReg(SrcReg, SubIdx)) {
+      reportIllegalCopy(this, MBB, MI, DL, DestReg, SrcReg, KillSrc,
+                        "Cannot decompose copy into subregister moves!");
+      return;
+    }
+  }
+
   // If there is an overlap, we can't kill the super-register on the last
   // instruction, since it will also kill the components made live by this def.
   const bool Overlap = RI.regsOverlap(SrcReg, DestReg);
diff --git a/llvm/test/CodeGen/AMDGPU/illegal-aperture-reg-copy.mir b/llvm/test/CodeGen/AMDGPU/illegal-aperture-reg-copy.mir
new file mode 100644
index 0000000000000..e3c5ac9abbe7f
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/illegal-aperture-reg-copy.mir
@@ -0,0 +1,14 @@
+# RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 -run-pass=postrapseudos -o /dev/null %s 2>&1 | FileCheck %s
+
+# src_shared_base has no addressable high half. copyPhysReg must not assert.
+
+# CHECK: error: {{.*}} in function illegal_aperture_reg_copy void (): Cannot decompose copy into subregister moves!
+
+---
+name: illegal_aperture_reg_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    renamable $vgpr0_vgpr1 = COPY $src_shared_base
+    S_ENDPGM 0, implicit $vgpr0_vgpr1
+...
diff --git a/llvm/test/CodeGen/AMDGPU/machine-cp-aperture-reg.ll b/llvm/test/CodeGen/AMDGPU/machine-cp-aperture-reg.ll
new file mode 100644
index 0000000000000..9e44e9e72973b
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/machine-cp-aperture-reg.ll
@@ -0,0 +1,15 @@
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 -global-isel < %s | FileCheck %s
+
+; src_shared_base has no addressable high half. Must not forward into VGPRs.
+
+ at lds = internal addrspace(3) global [32 x float] poison, align 4
+
+; CHECK-LABEL: aperture_copy_to_vgpr_pair:
+; CHECK: s_mov_b64 s[{{[0-9]+}}:{{[0-9]+}}], src_shared_base
+define float @aperture_copy_to_vgpr_pair(i32 %i) {
+  %idx = zext i32 %i to i64
+  %gep = getelementptr float, ptr addrspacecast (ptr addrspace(3) @lds to ptr), i64 %idx
+  %cast = addrspacecast ptr %gep to ptr addrspace(3)
+  %v = load float, ptr addrspace(3) %cast, align 4
+  ret float %v
+}
diff --git a/llvm/test/CodeGen/AMDGPU/machine-cp-propagation.mir b/llvm/test/CodeGen/AMDGPU/machine-cp-propagation.mir
index f8630245b6938..8cbd8cac4c588 100644
--- a/llvm/test/CodeGen/AMDGPU/machine-cp-propagation.mir
+++ b/llvm/test/CodeGen/AMDGPU/machine-cp-propagation.mir
@@ -34,3 +34,35 @@ body:             |
   S_ENDPGM 0
 ...
 
+
+# src_shared_base has no addressable high half. machine-cp must not forward it.
+
+---
+name: no_forward_aperture_into_vgpr_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: no_forward_aperture_into_vgpr_copy
+    ; CHECK: renamable $sgpr0_sgpr1 = COPY $src_shared_base
+    ; CHECK-NEXT: renamable $vgpr0_vgpr1 = COPY killed renamable $sgpr0_sgpr1
+    ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0_vgpr1
+    renamable $sgpr0_sgpr1 = COPY $src_shared_base
+    renamable $vgpr0_vgpr1 = COPY killed renamable $sgpr0_sgpr1
+    S_ENDPGM 0, implicit $vgpr0_vgpr1
+...
+
+---
+name: forward_sgpr_into_vgpr_copy
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $sgpr4_sgpr5
+    ; CHECK-LABEL: name: forward_sgpr_into_vgpr_copy
+    ; CHECK: liveins: $sgpr4_sgpr5
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: renamable $vgpr0_vgpr1 = COPY $sgpr4_sgpr5
+    ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0_vgpr1
+    renamable $sgpr0_sgpr1 = COPY $sgpr4_sgpr5
+    renamable $vgpr0_vgpr1 = COPY killed renamable $sgpr0_sgpr1
+    S_ENDPGM 0, implicit $vgpr0_vgpr1
+...



More information about the llvm-commits mailing list