[llvm] [AMDGPU] Refactor GFX11 VALU Mask Hazard Waitcnt Merging (PR #169213)

Carl Ritson via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 03:10:11 PDT 2026


================
@@ -437,9 +438,121 @@ class AMDGPUWaitSGPRHazards {
     return Changed;
   }
 
+  bool runWaitMerging(MachineFunction &MF) {
+    // Perform per-block merging of existing s_waitcnt_depctr instructions.
+    // Track set of SGPR writes before a given wait instruction, and search
+    // for reads of these SGPRs.
+    // Move the wait to just before the read to improve pipelining.
+    // If no related reads occur before subsequent wait then merged waits.
+    const unsigned ConstantMaskBits = AMDGPU::DepCtr::encodeFieldSaSdst(
+        AMDGPU::DepCtr::encodeFieldVaSdst(
+            AMDGPU::DepCtr::encodeFieldVaVcc(0, *ST), 0),
+        0);
+    const unsigned VccLoIdx = *sgprNumber(AMDGPU::VCC_LO, *TRI);
+    const unsigned VccHiIdx = *sgprNumber(AMDGPU::VCC_HI, *TRI);
+    bool Changed = false;
+    for (MachineBasicBlock &MBB : MF) {
+      std::bitset<128> WriteSet, PendingSALUWriteSet, PendingVALUWriteSet;
+      MachineInstr *PrevWait = nullptr;
+
+      auto CommitWrites = [&](unsigned Mask) {
+        if (!AMDGPU::DepCtr::decodeFieldSaSdst(Mask))
+          WriteSet |= PendingSALUWriteSet;
+        bool VccLoBit = WriteSet[VccLoIdx];
+        bool VccHiBit = WriteSet[VccHiIdx];
+        if (!AMDGPU::DepCtr::decodeFieldVaSdst(Mask)) {
+          WriteSet |= PendingVALUWriteSet;
+          WriteSet.set(VccLoIdx, VccLoBit);
+          WriteSet.set(VccLoIdx, VccHiBit);
+        }
+        if (!AMDGPU::DepCtr::decodeFieldVaVcc(Mask)) {
+          WriteSet.set(VccLoIdx, VccLoBit | PendingVALUWriteSet[VccLoIdx]);
+          WriteSet.set(VccHiIdx, VccHiBit | PendingVALUWriteSet[VccHiIdx]);
+        }
+        // Clear all pending writes
+        PendingSALUWriteSet.reset();
+        PendingVALUWriteSet.reset();
+      };
+
+      for (MachineBasicBlock::instr_iterator MI = MBB.instr_begin(),
+                                             E = MBB.instr_end();
+           MI != E; ++MI) {
+        if (MI->isMetaInstruction())
+          continue;
+
+        if (MI->getOpcode() == AMDGPU::S_WAITCNT_DEPCTR && !MI->isBundled() &&
+            (MI->getOperand(0).getImm() & ConstantMaskBits) ==
+                ConstantMaskBits) {
+          if (PrevWait) {
+            // Merge previous wait into this one.
+            MachineOperand &MaskOp = MI->getOperand(0);
+            MaskOp.setImm(
+                mergeMasks(PrevWait->getOperand(0).getImm(), MaskOp.getImm()));
+            PrevWait->eraseFromParent();
+            Changed = true;
+          } else {
+            // Starting a new region using fresh write set.
+            WriteSet.reset();
+          }
+          CommitWrites(MI->getOperand(0).getImm());
+          PrevWait = &*MI;
+          continue;
+        }
+
+        // Do not optimize over branches
+        if (PrevWait && (MI->isCall() || MI->isReturn() || MI->isBranch())) {
+          PrevWait->moveBefore(&*MI);
+          PrevWait = nullptr;
+          Changed = true;
+        }
+
+        const bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
+        const bool IsSALU = SIInstrInfo::isSALU(*MI);
+        if (!IsVALU && !IsSALU)
+          continue;
+
+        for (const MachineOperand &Op : MI->operands()) {
+          if (!Op.isReg())
+            continue;
+          Register Reg = Op.getReg();
+          if (!TRI->isSGPRReg(*MRI, Reg))
+            continue;
+
+          auto RegNumber = sgprNumber(Reg, *TRI);
+          if (!RegNumber)
+            continue;
+          unsigned RegN = *RegNumber;
+
+          uint8_t SGPRCount =
+              AMDGPU::getRegBitWidth(*TRI->getRegClassForReg(*MRI, Reg)) / 32;
+
+          if (Op.isDef()) {
+            for (uint8_t RegIdx = 0; RegIdx < SGPRCount; ++RegIdx) {
+              if (IsSALU)
+                PendingSALUWriteSet.set(RegN + RegIdx);
+              else
+                PendingVALUWriteSet.set(RegN + RegIdx);
+            }
+            continue;
+          }
+
+          for (uint8_t RegIdx = 0; RegIdx < SGPRCount && PrevWait; ++RegIdx) {
+            if (!WriteSet[RegN + RegIdx])
+              continue;
+            // Move the wait to here, the last point it can be valid
+            PrevWait->moveBefore(&*MI);
+            PrevWait = nullptr;
+            Changed = true;
----------------
perlfu wrote:

Switch to Small Bit Vector

https://github.com/llvm/llvm-project/pull/169213


More information about the llvm-commits mailing list