Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CodeGen] Support start/stop in CodeGenPassBuilder #70912

Merged
merged 1 commit into from Jan 18, 2024

Conversation

paperchalice
Copy link
Contributor

@paperchalice paperchalice commented Nov 1, 2023

Add -start/stop-before/after support for CodeGenPassBuilder.
Part of #69879.

@llvmbot llvmbot added the llvm:ir label Nov 1, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Nov 1, 2023

@llvm/pr-subscribers-llvm-ir

Author: None (paperchalice)

Changes

Add a special hook to support -start-*=<passes> and -stop-*=<passes> in llc. If still use registerShouldRunOptionalPassCallback then llc can't skip some passes.
Part of #69879.
NOTE: This hook has a higher priority than PassName::isRequired().


Full diff: https://github.com/llvm/llvm-project/pull/70912.diff

3 Files Affected:

  • (modified) llvm/include/llvm/IR/PassInstrumentation.h (+33)
  • (modified) llvm/lib/CodeGen/TargetPassConfig.cpp (+16-3)
  • (modified) llvm/lib/Passes/StandardInstrumentations.cpp (+4-3)
diff --git a/llvm/include/llvm/IR/PassInstrumentation.h b/llvm/include/llvm/IR/PassInstrumentation.h
index 519a5e46b4373b7..3f70fcf180af81a 100644
--- a/llvm/include/llvm/IR/PassInstrumentation.h
+++ b/llvm/include/llvm/IR/PassInstrumentation.h
@@ -84,6 +84,23 @@ class PassInstrumentationCallbacks {
   using AfterAnalysisFunc = void(StringRef, Any);
   using AnalysisInvalidatedFunc = void(StringRef, Any);
   using AnalysesClearedFunc = void(StringRef);
+  using StartStopFunc = bool(StringRef, Any);
+
+  struct CodeGenStartStopInfo {
+    StringRef Start;
+    StringRef Stop;
+
+    bool IsStopMachinePass = false;
+
+    llvm::unique_function<StartStopFunc> StartStopCallback;
+
+    bool operator()(StringRef PassID, Any IR) {
+      return StartStopCallback(PassID, IR);
+    }
+    bool isStopMachineFunctionPass() const { return IsStopMachinePass; }
+    bool willCompleteCodeGenPipeline() const { return Stop.empty(); }
+    StringRef getStop() const { return Stop; }
+  };
 
 public:
   PassInstrumentationCallbacks() = default;
@@ -148,6 +165,17 @@ class PassInstrumentationCallbacks {
     AnalysesClearedCallbacks.emplace_back(std::move(C));
   }
 
+  void registerStartStopInfo(CodeGenStartStopInfo &&C) {
+    StartStopInfo = std::move(C);
+  }
+
+  bool isStartStopInfoRegistered() const { return StartStopInfo.has_value(); }
+
+  CodeGenStartStopInfo &getStartStopInfo() {
+    assert(StartStopInfo.has_value() && "StartStopInfo is unregistered!");
+    return *StartStopInfo;
+  }
+
   /// Add a class name to pass name mapping for use by pass instrumentation.
   void addClassToPassName(StringRef ClassName, StringRef PassName);
   /// Get the pass name for a given pass class name.
@@ -183,6 +211,8 @@ class PassInstrumentationCallbacks {
   /// These are run on analyses that have been cleared.
   SmallVector<llvm::unique_function<AnalysesClearedFunc>, 4>
       AnalysesClearedCallbacks;
+  /// For `llc` -start-* -stop-* options.
+  std::optional<CodeGenStartStopInfo> StartStopInfo;
 
   StringMap<std::string> ClassToPassName;
 };
@@ -236,6 +266,9 @@ class PassInstrumentation {
         ShouldRun &= C(Pass.name(), llvm::Any(&IR));
     }
 
+    if (Callbacks->StartStopInfo)
+      ShouldRun &= (*Callbacks->StartStopInfo)(Pass.name(), llvm::Any(&IR));
+
     if (ShouldRun) {
       for (auto &C : Callbacks->BeforeNonSkippedPassCallbacks)
         C(Pass.name(), llvm::Any(&IR));
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index e6ecbc9b03f7149..bea8590a14080ca 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -508,6 +508,9 @@ static void registerPartialPipelineCallback(PassInstrumentationCallbacks &PIC,
   unsigned StopBeforeInstanceNum = 0;
   unsigned StopAfterInstanceNum = 0;
 
+  bool IsStopBeforeMachinePass = false;
+  bool IsStopAfterMachinePass = false;
+
   std::tie(StartBefore, StartBeforeInstanceNum) =
       getPassNameAndInstanceNum(StartBeforeOpt);
   std::tie(StartAfter, StartAfterInstanceNum) =
@@ -536,7 +539,15 @@ static void registerPartialPipelineCallback(PassInstrumentationCallbacks &PIC,
     report_fatal_error(Twine(StopBeforeOptName) + Twine(" and ") +
                        Twine(StopAfterOptName) + Twine(" specified!"));
 
-  PIC.registerShouldRunOptionalPassCallback(
+  std::vector<StringRef> SpecialPasses = {"PassManager", "PassAdaptor",
+                                          "PrintMIRPass", "PrintModulePass"};
+
+  PassInstrumentationCallbacks::CodeGenStartStopInfo Info;
+  Info.Start = StartBefore.empty() ? StartAfter : StartBefore;
+  Info.Stop = StopBefore.empty() ? StopAfter : StopBefore;
+
+  Info.IsStopMachinePass = IsStopBeforeMachinePass || IsStopAfterMachinePass;
+  Info.StartStopCallback =
       [=, EnableCurrent = StartBefore.empty() && StartAfter.empty(),
        EnableNext = std::optional<bool>(), StartBeforeCount = 0u,
        StartAfterCount = 0u, StopBeforeCount = 0u,
@@ -567,8 +578,10 @@ static void registerPartialPipelineCallback(PassInstrumentationCallbacks &PIC,
           EnableCurrent = true;
         if (StopBeforePass && StopBeforeCount++ == StopBeforeInstanceNum)
           EnableCurrent = false;
-        return EnableCurrent;
-      });
+        return EnableCurrent || isSpecialPass(P, SpecialPasses);
+      };
+
+  PIC.registerStartStopInfo(std::move(Info));
 }
 
 void llvm::registerCodeGenCallback(PassInstrumentationCallbacks &PIC,
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 06cc58c0219632d..c6ec1c34d74418d 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -1036,9 +1036,10 @@ void PrintPassInstrumentation::registerCallbacks(
     SpecialPasses.emplace_back("PassAdaptor");
   }
 
-  PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
-                                                              Any IR) {
-    assert(!isSpecialPass(PassID, SpecialPasses) &&
+  PIC.registerBeforeSkippedPassCallback([this, SpecialPasses,
+                                         &PIC](StringRef PassID, Any IR) {
+    assert((!isSpecialPass(PassID, SpecialPasses) ||
+            PIC.isStartStopInfoRegistered()) &&
            "Unexpectedly skipping special pass");
 
     print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";

llvm/include/llvm/IR/PassInstrumentation.h Outdated Show resolved Hide resolved
@aeubanks
Copy link
Contributor

aeubanks commented Jan 2, 2024

instead of doing this in the instrumentation, can we do this by not adding the pass to begin with? that seems cleaner.

e.g. AddMachinePass can check if we've added some pass and bail if we have/haven't seen the pass so far

@paperchalice paperchalice force-pushed the startstop branch 3 times, most recently from 1cbce28 to 5e9c1dc Compare January 3, 2024 03:54
@paperchalice
Copy link
Contributor Author

paperchalice commented Jan 3, 2024

instead of doing this in the instrumentation, can we do this by not adding the pass to begin with? that seems cleaner.

e.g. AddMachinePass can check if we've added some pass and bail if we have/haven't seen the pass so far

Update for this now. Add a callback to PassInstrumentationCallbacks now, Add*Pass can decide whether to add pass through this callback.

The work of determining whether a pass is a machine pass will be completed by the pass builder, which requires #76320.

Update: In this way, it may not recognize some passes which is added by adaptor class, like LoopStrengthReducePass.

@aeubanks
Copy link
Contributor

aeubanks commented Jan 5, 2024

sorry, been swamped with unbreaking things this week, will try to review next week

@paperchalice
Copy link
Contributor Author

If use this way, I'd like to finish #76320 and #77084 firstly so we can at least verify the pass pipeline string in unittest.

Copy link
Contributor

@aeubanks aeubanks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think this makes more sense, thanks

LoopStrengthReducePass(), /*UseMemorySSA*/ true, Opt.DebugPM));
addPass(createFunctionToLoopPassAdaptor(LoopStrengthReducePass(),
/*UseMemorySSA*/ true, Opt.DebugPM),
LoopStrengthReducePass::name());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unfortunate, I wonder if we should just make this a function pass, but we can do that in the future

@@ -28,6 +28,14 @@ PassInstrumentationCallbacks::getPassNameForClassName(StringRef ClassName) {
return ClassToPassName[ClassName];
}

StringRef
PassInstrumentationCallbacks::getClassNameForPassName(StringRef PassName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than adding this reverse map, let's be consistent with existing instrumentation like here where we check the pass name against PIC->getPassNameForClassName(PassID) in the callbacks. even if this is slower it doesn't really matter since this is just used for testing iiuc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we may need #76320 to populate pass names.

StringRef getClassNameForPassName(StringRef PassName);

/// Helper callback to support options like start-before.
llvm::unique_function<StartStopFunc> StartStopCallback;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing where this is being used.

Also, PassInstrumentationCallbacks doesn't really seem like the right place to put this. The only reason we interact with PIC is to get the class/pass name map. If we can somehow separate that out, that would be ideal, but perhaps that's too hard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I forgot to remove this, this implementation doesn't need this any more, sorry.

@paperchalice paperchalice force-pushed the startstop branch 3 times, most recently from d7fa9a8 to 6eb14fe Compare January 10, 2024 06:08
@pravinjagtap pravinjagtap self-requested a review January 11, 2024 12:51
@paperchalice paperchalice changed the title [Pass] Support start/stop in instrumentation [CodeGen] Support start/stop in CodeGenPassBuilder Jan 13, 2024
@paperchalice paperchalice marked this pull request as ready for review January 13, 2024 10:32
@paperchalice
Copy link
Contributor Author

paperchalice commented Jan 14, 2024

Add simple unit test and will move to lit test in future.
Is -stop-before=free-machine-function/-stop-after=asm-printer a meaningful option?

Copy link
Contributor

@aeubanks aeubanks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lg with some comments

we really should get basic llc support soon

static_assert((is_detected<is_function_pass_t, PassT>::value ||
is_detected<is_module_pass_t, PassT>::value) &&
"Only module pass and function pass are supported.");

// Add Function Pass
if constexpr (is_detected<is_function_pass_t, PassT>::value) {
if (!PB.runBeforeAdding(Name))
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can factor this out of if/else branches

C(&PassT::Key);

for (auto &C : PB.AfterCallbacks)
C(PassT::name());
}

template <typename PassT> void insertPass(MachinePassKey *ID, PassT Pass) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated, and I think I mentioned this before, but I'd like to see if we can come up with a nicer way of doing this, perhaps with something like PassBuilder extension points (e.g. PassBuilder::registerPeepholeEPCallback()). it seems in line with various per-target TargetMachines adding their own passes anyway. do you know if we could potentially replace insertPass() with the various TargetMachines simply adding passes in the right place, or are the passes they add too ad hoc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently AMDGPU, Hexagon, PowerPC and RISCV uses insertPass to adjust the regalloc pipeline, we need add extension points after PHIElimination, TwoAddressInstruction, MachineScheduler, RenameIndependentSubregs, LiveVariables and DetectDeadLanes. They inject passes between these passes directly and only happens in regalloc pipeline.

@@ -123,6 +124,13 @@ namespace llvm {
/// all of the built-in passes, and those may reference these members during
/// construction.
template <typename DerivedT> class CodeGenPassBuilder {
bool runBeforeAdding(StringRef Name) const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move this definition somewhere else in the class? it doesn't belong right at the top


Error verifyStartStop(const TargetPassConfig::StartStopInfo &Info) const;

mutable SmallVector<llvm::unique_function<bool(StringRef)>, 4>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems nicer to keep this in AddPass. is the reason that these are moved out of AddPass because it references Started/Stopped in CodeGenPassBuilder? and there's no way to easily validate them if these are somewhere else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently IR passes and machine function passes are handled by different classes, and -start/stop options should support both IR and machine function passes, but it's OK to merge them into one class, because only buildPipeline creates instance of AddIRPass and AddMachinePass, but IMHO keeping these in CodeGenPassBuilder can let target disable passes in constructor.

@paperchalice
Copy link
Contributor Author

Address some comments.

@paperchalice paperchalice merged commit baaf0c9 into llvm:main Jan 18, 2024
4 checks passed
paperchalice added a commit that referenced this pull request Jan 18, 2024
paperchalice added a commit to paperchalice/llvm-project that referenced this pull request Jan 19, 2024
Add `-start/stop-before/after` support for CodeGenPassBuilder.
Part of llvm#69879.
ampandey-1995 pushed a commit to ampandey-1995/llvm-project that referenced this pull request Jan 19, 2024
Add `-start/stop-before/after` support for CodeGenPassBuilder.
Part of llvm#69879.
paperchalice added a commit that referenced this pull request Jan 20, 2024
…78570)

Unfortunately the legacy pass system can't recognize `no-op-module` and
`no-op-function` so it causes test failure in `CodeGenTests`. Add a
workaround in function `PassInfo *getPassInfo(StringRef PassName)`,
`TargetPassConfig.cpp`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants