[llvm] [AMDGPU] Preserve physical WWM_COPY destinations (PR #227279)

Yaxun Liu via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 04:23:26 PDT 2026


https://github.com/yxsamliu created https://github.com/llvm/llvm-project/pull/227279

`WWM_COPY` writes all lanes of its destination. Callable functions must preserve the caller's inactive lanes, but the lowering currently skips destinations that are already physical registers. Handle those destinations directly, keep the `VirtRegMap` lookup for virtual registers, and use the register class for spill size and alignment.

When WWM VGPRs are compacted, update their spill entries by rebuilding the map once, preserving its order.

Split register preservation out of #223278, leaving the AGPR ownership fix there.


>From 49b93dbf7040140bc9bb3fc1b6ad9b1b6ee87c15 Mon Sep 17 00:00:00 2001
From: "Yaxun (Sam) Liu" <yaxun.liu at amd.com>
Date: Tue, 29 Sep 2026 00:16:35 -0400
Subject: [PATCH] [AMDGPU] Preserve physical WWM_COPY destinations

Fast register allocation rewrites WWM_COPY operands before their lowering.
Skipping physical destinations therefore misses the spill slots needed to
preserve inactive lanes across a callable function.

Resolve virtual destinations through VirtRegMap, and handle physical
registers directly. Allocate the spill slot using the register class size
and alignment. If PEI later compacts a reserved VGPR, remap its existing
spill entry once after compaction while retaining spill/restore order.

Add coverage for fast allocation without VirtRegMap, physical scalar and
tuple destinations, and several simultaneous spill-slot renames.
---
 llvm/lib/Target/AMDGPU/SILowerWWMCopies.cpp   |  20 +-
 .../Target/AMDGPU/SIMachineFunctionInfo.cpp   |  19 ++
 .../CodeGen/AMDGPU/wwm-copy-fast-regalloc.mir |  49 +++++
 .../CodeGen/AMDGPU/wwm-physical-copy-pei.mir  | 176 ++++++++++++++++++
 4 files changed, 255 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/wwm-copy-fast-regalloc.mir
 create mode 100644 llvm/test/CodeGen/AMDGPU/wwm-physical-copy-pei.mir

diff --git a/llvm/lib/Target/AMDGPU/SILowerWWMCopies.cpp b/llvm/lib/Target/AMDGPU/SILowerWWMCopies.cpp
index ac8f5b990c5fa..ee3e748b8b36a 100644
--- a/llvm/lib/Target/AMDGPU/SILowerWWMCopies.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerWWMCopies.cpp
@@ -92,17 +92,19 @@ bool SILowerWWMCopies::isSCCLiveAtMI(const MachineInstr &MI) {
   return LR.liveAt(Idx);
 }
 
-// If \p Reg is assigned with a physical VGPR, add the latter into wwm-spills
-// for preserving its entire lanes at function prolog/epilog.
+// Preserve the inactive lanes of a WWM copy destination at function entry/exit.
+// Fast register allocation has already rewritten virtual registers here.
 void SILowerWWMCopies::addToWWMSpills(MachineFunction &MF, Register Reg) {
-  if (Reg.isPhysical())
-    return;
-
-  // FIXME: VRM may be null here.
-  MCRegister PhysReg = VRM->getPhys(Reg);
-  assert(PhysReg && "should have allocated a physical register");
+  Register PhysReg = Reg;
+  if (Reg.isVirtual()) {
+    assert(VRM && "expected VirtRegMap after WWM register allocation");
+    PhysReg = VRM->getPhys(Reg);
+    assert(PhysReg && "should have allocated a physical register");
+  }
 
-  MFI->allocateWWMSpill(MF, PhysReg);
+  const TargetRegisterClass *RC = TRI->getPhysRegBaseClass(PhysReg);
+  MFI->allocateWWMSpill(MF, PhysReg, TRI->getSpillSize(*RC),
+                        TRI->getSpillAlign(*RC));
 }
 
 bool SILowerWWMCopiesLegacy::runOnMachineFunction(MachineFunction &MF) {
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index d1df50d26a832..bc7c733d96b6f 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -348,6 +348,7 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
     BitVector &SavedVGPRs) {
   const SIRegisterInfo *TRI = MF.getSubtarget<GCNSubtarget>().getRegisterInfo();
   MachineRegisterInfo &MRI = MF.getRegInfo();
+  DenseMap<Register, Register> RenamedSpills;
   for (unsigned I = 0, E = WWMVGPRs.size(); I < E; ++I) {
     Register Reg = WWMVGPRs[I];
     Register NewReg =
@@ -361,6 +362,13 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
     WWMVGPRs[I] = NewReg;
     WWMReservedRegs.remove(Reg);
     WWMReservedRegs.insert(NewReg);
+
+    if (WWMSpills.contains(Reg)) {
+      assert(!WWMSpills.contains(NewReg) &&
+             "replacement WWM register already has a spill slot");
+      RenamedSpills.insert({Reg, NewReg});
+    }
+
     MRI.reserveReg(NewReg, TRI);
 
     // Replace the register in SpillPhysVGPRs. This is needed to look for free
@@ -385,6 +393,17 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
 
     Reg = NewReg;
   }
+
+  // Remap spill slots once after compaction, preserving spill/restore order.
+  if (!RenamedSpills.empty()) {
+    SmallVector<std::pair<Register, int>, 0> Spills = WWMSpills.takeVector();
+    for (std::pair<Register, int> Entry : Spills) {
+      auto It = RenamedSpills.find(Entry.first);
+      if (It != RenamedSpills.end())
+        Entry.first = It->second;
+      WWMSpills.insert(Entry);
+    }
+  }
 }
 
 bool SIMachineFunctionInfo::allocateVirtualVGPRForSGPRSpills(
diff --git a/llvm/test/CodeGen/AMDGPU/wwm-copy-fast-regalloc.mir b/llvm/test/CodeGen/AMDGPU/wwm-copy-fast-regalloc.mir
new file mode 100644
index 0000000000000..d06a702b89183
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/wwm-copy-fast-regalloc.mir
@@ -0,0 +1,49 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -O0 -start-before=si-lower-sgpr-spills -stop-after=si-lower-wwm-copies -verify-machineinstrs -o %t %s
+# RUN: FileCheck %s < %t
+# RUN: FileCheck %s --check-prefix=SPILLS < %t
+
+# Fast allocation rewrites WWM_COPY operands before lowering, when VirtRegMap
+# is no longer available.
+
+# SPILLS-LABEL: name: fast_wwm_copy
+# SPILLS: stack:
+# SPILLS-NEXT: - { id: 0, name: '', type: spill-slot, offset: 0, size: 4, alignment: 4,
+# SPILLS: - { id: 1, name: '', type: spill-slot, offset: 0, size: 4, alignment: 4,
+
+---
+name: fast_wwm_copy
+tracksRegLiveness: true
+isSSA: false
+registers:
+  - { id: 0, class: vgpr_32, flags: [ WWM_REG ] }
+  - { id: 1, class: vgpr_32, flags: [ WWM_REG ] }
+frameInfo:
+  maxAlignment: 4
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+  stackPtrOffsetReg: '$sgpr32'
+  frameOffsetReg: '$sgpr33'
+  sgprForEXECCopy: '$sgpr4_sgpr5'
+body: |
+  bb.0:
+    liveins: $vgpr63, $vgpr62, $sgpr30_sgpr31
+    ; CHECK-LABEL: name: fast_wwm_copy
+    ; CHECK: liveins: $vgpr63, $vgpr62, $sgpr30_sgpr31
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $sgpr4_sgpr5 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: renamable $vgpr0 = COPY killed $vgpr63
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr4_sgpr5
+    ; CHECK-NEXT: $sgpr4_sgpr5 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: renamable $vgpr1 = COPY killed $vgpr62
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr4_sgpr5
+    ; CHECK-NEXT: S_NOP 0, implicit killed renamable $vgpr0, implicit killed renamable $vgpr1
+    ; CHECK-NEXT: S_SETPC_B64_return killed $sgpr30_sgpr31
+    %0 = WWM_COPY $vgpr63
+    %1 = WWM_COPY $vgpr62
+    S_NOP 0, implicit %0, implicit %1
+    S_SETPC_B64_return $sgpr30_sgpr31
+...
diff --git a/llvm/test/CodeGen/AMDGPU/wwm-physical-copy-pei.mir b/llvm/test/CodeGen/AMDGPU/wwm-physical-copy-pei.mir
new file mode 100644
index 0000000000000..3058e7c66ac46
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/wwm-physical-copy-pei.mir
@@ -0,0 +1,176 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -O0 -run-pass=regallocfast,si-lower-wwm-copies,prolog-epilog -verify-machineinstrs -o - %s | FileCheck %s
+
+# Physical WWM copies arise after register rewriting, including fast allocation.
+# Preserve inactive lanes even for an unreserved scratch VGPR. The second
+# function models existing scalar-spill reservations and checks that compaction
+# remaps several existing spill slots without disturbing an unmoved entry.
+
+---
+name: physical_wwm_copy
+tracksRegLiveness: true
+noVRegs: false
+isSSA: false
+registers:
+  # Keep VRegFlags non-empty so si-lower-wwm-copies processes the physical
+  # WWM_COPY instructions below, as it does after WWM register allocation.
+  - { id: 0, class: vgpr_32, flags: [ WWM_REG ] }
+frameInfo:
+  maxAlignment: 4
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+  stackPtrOffsetReg: '$sgpr32'
+  frameOffsetReg: '$sgpr33'
+  sgprForEXECCopy: '$sgpr4_sgpr5'
+body: |
+  bb.0:
+    liveins: $vgpr63, $sgpr30_sgpr31
+    ; CHECK-LABEL: name: physical_wwm_copy
+    ; CHECK: liveins: $vgpr63, $sgpr30_sgpr31, $vgpr0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr0
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $sgpr6
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET $vgpr0, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.0, addrspace 5)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $vgpr0, 0
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: $vgpr0 = COPY killed $vgpr63
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: S_NOP 0, implicit killed $vgpr0
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    ; CHECK-NEXT: $vgpr0 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.0, addrspace 5)
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: S_SETPC_B64_return killed $sgpr30_sgpr31
+    $vgpr0 = WWM_COPY $vgpr63
+    S_NOP 0, implicit $vgpr0
+    S_SETPC_B64_return $sgpr30_sgpr31
+...
+
+---
+name: compact_wwm_spills
+tracksRegLiveness: true
+noVRegs: false
+isSSA: false
+registers:
+  # Keep VRegFlags non-empty so si-lower-wwm-copies processes the physical
+  # WWM_COPY instructions below, as it does after WWM register allocation.
+  - { id: 0, class: vgpr_32, flags: [ WWM_REG ] }
+frameInfo:
+  maxAlignment: 4
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+  stackPtrOffsetReg: '$sgpr32'
+  frameOffsetReg: '$sgpr33'
+  sgprForEXECCopy: '$sgpr4_sgpr5'
+  wwmReservedRegs: [ '$vgpr0', '$vgpr60', '$vgpr61', '$vgpr62' ]
+body: |
+  bb.0:
+    liveins: $vgpr63, $sgpr30_sgpr31
+    ; CHECK-LABEL: name: compact_wwm_spills
+    ; CHECK: liveins: $vgpr63, $sgpr30_sgpr31
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr0
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr1
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr2
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr3
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $sgpr6
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET killed $vgpr0, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.0, addrspace 5)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $vgpr0, 0
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET killed $vgpr2, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 4, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.1, addrspace 5)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $vgpr2, 256
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET killed $vgpr1, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 8, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.2, addrspace 5)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $vgpr1, 512
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET killed $vgpr3, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 12, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.3, addrspace 5)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $vgpr3, 768
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: $vgpr0 = COPY $vgpr63
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: $vgpr2 = COPY killed $vgpr63
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: $vgpr1 = COPY $vgpr2
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: $vgpr3 = COPY $vgpr1
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: S_NOP 0, implicit $vgpr0, implicit $vgpr2, implicit $vgpr1, implicit $vgpr3
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    ; CHECK-NEXT: $vgpr0 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.0, addrspace 5)
+    ; CHECK-NEXT: $vgpr2 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 4, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.1, addrspace 5)
+    ; CHECK-NEXT: $vgpr1 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 8, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.2, addrspace 5)
+    ; CHECK-NEXT: $vgpr3 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 12, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.3, addrspace 5)
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: S_SETPC_B64_return killed $sgpr30_sgpr31
+    $vgpr0 = WWM_COPY $vgpr63
+    $vgpr61 = WWM_COPY $vgpr63
+    $vgpr62 = WWM_COPY $vgpr61
+    $vgpr60 = WWM_COPY $vgpr62
+    S_NOP 0, implicit $vgpr0, implicit $vgpr61, implicit $vgpr62, implicit $vgpr60
+    S_SETPC_B64_return $sgpr30_sgpr31
+...
+
+---
+name: physical_wwm_tuple_copy
+tracksRegLiveness: true
+noVRegs: false
+isSSA: false
+registers:
+  # Keep VRegFlags non-empty so si-lower-wwm-copies processes the physical
+  # WWM_COPY instructions below, as it does after WWM register allocation.
+  - { id: 0, class: vgpr_32, flags: [ WWM_REG ] }
+frameInfo:
+  maxAlignment: 4
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+  stackPtrOffsetReg: '$sgpr32'
+  frameOffsetReg: '$sgpr33'
+  sgprForEXECCopy: '$sgpr4_sgpr5'
+body: |
+  bb.0:
+    liveins: $vgpr62_vgpr63, $sgpr30_sgpr31
+    ; CHECK-LABEL: name: physical_wwm_tuple_copy
+    ; CHECK: liveins: $vgpr62_vgpr63, $sgpr30_sgpr31, $vgpr0_vgpr1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr0
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $vgpr1
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $sgpr6
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION undefined $sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET $vgpr0, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec, implicit-def $vgpr0_vgpr1, implicit $vgpr0_vgpr1 :: ("amdgpu-thread-private" store (s32) into %stack.0, addrspace 5)
+    ; CHECK-NEXT: BUFFER_STORE_DWORD_OFFSET $vgpr1, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 4, 0, 0, implicit $exec, implicit $vgpr0_vgpr1 :: ("amdgpu-thread-private" store (s32) into %stack.0 + 4, addrspace 5)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset <badreg>, 0
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_MOV_B64 killed $exec
+    ; CHECK-NEXT: $exec = S_MOV_B64 -1
+    ; CHECK-NEXT: $vgpr0_vgpr1 = COPY killed $vgpr62_vgpr63
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: S_NOP 0, implicit killed $vgpr0_vgpr1
+    ; CHECK-NEXT: $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+    ; CHECK-NEXT: $vgpr0 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec, implicit-def $vgpr0_vgpr1 :: ("amdgpu-thread-private" load (s32) from %stack.0, addrspace 5)
+    ; CHECK-NEXT: $vgpr1 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 4, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.0 + 4, addrspace 5)
+    ; CHECK-NEXT: $exec = S_MOV_B64 killed $sgpr6_sgpr7
+    ; CHECK-NEXT: S_SETPC_B64_return killed $sgpr30_sgpr31
+    $vgpr0_vgpr1 = WWM_COPY $vgpr62_vgpr63
+    S_NOP 0, implicit $vgpr0_vgpr1
+    S_SETPC_B64_return $sgpr30_sgpr31
+...



More information about the llvm-commits mailing list