[llvm] [Draft] Integrate EmitC-translated MLGO models (PR #209829)
ioana ghiban via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 02:28:23 PDT 2026
https://github.com/ioghiban updated https://github.com/llvm/llvm-project/pull/209829
>From f1714dbc43381a6f02ef39cdc6adf703d0238245 Mon Sep 17 00:00:00 2001
From: Ioana Ghiban <ioana.ghiban at arm.com>
Date: Mon, 13 Jul 2026 17:08:13 +0200
Subject: [PATCH 1/2] Integrate EmitC translated model
---
.../llvm/Analysis/EmitCInlinerSizeModel.h | 82 ++++++
.../llvm/CodeGen/EmitCRegAllocEvictModel.h | 98 +++++++
llvm/lib/Analysis/CMakeLists.txt | 51 ++--
llvm/lib/Analysis/EmitCInlinerSizeModel.cpp | 250 ++++++++++++++++++
llvm/lib/Analysis/MLInlineAdvisor.cpp | 5 +-
llvm/lib/CodeGen/CMakeLists.txt | 17 +-
llvm/lib/CodeGen/EmitCRegAllocEvictModel.cpp | 209 +++++++++++++++
llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp | 7 +-
.../MLRegAlloc/default-eviction-advisor.ll | 1 +
llvm/test/lit.cfg.py | 3 +
llvm/test/lit.site.cfg.py.in | 1 +
11 files changed, 700 insertions(+), 24 deletions(-)
create mode 100644 llvm/include/llvm/Analysis/EmitCInlinerSizeModel.h
create mode 100644 llvm/include/llvm/CodeGen/EmitCRegAllocEvictModel.h
create mode 100644 llvm/lib/Analysis/EmitCInlinerSizeModel.cpp
create mode 100644 llvm/lib/CodeGen/EmitCRegAllocEvictModel.cpp
diff --git a/llvm/include/llvm/Analysis/EmitCInlinerSizeModel.h b/llvm/include/llvm/Analysis/EmitCInlinerSizeModel.h
new file mode 100644
index 0000000000000..63e298e4ce9fa
--- /dev/null
+++ b/llvm/include/llvm/Analysis/EmitCInlinerSizeModel.h
@@ -0,0 +1,82 @@
+//===- EmitCInlinerSizeModel.h - EmitC inliner model wrapper ----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// Declares the wrapper around the EmitC-translated MLGO inliner model.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_ANALYSIS_EMITCINLINERSIZEMODEL_H
+#define LLVM_LIB_ANALYSIS_EMITCINLINERSIZEMODEL_H
+
+#include <array>
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+
+class EmitCInlinerSizeModel final {
+public:
+ int LookupArgIndex(const std::string &Name);
+ int LookupResultIndex(const std::string &Name);
+ void *arg_data(int Index);
+ void *result_data(int Index);
+ void Run();
+
+private:
+ enum ArgIndex : int {
+ DeadBlocks = 0,
+ CaseClusterPenalty,
+ SroaSavings,
+ JumpTablePenalty,
+ CallsiteHeight,
+ CalleeBasicBlockCount,
+ CallArgumentSetup,
+ LoweredCallArgSetup,
+ SimplifiedInstructions,
+ NrCtantParams,
+ IsMultipleBlocks,
+ LoadElimination,
+ EdgeCount,
+ CallerUsers,
+ CallerConditionallyExecutedBlocks,
+ ConstantOffsetPtrArgs,
+ CallsiteCost,
+ CallerBasicBlockCount,
+ LoadRelativeIntrinsic,
+ IndirectCallPenalty,
+ CostEstimate,
+ Threshold,
+ NestedInlineCostEstimate,
+ UnsimplifiedCommonInstructions,
+ SroaLosses,
+ NumLoops,
+ SwitchPenalty,
+ CalleeUsers,
+ NodeCount,
+ ConstantArgs,
+ LastCallToStaticBonus,
+ ColdCCPenalty,
+ CalleeConditionallyExecutedBlocks,
+ CallPenalty,
+ NestedInlines,
+
+ NumArgs
+ };
+
+ std::array<std::array<int64_t, 1>, NumArgs> Inputs{};
+ std::array<int64_t, 1> Result{};
+
+ std::array<int64_t, 1> DummyInliningDefault{};
+ std::array<int32_t, 1> DummyStepType{};
+ std::array<float, 1> DummyDiscount{};
+ std::array<float, 1> DummyReward{};
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/CodeGen/EmitCRegAllocEvictModel.h b/llvm/include/llvm/CodeGen/EmitCRegAllocEvictModel.h
new file mode 100644
index 0000000000000..41a19ec62522e
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/EmitCRegAllocEvictModel.h
@@ -0,0 +1,98 @@
+//===- EmitCRegAllocEvictModel.h - EmitC regalloc model wrapper -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Declares the wrapper around the EmitC-translated MLGO regalloc eviction
+/// model.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_EMITCREGALLOCEVICTMODEL_H
+#define LLVM_CODEGEN_EMITCREGALLOCEVICTMODEL_H
+
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+
+class EmitCRegAllocEvictModel final {
+public:
+ int LookupArgIndex(const std::string &Name);
+ int LookupResultIndex(const std::string &Name);
+ void *arg_data(int Index);
+ void *result_data(int Index);
+ void Run();
+
+private:
+ static constexpr std::size_t InterferenceCount = 33;
+
+ using F32InterferenceTensor = float[1][InterferenceCount];
+ using I64InterferenceTensor = int64_t[1][InterferenceCount];
+ using F32Scalar = float[1];
+ using I32Scalar = int32_t[1];
+ using I64Scalar = int64_t[1];
+
+ enum ArgIndex : int {
+ Mask = 0,
+ IsFree,
+ NrUrgent,
+ NrBrokenHints,
+ IsHint,
+ IsLocal,
+ NrRematerializable,
+ NrDefsAndUses,
+ WeighedReadsByMax,
+ WeighedWritesByMax,
+ WeighedReadWritesByMax,
+ WeighedIndvarsByMax,
+ HintWeightsByMax,
+ StartBBFreqByMax,
+ EndBBFreqByMax,
+ HottestBBFreqByMax,
+ LiverangeSize,
+ UseDefDensity,
+ MaxStage,
+ MinStage,
+ Progress,
+
+ NumArgs
+ };
+
+ I64InterferenceTensor MaskInput{};
+ I64InterferenceTensor IsFreeInput{};
+ F32InterferenceTensor NrUrgentInput{};
+ F32InterferenceTensor NrBrokenHintsInput{};
+ I64InterferenceTensor IsHintInput{};
+ I64InterferenceTensor IsLocalInput{};
+ F32InterferenceTensor NrRematerializableInput{};
+ F32InterferenceTensor NrDefsAndUsesInput{};
+ F32InterferenceTensor WeighedReadsByMaxInput{};
+ F32InterferenceTensor WeighedWritesByMaxInput{};
+ F32InterferenceTensor WeighedReadWritesByMaxInput{};
+ F32InterferenceTensor WeighedIndvarsByMaxInput{};
+ F32InterferenceTensor HintWeightsByMaxInput{};
+ F32InterferenceTensor StartBBFreqByMaxInput{};
+ F32InterferenceTensor EndBBFreqByMaxInput{};
+ F32InterferenceTensor HottestBBFreqByMaxInput{};
+ F32InterferenceTensor LiverangeSizeInput{};
+ F32InterferenceTensor UseDefDensityInput{};
+ I64InterferenceTensor MaxStageInput{};
+ I64InterferenceTensor MinStageInput{};
+ F32Scalar ProgressInput{};
+
+ I32Scalar DummyStepType{};
+ F32Scalar DummyDiscount{};
+ F32Scalar DummyReward{};
+ I64Scalar Result{};
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index f3586c66cb056..474d96df9b619 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -1,26 +1,31 @@
-if (DEFINED LLVM_HAVE_TF_AOT OR LLVM_HAVE_TFLITE)
- include(TensorFlowCompile)
- set(LLVM_INLINER_MODEL_PATH_DEFAULT "models/inliner-Oz")
+option(LLVM_USE_EMITC_INLINER_MODEL
+ "Use the in-tree EmitC inliner model instead of TensorFlow AOT"
+ OFF)
- set(LLVM_INLINER_MODEL_CURRENT_URL "<UNSPECIFIED>" CACHE STRING "URL to download the LLVM inliner model")
+if (LLVM_HAVE_TFLITE)
+ list(APPEND MLLinkDeps
+ tensorflow-lite::tensorflow-lite)
+endif()
- if (DEFINED LLVM_HAVE_TF_AOT)
- tf_find_and_compile(
- ${LLVM_INLINER_MODEL_PATH}
- ${LLVM_INLINER_MODEL_CURRENT_URL}
- ${LLVM_INLINER_MODEL_PATH_DEFAULT}
- "models/gen-inline-oz-test-model.py"
- serve
- action
- InlinerSizeModel
- llvm::InlinerSizeModel
- )
- endif()
+if (LLVM_USE_EMITC_INLINER_MODEL)
+ list(APPEND LLVM_COMPILE_DEFINITIONS
+ LLVM_HAVE_EMITC_INLINERSIZEMODEL)
+elseif (DEFINED LLVM_HAVE_TF_AOT)
+ include(TensorFlowCompile)
+ set(LLVM_INLINER_MODEL_PATH_DEFAULT "models/inliner-Oz")
+ set(LLVM_INLINER_MODEL_CURRENT_URL "<UNSPECIFIED>" CACHE STRING
+ "URL to download the LLVM inliner model")
- if (LLVM_HAVE_TFLITE)
- list(APPEND MLLinkDeps
- tensorflow-lite::tensorflow-lite)
- endif()
+ tf_find_and_compile(
+ ${LLVM_INLINER_MODEL_PATH}
+ ${LLVM_INLINER_MODEL_CURRENT_URL}
+ ${LLVM_INLINER_MODEL_PATH_DEFAULT}
+ "models/gen-inline-oz-test-model.py"
+ serve
+ action
+ InlinerSizeModel
+ llvm::InlinerSizeModel
+ )
endif()
# The implementation of ConstantFolding.cpp relies on the use of math functions
@@ -77,6 +82,7 @@ add_llvm_component_library(LLVMAnalysis
DominanceFrontier.cpp
DXILResource.cpp
DXILMetadataAnalysis.cpp
+ EmitCInlinerSizeModel.cpp
EphemeralValuesCache.cpp
FloatingPointPredicateUtils.cpp
FunctionPropertiesAnalysis.cpp
@@ -187,6 +193,11 @@ add_llvm_component_library(LLVMAnalysis
TargetParser
)
+if (LLVM_USE_EMITC_INLINER_MODEL)
+ target_compile_definitions(LLVMAnalysis
+ PRIVATE LLVM_HAVE_EMITC_INLINERSIZEMODEL)
+endif()
+
include(CheckCXXSymbolExists)
check_cxx_symbol_exists(logf128 math.h HAS_LOGF128)
if(HAS_LOGF128)
diff --git a/llvm/lib/Analysis/EmitCInlinerSizeModel.cpp b/llvm/lib/Analysis/EmitCInlinerSizeModel.cpp
new file mode 100644
index 0000000000000..a8e0094737bd6
--- /dev/null
+++ b/llvm/lib/Analysis/EmitCInlinerSizeModel.cpp
@@ -0,0 +1,250 @@
+//===- EmitCInlinerSizeModel.cpp - EmitC inliner model wrapper ------------===//
+//
+// 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 the wrapper around the EmitC-translated MLGO inliner
+/// model.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/EmitCInlinerSizeModel.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include <math.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <type_traits>
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-braces"
+#endif
+
+namespace llvm::emitc_inliner_model {
+#define main action
+#include "llvm/Analysis/EmitCInlinerSizeModel.inc"
+#undef main
+} // namespace llvm::emitc_inliner_model
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+using namespace llvm;
+
+namespace {
+template <typename T> inline constexpr bool AlwaysFalse = false;
+using I64Ptr = int64_t *;
+using I32Ptr = int32_t *;
+using F32Ptr = float *;
+
+using InlinerProductionActionTy =
+ int64_t (*)(I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I32Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, F32Ptr, I64Ptr, F32Ptr);
+using InlinerMockActionTy = int64_t (*)(I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I32Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, I64Ptr, I64Ptr, I64Ptr,
+ I64Ptr, I64Ptr, F32Ptr, I64Ptr, F32Ptr);
+
+struct InlinerRunInputs {
+ I64Ptr deadBlocks;
+ I64Ptr caseClusterPenalty;
+ I64Ptr sroaSavings;
+ I64Ptr jumpTablePenalty;
+ I64Ptr callsiteHeight;
+ I64Ptr calleeBasicBlockCount;
+ I64Ptr callArgumentSetup;
+ I64Ptr loweredCallArgSetup;
+ I64Ptr simplifiedInstructions;
+ I64Ptr nrCtantParams;
+ I64Ptr isMultipleBlocks;
+ I64Ptr loadElimination;
+ I64Ptr edgeCount;
+ I64Ptr callerUsers;
+ I64Ptr callerConditionallyExecutedBlocks;
+ I64Ptr constantOffsetPtrArgs;
+ I64Ptr callsiteCost;
+ I64Ptr callerBasicBlockCount;
+ I64Ptr loadRelativeIntrinsic;
+ I64Ptr indirectCallPenalty;
+ I64Ptr costEstimate;
+ I64Ptr threshold;
+ I64Ptr nestedInlineCostEstimate;
+ I64Ptr unsimplifiedCommonInstructions;
+ I64Ptr sroaLosses;
+ I64Ptr numLoops;
+ I64Ptr switchPenalty;
+ I64Ptr calleeUsers;
+ I64Ptr nodeCount;
+ I64Ptr constantArgs;
+ I64Ptr lastCallToStaticBonus;
+ I64Ptr coldCCPenalty;
+ I64Ptr calleeConditionallyExecutedBlocks;
+ I64Ptr callPenalty;
+ I64Ptr nestedInlines;
+ I32Ptr dummyStepType;
+ F32Ptr dummyDiscount;
+ F32Ptr dummyReward;
+ I64Ptr dummyInliningDefault;
+};
+
+template <typename ActionTy>
+int64_t runEmitCInlinerAction(const InlinerRunInputs &I) {
+ if constexpr (std::is_same_v<ActionTy, InlinerProductionActionTy>) {
+ return static_cast<ActionTy>(emitc_inliner_model::action)(
+ I.callsiteCost, I.isMultipleBlocks, I.callerConditionallyExecutedBlocks,
+ I.dummyInliningDefault, I.coldCCPenalty,
+ I.calleeConditionallyExecutedBlocks, I.calleeUsers,
+ I.calleeBasicBlockCount, I.nrCtantParams, I.loadRelativeIntrinsic,
+ I.jumpTablePenalty, I.unsimplifiedCommonInstructions,
+ I.indirectCallPenalty, I.loadElimination, I.callPenalty, I.costEstimate,
+ I.caseClusterPenalty, I.nodeCount, I.callArgumentSetup, I.sroaSavings,
+ I.loweredCallArgSetup, I.threshold, I.deadBlocks, I.constantArgs,
+ I.sroaLosses, I.simplifiedInstructions, I.numLoops, I.dummyStepType,
+ I.edgeCount, I.nestedInlines, I.callerBasicBlockCount,
+ I.lastCallToStaticBonus, I.nestedInlineCostEstimate, I.callsiteHeight,
+ I.constantOffsetPtrArgs, I.switchPenalty, I.dummyDiscount,
+ I.callerUsers, I.dummyReward);
+ } else if constexpr (std::is_same_v<ActionTy, InlinerMockActionTy>) {
+ return static_cast<ActionTy>(emitc_inliner_model::action)(
+ I.callerBasicBlockCount, I.callerConditionallyExecutedBlocks,
+ I.callerUsers, I.calleeBasicBlockCount,
+ I.calleeConditionallyExecutedBlocks, I.calleeUsers, I.nrCtantParams,
+ I.nodeCount, I.edgeCount, I.callsiteHeight, I.costEstimate,
+ I.sroaSavings, I.sroaLosses, I.loadElimination, I.callPenalty,
+ I.callArgumentSetup, I.loadRelativeIntrinsic, I.loweredCallArgSetup,
+ I.indirectCallPenalty, I.jumpTablePenalty, I.caseClusterPenalty,
+ I.switchPenalty, I.unsimplifiedCommonInstructions, I.numLoops,
+ I.deadBlocks, I.simplifiedInstructions, I.constantArgs, I.dummyStepType,
+ I.constantOffsetPtrArgs, I.callsiteCost, I.coldCCPenalty,
+ I.lastCallToStaticBonus, I.isMultipleBlocks, I.nestedInlines,
+ I.nestedInlineCostEstimate, I.threshold, I.dummyInliningDefault,
+ I.dummyDiscount, I.callerUsers, I.dummyReward);
+ } else {
+ static_assert(AlwaysFalse<ActionTy>,
+ "Unsupported EmitC inliner model signature");
+ }
+}
+} // namespace
+
+int EmitCInlinerSizeModel::LookupArgIndex(const std::string &Name) {
+ return StringSwitch<int>(Name)
+ .Case("feed_dead_blocks", DeadBlocks)
+ .Case("feed_case_cluster_penalty", CaseClusterPenalty)
+ .Case("feed_sroa_savings", SroaSavings)
+ .Case("feed_jump_table_penalty", JumpTablePenalty)
+ .Case("feed_callsite_height", CallsiteHeight)
+ .Case("feed_callee_basic_block_count", CalleeBasicBlockCount)
+ .Case("feed_call_argument_setup", CallArgumentSetup)
+ .Case("feed_lowered_call_arg_setup", LoweredCallArgSetup)
+ .Case("feed_simplified_instructions", SimplifiedInstructions)
+ .Case("feed_nr_ctant_params", NrCtantParams)
+ .Case("feed_is_multiple_blocks", IsMultipleBlocks)
+ .Case("feed_load_elimination", LoadElimination)
+ .Case("feed_edge_count", EdgeCount)
+ .Case("feed_caller_users", CallerUsers)
+ .Case("feed_caller_conditionally_executed_blocks",
+ CallerConditionallyExecutedBlocks)
+ .Case("feed_constant_offset_ptr_args", ConstantOffsetPtrArgs)
+ .Case("feed_callsite_cost", CallsiteCost)
+ .Case("feed_caller_basic_block_count", CallerBasicBlockCount)
+ .Case("feed_load_relative_intrinsic", LoadRelativeIntrinsic)
+ .Case("feed_indirect_call_penalty", IndirectCallPenalty)
+ .Case("feed_cost_estimate", CostEstimate)
+ .Case("feed_threshold", Threshold)
+ .Case("feed_nested_inline_cost_estimate", NestedInlineCostEstimate)
+ .Case("feed_unsimplified_common_instructions",
+ UnsimplifiedCommonInstructions)
+ .Case("feed_sroa_losses", SroaLosses)
+ .Case("feed_num_loops", NumLoops)
+ .Case("feed_switch_penalty", SwitchPenalty)
+ .Case("feed_callee_users", CalleeUsers)
+ .Case("feed_node_count", NodeCount)
+ .Case("feed_constant_args", ConstantArgs)
+ .Case("feed_last_call_to_static_bonus", LastCallToStaticBonus)
+ .Case("feed_cold_cc_penalty", ColdCCPenalty)
+ .Case("feed_callee_conditionally_executed_blocks",
+ CalleeConditionallyExecutedBlocks)
+ .Case("feed_call_penalty", CallPenalty)
+ .Case("feed_nested_inlines", NestedInlines)
+ .Default(-1);
+}
+
+int EmitCInlinerSizeModel::LookupResultIndex(const std::string &Name) {
+ return Name == "fetch_inlining_decision" ? 0 : -1;
+}
+
+void *EmitCInlinerSizeModel::arg_data(int Index) {
+ if (Index < 0 || Index >= NumArgs)
+ llvm_unreachable("invalid EmitC inliner input index");
+ return Inputs[Index].data();
+}
+
+void *EmitCInlinerSizeModel::result_data(int Index) {
+ if (Index != 0)
+ llvm_unreachable("invalid EmitC inliner result index");
+ return Result.data();
+}
+
+void EmitCInlinerSizeModel::Run() {
+ using ActionTy = decltype(&emitc_inliner_model::action);
+ InlinerRunInputs I{};
+ I.deadBlocks = Inputs[DeadBlocks].data();
+ I.caseClusterPenalty = Inputs[CaseClusterPenalty].data();
+ I.sroaSavings = Inputs[SroaSavings].data();
+ I.jumpTablePenalty = Inputs[JumpTablePenalty].data();
+ I.callsiteHeight = Inputs[CallsiteHeight].data();
+ I.calleeBasicBlockCount = Inputs[CalleeBasicBlockCount].data();
+ I.callArgumentSetup = Inputs[CallArgumentSetup].data();
+ I.loweredCallArgSetup = Inputs[LoweredCallArgSetup].data();
+ I.simplifiedInstructions = Inputs[SimplifiedInstructions].data();
+ I.nrCtantParams = Inputs[NrCtantParams].data();
+ I.isMultipleBlocks = Inputs[IsMultipleBlocks].data();
+ I.loadElimination = Inputs[LoadElimination].data();
+ I.edgeCount = Inputs[EdgeCount].data();
+ I.callerUsers = Inputs[CallerUsers].data();
+ I.callerConditionallyExecutedBlocks =
+ Inputs[CallerConditionallyExecutedBlocks].data();
+ I.constantOffsetPtrArgs = Inputs[ConstantOffsetPtrArgs].data();
+ I.callsiteCost = Inputs[CallsiteCost].data();
+ I.callerBasicBlockCount = Inputs[CallerBasicBlockCount].data();
+ I.loadRelativeIntrinsic = Inputs[LoadRelativeIntrinsic].data();
+ I.indirectCallPenalty = Inputs[IndirectCallPenalty].data();
+ I.costEstimate = Inputs[CostEstimate].data();
+ I.threshold = Inputs[Threshold].data();
+ I.nestedInlineCostEstimate = Inputs[NestedInlineCostEstimate].data();
+ I.unsimplifiedCommonInstructions =
+ Inputs[UnsimplifiedCommonInstructions].data();
+ I.sroaLosses = Inputs[SroaLosses].data();
+ I.numLoops = Inputs[NumLoops].data();
+ I.switchPenalty = Inputs[SwitchPenalty].data();
+ I.calleeUsers = Inputs[CalleeUsers].data();
+ I.nodeCount = Inputs[NodeCount].data();
+ I.constantArgs = Inputs[ConstantArgs].data();
+ I.lastCallToStaticBonus = Inputs[LastCallToStaticBonus].data();
+ I.coldCCPenalty = Inputs[ColdCCPenalty].data();
+ I.calleeConditionallyExecutedBlocks =
+ Inputs[CalleeConditionallyExecutedBlocks].data();
+ I.callPenalty = Inputs[CallPenalty].data();
+ I.nestedInlines = Inputs[NestedInlines].data();
+ I.dummyStepType = DummyStepType.data();
+ I.dummyDiscount = DummyDiscount.data();
+ I.dummyReward = DummyReward.data();
+ I.dummyInliningDefault = DummyInliningDefault.data();
+ Result[0] = runEmitCInlinerAction<ActionTy>(I);
+}
diff --git a/llvm/lib/Analysis/MLInlineAdvisor.cpp b/llvm/lib/Analysis/MLInlineAdvisor.cpp
index 9a5ae2ae26799..e698f066b9336 100644
--- a/llvm/lib/Analysis/MLInlineAdvisor.cpp
+++ b/llvm/lib/Analysis/MLInlineAdvisor.cpp
@@ -64,7 +64,10 @@ static cl::opt<std::string> ModelSelector("ml-inliner-model-selector",
static cl::opt<bool> StopImmediatelyForTest("ml-inliner-stop-immediately",
cl::Hidden);
-#if defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL)
+#if defined(LLVM_HAVE_EMITC_INLINERSIZEMODEL)
+#include "llvm/Analysis/EmitCInlinerSizeModel.h"
+using CompiledModelType = llvm::EmitCInlinerSizeModel;
+#elif defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL)
// codegen-ed file
#include "InlinerSizeModel.h" // NOLINT
using CompiledModelType = llvm::InlinerSizeModel;
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index c572128b023c1..bf05ca6d7cb19 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -1,10 +1,19 @@
+option(LLVM_USE_EMITC_REGALLOC_EVICT_MODEL
+ "Use the in-tree EmitC regalloc eviction model instead of TensorFlow AOT"
+ OFF)
+
+if (LLVM_USE_EMITC_REGALLOC_EVICT_MODEL)
+ list(APPEND LLVM_COMPILE_DEFINITIONS
+ LLVM_HAVE_EMITC_REGALLOCEVICTMODEL)
+endif()
+
if (DEFINED LLVM_HAVE_TF_AOT OR LLVM_HAVE_TFLITE)
include(TensorFlowCompile)
set(LLVM_RAEVICT_MODEL_PATH_DEFAULT "models/regalloc-eviction")
set(LLVM_RAEVICT_MODEL_CURRENT_URL "<UNSPECIFIED>" CACHE STRING "URL to download the LLVM register allocator eviction model")
- if (DEFINED LLVM_HAVE_TF_AOT)
+ if (DEFINED LLVM_HAVE_TF_AOT AND NOT LLVM_USE_EMITC_REGALLOC_EVICT_MODEL)
tf_find_and_compile(
${LLVM_RAEVICT_MODEL_PATH}
${LLVM_RAEVICT_MODEL_CURRENT_URL}
@@ -53,6 +62,7 @@ add_llvm_component_library(LLVMCodeGen
DroppedVariableStatsMIR.cpp
DwarfEHPrepare.cpp
EarlyIfConversion.cpp
+ EmitCRegAllocEvictModel.cpp
EdgeBundles.cpp
EHContGuardTargets.cpp
ExecutionDomainFix.cpp
@@ -295,6 +305,11 @@ add_llvm_component_library(LLVMCodeGen
TransformUtils
)
+if (LLVM_USE_EMITC_REGALLOC_EVICT_MODEL)
+ target_compile_definitions(LLVMCodeGen
+ PRIVATE LLVM_HAVE_EMITC_REGALLOCEVICTMODEL)
+endif()
+
add_subdirectory(SelectionDAG)
add_subdirectory(AsmPrinter)
add_subdirectory(MIRParser)
diff --git a/llvm/lib/CodeGen/EmitCRegAllocEvictModel.cpp b/llvm/lib/CodeGen/EmitCRegAllocEvictModel.cpp
new file mode 100644
index 0000000000000..120268ec1f389
--- /dev/null
+++ b/llvm/lib/CodeGen/EmitCRegAllocEvictModel.cpp
@@ -0,0 +1,209 @@
+//===- EmitCRegAllocEvictModel.cpp - EmitC regalloc model wrapper ---------===//
+//
+// 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 the wrapper around the EmitC-translated MLGO
+/// regalloc eviction model.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/EmitCRegAllocEvictModel.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+namespace llvm::emitc_regalloc_evict_model {
+#define main action
+#include "llvm/CodeGen/EmitCRegAllocEvictModel.inc"
+#undef main
+} // namespace llvm::emitc_regalloc_evict_model
+
+using namespace llvm;
+
+namespace {
+template <typename T> inline constexpr bool AlwaysFalse = false;
+constexpr std::size_t EmitCRegAllocInterferenceCount = 33;
+using F32TensorPtr = float (*)[EmitCRegAllocInterferenceCount];
+using I64TensorPtr = int64_t (*)[EmitCRegAllocInterferenceCount];
+using F32ScalarPtr = float *;
+using I32ScalarPtr = int32_t *;
+using I64ScalarPtr = int64_t *;
+
+using RegAllocProductionActionTy = int64_t (*)(
+ F32TensorPtr, F32TensorPtr, I64TensorPtr, F32TensorPtr, F32TensorPtr,
+ F32TensorPtr, F32ScalarPtr, F32TensorPtr, F32TensorPtr, F32TensorPtr,
+ I64TensorPtr, I64TensorPtr, F32TensorPtr, F32TensorPtr, I32ScalarPtr,
+ F32TensorPtr, I64TensorPtr, F32TensorPtr, I64TensorPtr, F32TensorPtr,
+ F32ScalarPtr, F32TensorPtr, I64TensorPtr, F32ScalarPtr);
+using RegAllocMaskOnlyActionTy = int64_t (*)(I64ScalarPtr);
+
+struct RegAllocRunInputs {
+ F32TensorPtr liverangeSize;
+ F32TensorPtr hintWeightsByMax;
+ I64TensorPtr isFree;
+ F32TensorPtr weighedReadsByMax;
+ F32TensorPtr weighedReadWritesByMax;
+ F32TensorPtr nrBrokenHints;
+ F32ScalarPtr progress;
+ F32TensorPtr hottestBBFreqByMax;
+ F32TensorPtr useDefDensity;
+ F32TensorPtr startBBFreqByMax;
+ I64TensorPtr maxStage;
+ I64TensorPtr isHint;
+ F32TensorPtr nrRematerializable;
+ F32TensorPtr weighedWritesByMax;
+ I32ScalarPtr dummyStepType;
+ F32TensorPtr nrUrgent;
+ I64TensorPtr mask;
+ F32TensorPtr nrDefsAndUses;
+ I64TensorPtr isLocal;
+ F32TensorPtr endBBFreqByMax;
+ F32ScalarPtr dummyDiscount;
+ F32TensorPtr weighedIndvarsByMax;
+ I64TensorPtr minStage;
+ F32ScalarPtr dummyReward;
+ I64ScalarPtr maskFlat;
+};
+
+template <typename ActionTy>
+int64_t runEmitCRegAllocAction(const RegAllocRunInputs &I) {
+ if constexpr (std::is_same_v<ActionTy, RegAllocProductionActionTy>) {
+ return static_cast<ActionTy>(emitc_regalloc_evict_model::action)(
+ I.liverangeSize, I.hintWeightsByMax, I.isFree, I.weighedReadsByMax,
+ I.weighedReadWritesByMax, I.nrBrokenHints, I.progress,
+ I.hottestBBFreqByMax, I.useDefDensity, I.startBBFreqByMax, I.maxStage,
+ I.isHint, I.nrRematerializable, I.weighedWritesByMax, I.dummyStepType,
+ I.nrUrgent, I.mask, I.nrDefsAndUses, I.isLocal, I.endBBFreqByMax,
+ I.dummyDiscount, I.weighedIndvarsByMax, I.minStage, I.dummyReward);
+ } else if constexpr (std::is_same_v<ActionTy, RegAllocMaskOnlyActionTy>) {
+ return static_cast<ActionTy>(emitc_regalloc_evict_model::action)(
+ I.maskFlat);
+ } else {
+ static_assert(AlwaysFalse<ActionTy>,
+ "Unsupported EmitC regalloc eviction model signature");
+ }
+}
+} // namespace
+
+int EmitCRegAllocEvictModel::LookupArgIndex(const std::string &Name) {
+ return StringSwitch<int>(Name)
+ .Case("feed_mask", Mask)
+ .Case("feed_is_free", IsFree)
+ .Case("feed_nr_urgent", NrUrgent)
+ .Case("feed_nr_broken_hints", NrBrokenHints)
+ .Case("feed_is_hint", IsHint)
+ .Case("feed_is_local", IsLocal)
+ .Case("feed_nr_rematerializable", NrRematerializable)
+ .Case("feed_nr_defs_and_uses", NrDefsAndUses)
+ .Case("feed_weighed_reads_by_max", WeighedReadsByMax)
+ .Case("feed_weighed_writes_by_max", WeighedWritesByMax)
+ .Case("feed_weighed_read_writes_by_max", WeighedReadWritesByMax)
+ .Case("feed_weighed_indvars_by_max", WeighedIndvarsByMax)
+ .Case("feed_hint_weights_by_max", HintWeightsByMax)
+ .Case("feed_start_bb_freq_by_max", StartBBFreqByMax)
+ .Case("feed_end_bb_freq_by_max", EndBBFreqByMax)
+ .Case("feed_hottest_bb_freq_by_max", HottestBBFreqByMax)
+ .Case("feed_liverange_size", LiverangeSize)
+ .Case("feed_use_def_density", UseDefDensity)
+ .Case("feed_max_stage", MaxStage)
+ .Case("feed_min_stage", MinStage)
+ .Case("feed_progress", Progress)
+ .Default(-1);
+}
+
+int EmitCRegAllocEvictModel::LookupResultIndex(const std::string &Name) {
+ return Name == "fetch_index_to_evict" ? 0 : -1;
+}
+
+void *EmitCRegAllocEvictModel::arg_data(int Index) {
+ switch (Index) {
+ case Mask:
+ return MaskInput;
+ case IsFree:
+ return IsFreeInput;
+ case NrUrgent:
+ return NrUrgentInput;
+ case NrBrokenHints:
+ return NrBrokenHintsInput;
+ case IsHint:
+ return IsHintInput;
+ case IsLocal:
+ return IsLocalInput;
+ case NrRematerializable:
+ return NrRematerializableInput;
+ case NrDefsAndUses:
+ return NrDefsAndUsesInput;
+ case WeighedReadsByMax:
+ return WeighedReadsByMaxInput;
+ case WeighedWritesByMax:
+ return WeighedWritesByMaxInput;
+ case WeighedReadWritesByMax:
+ return WeighedReadWritesByMaxInput;
+ case WeighedIndvarsByMax:
+ return WeighedIndvarsByMaxInput;
+ case HintWeightsByMax:
+ return HintWeightsByMaxInput;
+ case StartBBFreqByMax:
+ return StartBBFreqByMaxInput;
+ case EndBBFreqByMax:
+ return EndBBFreqByMaxInput;
+ case HottestBBFreqByMax:
+ return HottestBBFreqByMaxInput;
+ case LiverangeSize:
+ return LiverangeSizeInput;
+ case UseDefDensity:
+ return UseDefDensityInput;
+ case MaxStage:
+ return MaxStageInput;
+ case MinStage:
+ return MinStageInput;
+ case Progress:
+ return ProgressInput;
+ }
+ llvm_unreachable("invalid EmitC regalloc eviction input index");
+}
+
+void *EmitCRegAllocEvictModel::result_data(int Index) {
+ if (Index != 0)
+ llvm_unreachable("invalid EmitC regalloc eviction result index");
+ return Result;
+}
+
+void EmitCRegAllocEvictModel::Run() {
+ using ActionTy = decltype(&emitc_regalloc_evict_model::action);
+ RegAllocRunInputs I{};
+ I.liverangeSize = LiverangeSizeInput;
+ I.hintWeightsByMax = HintWeightsByMaxInput;
+ I.isFree = IsFreeInput;
+ I.weighedReadsByMax = WeighedReadsByMaxInput;
+ I.weighedReadWritesByMax = WeighedReadWritesByMaxInput;
+ I.nrBrokenHints = NrBrokenHintsInput;
+ I.progress = ProgressInput;
+ I.hottestBBFreqByMax = HottestBBFreqByMaxInput;
+ I.useDefDensity = UseDefDensityInput;
+ I.startBBFreqByMax = StartBBFreqByMaxInput;
+ I.maxStage = MaxStageInput;
+ I.isHint = IsHintInput;
+ I.nrRematerializable = NrRematerializableInput;
+ I.weighedWritesByMax = WeighedWritesByMaxInput;
+ I.dummyStepType = DummyStepType;
+ I.nrUrgent = NrUrgentInput;
+ I.mask = MaskInput;
+ I.nrDefsAndUses = NrDefsAndUsesInput;
+ I.isLocal = IsLocalInput;
+ I.endBBFreqByMax = EndBBFreqByMaxInput;
+ I.dummyDiscount = DummyDiscount;
+ I.weighedIndvarsByMax = WeighedIndvarsByMaxInput;
+ I.minStage = MinStageInput;
+ I.dummyReward = DummyReward;
+ I.maskFlat = MaskInput[0];
+ Result[0] = runEmitCRegAllocAction<ActionTy>(I);
+}
diff --git a/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp b/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp
index 23dc6fbd6e500..03ba2da4e945e 100644
--- a/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp
+++ b/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp
@@ -47,8 +47,11 @@ using namespace llvm;
#define DEBUG_TYPE "ml-regalloc"
-// Generated header in release (AOT) mode
-#if defined(LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL)
+// Generated header in release (AOT / EmitC) mode
+#if defined(LLVM_HAVE_EMITC_REGALLOCEVICTMODEL)
+#include "llvm/CodeGen/EmitCRegAllocEvictModel.h"
+using CompiledModelType = llvm::EmitCRegAllocEvictModel;
+#elif defined(LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL)
#include "RegAllocEvictModel.h"
using CompiledModelType = RegAllocEvictModel;
#else
diff --git a/llvm/test/CodeGen/MLRegAlloc/default-eviction-advisor.ll b/llvm/test/CodeGen/MLRegAlloc/default-eviction-advisor.ll
index 881a80c41361c..fc9d244a617a9 100644
--- a/llvm/test/CodeGen/MLRegAlloc/default-eviction-advisor.ll
+++ b/llvm/test/CodeGen/MLRegAlloc/default-eviction-advisor.ll
@@ -2,6 +2,7 @@
; trying to use ML-driven advisor.
; REQUIRES: !have_tf_aot
; REQUIRES: !have_tflite
+; REQUIRES: !have_emitc_raevict_model
; REQUIRES: default_triple
; RUN: not llc -O2 -regalloc-enable-advisor=development < %s 2>&1 | FileCheck %s
; RUN: not llc -O2 -regalloc-enable-advisor=release < %s 2>&1 | FileCheck %s
diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py
index cd028963dd59e..796d258515e5b 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -597,6 +597,9 @@ def enable_ptxas(ptxas_executable):
if config.have_tflite:
config.available_features.add("have_tflite")
+if config.have_emitc_raevict_model:
+ config.available_features.add("have_emitc_raevict_model")
+
if config.llvm_inliner_model_autogenerated:
config.available_features.add("llvm_inliner_model_autogenerated")
diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in
index 64679c2f64034..8c60b0d1a5d1b 100644
--- a/llvm/test/lit.site.cfg.py.in
+++ b/llvm/test/lit.site.cfg.py.in
@@ -57,6 +57,7 @@ config.linked_bye_extension = @LLVM_BYE_LINK_INTO_TOOLS@
config.linked_exampleirtransforms_extension = @LLVM_EXAMPLEIRTRANSFORMS_LINK_INTO_TOOLS@
config.have_tf_aot = @LLVM_HAVE_TF_AOT@
config.have_tflite = @LLVM_HAVE_TFLITE@
+config.have_emitc_raevict_model = @LLVM_USE_EMITC_REGALLOC_EVICT_MODEL@
config.enable_profcheck = @LLVM_ENABLE_PROFCHECK@
config.llvm_inliner_model_autogenerated = @LLVM_INLINER_MODEL_AUTOGENERATED@
config.llvm_raevict_model_autogenerated = @LLVM_RAEVICT_MODEL_AUTOGENERATED@
>From 33bdfa86d8a408260351bb220b2fa0944549f75d Mon Sep 17 00:00:00 2001
From: Ioana Ghiban <ioana.ghiban at arm.com>
Date: Thu, 16 Jul 2026 11:26:09 +0200
Subject: [PATCH 2/2] Mark model wrapper implementations optional
---
llvm/lib/Analysis/CMakeLists.txt | 13 ++++++++++---
llvm/lib/CodeGen/CMakeLists.txt | 14 +++++++++++---
2 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 474d96df9b619..50f10c58e6892 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -2,14 +2,21 @@ option(LLVM_USE_EMITC_INLINER_MODEL
"Use the in-tree EmitC inliner model instead of TensorFlow AOT"
OFF)
+# The EmitC wrapper is only built when the in-tree EmitC model is enabled.
+# Mark it optional so LLVM's source audit does not require it in default builds.
+list(APPEND LLVM_OPTIONAL_SOURCES
+ EmitCInlinerSizeModel.cpp)
+
if (LLVM_HAVE_TFLITE)
list(APPEND MLLinkDeps
tensorflow-lite::tensorflow-lite)
endif()
+# Only compile the EmitC inliner wrapper when the EmitC-backed release model
+# is selected. Otherwise the generated .inc file may not exist.
if (LLVM_USE_EMITC_INLINER_MODEL)
- list(APPEND LLVM_COMPILE_DEFINITIONS
- LLVM_HAVE_EMITC_INLINERSIZEMODEL)
+ list(APPEND LLVMAnalysisOptionalSources
+ EmitCInlinerSizeModel.cpp)
elseif (DEFINED LLVM_HAVE_TF_AOT)
include(TensorFlowCompile)
set(LLVM_INLINER_MODEL_PATH_DEFAULT "models/inliner-Oz")
@@ -82,7 +89,6 @@ add_llvm_component_library(LLVMAnalysis
DominanceFrontier.cpp
DXILResource.cpp
DXILMetadataAnalysis.cpp
- EmitCInlinerSizeModel.cpp
EphemeralValuesCache.cpp
FloatingPointPredicateUtils.cpp
FunctionPropertiesAnalysis.cpp
@@ -170,6 +176,7 @@ add_llvm_component_library(LLVMAnalysis
ValueLatticeUtils.cpp
ValueTracking.cpp
VectorUtils.cpp
+ ${LLVMAnalysisOptionalSources}
${GeneratedMLSources}
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index bf05ca6d7cb19..72496671b3d68 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -2,9 +2,17 @@ option(LLVM_USE_EMITC_REGALLOC_EVICT_MODEL
"Use the in-tree EmitC regalloc eviction model instead of TensorFlow AOT"
OFF)
+# The EmitC wrapper is only built when the in-tree EmitC regalloc model is
+# enabled. Mark it optional so LLVM's source audit accepts its absence from the
+# default target source list.
+list(APPEND LLVM_OPTIONAL_SOURCES
+ EmitCRegAllocEvictModel.cpp)
+
+# Only compile the EmitC regalloc wrapper when the EmitC-backed release model
+# is selected. Otherwise the generated .inc file may not exist.
if (LLVM_USE_EMITC_REGALLOC_EVICT_MODEL)
- list(APPEND LLVM_COMPILE_DEFINITIONS
- LLVM_HAVE_EMITC_REGALLOCEVICTMODEL)
+ list(APPEND LLVMCodeGenOptionalSources
+ EmitCRegAllocEvictModel.cpp)
endif()
if (DEFINED LLVM_HAVE_TF_AOT OR LLVM_HAVE_TFLITE)
@@ -62,7 +70,6 @@ add_llvm_component_library(LLVMCodeGen
DroppedVariableStatsMIR.cpp
DwarfEHPrepare.cpp
EarlyIfConversion.cpp
- EmitCRegAllocEvictModel.cpp
EdgeBundles.cpp
EHContGuardTargets.cpp
ExecutionDomainFix.cpp
@@ -268,6 +275,7 @@ add_llvm_component_library(LLVMCodeGen
WindowsSecureHotPatching.cpp
WinEHPrepare.cpp
XRayInstrumentation.cpp
+ ${LLVMCodeGenOptionalSources}
${GeneratedMLSources}
LiveDebugValues/LiveDebugValues.cpp
More information about the llvm-commits
mailing list