[llvm] [LLVM] Add flatten function attribute to LLVM IR and implement recursive inlining in AlwaysInliner (PR #174899)
Wei Wang via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 15 09:36:27 PST 2026
================
@@ -30,21 +31,206 @@ using namespace llvm;
namespace {
+class InlinerHelper {
+ Module &M;
+ FunctionAnalysisManager *FAM;
+ function_ref<AssumptionCache &(Function &)> GetAssumptionCache;
+ function_ref<AAResults &(Function &)> GetAAR;
+ bool InsertLifetime;
+
+ SmallSetVector<Function *, 16> MaybeInlinedFunctions;
+ InlineFunctionInfo IFI;
+
+public:
+ InlinerHelper(Module &M, ProfileSummaryInfo &PSI,
+ FunctionAnalysisManager *FAM,
+ function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
+ function_ref<AAResults &(Function &)> GetAAR,
+ bool InsertLifetime)
+ : M(M), FAM(FAM), GetAssumptionCache(GetAssumptionCache), GetAAR(GetAAR),
+ InsertLifetime(InsertLifetime), IFI(GetAssumptionCache, &PSI) {}
+
+ bool canInline(Function &F) {
+ return !F.isPresplitCoroutine() && !F.isDeclaration() &&
+ isInlineViable(F).isSuccess();
+ }
+
+ bool tryInline(CallBase &CB, StringRef InlignReason) {
+ IFI.reset();
+ Function &Callee = *CB.getCalledFunction();
+ Function *Caller = CB.getCaller();
+ OptimizationRemarkEmitter ORE(Caller);
+ DebugLoc DLoc = CB.getDebugLoc();
+ BasicBlock *Block = CB.getParent();
+
+ InlineResult Res = InlineFunction(CB, IFI, /*MergeAttributes=*/true,
+ &GetAAR(Callee), InsertLifetime);
+ if (!Res.isSuccess()) {
+ ORE.emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
+ << "'" << ore::NV("Callee", &Callee) << "' is not inlined into '"
+ << ore::NV("Caller", Caller)
+ << "': " << ore::NV("Reason", Res.getFailureReason());
+ });
+ return false;
+ }
+
+ emitInlinedIntoBasedOnCost(ORE, DLoc, Block, Callee, *Caller,
+ InlineCost::getAlways(InlignReason.data()),
+ /*ForProfileContext=*/false, DEBUG_TYPE);
+ if (FAM)
+ FAM->invalidate(*Caller, PreservedAnalyses::none());
+ return true;
+ }
+
+ void addNewCallsToWorklist(
+ SmallVectorImpl<std::pair<CallBase *, int>> &Worklist,
+ int InlineHistoryID,
+ SmallVectorImpl<std::pair<Function *, int>> &InlineHistory,
+ Function *InlinedCallee) {
+ if (IFI.InlinedCallSites.empty())
+ return;
+ int NewHistoryID = InlineHistory.size();
+ InlineHistory.push_back({InlinedCallee, InlineHistoryID});
+ for (CallBase *CB : IFI.InlinedCallSites)
+ Worklist.push_back({CB, NewHistoryID});
+ }
+
+ void addToMaybeInlinedFunctions(Function &F) {
+ MaybeInlinedFunctions.insert(&F);
+ }
+
+ bool postInlinerCleanup() {
+ SmallVector<Function *, 16> InlinedComdatFunctions;
+ bool Changed = false;
+ for (Function *F : MaybeInlinedFunctions) {
+ F->removeDeadConstantUsers();
+ if (F->hasFnAttribute(Attribute::AlwaysInline) &&
+ F->isDefTriviallyDead()) {
+ if (F->hasComdat()) {
+ InlinedComdatFunctions.push_back(F);
+ } else {
+ if (FAM)
+ FAM->clear(*F, F->getName());
+ M.getFunctionList().erase(F);
+ Changed = true;
+ }
+ }
+ }
+ if (!InlinedComdatFunctions.empty()) {
+ // Now we just have the comdat functions. Filter out the ones whose
+ // comdats are not actually dead.
+ filterDeadComdatFunctions(InlinedComdatFunctions);
+ // The remaining functions are actually dead.
+ for (Function *F : InlinedComdatFunctions) {
+ if (FAM)
+ FAM->clear(*F, F->getName());
+ M.getFunctionList().erase(F);
+ Changed = true;
+ }
+ }
+ return Changed;
+ }
+};
+
+static bool inlineHistoryIncludes(
+ Function *F, int InlineHistoryID,
+ const SmallVectorImpl<std::pair<Function *, int>> &InlineHistory) {
+ while (InlineHistoryID != -1) {
----------------
apolloww wrote:
I mean if the function is first seen, there can't be a cycle, so it's a fast path to return "false".
Since it's used in inliner and doesn't cause issue, I think it's fine that we keep using it here.
https://github.com/llvm/llvm-project/pull/174899
More information about the llvm-commits
mailing list