[llvm-branch-commits] [llvm] llvm-reduce: Add new pass to inline call sites (PR #134223)

Nick Desaulniers via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Apr 8 22:22:32 PDT 2025


================
@@ -0,0 +1,103 @@
+//===- ReduceInlineCallSites.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 "ReduceInlineCallSites.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+using namespace llvm;
+
+extern cl::OptionCategory LLVMReduceOptions;
+
+static cl::opt<int> CallsiteInlineThreshold(
+    "reduce-callsite-inline-threshold",
+    cl::desc("Number of instructions in a function to unconditionally inline "
+             "(-1 for inline all)"),
+    cl::init(5), cl::cat(LLVMReduceOptions));
+
+static bool functionHasMoreThanNonTerminatorInsts(const Function &F,
+                                                  uint64_t NumInsts) {
+  uint64_t InstCount = 0;
+  for (const BasicBlock &BB : F) {
+    for (const Instruction &I : make_range(BB.begin(), std::prev(BB.end()))) {
+      (void)I;
+      if (InstCount++ > NumInsts)
+        return true;
+    }
+  }
+
+  return false;
+}
+
+static bool hasOnlyOneCallUse(const Function &F) {
+  unsigned UseCount = 0;
+  for (const Use &U : F.uses()) {
+    const CallBase *CB = dyn_cast<CallBase>(U.getUser());
+    if (!CB || !CB->isCallee(&U))
+      return false;
+    if (UseCount++ > 1)
+      return false;
+  }
+
+  return UseCount == 1;
+}
+
+// TODO: This could use more thought.
+static bool inlineWillReduceComplexity(const Function &Caller,
+                                       const Function &Callee) {
+  // Backdoor to force all possible inlining.
+  if (CallsiteInlineThreshold < 0)
+    return true;
+
+  if (!hasOnlyOneCallUse(Callee))
+    return false;
+
+  // Permit inlining small functions into big functions, or big functions into
+  // small functions.
+  if (!functionHasMoreThanNonTerminatorInsts(Callee, CallsiteInlineThreshold) &&
+      !functionHasMoreThanNonTerminatorInsts(Caller, CallsiteInlineThreshold))
+    return true;
+
+  return false;
+}
+
+static void reduceCallSites(Oracle &O, Function &F) {
+  std::vector<std::pair<CallBase *, InlineFunctionInfo>> CallSitesToInline;
+
+  for (Use &U : F.uses()) {
+    if (CallBase *CB = dyn_cast<CallBase>(U.getUser())) {
+      // Ignore callsites with wrong call type.
+      if (!CB->isCallee(&U))
+        continue;
+
+      // We do not consider isInlineViable here. It is overly conservative in
+      // cases that the inliner should handle correctly (e.g. disallowing inline
+      // of of functions with indirectbr). Some of the other cases are for other
+      // correctness issues which we do need to worry about here.
+
+      // TODO: Should we delete the function body?
+      InlineFunctionInfo IFI;
+      if (CanInlineCallSite(*CB, IFI).isSuccess() &&
----------------
nickdesaulniers wrote:

Would you also filter with `isInlineViable` or no?

https://github.com/llvm/llvm-project/pull/134223


More information about the llvm-branch-commits mailing list