-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[CodeGen][Pass] Add TargetPassBuilder
#137290
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
base: main
Are you sure you want to change the base?
Conversation
|
But there are no virtual methods, so are we removing distinct phases (like |
IMHO some phases here is not clear, the example is pre emit, we have
Yeah pre isel is one of phases To be more radical, I even want to use type erasure to ensure backends only add dag isel and asm printer to replace the |
22d7f27 to
b34d27c
Compare
d9d61ec to
d30808d
Compare
d30808d to
5e3864a
Compare
5e3864a to
b4867b3
Compare
|
Support dummy injection points now, they are PreISel, PostBBSections and PreEmit. |
|
Instead of force pushing, can you keep separate commits each time you add a new patch? It would be easier to identify the new changes coming in. |
|
ping @aeubanks |
same as #138830 This partly solves the issue #138831 for -enable-new-pm. #137290 will not have this problem, but this needs to be added this till we migrate to the new pass builder structure. Even with this, there is no way to -start-after an inserted pass right now. Co-authored-by : Oke, Akshat <[[email protected]](mailto:[email protected])>
…ions (#148111) same as llvm/llvm-project#138830 This partly solves the issue llvm/llvm-project#138831 for -enable-new-pm. llvm/llvm-project#137290 will not have this problem, but this needs to be added this till we migrate to the new pass builder structure. Even with this, there is no way to -start-after an inserted pass right now. Co-authored-by : Oke, Akshat <[[email protected]](mailto:[email protected])>
|
Ping? @aeubanks |
|
If I understand correctly, the idea in this patch is that TargetPassBuilder mimics the interface of PassBuilder, but doesn't build the final structure of PassManagers yet. Instead it stores the the final PassInfoMixin instances in an intermediate structure of |
You are right. This is a dirty hack to implement |
|
Thanks! The However, the RFC also notes that this change to the testing strategy would involve a "huge amount of tedious work porting tests". This part of the proposal also received critical feedback from @arsenm and @akorobeynikov, who explain why it doesn't fit the nature of the codegen pipeline. I think their arguments are sounds and convincing. Coming back to your patch: If we need an intermediate structure to provide this feature, it should be fine to have it. It might be worth to make it more explicit though. Perhaps consider it more as a planning mode for the PassBuilder, rather than hiding it behind a hack?
What exactly do you consider the hack here? The logic in |
Shadowing |
weliveindetail
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the interface should be as close as possible, but matching the interface doesn't mean we have to fake the classes. Let's look at an example that might make the code simpler. It might also help reviewers :)
|
|
||
| injectBefore<PreISelIntrinsicLoweringPass>([]() { | ||
| ModulePassManager MPM; | ||
| MPM.addPass(NoOpModulePass()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very much like we use a llvm::PassManager<Module> while we actually get a llvm::TargetPassBuilder::PassManagerWrapper<llvm::PassManager<Module>, <more templates here>>. That might be surprising and figuring out the relations behind the scenes isn't exactly trivial :)
| using FunctionPassManager = | ||
| PassManagerWrapper<llvm::FunctionPassManager, MachineFunctionPassManager>; | ||
| using ModulePassManager = | ||
| PassManagerWrapper<llvm::ModulePassManager, FunctionPassManager>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't we just have a TargetModulePassManager instead? It wouldn't need to be hidden as a subclass anymore. And maybe even without templates? After all, PassManagerWrapper doesn't do so much.
| is_detected<HasRunOnIRUnit, PassT, Function>::value; | ||
| template <typename PassT> | ||
| static constexpr bool isMachineFunctionPass = | ||
| is_detected<HasRunOnIRUnit, PassT, MachineFunction>::value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we could get rid of the type detection here (which btw doesn't work out-of-the-box on current main anymore)
| std::conditional_t<isFunctionPass<PassT>, FunctionPassManager, | ||
| MachineFunctionPassManager>>> | ||
| void injectBefore( | ||
| typename llvm::identity<std::function<PassManagerT()>>::argument_type F) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And then.. maybe we could spell these out for the actual pass managers we have? This looks a lot simpler to me:
protected:
template <typename PassT>
void injectModulePassManagerBefore(std::function<ModulePassManager()> F) {
injectCallback(PassT::name(), std::move(F));
}
private:
template <typename PassManagerT>
void injectCallback(StringRef PassName, std::function<PassManagerT()> F) {
InjectionCallbacks.push_back(
...
And the interface still seems acceptable:
injectModulePassManagerBefore<ExpandFpPass>([] {
TargetModulePassManager MPM;
MPM.addPass(NoOpModulePass());
return MPM;
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need syntactic salt for pass pipeline building DSL here, i.e. let users know they are injecting module pass into function or machine function pass pipeline, module pass would cause higher memory usage in codegen pipeline.
Maybe we can make injectModulePassManagerBefore usable only when PassT is a function pass or machine function pass.
This implementation supports
--start/stop-before/afteroptions by hijacking original pass managers. With injected-class-name, user should not feel any difference from original pass manager in most cases.Except virtual functions to add necessary passes (e.g. instruction select pass), the only method to extend the pipeline is
injectBefore, which accept a callback to extend pipeline at the specified point. The return type of the callback is depend on the selected passinjectBefore<SomeFunctionPass>([](){ FunctionPassManager FPM; // Add passes you want. return FPM; }); // If you really want to add module pass between machine function passes... injectBefore<SomeMachineFunctionPass, ModulePassManager>([](){ ModulePassManager MPM; MachineFunctionPass MFPM; // Add passes you want. MPM.createModuleToFunctionPassAdaptor(createFunctionToMachineFunctionPassAdaptor(std::move(MFPM))); return MPM; });