Skip to content

AMDGPU: Add NextUseAnalysis Pass - #178873

Merged
macurtis-amd merged 12 commits into
llvm:mainfrom
macurtis-amd:next-use-analysis-003
Apr 16, 2026
Merged

macurtis-amd merged 12 commits into
llvm:mainfrom
macurtis-amd:next-use-analysis-003

Conversation

@macurtis-amd

@macurtis-amd macurtis-amd commented Jan 30, 2026

Copy link
Copy Markdown
Contributor

Based on

See those PRs for background.

Provides a compatibility mode option
--amdgpu-next-use-analysis-compatibility-mode that produces results that match either PR #156079 (compute) or PR #171520 (graphics).

Co-authored-by: alex-t atimofee@amd.com
Co-authored-by: Konstantina Mitropoulou KonstantinaMitropoulou@amd.com

@macurtis-amd
macurtis-amd force-pushed the next-use-analysis-003 branch from 7804146 to a46ffd9 Compare February 9, 2026 14:34
@macurtis-amd
macurtis-amd force-pushed the next-use-analysis-003 branch 2 times, most recently from d10c71b to 466868a Compare February 19, 2026 01:36
@github-actions

github-actions Bot commented Feb 19, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 193778 tests passed
  • 5056 tests skipped

✅ The build succeeded and all tests passed.

@macurtis-amd
macurtis-amd force-pushed the next-use-analysis-003 branch 3 times, most recently from 0d20ec4 to 3b16136 Compare February 20, 2026 17:26
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h
Comment thread llvm/include/llvm/CodeGen/TargetRegisterInfo.h Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
if (!LoopTo)
return encodeLoopDepth(getEffectiveLoopDepth(LoopFrom, To, MLI));

if (LoopFrom->contains(LoopTo)) // covers LoopFrom == LoopTo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this be implied by the loop depth subtract below

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure what you are asking here.

FWIW, I re-worked the logic a little bit (now in calcLoopExits).
There are four branches

  1. No from loop
  2. From loop contains To loop
  3. To loop contains From loop
  4. All other loop relationships

Is this better?

Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp

@linuxrocks123 linuxrocks123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good work. I am generally impressed with the quality of the code. My main overall criticism is that more in-code documentation is required for clarity. Please see my line comments as well.

Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
InstrIdTy Id = 0;
for (auto &MI : BB->instrs()) {
InstrToId[&MI] = Id;
if (!computeMode() || !MI.isPHI())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this conditional? It results in duplicate IDs which you are having to special case elsewhere. A comment explaining the reasoning would be helpful, and an explanation would help evaluate @arsenm's objection to the special casing that the duplicate IDs require.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my solution to maintaining compatibility with PR #156079 AMDGPUNextUseAnalysis.cpp#L411-L412.

Basically PHIs do not contribute to distances.

This has resulted in two special cases:

  1. LiveRegUse::isCloserThan AMDGPU/AMDGPUNextUseAnalysis.cpp#L97-L108
  2. calcDistanceToUseForCompute AMDGPUNextUseAnalysis.cpp#L1359-L1361

I'm open to other suggestions.

I'll at least add a comment in the next drop.

Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
Comment thread llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp Outdated
@macurtis-amd
macurtis-amd force-pushed the next-use-analysis-003 branch from 9ba0c5d to 2faaba6 Compare March 12, 2026 15:59
@github-actions

github-actions Bot commented Mar 12, 2026

Copy link
Copy Markdown

✅ With the latest revision this PR passed the C/C++ code formatter.

@macurtis-amd
macurtis-amd force-pushed the next-use-analysis-003 branch from 2faaba6 to 7ba99b9 Compare March 12, 2026 16:17
@macurtis-amd
macurtis-amd marked this pull request as ready for review March 12, 2026 18:17
@llvmbot

llvmbot commented Mar 12, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-backend-amdgpu

Author: None (macurtis-amd)

Changes

Based on

See those PRs for background.

Provides a compatibility mode option
--amdgpu-next-use-analysis-compatibility-mode that produces results that match either PR #156079 (machine-learning) or PR #171520 (graphics).

Currently has performance charactistics similar to PR #171520.


Patch is 29.47 MiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178873.diff

40 Files Affected:

  • (modified) llvm/include/llvm/Passes/TargetPassRegistry.inc (+18)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPU.h (+8)
  • (added) llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp (+2296)
  • (added) llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.h (+150)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUPassRegistry.def (+2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp (+3)
  • (modified) llvm/lib/Target/AMDGPU/CMakeLists.txt (+1)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/acyclic-cfg-with-self-loop.mir (+9924)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/acyclic-phi-merge-distances.mir (+2980)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/complex-acyclic-cfg-with-4-self-loops.mir (+16630)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/complex-control-flow-11blocks.mir (+4885)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/complex-control-flow-15blocks.mir (+5974)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/complex-single-loop-a.mir (+5910)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/complex-single-loop.mir (+4082)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/double-nested-loops-complex-cfg.mir (+56719)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/if_else_with_loops_nested_in_2_outer_loops.mir (+16805)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/inner_cfg_in_2_nested_loops.mir (+6723)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/loop_nested_in_3_outer_loops_complex_cfg.mir (+16940)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/nested-loops-with-side-exits-a.mir (+11861)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/sequence_2_loops.mir (+4750)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/simple-loop-3blocks.mir (+1308)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/spill-vreg-many-lanes.mir (+273562)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_basic_case.mir (+2984)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_do_not_spill_restore_inside_loop.mir (+6239)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_emit_restore_in_common_dominator.mir (+6014)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_emit_restore_in_loop_preheader1.mir (+3505)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_emit_restore_in_loop_preheader2.mir (+4729)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_emit_restore_in_loop_preheader3.mir (+16768)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_emit_restore_in_loop_preheader4.mir (+5341)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_keep_spilled_reg_live.mir (+2252)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_multiple_spills1.mir (+39917)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_multiple_spills2.mir (+41132)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_multiple_spills3.mir (+36499)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_nested_loops.mir (+6080)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_spill_in_common_dominator_and_optimize_restores.mir (+9772)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_spill_loop_livethrough_reg.mir (+4057)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/test_ers_spill_loop_value_in_exit_block.mir (+3585)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/three-tier-ranking-nested-loops.mir (+1015)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/triple-nested-loops.mir (+6103)
  • (added) llvm/test/CodeGen/AMDGPU/NextUseAnalysis/two-sequential-loops.mir (+5075)
diff --git a/llvm/include/llvm/Passes/TargetPassRegistry.inc b/llvm/include/llvm/Passes/TargetPassRegistry.inc
index 068b27794191c..4e778e77fa128 100644
--- a/llvm/include/llvm/Passes/TargetPassRegistry.inc
+++ b/llvm/include/llvm/Passes/TargetPassRegistry.inc
@@ -92,6 +92,14 @@ if (PIC) {
     return true;                                                               \
   }
 
+#define ADD_ANALYSIS_PASS(NAME, CREATE_PASS)                                   \
+  if (Name == "require<" NAME ">") {                                           \
+    PM.addPass(                                                                \
+        RequireAnalysisPass<std::remove_reference_t<decltype(CREATE_PASS)>,    \
+                            MachineFunction>());                               \
+    return true;                                                               \
+  }
+
 PB.registerPipelineParsingCallback([=](StringRef Name, ModulePassManager &PM,
                                        ArrayRef<PassBuilder::PipelineElement>) {
 #define MODULE_PASS(NAME, CREATE_PASS) ADD_PASS(NAME, CREATE_PASS)
@@ -151,6 +159,16 @@ PB.registerPipelineParsingCallback([=](StringRef Name, FunctionPassManager &PM,
   return false;
 });
 
+PB.registerPipelineParsingCallback([=](StringRef Name,
+                                       MachineFunctionPassManager &PM,
+                                       ArrayRef<PassBuilder::PipelineElement>) {
+#define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS)                           \
+  ADD_ANALYSIS_PASS(NAME, CREATE_PASS)
+#include GET_PASS_REGISTRY
+#undef MACHINE_FUNCTION_ANALYSIS
+  return false;
+});
+
 #undef ADD_PASS
 #undef ADD_PASS_WITH_PARAMS
 
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.h b/llvm/lib/Target/AMDGPU/AMDGPU.h
index 878f374110159..9680ac648c4de 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.h
@@ -47,6 +47,8 @@ FunctionPass *createSIWholeQuadModeLegacyPass();
 FunctionPass *createSIFixControlFlowLiveIntervalsPass();
 FunctionPass *createSIOptimizeExecMaskingPreRAPass();
 FunctionPass *createSIOptimizeVGPRLiveRangeLegacyPass();
+FunctionPass *createAMDGPUNextUseAnalysisLegacyPass();
+FunctionPass *createAMDGPUNextUseAnalysisPrinterLegacyPass();
 FunctionPass *createSIFixSGPRCopiesLegacyPass();
 FunctionPass *createLowerWWMCopiesPass();
 FunctionPass *createSIMemoryLegalizerPass();
@@ -193,6 +195,12 @@ extern char &SIFixSGPRCopiesLegacyID;
 void initializeSIFixVGPRCopiesLegacyPass(PassRegistry &);
 extern char &SIFixVGPRCopiesID;
 
+void initializeAMDGPUNextUseAnalysisLegacyPassPass(PassRegistry &);
+extern char &AMDGPUNextUseAnalysisLegacyID;
+
+void initializeAMDGPUNextUseAnalysisPrinterLegacyPassPass(PassRegistry &);
+extern char &AMDGPUNextUseAnalysisPrinterLegacyID;
+
 void initializeSILowerWWMCopiesLegacyPass(PassRegistry &);
 extern char &SILowerWWMCopiesLegacyID;
 
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
new file mode 100644
index 0000000000000..5e36737c6d2f8
--- /dev/null
+++ b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
@@ -0,0 +1,2296 @@
+//===---------------------- 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/ADT/DenseMap.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/IR/ModuleSlotTracker.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <queue>
+#include <string>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "amdgpu-next-use-analysis"
+
+//==============================================================================
+// Options etc
+//==============================================================================
+namespace {
+
+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")));
+} // namespace
+
+//==============================================================================
+// LiveRegUse - Represents a live register use with its distance. Used for
+// tracking and sorting register uses by distance.
+//==============================================================================
+namespace {
+using UseDistancePair = AMDGPUNextUseAnalysis::UseDistancePair;
+struct LiveRegUse : public UseDistancePair {
+  using Base = UseDistancePair;
+
+  // 'nullptr' indicates an unset/invalid state.
+  LiveRegUse() : UseDistancePair(nullptr, 0.0) {}
+  LiveRegUse(const MachineOperand *Use, double Dist)
+      : UseDistancePair(Use, Dist) {}
+  LiveRegUse(const UseDistancePair &P) : UseDistancePair(P) {}
+
+  bool isUnset() const { return Use == nullptr; }
+
+  Register getReg() const { return Use->getReg(); }
+  unsigned getSubReg() const { return Use->getSubReg(); }
+  LaneBitmask getLaneMask(const SIRegisterInfo *TRI) const {
+    return TRI->getSubRegIndexLaneMask(Use->getSubReg());
+  }
+
+  bool isCloserThan(const LiveRegUse &X) const {
+    if (Dist < X.Dist)
+      return true;
+
+    if (Dist > X.Dist)
+      return false;
+
+    if (Use == X.Use)
+      return false;
+
+    // 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.
+    const MachineInstr *ThisMI = Use->getParent();
+    const MachineInstr *XMI = X.Use->getParent();
+    const MachineBasicBlock *ThisMBB = ThisMI->getParent();
+    if (ThisMBB == XMI->getParent()) {
+      bool XIsPhiOp = ThisMI->isPHI();
+      bool YIsPhiOp = XMI->isPHI();
+      if (XIsPhiOp && !YIsPhiOp && XMI == &(*ThisMBB->getFirstNonPHI()))
+        return true;
+    }
+
+    // Ensure deterministic results
+    return X.getReg() < getReg();
+  }
+};
+
+inline bool updateClosest(LiveRegUse &Closest, const LiveRegUse &X) {
+  if (!Closest.Use || X.isCloserThan(Closest)) {
+    Closest = X;
+    return true;
+  }
+  return false;
+}
+
+inline bool updateFurthest(LiveRegUse &Furthest, const LiveRegUse &X) {
+  if (!Furthest.Use || Furthest.isCloserThan(X)) {
+    Furthest = X;
+    return true;
+  }
+  return false;
+}
+} // namespace
+
+//==============================================================================
+// json helpers
+//==============================================================================
+namespace {
+template <typename Lambda>
+void printStringAttr(json::OStream &J, const char *Name, Lambda L) {
+  J.attributeBegin(Name);
+  raw_ostream &OS = J.rawValueBegin();
+  OS << '"';
+  L(OS);
+  OS << '"';
+  J.rawValueEnd();
+  J.attributeEnd();
+}
+void printStringAttr(json::OStream &J, const char *Name, Printable P) {
+  printStringAttr(J, Name, [&](raw_ostream &OS) { OS << P; });
+}
+
+void printStringAttr(json::OStream &J, const char *Name, const MachineInstr &MI,
+                     ModuleSlotTracker &MST) {
+  printStringAttr(J, Name, [&](raw_ostream &OS) {
+    MI.print(OS, MST,
+             /* IsStandalone    */ false,
+             /* SkipOpers       */ false,
+             /* SkipDebugLoc    */ false,
+             /* AddNewLine ---> */ false,
+             /* TargetInstrInfo */ nullptr);
+  });
+}
+
+void printMBBNameAttr(json::OStream &J, const char *Name,
+                      const MachineBasicBlock &MBB, ModuleSlotTracker &MST) {
+  printStringAttr(J, Name, [&](raw_ostream &OS) {
+    MBB.printName(OS, MachineBasicBlock::PrintNameIr, &MST);
+  });
+}
+
+template <typename NameLambda, typename ValueT>
+void printAttr(json::OStream &J, NameLambda NL, ValueT V) {
+  std::string Name;
+  raw_string_ostream NameOS(Name);
+  NL(NameOS);
+  J.attribute(NameOS.str(), V);
+}
+
+template <typename ValueT>
+void printAttr(json::OStream &J, const Printable &P, ValueT V) {
+  printAttr(J, [&](raw_ostream &OS) { OS << P; }, V);
+}
+
+} // namespace
+
+//==============================================================================
+// AMDGPUNextUseAnalysisImpl
+//==============================================================================
+class llvm::AMDGPUNextUseAnalysisImpl {
+  using CompatibilityMode = AMDGPUNextUseAnalysis::CompatibilityMode;
+  const MachineFunction *MF = nullptr;
+  const SIRegisterInfo *TRI = nullptr;
+  const SIInstrInfo *TII = nullptr;
+  const MachineLoopInfo *MLI = nullptr;
+  const MachineRegisterInfo *MRI = nullptr;
+
+  using InstrIdTy = unsigned;
+  using InstrToIdMap = DenseMap<const MachineInstr *, InstrIdTy>;
+  InstrToIdMap InstrToId;
+  CompatibilityMode CompatMode;
+
+  void initializeTables() {
+    for (const MachineBasicBlock &BB : *MF)
+      calcInstrIds(&BB, InstrToId);
+    initializeCfgPaths();
+    initializeInterBlockDistances();
+  }
+
+  void clearTables() {
+    InstrToId.clear();
+    RegUseMap.clear();
+    Paths.clear();
+
+    LastMI = nullptr;
+    LastDistances.clear();
+  }
+
+  bool computeMode() const { return CompatMode == CompatibilityMode::Compute; }
+
+  bool graphicsMode() const {
+    return CompatMode == CompatibilityMode::Graphics;
+  }
+
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // Instruction Ids
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+private:
+  void calcInstrIds(const MachineBasicBlock *BB,
+                    InstrToIdMap &MutableInstrToId) const {
+    InstrIdTy Id = 0;
+    for (auto &MI : BB->instrs()) {
+      MutableInstrToId[&MI] = Id;
+      if (!computeMode() || !MI.isPHI())
+        ++Id;
+    }
+  }
+
+  /// Returns MI's instruction Id. It renumbers (part of) the BB if MI is not
+  /// found in the map.
+  InstrIdTy getInstrId(const MachineInstr *MI) const {
+    auto It = InstrToId.find(MI);
+    if (It != InstrToId.end())
+      return It->second;
+
+    // Renumber the MBB.
+    // TODO: Renumber from MI onwards.
+    auto &MutableInstrToId = const_cast<InstrToIdMap &>(InstrToId);
+    calcInstrIds(MI->getParent(), MutableInstrToId);
+    return InstrToId.find(MI)->second;
+  }
+
+  // Length of the segment from MI (inclusive) to the first instruction of the
+  // basic block.
+  InstrIdTy getHeadLen(const MachineInstr *MI) const {
+    const MachineBasicBlock *MBB = MI->getParent();
+    return getInstrId(MI) + getInstrId(&MBB->instr_front()) + 1;
+  }
+
+  // Length of the segment from MI (exclusive) to the last instruction of the
+  // basic block.
+  InstrIdTy getTailLen(const MachineInstr *MI) const {
+    const MachineBasicBlock *MBB = MI->getParent();
+    return getInstrId(&MBB->instr_back()) - getInstrId(MI);
+  }
+
+  // Length of the segment from 'From' to 'To' (exclusive). Both instructions
+  // must be in the same basic block.
+  InstrIdTy getDistance(const MachineInstr *From,
+                        const MachineInstr *To) const {
+    assert(From->getParent() == To->getParent());
+    return getInstrId(To) - getInstrId(From);
+  }
+
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // RegUses - cache of uses by register
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+private:
+  DenseMap<Register, SmallVector<const MachineOperand *>> RegUseMap;
+
+  const SmallVector<const MachineOperand *> &getRegisterUses(Register Reg) {
+    auto I = RegUseMap.find(Reg);
+    if (I != RegUseMap.end())
+      return I->second;
+
+    SmallVector<const MachineOperand *> &Uses = RegUseMap[Reg];
+    for (const MachineOperand &UseMO : MRI->use_nodbg_operands(Reg)) {
+      if (!UseMO.isUndef())
+        Uses.push_back(&UseMO);
+    }
+    return Uses;
+  }
+
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // Paths
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+private:
+  class Path
+      : public std::pair<const MachineBasicBlock *, const MachineBasicBlock *> {
+  public:
+    using Base =
+        std::pair<const MachineBasicBlock *, const MachineBasicBlock *>;
+    using Base::pair;
+    Path(const Base &Pair) : Base(Pair) {};
+
+    const MachineBasicBlock *src() const { return first; }
+    const MachineBasicBlock *dst() const { return second; }
+
+    using DenseMapInfo = llvm::DenseMapInfo<Base>;
+  };
+
+  enum EdgeKind { Back = -1, None = 0, Tree = 1, Forward = 2, Cross = 3 };
+  struct PathInfo {
+    EdgeKind EK;
+    bool Reachable;
+    int ForwardReachable;
+    double LoopWeight;
+    std::optional<double> ShortestDistance;
+    std::optional<double> ShortestUnweightedDistance;
+    InstrIdTy Size;
+
+    bool isBackedge() const { return EK == EdgeKind::Back; }
+
+    bool isForwardReachableSet() const { return 0 <= ForwardReachable; }
+    bool isForwardReachableUnset() const { return ForwardReachable < 0; }
+    bool isForwardReachable() const { return ForwardReachable == 1; }
+    bool isNotForwardReachable() const { return ForwardReachable == 0; }
+  };
+
+  //----------------------------------------------------------------------------
+  // Path Storage - 'Paths' is lazily populated and some members are lazily
+  // computed. All mutations should go through one of the 'initializePathInfo*'
+  // flavors below.
+  //----------------------------------------------------------------------------
+  DenseMap<Path, PathInfo, Path::DenseMapInfo> Paths;
+
+  const PathInfo *maybePathInfoFor(const MachineBasicBlock *From,
+                                   const MachineBasicBlock *To) const {
+    auto I = Paths.find({From, To});
+    return I == Paths.end() ? nullptr : &I->second;
+  }
+
+  PathInfo &getOrInitPathInfo(const MachineBasicBlock *From,
+                              const MachineBasicBlock *To) const {
+    auto *NonConstThis = const_cast<AMDGPUNextUseAnalysisImpl *>(this);
+    auto &MutablePaths = NonConstThis->Paths;
+
+    Path P(From, To);
+    auto [I, Inserted] = MutablePaths.try_emplace(P);
+    if (!Inserted)
+      return I->second;
+
+    bool Reachable = calcIsReachable(P.src(), P.dst());
+
+    // Iterator may have been invalidated by calcIsReachable, so get a fresh
+    // reference to the slot.
+    return NonConstThis->initializePathInfo(MutablePaths.at(P), P,
+                                            EdgeKind::None, Reachable);
+  }
+
+  const PathInfo &pathInfoFor(const MachineBasicBlock *From,
+                              const MachineBasicBlock *To) const {
+    return getOrInitPathInfo(From, To);
+  }
+
+  //----------------------------------------------------------------------------
+  // initializePathInfo* - various flavors of PathInfo initialization. They
+  // (should) always funnel to the first flavor below.
+  //----------------------------------------------------------------------------
+  PathInfo &initializePathInfo(PathInfo &Slot, Path P, EdgeKind EK,
+                               bool Reachable) {
+    Slot.EK = EK;
+    Slot.Reachable = Reachable;
+    Slot.ForwardReachable = EK != EdgeKind::None ? (0 < EK) : -1;
+    Slot.LoopWeight = Slot.Reachable ? calcLoopWeight(P.src(), P.dst()) : 0.0;
+    Slot.Size = P.src() == P.dst() ? calcSize(P.src()) : 0;
+    if (EK != EdgeKind::None)
+      Slot.ShortestUnweightedDistance = 0.0;
+    return Slot;
+  }
+
+  PathInfo &initializePathInfo(Path P, EdgeKind EK, bool Reachable) const {
+    auto *NonConstThis = const_cast<AMDGPUNextUseAnalysisImpl *>(this);
+    auto &MutablePaths = NonConstThis->Paths;
+    return NonConstThis->initializePathInfo(MutablePaths[P], P, EK, Reachable);
+  }
+
+  std::pair<PathInfo *, bool> maybeInitializePathInfo(Path P, EdgeKind EK,
+                                                      bool Reachable) const {
+    auto *NonConstThis = const_cast<AMDGPUNextUseAnalysisImpl *>(this);
+    auto &MutablePaths = NonConstThis->Paths;
+    auto [I, Inserted] = MutablePaths.try_emplace(P);
+    if (Inserted)
+      NonConstThis->initializePathInfo(I->second, P, EK, Reachable);
+    return {&I->second, Inserted};
+  }
+
+  bool initializePathInfoForwardReachable(const MachineBasicBlock *From,
+                                          const MachineBasicBlock *To,
+                                          bool Value) const {
+    PathInfo &Slot = getOrInitPathInfo(From, To);
+    assert(Slot.isForwardReachableUnset());
+    Slot.ForwardReachable = Value;
+    return Value;
+  }
+
+  double initializePathInfoShortestDistance(const MachineBasicBlock *From,
+                                            const MachineBasicBlock *To,
+                                            double Value) const {
+    PathInfo &Slot = getOrInitPathInfo(From, To);
+    assert(!Slot.ShortestDistance.has_value());
+    Slot.ShortestDistance = Value;
+    return Value;
+  }
+
+  double
+  initializePathInfoShortestUnweightedDistance(const MachineBasicBlock *From,
+                                               const MachineBasicBlock *To,
+                                               double Value) const {
+    PathInfo &Slot = getOrInitPathInfo(From, To);
+    assert(!Slot.ShortestUnweightedDistance.has_value());
+    Slot.ShortestUnweightedDistance = Value;
+    return Value;
+  }
+
+  //----------------------------------------------------------------------------
+  // initialize*Paths
+  //----------------------------------------------------------------------------
+private:
+  void initializePaths(const SmallVector<Path> &ReachablePaths,
+                       const SmallVector<Path> &UnreachablePaths) const {
+    for (bool R : {true, false}) {
+      const auto &ToInit = R ? ReachablePaths : UnreachablePaths;
+      for (const Path &P : ToInit)
+        initializePathInfo(P, EdgeKind::None, R);
+    }
+  }
+
+  void
+  initializeForwardOnlyPaths(const SmallVector<Path> &ReachablePaths,
+                             const SmallVector<Path> &UnreachablePaths) const {
+    for (bool R : {true, false}) {
+      const auto &ToInit = R ? ReachablePaths : UnreachablePaths;
+      for (const Path &P : ToInit) {
+        PathInfo &Slot = getOrInitPathInfo(P.src(), P.dst());
+        assert(Slot.isForwardReachableUnset() || Slot.ForwardReachable == R);
+        Slot.ForwardReachable = R;
+      }
+    }
+  }
+
+  // Follow the control flow graph starting at the entry block until all blocks
+  // have been visited. Along the way, initialize the PathInfo for each edge
+  // traversed.
+  void initializeCfgPaths() {
+    Paths.clear();
+
+    int LastOrdinal = 0;
+    struct Ordinals {
+      int Discovered;
+      int Visited;
+      int Finished;
+    };
+    DenseMap<const MachineBasicBlock *, Ordinals> OrdFor;
+
+    SmallVector<const MachineBasicBlock *> Work{&MF->front()};
+    OrdFor[&MF->front()].Discovered = ++LastOrdinal;
+
+    while (!Work.empty()) {
+
+      const MachineBasicBlock *Src = Work.back();
+      Ordinals &SrcOrd = OrdFor[Src];
+
+      if (SrcOrd.Visited) {
+        Work.pop_back();
+        SrcOrd.Finished = ++LastOrdinal;
+        continue;
+      }
+
+      SrcOrd.Vis...
[truncated]

@macurtis-amd
macurtis-amd requested review from kmitropoulou, kzhuravl and linuxrocks123 and removed request for linuxrocks123 March 13, 2026 16:46
@kmitropoulou

Copy link
Copy Markdown
Contributor

LGTM

* Replaced `double` distance values with a class - `NextUseDistance`. And then
  replaced double representation with int64_t which included changing how loop
  weights are encoded/computed.

* Minor fixes to distance calculations uncovered by the change in distance
  representation.

* Regenerated test MIR CHECKs based on new distance values.

* Removed unneeded `EdgeKind`s and simplified `initializeCfgPaths`.

* Updated test MIR so that virtual register numbering matches what the analysis
  pass sees.
* Add cache support in graphics mode
* Minor cleanup
Address feedback from Konstantina.

* Distance cache cleanup/improvements:
  - Add `-amdgpu-next-use-analysis-distance-cache` option.
  - Add `resetDistanceCache()`.
  - Prefix data member names with `DistanceCache`.
  - Add hit/miss tracking and reporting.

* Make `getRegisterUses` `const`.

* Rename `LoopExits` to `RelativeLoopDepth`.

* Minor rework of `calcRelativeLoopDepth` for clarity.

* Simplify calculation of Inter-block distances by removing negative seeding.

* Fix DFS bug fix in `initializeCfgPaths`.

* Add `print`/`dump` methods for all key data structures.

* Add `LLVM_DEBUG` hooks.

* Add test files two new tests:
  - `acyclic-014bb.mir` — CFG that triggered the DFS bug
  - `acyclic-770bb.mir` — new larger acyclic test case

* Other minor changes as requested.
* Replace graphics/compute mode with finer-grained semantic config
  options. However, for now, the only valid permutations of the config options
  correspond to the 'graphics' and 'compute' presets.

* Fix an issue in 'graphics' mode where distance values that were intended to
  remain equal when entering a loop were not. This was caused by the change to
  loop weight calculation. 'fromLoopDepth' was no longer multiplicative,
  f(a+b) != f(a) * f(b), but other distance calculation code assumed it was so.

* Fix a few minor issues in calculating through-loop distances.

* Address other minor review comments.

* Regenerate test MIR CHECKs based on new distance values.
@macurtis-amd
macurtis-amd force-pushed the next-use-analysis-003 branch from 39292dc to 75a54c7 Compare April 16, 2026 11:30
@kmitropoulou

Copy link
Copy Markdown
Contributor

LGTM

@macurtis-amd
macurtis-amd merged commit b9ae015 into llvm:main Apr 16, 2026
13 of 14 checks passed
@llvm-ci

llvm-ci commented Apr 16, 2026

Copy link
Copy Markdown

LLVM Buildbot has detected a new failure on builder intel-sycl-gpu running on intel-sycl-gpu-01 while building llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/225/builds/6067

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'libomptarget :: x86_64-unknown-linux-gnu :: mapping/map_ordering_tgt_exit_data_delete_from.c' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/clang -fopenmp    -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src  -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib  -fopenmp-targets=x86_64-unknown-linux-gnu /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test/mapping/map_ordering_tgt_exit_data_delete_from.c -o /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload/test/x86_64-unknown-linux-gnu/mapping/Output/map_ordering_tgt_exit_data_delete_from.c.tmp && /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload/test/x86_64-unknown-linux-gnu/mapping/Output/map_ordering_tgt_exit_data_delete_from.c.tmp | /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/FileCheck /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test/mapping/map_ordering_tgt_exit_data_delete_from.c
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/clang -fopenmp -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./lib -fopenmp-targets=x86_64-unknown-linux-gnu /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test/mapping/map_ordering_tgt_exit_data_delete_from.c -o /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload/test/x86_64-unknown-linux-gnu/mapping/Output/map_ordering_tgt_exit_data_delete_from.c.tmp
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/offload/test/x86_64-unknown-linux-gnu/mapping/Output/map_ordering_tgt_exit_data_delete_from.c.tmp
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/FileCheck /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test/mapping/map_ordering_tgt_exit_data_delete_from.c
# .---command stderr------------
# | /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test/mapping/map_ordering_tgt_exit_data_delete_from.c:13:43: error: CHECK-NOT: excluded string found in input
# |  printf("In tgt: %d\n", x); // CHECK-NOT: In tgt: 111
# |                                           ^
# | <stdin>:1:1: note: found here
# | In tgt: 1115700000
# | ^~~~~~~~~~~
# | 
# | Input file: <stdin>
# | Check file: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/offload/test/mapping/map_ordering_tgt_exit_data_delete_from.c
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |         1: In tgt: 1115700000 
# | not:13     !~~~~~~~~~~         error: no match expected
# |         2: After tgt exit data: 222 
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

********************


void initializeSIFixVGPRCopiesLegacyPass(PassRegistry &);
extern char &SIFixVGPRCopiesID;

void initializeAMDGPUNextUseAnalysisLegacyPassPass(PassRegistry &);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PassPass

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private:
unsigned sizeOf(const MachineInstr &MI) const {
// When !Cfg.CountPhis, PHIs do not contribute to distances/sizes since they

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should be isTransient

void calcInstrIds(const MachineBasicBlock *BB,
InstrToIdMap &MutableInstrToId) const {
InstrIdTy Id = 0;
for (auto &MI : BB->instrs()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No auto

// TODO: Renumber from MI onwards.
auto &MutableInstrToId = const_cast<InstrToIdMap &>(InstrToId);
calcInstrIds(MI->getParent(), MutableInstrToId);
return InstrToId.find(MI)->second;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double find

// basic block.
InstrIdTy getHeadLen(const MachineInstr *MI) const {
const MachineBasicBlock *MBB = MI->getParent();
return getInstrId(MI) + getInstrId(&MBB->instr_front()) + 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost all of this code is using the wrong iterator. You should be using the default begin/end and ranges instead of instrs* to correctly handle bundles


// Length of the segment from 'From' to 'To' (exclusive). Both instructions
// must be in the same basic block.
InstrIdTy getDistance(const MachineInstr *From,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const references


enum class EdgeKind { Back = -1, None = 0, Forward = 1 };
static constexpr StringRef toString(EdgeKind EK) {
if (EK == EdgeKind::Back)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switch so new entries get a warning

return "none";
}

struct PathInfo {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fields can be reordered for packing size

@arsenm arsenm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still object to having the "compute" and "graphics" modes, and really object to calling them that. They should have algorithmic names

return NextUseDistance(-Value);
}

constexpr NextUseDistance applyLoopWeight() const {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This smells like reinventing BlockFrequencies?

return A -= B;
}

constexpr inline NextUseDistance min(NextUseDistance A, NextUseDistance B) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With operator< implemented std::min should work

alexfh pushed a commit to alexfh/llvm-project that referenced this pull request Apr 18, 2026
Based on
- llvm#156079 and
- llvm#171520

See those PRs for background.

Provides a compatibility mode option
`--amdgpu-next-use-analysis-compatibility-mode` that produces results
that match either PR llvm#156079 (`compute`) or PR llvm#171520 (`graphics`).

Co-authored-by: alex-t <atimofee@amd.com>
Co-authored-by: Konstantina Mitropoulou <KonstantinaMitropoulou@amd.com>

---------

Co-authored-by: Konstantina Mitropoulou <KonstantinaMitropoulou@amd.com>
macurtis-amd added a commit to macurtis-amd/llvm-project that referenced this pull request Apr 20, 2026
macurtis-amd added a commit to macurtis-amd/llvm-project that referenced this pull request Apr 20, 2026
llvm#178873 (comment)
> PassPass

llvm#178873 (comment)
> This probably should be isTransient

llvm#178873 (comment)
> No auto

llvm#178873 (comment)
> switch so new entries get a warning

llvm#178873 (comment)
> With operator< implemented std::min should work
macurtis-amd added a commit to macurtis-amd/llvm-project that referenced this pull request Apr 28, 2026
macurtis-amd added a commit to macurtis-amd/llvm-project that referenced this pull request Apr 28, 2026
llvm#178873 (comment)
> PassPass

llvm#178873 (comment)
> This probably should be isTransient

llvm#178873 (comment)
> No auto

llvm#178873 (comment)
> switch so new entries get a warning

llvm#178873 (comment)
> With operator< implemented std::min should work
macurtis-amd added a commit to macurtis-amd/llvm-project that referenced this pull request Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants