[llvm] [AMDGPU] Set SGPR spill stack IDs when creating spill slots (PR #197628)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 05:13:21 PDT 2026


https://github.com/woruyu updated https://github.com/llvm/llvm-project/pull/197628

>From aa310a5524e11c978de5cabec5b707d729730679 Mon Sep 17 00:00:00 2001
From: woruyu <1214539920 at qq.com>
Date: Mon, 8 Jun 2026 20:13:01 +0800
Subject: [PATCH] fix: all

---
 llvm/include/llvm/CodeGen/MachineFrameInfo.h  |   4 +-
 .../include/llvm/CodeGen/TargetRegisterInfo.h |   8 +
 llvm/include/llvm/Target/Target.td            |   3 +
 llvm/lib/CodeGen/MachineFrameInfo.cpp         |   5 +-
 llvm/lib/CodeGen/PrologEpilogInserter.cpp     |   3 +-
 llvm/lib/CodeGen/RegAllocFast.cpp             |   3 +-
 llvm/lib/CodeGen/VirtRegMap.cpp               |   3 +-
 llvm/lib/Target/AMDGPU/SIInstrInfo.cpp        |  10 +-
 llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp  |   8 +-
 llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp     |   8 +-
 llvm/lib/Target/AMDGPU/SIRegisterInfo.td      |   1 +
 .../AMDGPU/sgpr-scavenge-fi-stack-id.ll       | 294 ++++++++++++++++++
 .../TableGen/RegisterInfoEmitter-errors.td    |  10 +-
 llvm/unittests/CodeGen/MachineInstrTest.cpp   |   2 +-
 .../TableGen/Common/CodeGenRegisters.cpp      |   7 +-
 llvm/utils/TableGen/Common/CodeGenRegisters.h |   1 +
 llvm/utils/TableGen/RegisterInfoEmitter.cpp   |   1 +
 17 files changed, 351 insertions(+), 20 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll

diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 22729e736fbd3..9cafbf5a1ce6c 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -833,7 +833,9 @@ class MachineFrameInfo {
 
   /// Create a new statically sized stack object that represents a spill slot,
   /// returning a nonnegative identifier to represent it.
-  LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment);
+  LLVM_ABI int
+  CreateSpillStackObject(uint64_t Size, Align Alignment,
+                         TargetStackID::Value StackID = TargetStackID::Default);
 
   /// Remove or mark dead a statically sized stack object.
   void RemoveStackObject(int ObjectIdx) {
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 7c3c56552b82c..8ae24ff84401e 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -21,6 +21,7 @@
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/RegisterBank.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/MC/LaneBitmask.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -61,6 +62,7 @@ class TargetRegisterClass {
 
   /// Configurable target specific flags.
   const uint8_t TSFlags;
+  const uint8_t SpillStackID;
   /// Whether the class supports two (or more) disjunct subregister indices.
   const bool HasDisjunctSubRegs;
   /// Whether a combination of subregisters can cover every register in the
@@ -319,6 +321,12 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
     return Align(getRegClassInfo(RC).SpillAlignment / 8);
   }
 
+  /// Return the stack ID for spill slots holding a spilled copy of a register
+  /// from this class.
+  TargetStackID::Value getSpillStackID(const TargetRegisterClass &RC) const {
+    return static_cast<TargetStackID::Value>(RC.SpillStackID);
+  }
+
   /// Return true if the given TargetRegisterClass has the ValueType T.
   bool isTypeLegalForClass(const TargetRegisterClass &RC, MVT T) const {
     for (auto I = legalclasstypes_begin(RC); *I != MVT::Other; ++I)
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 4e973ece07e8e..a02a4209f86fe 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -398,6 +398,9 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
   // classes will be resolved in the order defined by this value, with lower values
   // taking precedence over higher ones. Ties are resolved by enumeration order.
   int BaseClassOrder = ?;
+
+  // Stack ID to use for spill slots of this register class.
+  int SpillStackID = 0;
 }
 
 // The memberList in a RegisterClass is a dag of set operations. TableGen
diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp
index aed68afb4eb1b..515c95006af00 100644
--- a/llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ b/llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -63,9 +63,10 @@ int MachineFrameInfo::CreateStackObject(uint64_t Size, Align Alignment,
   return Index;
 }
 
-int MachineFrameInfo::CreateSpillStackObject(uint64_t Size, Align Alignment) {
+int MachineFrameInfo::CreateSpillStackObject(uint64_t Size, Align Alignment,
+                                             TargetStackID::Value StackID) {
   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
-  CreateStackObject(Size, Alignment, true);
+  CreateStackObject(Size, Alignment, true, nullptr, StackID);
   int Index = (int)Objects.size() - NumFixedObjects - 1;
   ensureMaxAlignment(Alignment);
   return Index;
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 68fd54cf00146..d9557a3958978 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -523,7 +523,8 @@ static void assignCalleeSavedSpillSlots(MachineFunction &F,
         // the TargetRegisterClass if the stack alignment is smaller. Use the
         // min.
         Alignment = std::min(Alignment, TFI->getStackAlign());
-        FrameIdx = MFI.CreateStackObject(Size, Alignment, true);
+        FrameIdx = MFI.CreateStackObject(Size, Alignment, true, nullptr,
+                                         RegInfo->getSpillStackID(*RC));
         MFI.setIsCalleeSavedObjectIndex(FrameIdx, true);
       } else {
         // Spill it to the stack where we must.
diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp
index dc505114ae6d7..f10283272f1d9 100644
--- a/llvm/lib/CodeGen/RegAllocFast.cpp
+++ b/llvm/lib/CodeGen/RegAllocFast.cpp
@@ -494,7 +494,8 @@ int RegAllocFastImpl::getStackSpaceFor(Register VirtReg) {
   if (Alignment > CurrentAlign && !TRI->canRealignStack(MF))
     Alignment = CurrentAlign;
 
-  int FrameIdx = MFI->CreateSpillStackObject(Size, Alignment);
+  int FrameIdx =
+      MFI->CreateSpillStackObject(Size, Alignment, TRI->getSpillStackID(RC));
 
   // Assign the slot.
   StackSlotForVirtReg[VirtReg] = FrameIdx;
diff --git a/llvm/lib/CodeGen/VirtRegMap.cpp b/llvm/lib/CodeGen/VirtRegMap.cpp
index 972bd8f550e8b..5a10a31050186 100644
--- a/llvm/lib/CodeGen/VirtRegMap.cpp
+++ b/llvm/lib/CodeGen/VirtRegMap.cpp
@@ -102,7 +102,8 @@ unsigned VirtRegMap::createSpillSlot(const TargetRegisterClass *RC) {
   if (Alignment > CurrentAlign && !TRI->canRealignStack(*MF)) {
     Alignment = CurrentAlign;
   }
-  int SS = MF->getFrameInfo().CreateSpillStackObject(Size, Alignment);
+  int SS = MF->getFrameInfo().CreateSpillStackObject(Size, Alignment,
+                                                     TRI->getSpillStackID(*RC));
   ++NumSpillSlots;
   return SS;
 }
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 3b72ba4bd4967..417ed4b6a22ed 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -1737,7 +1737,8 @@ void SIInstrInfo::storeRegToStackSlotImpl(
 
   MachineRegisterInfo &MRI = MF->getRegInfo();
   if (RI.isSGPRClass(RC)) {
-    MFI->setHasSpilledSGPRs();
+    if (FrameInfo.getStackID(FrameIndex) == TargetStackID::SGPRSpill)
+      MFI->setHasSpilledSGPRs();
     assert(SrcReg != AMDGPU::M0 && "m0 should not be spilled");
     assert(SrcReg != AMDGPU::EXEC_LO && SrcReg != AMDGPU::EXEC_HI &&
            SrcReg != AMDGPU::EXEC && "exec should not be spilled");
@@ -1759,8 +1760,6 @@ void SIInstrInfo::storeRegToStackSlotImpl(
       .addMemOperand(MMO)
       .addReg(MFI->getStackPtrOffsetReg(), RegState::Implicit);
 
-    if (RI.spillSGPRToVGPR())
-      FrameInfo.setStackID(FrameIndex, TargetStackID::SGPRSpill);
     return;
   }
 
@@ -1949,7 +1948,8 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
       FrameInfo.getObjectAlign(FrameIndex));
 
   if (RI.isSGPRClass(RC)) {
-    MFI->setHasSpilledSGPRs();
+    if (FrameInfo.getStackID(FrameIndex) == TargetStackID::SGPRSpill)
+      MFI->setHasSpilledSGPRs();
     assert(DestReg != AMDGPU::M0 && "m0 should not be reloaded into");
     assert(DestReg != AMDGPU::EXEC_LO && DestReg != AMDGPU::EXEC_HI &&
            DestReg != AMDGPU::EXEC && "exec should not be spilled");
@@ -1962,8 +1962,6 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
       MRI.constrainRegClass(DestReg, &AMDGPU::SReg_32_XM0_XEXECRegClass);
     }
 
-    if (RI.spillSGPRToVGPR())
-      FrameInfo.setStackID(FrameIndex, TargetStackID::SGPRSpill);
     BuildMI(MBB, MI, DL, OpDesc, DestReg)
       .addFrameIndex(FrameIndex) // addr
       .addMemOperand(MMO)
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index defac5304e7d4..48a38b1ffd460 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -265,7 +265,8 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
 
         const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
         int JunkFI = MFI.CreateStackObject(TRI->getSpillSize(*RC),
-                                           TRI->getSpillAlign(*RC), true);
+                                           TRI->getSpillAlign(*RC), true,
+                                           nullptr, TRI->getSpillStackID(*RC));
 
         CSI.emplace_back(Reg, JunkFI);
         CalleeSavedFIs.push_back(JunkFI);
@@ -277,8 +278,9 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
     // can be emitted appropriately.
     if (SpillRetAddrReg) {
       const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(RetAddrReg);
-      int JunkFI = MFI.CreateStackObject(TRI->getSpillSize(*RC),
-                                         TRI->getSpillAlign(*RC), true);
+      int JunkFI =
+          MFI.CreateStackObject(TRI->getSpillSize(*RC), TRI->getSpillAlign(*RC),
+                                true, nullptr, TRI->getSpillStackID(*RC));
       CSI.push_back(CalleeSavedInfo(RetAddrReg, JunkFI));
       CalleeSavedFIs.push_back(JunkFI);
     }
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index 7557205fb5317..6e72e082fb9bc 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -2569,7 +2569,9 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
     case AMDGPU::SI_SPILL_S96_SAVE:
     case AMDGPU::SI_SPILL_S64_SAVE:
     case AMDGPU::SI_SPILL_S32_SAVE: {
-      return spillSGPR(MI, Index, RS, nullptr, nullptr, false, false, NeedsCFI);
+      return spillSGPR(MI, Index, RS, nullptr, nullptr,
+                       FrameInfo.getStackID(Index) == TargetStackID::SGPRSpill,
+                       false, NeedsCFI);
     }
 
     // SGPR register restore
@@ -2587,7 +2589,9 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
     case AMDGPU::SI_SPILL_S96_RESTORE:
     case AMDGPU::SI_SPILL_S64_RESTORE:
     case AMDGPU::SI_SPILL_S32_RESTORE: {
-      return restoreSGPR(MI, Index, RS);
+      return restoreSGPR(MI, Index, RS, nullptr, nullptr,
+                         FrameInfo.getStackID(Index) ==
+                             TargetStackID::SGPRSpill);
     }
 
     // VGPR register spill
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index a0a7fb62f9159..f3e0a597c4db8 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -116,6 +116,7 @@ class SIRegisterClass <string n, list<ValueType> rTypes, int Align, dag rList>
   let TSFlags{2} = HasVGPR;
   let TSFlags{3} = HasAGPR;
   let TSFlags{4} = HasSGPR;
+  let SpillStackID = !if(HasSGPR, 1, 0); // TargetStackID::SGPRSpill
 
   // RA will use RegisterClass AllocationPriority amongst other info (e.g. ordering in the basic block)
   // to decide which registers to try to assign first. Usually, this RegisterClass priority is given
diff --git a/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll b/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
new file mode 100644
index 0000000000000..96a20e686ab60
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
@@ -0,0 +1,294 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -O1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -verify-machineinstrs < %s | FileCheck %s
+
+define void @sgpr_scavenge_fi_stack_id(double %input, i1 %enter_fma_path, i1 %repeat_outer_loop, i1 %enter_sgpr_loop, i1 %enter_inner_loop, i1 %exit_inner_loop, i1 %zero_fma_result) {
+; CHECK-LABEL: sgpr_scavenge_fi_stack_id:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_xor_saveexec_b64 s[4:5], -1
+; CHECK-NEXT:    buffer_store_dword v10, off, s[0:3], s32 offset:4 ; 4-byte Folded Spill
+; CHECK-NEXT:    s_mov_b64 exec, s[4:5]
+; CHECK-NEXT:    v_writelane_b32 v10, s30, 0
+; CHECK-NEXT:    v_writelane_b32 v10, s31, 1
+; CHECK-NEXT:    v_and_b32_e32 v2, 1, v2
+; CHECK-NEXT:    v_cmp_eq_u32_e64 s[10:11], 1, v2
+; CHECK-NEXT:    v_and_b32_e32 v2, 1, v4
+; CHECK-NEXT:    v_cmp_eq_u32_e64 s[12:13], 1, v2
+; CHECK-NEXT:    v_and_b32_e32 v2, 1, v3
+; CHECK-NEXT:    v_and_b32_e32 v7, 1, v7
+; CHECK-NEXT:    v_and_b32_e32 v6, 1, v6
+; CHECK-NEXT:    v_and_b32_e32 v5, 1, v5
+; CHECK-NEXT:    v_cmp_eq_u32_e64 s[14:15], 1, v2
+; CHECK-NEXT:    v_cmp_eq_u32_e64 s[4:5], 1, v7
+; CHECK-NEXT:    v_cmp_eq_u32_e64 s[6:7], 1, v6
+; CHECK-NEXT:    v_cmp_eq_u32_e64 s[8:9], 1, v5
+; CHECK-NEXT:    s_xor_b64 s[16:17], s[14:15], -1
+; CHECK-NEXT:    s_xor_b64 s[18:19], s[12:13], -1
+; CHECK-NEXT:    s_xor_b64 s[22:23], s[10:11], -1
+; CHECK-NEXT:    s_mov_b64 s[20:21], 0
+; CHECK-NEXT:    s_mov_b32 s25, 0x3fe62e42
+; CHECK-NEXT:    s_mov_b32 s24, 0xfefa39ef
+; CHECK-NEXT:    s_mov_b32 s27, 0x3c7abc9e
+; CHECK-NEXT:    s_mov_b32 s26, 0x3b39803f
+; CHECK-NEXT:    v_mov_b32_e32 v6, 0
+; CHECK-NEXT:    s_mov_b32 s28, 0
+; CHECK-NEXT:    s_mov_b32 s29, 0x7ff00000
+; CHECK-NEXT:    s_mov_b32 s41, 0x40417e50
+; CHECK-NEXT:    s_mov_b32 s40, 0xa9dc6553
+; CHECK-NEXT:    s_mov_b32 s42, 0
+; CHECK-NEXT:    s_mov_b32 s43, 0x7ff80000
+; CHECK-NEXT:    s_branch .LBB0_2
+; CHECK-NEXT:  .LBB0_1: ; %loop.exit.guard
+; CHECK-NEXT:    ; in Loop: Header=BB0_2 Depth=1
+; CHECK-NEXT:    s_or_b64 exec, exec, s[46:47]
+; CHECK-NEXT:    s_and_b64 s[44:45], exec, s[44:45]
+; CHECK-NEXT:    s_or_b64 s[20:21], s[44:45], s[20:21]
+; CHECK-NEXT:    s_andn2_b64 exec, exec, s[20:21]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_21
+; CHECK-NEXT:  .LBB0_2: ; %outer_latch
+; CHECK-NEXT:    ; =>This Loop Header: Depth=1
+; CHECK-NEXT:    ; Child Loop BB0_4 Depth 2
+; CHECK-NEXT:    ; Child Loop BB0_8 Depth 3
+; CHECK-NEXT:    ; Child Loop BB0_11 Depth 4
+; CHECK-NEXT:    ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT:    s_mov_b64 s[46:47], 0
+; CHECK-NEXT:    ; implicit-def: $sgpr44_sgpr45
+; CHECK-NEXT:    ; implicit-def: $sgpr56_sgpr57
+; CHECK-NEXT:    s_branch .LBB0_4
+; CHECK-NEXT:  .LBB0_3: ; %Flow11
+; CHECK-NEXT:    ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT:    s_or_b64 exec, exec, s[60:61]
+; CHECK-NEXT:    s_and_b64 s[58:59], exec, s[58:59]
+; CHECK-NEXT:    s_or_b64 s[46:47], s[58:59], s[46:47]
+; CHECK-NEXT:    s_andn2_b64 s[44:45], s[44:45], exec
+; CHECK-NEXT:    s_and_b64 s[58:59], s[56:57], exec
+; CHECK-NEXT:    s_or_b64 s[44:45], s[44:45], s[58:59]
+; CHECK-NEXT:    s_andn2_b64 exec, exec, s[46:47]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_1
+; CHECK-NEXT:  .LBB0_4: ; %outer_header
+; CHECK-NEXT:    ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT:    ; => This Loop Header: Depth=2
+; CHECK-NEXT:    ; Child Loop BB0_8 Depth 3
+; CHECK-NEXT:    ; Child Loop BB0_11 Depth 4
+; CHECK-NEXT:    ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT:    s_mov_b64 s[58:59], -1
+; CHECK-NEXT:    s_mov_b64 s[62:63], -1
+; CHECK-NEXT:    s_and_saveexec_b64 s[60:61], s[10:11]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_19
+; CHECK-NEXT:  ; %bb.5: ; %fma_setup
+; CHECK-NEXT:    ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT:    v_fma_f64 v[2:3], v[0:1], s[24:25], 0
+; CHECK-NEXT:    v_fmac_f64_e64 v[2:3], 0, s[26:27]
+; CHECK-NEXT:    s_mov_b64 s[62:63], 0
+; CHECK-NEXT:    ; implicit-def: $sgpr72_sgpr73
+; CHECK-NEXT:    ; implicit-def: $sgpr74_sgpr75
+; CHECK-NEXT:    ; implicit-def: $sgpr76_sgpr77
+; CHECK-NEXT:    s_branch .LBB0_8
+; CHECK-NEXT:  .LBB0_6: ; %Flow9
+; CHECK-NEXT:    ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT:    s_or_b64 exec, exec, s[88:89]
+; CHECK-NEXT:    s_andn2_b64 s[76:77], s[76:77], exec
+; CHECK-NEXT:    s_and_b64 s[88:89], s[92:93], exec
+; CHECK-NEXT:    s_or_b64 s[76:77], s[76:77], s[88:89]
+; CHECK-NEXT:    s_andn2_b64 s[74:75], s[74:75], exec
+; CHECK-NEXT:    s_and_b64 s[88:89], s[90:91], exec
+; CHECK-NEXT:    s_or_b64 s[74:75], s[74:75], s[88:89]
+; CHECK-NEXT:  .LBB0_7: ; %Flow8
+; CHECK-NEXT:    ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT:    s_or_b64 exec, exec, s[78:79]
+; CHECK-NEXT:    s_and_b64 s[78:79], exec, s[74:75]
+; CHECK-NEXT:    s_or_b64 s[62:63], s[78:79], s[62:63]
+; CHECK-NEXT:    s_andn2_b64 s[72:73], s[72:73], exec
+; CHECK-NEXT:    s_and_b64 s[78:79], s[76:77], exec
+; CHECK-NEXT:    s_or_b64 s[72:73], s[72:73], s[78:79]
+; CHECK-NEXT:    s_andn2_b64 exec, exec, s[62:63]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_18
+; CHECK-NEXT:  .LBB0_8: ; %sgpr_loop_header
+; CHECK-NEXT:    ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT:    ; Parent Loop BB0_4 Depth=2
+; CHECK-NEXT:    ; => This Loop Header: Depth=3
+; CHECK-NEXT:    ; Child Loop BB0_11 Depth 4
+; CHECK-NEXT:    ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT:    s_or_b64 s[76:77], s[76:77], exec
+; CHECK-NEXT:    s_or_b64 s[74:75], s[74:75], exec
+; CHECK-NEXT:    s_and_saveexec_b64 s[78:79], s[12:13]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_7
+; CHECK-NEXT:  ; %bb.9: ; %sgpr_pressure_loop.preheader
+; CHECK-NEXT:    ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT:    s_mov_b64 s[90:91], 0
+; CHECK-NEXT:    ; implicit-def: $sgpr88_sgpr89
+; CHECK-NEXT:    s_branch .LBB0_11
+; CHECK-NEXT:  .LBB0_10: ; %Flow7
+; CHECK-NEXT:    ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT:    s_xor_b64 s[94:95], s[94:95], -1
+; CHECK-NEXT:    s_and_b64 s[92:93], exec, s[92:93]
+; CHECK-NEXT:    s_or_b64 s[90:91], s[92:93], s[90:91]
+; CHECK-NEXT:    s_andn2_b64 s[88:89], s[88:89], exec
+; CHECK-NEXT:    s_and_b64 s[92:93], s[94:95], exec
+; CHECK-NEXT:    s_or_b64 s[88:89], s[88:89], s[92:93]
+; CHECK-NEXT:    s_andn2_b64 exec, exec, s[90:91]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_16
+; CHECK-NEXT:  .LBB0_11: ; %sgpr_pressure_loop
+; CHECK-NEXT:    ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT:    ; Parent Loop BB0_4 Depth=2
+; CHECK-NEXT:    ; Parent Loop BB0_8 Depth=3
+; CHECK-NEXT:    ; => This Loop Header: Depth=4
+; CHECK-NEXT:    ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT:    s_and_saveexec_b64 s[92:93], s[8:9]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_14
+; CHECK-NEXT:  ; %bb.12: ; %inner_stack_loop.preheader
+; CHECK-NEXT:    ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT:    v_cndmask_b32_e64 v5, v3, 0, s[4:5]
+; CHECK-NEXT:    v_cndmask_b32_e64 v4, v2, 0, s[4:5]
+; CHECK-NEXT:    v_cndmask_b32_e64 v5, v5, 0, s[14:15]
+; CHECK-NEXT:    v_cndmask_b32_e64 v4, v4, 0, s[14:15]
+; CHECK-NEXT:    v_mul_f64 v[4:5], v[4:5], s[28:29]
+; CHECK-NEXT:    v_mul_f64 v[4:5], v[4:5], s[40:41]
+; CHECK-NEXT:    s_mov_b32 vcc_lo, 0
+; CHECK-NEXT:    s_mov_b64 s[94:95], 0
+; CHECK-NEXT:    v_mul_f64 v[4:5], v[4:5], s[42:43]
+; CHECK-NEXT:  .LBB0_13: ; %inner_stack_loop
+; CHECK-NEXT:    ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT:    ; Parent Loop BB0_4 Depth=2
+; CHECK-NEXT:    ; Parent Loop BB0_8 Depth=3
+; CHECK-NEXT:    ; Parent Loop BB0_11 Depth=4
+; CHECK-NEXT:    ; => This Inner Loop Header: Depth=5
+; CHECK-NEXT:    s_and_b64 s[30:31], exec, s[6:7]
+; CHECK-NEXT:    s_or_b64 s[94:95], s[30:31], s[94:95]
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    buffer_store_dword v7, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    v_writelane_b32 v7, s4, 0
+; CHECK-NEXT:    buffer_store_dword v7, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    buffer_store_dword v7, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    buffer_load_dword v7, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    s_waitcnt vmcnt(0)
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    s_lshr_b32 s4, s32, 6
+; CHECK-NEXT:    s_lshl3_add_u32 vcc_hi, vcc_lo, s4
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    buffer_store_dword v8, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    buffer_load_dword v8, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    buffer_load_dword v8, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    s_waitcnt vmcnt(0)
+; CHECK-NEXT:    v_readlane_b32 s4, v8, 0
+; CHECK-NEXT:    buffer_load_dword v8, off, s[0:3], s32 offset:8
+; CHECK-NEXT:    s_waitcnt vmcnt(0)
+; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    v_mov_b32_e32 v7, vcc_hi
+; CHECK-NEXT:    buffer_load_dword v8, v7, s[0:3], 0 offen
+; CHECK-NEXT:    buffer_load_dword v9, v7, s[0:3], 0 offen offset:4
+; CHECK-NEXT:    v_mov_b32_e32 v7, vcc_lo
+; CHECK-NEXT:    s_mov_b32 vcc_lo, 1
+; CHECK-NEXT:    s_waitcnt vmcnt(0)
+; CHECK-NEXT:    v_mul_f64 v[8:9], v[4:5], v[8:9]
+; CHECK-NEXT:    buffer_store_dword v9, off, s[0:3], 0 offset:4
+; CHECK-NEXT:    buffer_store_dword v8, off, s[0:3], 0
+; CHECK-NEXT:    buffer_store_dword v6, v7, s[0:3], 0 offen
+; CHECK-NEXT:    buffer_store_dword v6, v7, s[0:3], 0 offen offset:4
+; CHECK-NEXT:    s_andn2_b64 exec, exec, s[94:95]
+; CHECK-NEXT:    s_cbranch_execnz .LBB0_13
+; CHECK-NEXT:  .LBB0_14: ; %Flow
+; CHECK-NEXT:    ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT:    s_or_b64 exec, exec, s[92:93]
+; CHECK-NEXT:    s_mov_b64 s[92:93], -1
+; CHECK-NEXT:    s_mov_b64 s[94:95], -1
+; CHECK-NEXT:    s_cbranch_execz .LBB0_10
+; CHECK-NEXT:  ; %bb.15: ; %sgpr_loop_merge
+; CHECK-NEXT:    ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT:    s_mov_b64 s[94:95], 0
+; CHECK-NEXT:    s_orn2_b64 s[92:93], s[22:23], exec
+; CHECK-NEXT:    s_branch .LBB0_10
+; CHECK-NEXT:  .LBB0_16: ; %loop.exit.guard6
+; CHECK-NEXT:    ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT:    s_or_b64 exec, exec, s[90:91]
+; CHECK-NEXT:    s_mov_b64 s[90:91], -1
+; CHECK-NEXT:    s_mov_b64 s[92:93], 0
+; CHECK-NEXT:    s_and_saveexec_b64 s[94:95], s[88:89]
+; CHECK-NEXT:    s_xor_b64 s[88:89], exec, s[94:95]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_6
+; CHECK-NEXT:  ; %bb.17: ; %after_sgpr_loop
+; CHECK-NEXT:    ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT:    s_mov_b64 s[92:93], exec
+; CHECK-NEXT:    s_orn2_b64 s[90:91], s[18:19], exec
+; CHECK-NEXT:    s_branch .LBB0_6
+; CHECK-NEXT:  .LBB0_18: ; %loop.exit.guard5
+; CHECK-NEXT:    ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT:    s_or_b64 exec, exec, s[62:63]
+; CHECK-NEXT:    s_orn2_b64 s[62:63], s[72:73], exec
+; CHECK-NEXT:  .LBB0_19: ; %Flow10
+; CHECK-NEXT:    ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT:    s_or_b64 exec, exec, s[60:61]
+; CHECK-NEXT:    s_or_b64 s[56:57], s[56:57], exec
+; CHECK-NEXT:    s_and_saveexec_b64 s[60:61], s[62:63]
+; CHECK-NEXT:    s_cbranch_execz .LBB0_3
+; CHECK-NEXT:  ; %bb.20: ; %outer_exit
+; CHECK-NEXT:    ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT:    s_andn2_b64 s[56:57], s[56:57], exec
+; CHECK-NEXT:    s_orn2_b64 s[58:59], s[16:17], exec
+; CHECK-NEXT:    s_branch .LBB0_3
+; CHECK-NEXT:  .LBB0_21: ; %DummyReturnBlock
+; CHECK-NEXT:    s_or_b64 exec, exec, s[20:21]
+; CHECK-NEXT:    v_readlane_b32 s30, v10, 0
+; CHECK-NEXT:    v_readlane_b32 s31, v10, 1
+; CHECK-NEXT:    s_xor_saveexec_b64 s[4:5], -1
+; CHECK-NEXT:    buffer_load_dword v10, off, s[0:3], s32 offset:4 ; 4-byte Folded Reload
+; CHECK-NEXT:    s_mov_b64 exec, s[4:5]
+; CHECK-NEXT:    s_waitcnt vmcnt(0)
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %private_slot = alloca i8, align 1, addrspace(5)
+  br label %outer_latch
+
+outer_latch:                                      ; preds = %outer_exit, %entry
+  br label %outer_header
+
+outer_header:                                     ; preds = %outer_exit, %outer_latch
+  br i1 %enter_fma_path, label %fma_setup, label %outer_exit
+
+fma_setup:                                        ; preds = %outer_header
+  %first_fma = call double @llvm.fma.f64(double %input, double f0x3FE62E42FEFA39EF, double 0.000000e+00)
+  %second_fma = call double @llvm.fma.f64(double 0.000000e+00, double f0x3C7ABC9E3B39803F, double %first_fma)
+  br label %sgpr_loop_header
+
+sgpr_loop_header:                                 ; preds = %after_sgpr_loop, %fma_setup
+  br i1 %enter_sgpr_loop, label %sgpr_pressure_loop, label %outer_exit
+
+sgpr_pressure_loop:                               ; preds = %sgpr_loop_merge, %sgpr_loop_header
+  %carried_sgpr_vec = phi <2 x i32> [ %next_sgpr_vec, %sgpr_loop_merge ], [ zeroinitializer, %sgpr_loop_header ]
+  %selected_fma = select i1 %zero_fma_result, double 0.000000e+00, double %second_fma
+  %new_sgpr_vec = insertelement <2 x i32> zeroinitializer, i32 0, i32 0
+  br i1 %enter_inner_loop, label %inner_stack_loop, label %sgpr_loop_merge
+
+inner_stack_loop:                                 ; preds = %inner_stack_loop, %sgpr_pressure_loop
+  %stack_offset = phi i32 [ 0, %sgpr_pressure_loop ], [ 1, %inner_stack_loop ]
+  %selected_fp = select i1 %repeat_outer_loop, double 0.000000e+00, double %selected_fma
+  %inf_mul = fmul double +inf, %selected_fp
+  %scaled_mul = fmul double %inf_mul, f0x40417E50A9DC6553
+  %nan_mul = fmul double %scaled_mul, +qnan
+  %private_gep = getelementptr [8 x i8], ptr addrspace(5) %private_slot, i32 %stack_offset
+  %private_load = load double, ptr addrspace(5) %private_gep, align 1
+  %spill_value = fmul double %nan_mul, %private_load
+  store double %spill_value, ptr addrspace(5) null, align 1
+  %indexed_null = getelementptr i8, ptr addrspace(5) null, i32 %stack_offset
+  store double 0.000000e+00, ptr addrspace(5) %indexed_null, align 1
+  br i1 %exit_inner_loop, label %inner_done, label %inner_stack_loop
+
+inner_done:                                       ; preds = %inner_stack_loop
+  br label %sgpr_loop_merge
+
+sgpr_loop_merge:                                  ; preds = %inner_done, %sgpr_pressure_loop
+  %next_sgpr_vec = phi <2 x i32> [ %new_sgpr_vec, %inner_done ], [ %carried_sgpr_vec, %sgpr_pressure_loop ]
+  br i1 %enter_fma_path, label %sgpr_pressure_loop, label %after_sgpr_loop
+
+after_sgpr_loop:                                  ; preds = %sgpr_loop_merge
+  br i1 %enter_sgpr_loop, label %sgpr_loop_header, label %outer_exit
+
+outer_exit:                                       ; preds = %after_sgpr_loop, %sgpr_loop_header, %outer_header
+  br i1 %repeat_outer_loop, label %outer_header, label %outer_latch
+}
+
+declare double @llvm.fma.f64(double, double, double)
diff --git a/llvm/test/TableGen/RegisterInfoEmitter-errors.td b/llvm/test/TableGen/RegisterInfoEmitter-errors.td
index cb1a1e9136e95..b0b9a2fbbda86 100644
--- a/llvm/test/TableGen/RegisterInfoEmitter-errors.td
+++ b/llvm/test/TableGen/RegisterInfoEmitter-errors.td
@@ -4,6 +4,7 @@
 // RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s -DERROR3 2>&1 | FileCheck %s --check-prefix=ERROR3
 // RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s -DERROR4 2>&1 | FileCheck %s --check-prefix=ERROR4
 // RUN: not llvm-tblgen -gen-register-bank -I %p/../../include %s -DERROR5 2>&1 | FileCheck %s --check-prefix=ERROR5
+// RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s -DERROR6 2>&1 | FileCheck %s --check-prefix=ERROR6
 
 include "llvm/Target/Target.td"
 
@@ -13,7 +14,11 @@ foreach Index = 0-15 in {
   def R#Index : Register <"r"#Index>;
 }
 
-def GPR32 : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 0, 15)>;
+def GPR32 : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 0, 15)> {
+#ifdef ERROR6
+  let SpillStackID = 256;
+#endif
+}
 
 def sub0 : SubRegIndex<32, 0>;
 def sub1 : SubRegIndex<32, 32>;
@@ -55,3 +60,6 @@ def R0_R1 : RegisterWithSubRegs<"r0_r1", [R0]> {
 // ERROR5: error: No register banks defined
 #endif
 
+#ifdef ERROR6
+// ERROR6: error: SpillStackID out of range [0,255]
+#endif
diff --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp
index 47e260104775f..7e1fd091fa1c3 100644
--- a/llvm/unittests/CodeGen/MachineInstrTest.cpp
+++ b/llvm/unittests/CodeGen/MachineInstrTest.cpp
@@ -593,7 +593,7 @@ TEST(MachineInstrTest, SpliceOperands) {
   // test tied operands
   MCRegisterClass MRC{
       0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
-  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+  TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   // MachineRegisterInfo will be very upset if these registers aren't
   // allocatable.
   assert(RC.isAllocatable() && "unusable TargetRegisterClass");
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 6f089bab7a89d..506d9b2ee8d7c 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -730,6 +730,10 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
   int CopyCostParsed = R->getValueAsInt("CopyCost");
   Allocatable = R->getValueAsBit("isAllocatable");
   AltOrderSelect = R->getValueAsString("AltOrderSelect");
+  int SpillStackIDParsed = R->getValueAsInt("SpillStackID");
+  if (!isUInt<8>(SpillStackIDParsed))
+    PrintFatalError(R->getLoc(), "SpillStackID out of range [0,255]");
+  SpillStackID = SpillStackIDParsed;
   int AllocationPriority = R->getValueAsInt("AllocationPriority");
   if (!isUInt<5>(AllocationPriority))
     PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,31]");
@@ -757,7 +761,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
     : Members(*Props.Members), TheDef(nullptr), Name(Name.str()),
       RegsWithSuperRegsTopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1),
       RSI(Props.RSI), CopyCost(0), Allocatable(true), AllocationPriority(0),
-      GlobalPriority(false), TSFlags(0) {
+      GlobalPriority(false), TSFlags(0), SpillStackID(0) {
   MemberBV.resize(RegBank.getRegisters().size());
   Artificial = true;
   GeneratePressureSet = false;
@@ -794,6 +798,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) {
   AllocationPriority = Super.AllocationPriority;
   GlobalPriority = Super.GlobalPriority;
   TSFlags = Super.TSFlags;
+  SpillStackID = Super.SpillStackID;
   GeneratePressureSet |= Super.GeneratePressureSet;
 
   // Copy all allocation orders, filter out foreign registers from the larger
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.h b/llvm/utils/TableGen/Common/CodeGenRegisters.h
index 1de5973084fdd..9a8c5aa25137c 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.h
@@ -374,6 +374,7 @@ class CodeGenRegisterClass {
   uint8_t AllocationPriority;
   bool GlobalPriority;
   uint8_t TSFlags;
+  uint8_t SpillStackID;
   /// Contains the combination of the lane masks of all subregisters.
   LaneBitmask LaneMask;
   /// True if there are at least 2 subregisters which do not interfere.
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index cb5b72e0c64b8..fa845c24aa720 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1514,6 +1514,7 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS,
       OS << ",\n    " << (unsigned)RC.AllocationPriority << ",\n    "
          << (RC.GlobalPriority ? "true" : "false") << ",\n    "
          << format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n    "
+         << (unsigned)RC.SpillStackID << ", /* SpillStackID */\n    "
          << (RC.HasDisjunctSubRegs ? "true" : "false")
          << ", /* HasDisjunctSubRegs */\n    "
          << (RC.CoveredBySubRegs ? "true" : "false")



More information about the llvm-commits mailing list