[llvm] [MLGO] Add EvolutionInlineAdvisor (PR #166386)

Hongzheng Chen via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 4 07:42:40 PST 2025


https://github.com/chhzh123 created https://github.com/llvm/llvm-project/pull/166386

This PR adds a new skeleton `EvolutionInlineAdvisor` class that is used for [AlphaEvolve](https://deepmind.google/blog/alphaevolve-a-gemini-powered-coding-agent-for-designing-advanced-algorithms/)-style code evolution.

Users can use `-enable-ml-inliner=evolution` to invoke this mode. By default, the inlining strategy is false, meaning all the functions won't be inlined.

RFC will be provided later.

cc: @mtrofin 

>From e9ba1fef1e2a010844eec2d295a6d70ce10c7e57 Mon Sep 17 00:00:00 2001
From: chhzh123 <hc676 at cornell.edu>
Date: Tue, 4 Nov 2025 15:35:30 +0000
Subject: [PATCH] Add EvolutionInlineAdvisor

---
 .../llvm/Analysis/EvolutionInlineAdvisor.h    | 35 ++++++++++
 llvm/include/llvm/Analysis/InlineAdvisor.h    |  7 +-
 llvm/lib/Analysis/CMakeLists.txt              |  1 +
 llvm/lib/Analysis/EvolutionInlineAdvisor.cpp  | 64 +++++++++++++++++++
 llvm/lib/Analysis/InlineAdvisor.cpp           |  5 ++
 llvm/lib/Passes/PassBuilderPipelines.cpp      |  4 +-
 .../Transforms/Inline/ML/default-evolution.ll | 20 ++++++
 .../gn/secondary/llvm/lib/Analysis/BUILD.gn   |  1 +
 8 files changed, 135 insertions(+), 2 deletions(-)
 create mode 100644 llvm/include/llvm/Analysis/EvolutionInlineAdvisor.h
 create mode 100644 llvm/lib/Analysis/EvolutionInlineAdvisor.cpp
 create mode 100644 llvm/test/Transforms/Inline/ML/default-evolution.ll

diff --git a/llvm/include/llvm/Analysis/EvolutionInlineAdvisor.h b/llvm/include/llvm/Analysis/EvolutionInlineAdvisor.h
new file mode 100644
index 0000000000000..9c797e4ec1ca3
--- /dev/null
+++ b/llvm/include/llvm/Analysis/EvolutionInlineAdvisor.h
@@ -0,0 +1,35 @@
+//===- EvolutionInlineAdvisor.h - LLM+Evolution-based InlineAdvisor factories
+//---*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_EvolutionInlineAdvisor_H
+#define LLVM_ANALYSIS_EvolutionInlineAdvisor_H
+
+#include "llvm/Analysis/FunctionPropertiesAnalysis.h"
+#include "llvm/Analysis/InlineAdvisor.h"
+#include "llvm/Analysis/LazyCallGraph.h"
+#include "llvm/IR/PassManager.h"
+
+#include <memory>
+
+namespace llvm {
+
+class EvolutionInlineAdvisor : public InlineAdvisor {
+public:
+  EvolutionInlineAdvisor(Module &M, FunctionAnalysisManager &FAM,
+                         InlineContext IC)
+      : InlineAdvisor(M, FAM, IC) {}
+
+private:
+  std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) override;
+  std::unique_ptr<InlineAdvice> getEvolutionAdviceImpl(CallBase &CB);
+};
+
+} // namespace llvm
+
+#endif // LLVM_ANALYSIS_EvolutionInlineAdvisor_H
\ No newline at end of file
diff --git a/llvm/include/llvm/Analysis/InlineAdvisor.h b/llvm/include/llvm/Analysis/InlineAdvisor.h
index 50ba3c13da70f..b0380635b920d 100644
--- a/llvm/include/llvm/Analysis/InlineAdvisor.h
+++ b/llvm/include/llvm/Analysis/InlineAdvisor.h
@@ -40,7 +40,12 @@ struct ReplayInlinerSettings;
 /// also permits generating training logs, for offline training.
 ///
 /// - Dynamically load an advisor via a plugin (PluginInlineAdvisorAnalysis)
-enum class InliningAdvisorMode : int { Default, Release, Development };
+enum class InliningAdvisorMode : int {
+  Default,
+  Release,
+  Development,
+  Evolution
+};
 
 // Each entry represents an inline driver.
 enum class InlinePass : int {
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 16dd6f8b86006..46a31af4725da 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -74,6 +74,7 @@ add_llvm_component_library(LLVMAnalysis
   DXILResource.cpp
   DXILMetadataAnalysis.cpp
   EphemeralValuesCache.cpp
+  EvolutionInlineAdvisor.cpp
   FloatingPointPredicateUtils.cpp
   FunctionPropertiesAnalysis.cpp
   GlobalsModRef.cpp
diff --git a/llvm/lib/Analysis/EvolutionInlineAdvisor.cpp b/llvm/lib/Analysis/EvolutionInlineAdvisor.cpp
new file mode 100644
index 0000000000000..b99134b42fef9
--- /dev/null
+++ b/llvm/lib/Analysis/EvolutionInlineAdvisor.cpp
@@ -0,0 +1,64 @@
+//-------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements EvolutionInlineAdvisor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/EvolutionInlineAdvisor.h"
+#include "llvm/Analysis/InlineAdvisor.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+// EVOLVE-BLOCK-START
+// You can include additional LLVM headers here.
+
+std::unique_ptr<InlineAdvice>
+EvolutionInlineAdvisor::getEvolutionAdviceImpl(CallBase &CB) {
+  // Implementation of inlining strategy. Do not change the function interface.
+  bool IsInliningRecommended = false;
+  return std::make_unique<InlineAdvice>(
+      this, CB,
+      FAM.getResult<OptimizationRemarkEmitterAnalysis>(*CB.getCaller()),
+      IsInliningRecommended);
+}
+
+// EVOLVE-BLOCK-END
+
+std::unique_ptr<InlineAdvice>
+EvolutionInlineAdvisor::getAdviceImpl(CallBase &CB) {
+  // legality check
+  // reference: MLInlineAdvisor::getAdviceImpl
+  auto &Caller = *CB.getCaller();
+  auto &Callee = *CB.getCalledFunction();
+  auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller);
+
+  auto MandatoryKind = InlineAdvisor::getMandatoryKind(CB, FAM, ORE);
+  // If this is a "never inline" case, there won't be any changes to internal
+  // state we need to track, so we can just return the base InlineAdvice, which
+  // will do nothing interesting.
+  // Same thing if this is a recursive case.
+  if (MandatoryKind == InlineAdvisor::MandatoryInliningKind::Never ||
+      &Caller == &Callee)
+    return getMandatoryAdvice(CB, false);
+
+  auto IsViable = isInlineViable(Callee);
+  if (!IsViable.isSuccess())
+    return std::make_unique<InlineAdvice>(this, CB, ORE, false);
+
+  bool Mandatory =
+      MandatoryKind == InlineAdvisor::MandatoryInliningKind::Always;
+
+  if (Mandatory)
+    return std::make_unique<InlineAdvice>(this, CB, ORE, true);
+
+  return getEvolutionAdviceImpl(CB);
+}
diff --git a/llvm/lib/Analysis/InlineAdvisor.cpp b/llvm/lib/Analysis/InlineAdvisor.cpp
index 0fa804f2959e8..48053161ff32e 100644
--- a/llvm/lib/Analysis/InlineAdvisor.cpp
+++ b/llvm/lib/Analysis/InlineAdvisor.cpp
@@ -14,6 +14,7 @@
 #include "llvm/Analysis/InlineAdvisor.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/EvolutionInlineAdvisor.h"
 #include "llvm/Analysis/AssumptionCache.h"
 #include "llvm/Analysis/EphemeralValuesCache.h"
 #include "llvm/Analysis/IR2Vec.h"
@@ -270,6 +271,10 @@ bool InlineAdvisorAnalysis::Result::tryCreate(
       return false;
     Advisor = llvm::getReleaseModeAdvisor(M, MAM, GetDefaultAdvice);
     break;
+  case InliningAdvisorMode::Evolution:
+    LLVM_DEBUG(dbgs() << "Using evolution-mode inliner policy.\n");
+    Advisor.reset(new EvolutionInlineAdvisor(M, FAM, IC));
+    break;
   }
 
   return !!Advisor;
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index bd03ac090721c..51f26e219f3fd 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -160,7 +160,9 @@ static cl::opt<InliningAdvisorMode> UseInlineAdvisor(
                clEnumValN(InliningAdvisorMode::Development, "development",
                           "Use development mode (runtime-loadable model)"),
                clEnumValN(InliningAdvisorMode::Release, "release",
-                          "Use release mode (AOT-compiled model)")));
+                          "Use release mode (AOT-compiled model)"),
+               clEnumValN(InliningAdvisorMode::Evolution, "evolution",
+                          "Use evolution mode (AlphaEvolve-like framework)")));
 
 /// Flag to enable inline deferral during PGO.
 static cl::opt<bool>
diff --git a/llvm/test/Transforms/Inline/ML/default-evolution.ll b/llvm/test/Transforms/Inline/ML/default-evolution.ll
new file mode 100644
index 0000000000000..81d16deeebbaf
--- /dev/null
+++ b/llvm/test/Transforms/Inline/ML/default-evolution.ll
@@ -0,0 +1,20 @@
+; RUN: opt -passes='default<O3>' \
+; RUN:   -S -enable-ml-inliner=evolution < %s 2>&1 | FileCheck %s
+
+declare i32 @f1()
+
+define i32 @f2() {
+    ret i32 1
+}
+
+define i32 @f3() {
+    %a = call i32 @f1()
+    %b = call i32 @f2()
+    %c = add i32 %a, %b
+    ret i32 %c
+}
+
+; all the functions are not inlined by default
+; CHECK-LABEL: @f1
+; CHECK-LABEL: @f2
+; CHECK-LABEL: @f3
\ No newline at end of file
diff --git a/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn
index ab25c263095fa..6cb46067d7c8c 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn
@@ -53,6 +53,7 @@ static_library("Analysis") {
     "DomTreeUpdater.cpp",
     "DominanceFrontier.cpp",
     "EphemeralValuesCache.cpp",
+    "EvolutionInlineAdvisor.cpp",
     "FloatingPointPredicateUtils.cpp",
     "FunctionPropertiesAnalysis.cpp",
     "GlobalsModRef.cpp",



More information about the llvm-commits mailing list