[llvm-branch-commits] [llvm] [PassBuilder][CodeGen] Add callback style pass buider (PR #116913)

Akshat Oke via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jan 17 01:51:56 PST 2025


================
@@ -0,0 +1,950 @@
+//===- Construction of code generation pass pipelines ---------------------===//
+//
+// 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
+///
+/// This file provides the implementation of the PassBuilder based on our
+/// static pass registry as well as related functionality.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/CallBrPrepare.h"
+#include "llvm/CodeGen/CodeGenPrepare.h"
+#include "llvm/CodeGen/DwarfEHPrepare.h"
+#include "llvm/CodeGen/ExpandLargeDivRem.h"
+#include "llvm/CodeGen/ExpandLargeFpConvert.h"
+#include "llvm/CodeGen/ExpandMemCmp.h"
+#include "llvm/CodeGen/ExpandReductions.h"
+#include "llvm/CodeGen/FinalizeISel.h"
+#include "llvm/CodeGen/GCMetadata.h"
+#include "llvm/CodeGen/GlobalMergeFunctions.h"
+#include "llvm/CodeGen/LiveVariables.h"
+#include "llvm/CodeGen/LocalStackSlotAllocation.h"
+#include "llvm/CodeGen/LowerEmuTLS.h"
+#include "llvm/CodeGen/MachineFunctionAnalysis.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/CodeGen/PreISelIntrinsicLowering.h"
+#include "llvm/CodeGen/ReplaceWithVeclib.h"
+#include "llvm/CodeGen/SafeStack.h"
+#include "llvm/CodeGen/SelectOptimize.h"
+#include "llvm/CodeGen/ShadowStackGCLowering.h"
+#include "llvm/CodeGen/SjLjEHPrepare.h"
+#include "llvm/CodeGen/StackProtector.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/CodeGen/UnreachableBlockElim.h"
+#include "llvm/CodeGen/WasmEHPrepare.h"
+#include "llvm/CodeGen/WinEHPrepare.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Passes/CodeGenPassBuilder.h" // Dummy passes only!
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/ObjCARC.h"
+#include "llvm/Transforms/Scalar/ConstantHoisting.h"
+#include "llvm/Transforms/Scalar/LoopStrengthReduce.h"
+#include "llvm/Transforms/Scalar/MergeICmps.h"
+#include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h"
+#include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
+#include "llvm/Transforms/Utils/LowerGlobalDtors.h"
+#include "llvm/Transforms/Utils/LowerInvoke.h"
+
+namespace llvm {
+extern cl::opt<std::string> FSRemappingFile;
+}
+
+using namespace llvm;
+
+void PassBuilder::invokeCodeGenIREarlyEPCallbacks(ModulePassManager &MPM) {
+  for (auto &C : CodeGenIREarlyEPCallbacks)
+    C(MPM);
+}
+
+void PassBuilder::invokeGCLoweringEPCallbacks(FunctionPassManager &FPM) {
+  for (auto &C : GCLoweringEPCallbacks)
+    C(FPM);
+}
+
+void PassBuilder::invokeISelPrepareEPCallbacks(ModulePassManager &MPM) {
+  for (auto &C : ISelPrepareEPCallbacks)
+    C(MPM);
+}
+
+void PassBuilder::invokeMachineSSAOptimizationEarlyEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : MachineSSAOptimizationEarlyEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokeMachineSSAOptimizationLastEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : MachineSSAOptimizationLastEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePreRegAllocEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : PreRegAllocEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePreRegBankSelectEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : PreRegBankSelectEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePreGlobalInstructionSelectEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : PreGlobalInstructionSelectEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePostGlobalInstructionSelectEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : PostGlobalInstructionSelectEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokeILPOptsEPCallbacks(MachineFunctionPassManager &MFPM) {
+  for (auto &C : ILPOptsEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokeMachineLateOptimizationEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : MachineLateOptimizationEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokeMIEmitEPCallbacks(MachineFunctionPassManager &MFPM) {
+  for (auto &C : MIEmitEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePreEmitEPCallbacks(MachineFunctionPassManager &MFPM) {
+  for (auto &C : PreEmitEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePostRegAllocEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : PostRegAllocEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePreSched2EPCallbacks(MachineFunctionPassManager &MFPM) {
+  for (auto &C : PreSched2EPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::invokePostBBSectionsEPCallbacks(
+    MachineFunctionPassManager &MFPM) {
+  for (auto &C : PostBBSectionsEPCallbacks)
+    C(MFPM);
+}
+
+void PassBuilder::addDefaultCodeGenPreparePasses(ModulePassManager &MPM) {
+  FunctionPassManager FPM;
+  // CodeGen prepare
+  if (TM->getOptLevel() != CodeGenOptLevel::None && !CGPBO.DisableCGP)
+    FPM.addPass(CodeGenPreparePass(TM));
+  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+}
+
+Error PassBuilder::addDefaultRegAllocFastPasses(
+    MachineFunctionPassManager &MFPM) {
+  MFPM.addPass(PHIEliminationPass());
+  MFPM.addPass(TwoAddressInstructionPass());
+  if (auto Err = addRegAllocPass(MFPM))
+    return Err;
+  return Error::success();
+}
+
+Error PassBuilder::addDefaultRegAllocOptimizedPasses(
+    MachineFunctionPassManager &MFPM) {
+  MFPM.addPass(DetectDeadLanesPass());
+  MFPM.addPass(InitUndefPass());
+  MFPM.addPass(ProcessImplicitDefsPass());
+
+  // LiveVariables currently requires pure SSA form.
+  //
+  // FIXME: Once TwoAddressInstruction pass no longer uses kill flags,
+  // LiveVariables can be removed completely, and LiveIntervals can be
+  // directly computed. (We still either need to regenerate kill flags after
+  // regalloc, or preferably fix the scavenger to not depend on them).
+  // FIXME: UnreachableMachineBlockElim is a dependant pass of LiveVariables.
+  // When LiveVariables is removed this has to be removed/moved either.
+  // Explicit addition of UnreachableMachineBlockElim allows stopping before
+  // or after it with -stop-before/-stop-after.
+  MFPM.addPass(UnreachableMachineBlockElimPass());
+  // FIXME: Some X86 tests failed because of incomplete pipeline.
+  // MFPM.addPass(RequireAnalysisPass<LiveVariablesAnalysis,
+  // MachineFunction>());
+
+  // Edge splitting is smarter with machine loop info.
+  MFPM.addPass(RequireAnalysisPass<MachineLoopAnalysis, MachineFunction>());
+  MFPM.addPass(PHIEliminationPass());
+
+  if (CGPBO.EarlyLiveIntervals)
+    MFPM.addPass(RequireAnalysisPass<LiveIntervalsAnalysis, MachineFunction>());
+
+  MFPM.addPass(TwoAddressInstructionPass());
+  MFPM.addPass(RegisterCoalescerPass());
+
+  // The machine scheduler may accidentally create disconnected components
+  // when moving subregister definitions around, avoid this by splitting them
+  // to separate vregs before. Splitting can also improve reg. allocation
+  // quality.
+  MFPM.addPass(RenameIndependentSubregsPass());
+
+  // PreRA instruction scheduling.
+  MFPM.addPass(MachineSchedulerPass());
+
+  if (auto Err = addRegAllocPass(MFPM))
+    return Err;
+  // Finally rewrite virtual registers.
+  MFPM.addPass(VirtRegRewriterPass());
+
+  // Regalloc scoring for ML-driven eviction - noop except when learning a new
+  // eviction policy.
+  MFPM.addPass(RegAllocScoringPass());
+
+  return Error::success();
+}
+
+bool PassBuilder::isOptimizedRegAlloc() const {
+  return CGPBO.OptimizeRegAlloc.value_or(TM->getOptLevel() !=
+                                         CodeGenOptLevel::None);
+}
+
+// Find the Profile remapping file name. The internal option takes the
+// precedence before getting from TargetMachine.
+static std::string getFSRemappingFile(const TargetMachine *TM,
+                                      const CGPassBuilderOption &Options) {
+  if (!Options.FSRemappingFile.empty())
+    return Options.FSRemappingFile;
+  const std::optional<PGOOptions> &PGOOpt = TM->getPGOOption();
+  if (PGOOpt == std::nullopt || PGOOpt->Action != PGOOptions::SampleUse)
+    return std::string();
+  return PGOOpt->ProfileRemappingFile;
+}
+
+// Find the FSProfile file name. The internal option takes the precedence
+// before getting from TargetMachine.
+static std::string getFSProfileFile(const TargetMachine *TM,
+                                    const CGPassBuilderOption &Options) {
+  if (!Options.FSProfileFile.empty())
+    return Options.FSProfileFile;
+  const std::optional<PGOOptions> &PGOOpt = TM->getPGOOption();
+  if (PGOOpt == std::nullopt || PGOOpt->Action != PGOOptions::SampleUse)
+    return std::string();
+  return PGOOpt->ProfileFile;
+}
+
+Error PassBuilder::addExceptionHandlingPasses(FunctionPassManager &FPM) {
+  const MCAsmInfo *MCAI = TM->getMCAsmInfo();
+  if (!MCAI)
+    return make_error<StringError>("No MCAsmInfo!", inconvertibleErrorCode());
+  switch (MCAI->getExceptionHandlingType()) {
+  case ExceptionHandling::SjLj:
+    // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both
+    // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise,
+    // catch info can get misplaced when a selector ends up more than one block
+    // removed from the parent invoke(s). This could happen when a landing
+    // pad is shared by multiple invokes and is also a target of a normal
+    // edge from elsewhere.
+    FPM.addPass(SjLjEHPreparePass(TM));
+    [[fallthrough]];
+  case ExceptionHandling::DwarfCFI:
+  case ExceptionHandling::ARM:
+  case ExceptionHandling::AIX:
+  case ExceptionHandling::ZOS:
+    FPM.addPass(DwarfEHPreparePass(TM));
+    break;
+  case ExceptionHandling::WinEH:
+    // We support using both GCC-style and MSVC-style exceptions on Windows, so
+    // add both preparation passes. Each pass will only actually run if it
+    // recognizes the personality function.
+    FPM.addPass(WinEHPreparePass());
+    FPM.addPass(DwarfEHPreparePass(TM));
+    break;
+  case ExceptionHandling::Wasm:
+    // Wasm EH uses Windows EH instructions, but it does not need to demote PHIs
+    // on catchpads and cleanuppads because it does not outline them into
+    // funclets. Catchswitch blocks are not lowered in SelectionDAG, so we
+    // should remove PHIs there.
+    FPM.addPass(WinEHPreparePass(/*DemoteCatchSwitchPHIOnly=*/true));
+    FPM.addPass(WasmEHPreparePass());
+    break;
+  case ExceptionHandling::None:
+    FPM.addPass(LowerInvokePass());
+
+    // The lower invoke pass may create unreachable code. Remove it.
+    FPM.addPass(UnreachableBlockElimPass());
+    break;
+  }
+  return Error::success();
+}
+
+Error PassBuilder::addInstructionSelectorPasses(
+    MachineFunctionPassManager &MFPM) {
+  CodeGenOptLevel OptLevel = TM->getOptLevel();
+
+  // Core ISel
+  // Enable FastISel with -fast-isel, but allow that to be overridden.
+  TM->setO0WantsFastISel(CGPBO.EnableFastISelOption.value_or(true));
+  // Determine an instruction selector.
+  enum class SelectorType { SelectionDAG, FastISel, GlobalISel };
+  SelectorType Selector;
+
+  CGPBO.EnableFastISelOption.value_or(false);
+  if (CGPBO.EnableFastISelOption.value_or(false))
+    Selector = SelectorType::FastISel;
+
+  else if (CGPBO.EnableGlobalISelOption.value_or(false) ||
+           (TM->Options.EnableGlobalISel &&
+            !CGPBO.EnableGlobalISelOption.value_or(false)))
+    Selector = SelectorType::GlobalISel;
+  else if (OptLevel == CodeGenOptLevel::None && TM->getO0WantsFastISel())
+    Selector = SelectorType::FastISel;
+  else
+    Selector = SelectorType::SelectionDAG;
+
+  // Set consistently TM.Options.EnableFastISel and EnableGlobalISel.
+  if (Selector == SelectorType::FastISel) {
+    TM->setFastISel(true);
+    TM->setGlobalISel(false);
+  } else if (Selector == SelectorType::GlobalISel) {
+    TM->setFastISel(false);
+    TM->setGlobalISel(true);
+  }
+
+  // Add instruction selector passes.
+  if (Selector == SelectorType::GlobalISel) {
+    MFPM.addPass(IRTranslatorPass());
+    MFPM.addPass(LegalizerPass());
+
+    // Before running the register bank selector, ask the target if it
+    // wants to run some passes.
+    invokePreRegBankSelectEPCallbacks(MFPM);
+    MFPM.addPass(RegBankSelectPass());
----------------
optimisan wrote:

I think we also need a mechanism to override adding RegBankSelect for targets, AMDGPU switches between custom passes and the default one.

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


More information about the llvm-branch-commits mailing list