[llvm] [IR][NFC] Avoid unneccessary move of analysis results (PR #210540)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 18 13:03:50 PDT 2026


https://github.com/aengelke created https://github.com/llvm/llvm-project/pull/210540

While benchmarking CycleAnalysis, I noticed that each analysis result is
constructed on the stack first and then moved to its final place on the
heap. This is unnecessary -- directly construct the analysis result in
its final place. Consequently, analysis results can be immovable.


>From b0be6ec9e83dbe639d402cd58b2c8136ceeef64e Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Sat, 18 Jul 2026 20:03:11 +0000
Subject: [PATCH] [spr] initial version

Created using spr 1.3.8-wip
---
 llvm/include/llvm/IR/PassManagerInternal.h | 45 ++++++----------------
 llvm/unittests/IR/PassManagerTest.cpp      |  5 +++
 2 files changed, 17 insertions(+), 33 deletions(-)

diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h
index 376dcd7d3af62..ba1f717fd76b1 100644
--- a/llvm/include/llvm/IR/PassManagerInternal.h
+++ b/llvm/include/llvm/IR/PassManagerInternal.h
@@ -226,22 +226,11 @@ template <typename IRUnitT, typename PassT, typename ResultT,
           typename InvalidatorT>
 struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, false>
     : AnalysisResultConcept<IRUnitT, InvalidatorT> {
-  explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
-  // We have to explicitly define all the special member functions because MSVC
-  // refuses to generate them.
-  AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
-  AnalysisResultModel(AnalysisResultModel &&Arg)
-      : Result(std::move(Arg.Result)) {}
-
-  friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
-    using std::swap;
-    swap(LHS.Result, RHS.Result);
-  }
-
-  AnalysisResultModel &operator=(AnalysisResultModel RHS) {
-    swap(*this, RHS);
-    return *this;
-  }
+  template <typename... ExtraArgTs>
+  AnalysisResultModel(PassT &Pass, IRUnitT &IR,
+                      AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
+                      ExtraArgTs &&...ExtraArgs)
+      : Result(Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)) {}
 
   /// The model bases invalidation solely on being in the preserved set.
   //
@@ -264,22 +253,11 @@ template <typename IRUnitT, typename PassT, typename ResultT,
           typename InvalidatorT>
 struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, true>
     : AnalysisResultConcept<IRUnitT, InvalidatorT> {
-  explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
-  // We have to explicitly define all the special member functions because MSVC
-  // refuses to generate them.
-  AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
-  AnalysisResultModel(AnalysisResultModel &&Arg)
-      : Result(std::move(Arg.Result)) {}
-
-  friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
-    using std::swap;
-    swap(LHS.Result, RHS.Result);
-  }
-
-  AnalysisResultModel &operator=(AnalysisResultModel RHS) {
-    swap(*this, RHS);
-    return *this;
-  }
+  template <typename... ExtraArgTs>
+  AnalysisResultModel(PassT &Pass, IRUnitT &IR,
+                      AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
+                      ExtraArgTs &&...ExtraArgs)
+      : Result(Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)) {}
 
   /// The model delegates to the \c ResultT method.
   bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
@@ -344,8 +322,9 @@ struct AnalysisPassModel
   std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
       ExtraArgTs... ExtraArgs) override {
+    // Call Pass.run in constructor to avoid move of analysis result.
     return std::make_unique<ResultModelT>(
-        Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...));
+        Pass, IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...);
   }
 
   /// The model delegates to a static \c PassT::name method.
diff --git a/llvm/unittests/IR/PassManagerTest.cpp b/llvm/unittests/IR/PassManagerTest.cpp
index fd4e3c97cb48a..8fd6ecfdfd09b 100644
--- a/llvm/unittests/IR/PassManagerTest.cpp
+++ b/llvm/unittests/IR/PassManagerTest.cpp
@@ -28,6 +28,11 @@ class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {
 public:
   struct Result {
     Result(int Count) : InstructionCount(Count) {}
+
+    // Test that analysis results can be immovable.
+    Result(const Result &) = delete;
+    Result &operator=(const Result &) = delete;
+
     int InstructionCount;
     bool invalidate(Function &, const PreservedAnalyses &PA,
                     FunctionAnalysisManager::Invalidator &) {



More information about the llvm-commits mailing list