[llvm] AMDGPU: Add NextUseAnalysis Pass (PR #178873)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 13 10:50:39 PDT 2026


================
@@ -0,0 +1,1734 @@
+//===---------------------- AMDGPUNextUseAnalysis.cpp ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPUNextUseAnalysis.h"
+#include "AMDGPU.h"
+#include "GCNRegPressure.h"
+#include "GCNSubtarget.h"
+
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/IR/ModuleSlotTracker.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+#include <cmath>
+#include <limits>
+#include <queue>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "amdgpu-next-use-analysis"
+
+namespace {
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Options
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+cl::opt<bool> DumpNextUseDistance("amdgpu-next-use-analysis-dump-distance",
+                                  cl::init(false), cl::Hidden);
+
+cl::opt<std::string>
+    DumpNextUseDistanceAsJson("amdgpu-next-use-analysis-dump-distance-as-json",
+                              cl::Hidden);
+cl::opt<bool>
+    DumpNextUseDistanceVerbose("amdgpu-next-use-analysis-dump-distance-verbose",
+                               cl::init(false), cl::Hidden);
+
+cl::opt<AMDGPUNextUseAnalysis::CompatibilityMode> CompatModeOpt(
+    "amdgpu-next-use-analysis-compatibility-mode", cl::Hidden,
+    cl::init(AMDGPUNextUseAnalysis::CompatibilityMode::Graphics),
+    cl::values(clEnumValN(AMDGPUNextUseAnalysis::CompatibilityMode::Graphics,
+                          "graphics", "TBD"),
+               clEnumValN(AMDGPUNextUseAnalysis::CompatibilityMode::Compute,
+                          "compute", "TBD")));
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// String helpers
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+template <typename T> inline std::string printToString(T &X) {
+  std::string S;
+  raw_string_ostream OS(S);
+  X.print(OS);
+  return StringRef(OS.str()).trim().str();
+}
+
+template <typename T> inline std::string printToString(T *X) {
+  return X ? printToString(*X) : "null";
+}
+
+inline std::string printToString(const MachineInstr &MI,
+                                 ModuleSlotTracker &MST) {
+  std::string S;
+  raw_string_ostream OS(S);
+  MI.print(OS, MST,
+           /* IsStandalone    */ false,
+           /* SkipOpers       */ false,
+           /* SkipDebugLoc    */ false,
+           /* AddNewLine      */ false,
+           /* TargetInstrInfo */ nullptr);
+  return StringRef(OS.str()).trim().str();
+}
+
+std::string printRegToString(Register Reg, unsigned SubRegIdx,
+                             const MachineRegisterInfo *MRI,
+                             const SIRegisterInfo *TRI) {
+  std::string S;
+  raw_string_ostream OS(S);
+  OS << printReg(Reg, TRI, SubRegIdx, MRI);
+  return OS.str();
+}
+
+std::string printRegToString(Register Reg, LaneBitmask LaneMask,
+                             const MachineRegisterInfo *MRI,
+                             const SIRegisterInfo *TRI) {
+  unsigned SubRegIdx = 0;
+  if (!Reg.isVirtual() || LaneMask != MRI->getMaxLaneMaskForVReg(Reg))
+    SubRegIdx = TRI->getSubRegIndexForLaneMask(LaneMask);
+  return printRegToString(Reg, SubRegIdx, MRI, TRI);
+}
+
+std::string nameForMBB(const MachineBasicBlock &BB, ModuleSlotTracker &MST) {
+  std::string S;
+  raw_string_ostream OS(S);
+  BB.printName(OS, MachineBasicBlock::PrintNameIr, &MST);
+  return OS.str();
+}
+
+struct InstructionInfo {
+  std::string MIStr; // Backing storage for StringRefs
+  StringRef DefName;
+  StringRef DefType;
+  StringRef Instr;
+};
+
+InstructionInfo parseInstructionString(const MachineInstr &MI,
+                                       ModuleSlotTracker &MST) {
+  InstructionInfo Info;
+  Info.MIStr = printToString(MI, MST);
+  StringRef MIRef(Info.MIStr);
+  StringRef Def;
+  std::tie(Def, Info.Instr) = MIRef.split('=');
+  if (Info.Instr.empty()) {
+    Def = "%void:void";
+    Info.Instr = MIRef;
+  }
+  Info.Instr = Info.Instr.trim();
+  std::tie(Info.DefName, Info.DefType) = Def.trim().split(":");
+  return Info;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/// MBBDistPair - Represents a distance to a machine basic block.
+/// Used for returning both the distance and the target block together.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+struct MBBDistPair {
+  double Distance;
+  const MachineBasicBlock *MBB;
+  constexpr MBBDistPair()
+      : Distance(std::numeric_limits<double>::max()), MBB(nullptr) {}
+  MBBDistPair(double D, const MachineBasicBlock *B) : Distance(D), MBB(B) {}
+
+  MBBDistPair operator+(double D) { return {Distance + D, MBB}; }
+  MBBDistPair &operator+=(double D) {
+    Distance += D;
+    return *this;
+  }
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/// LiveRegUse - Represents a live register use with its distance.
+/// Used for tracking and sorting register uses by distance.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+struct LiveRegUse {
+  const MachineOperand *Use = nullptr;
+  double Dist = 0.0;
+  LiveRegUse() = default;
+  LiveRegUse(const MachineOperand *Use, double Dist) : Use(Use), Dist(Dist) {}
+
+  std::string toString() const {
+    if (!valid())
+      return "<invalid>";
+    return std::to_string(Dist) + "@" + printToString(Use) + "*" +
+           printToString(Use->getParent());
+  }
+  bool valid() const { return Use; }
+
+  Register getReg() const { return Use->getReg(); }
+  LaneBitmask getLaneMask(const SIRegisterInfo *TRI) const {
+    return TRI->getSubRegIndexLaneMask(Use->getSubReg());
+  }
+
+  bool operator<(const LiveRegUse &Other) const {
+    if (!Use)
+      return true; // Other is better
+
+    if (Dist < Other.Dist)
+      return true; // Other is better
+
+    if (Dist != Other.Dist)
+      return false; // this is better
+
+    if (Use == Other.Use)
+      return false; // this is better
+
+    // Ugh. In computeMode PHIs and the first non-PHI instruction have id 0. In
+    // this case, consider PHIs as less than the first non-PHI instruction.
----------------
macurtis-amd wrote:

See comment [here](https://github.com/llvm/llvm-project/pull/178873#discussion_r3074795540).

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


More information about the llvm-commits mailing list