llvm-project
llvm-project copied to clipboard
[CodeGen][Pass] Add `TargetPassBuilder`
This implementation supports --start/stop-before/after options 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 pass
injectBefore<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;
});
injectBefore and disablePass methods are independent of addPass calls which is nice.
But there are no virtual methods, so are we removing distinct phases (like addPreEmitPasses()) completely and only using injectBefore() now?
If we don't want overrides (virtual/CRTP) we could add "phase marker" passes (that are dummy passes like ISelPrepareBegin()) to be used with injectBefore.
But there are no virtual methods, so are we removing distinct phases (like
addPreEmitPasses()) completely and only usinginjectBefore()now?
IMHO some phases here is not clear, the example is pre emit, we have addPreEmitPasses and addPreEmitPasses2() thus here only provides injectBefore.
If we don't want overrides (virtual/CRTP) we could add "phase marker" passes (that are dummy passes like
ISelPrepareBegin()) to be used withinjectBefore.
Yeah pre isel is one of phases injectBefore() can't handle easily, may add them in future.
To be more radical, I even want to use type erasure to ensure backends only add dag isel and asm printer to replace the getSelectionDAGISelPass in current code.
Ping @aeubanks @arsenm
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
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 PassManagerWrappers and PassWrappers. Backends will derive from TargetPassBuilder and adjust this intermediate structure with operations like filtPassList() and injectBefore(). Eventually, TargetPassBuilder's constructRealPassManager() will transcribe it into the final structure of actual PassManagers and return the executable pipeline. (This part of the patch has no test coverage yet.) Is that about right?
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
PassManagerWrappers andPassWrappers. Backends will derive from TargetPassBuilder and adjust this intermediate structure with operations likefiltPassList()andinjectBefore(). Eventually, TargetPassBuilder'sconstructRealPassManager()will transcribe it into the final structure of actual PassManagers and return the executable pipeline. (This part of the patch has no test coverage yet.) Is that about right?
You are right. This is a dirty hack to implement --{start,stop}-{before,after} with following the design principle of new pass manager (users need to consider pass nesting explicitly, pass manager/builder should not handle this).
Thanks! The --{start,stop}-{before,after} feature seems very important for testing purposes. The RFC first proposed to drop it in favor of testing individual passes in isolation or batches of passes with intermediate serialization. This is what the optimization pipeline already uses with the new pass manager and we should bring the codegen pipeline in line with it.
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?
You are right. This is a dirty hack to implement
--{start,stop}-{before,after}with following the design principle of new pass manager (users need to consider pass nesting explicitly, pass manager/builder should not handle this).
What exactly do you consider the hack here? The logic in constructRealPassManager() with respect to the explicit nesting requirement? Or do you mean the hijacking of the pass-managers for the intermediate structure?
What exactly do you consider the hack here? The logic in
constructRealPassManager()with respect to the explicit nesting requirement? Or do you mean the hijacking of the pass-managers for the intermediate structure?
Shadowing llvm::PassManager with llvm::TargetPassBuilder::PassManager, because I want to minimize the differences in usage between the two manager. Fortunately, it doesn't trigger warnings from -Wshadow.
@paperchalice Following up from your inline comment
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.
Yes, I understand this is what the RFC means with explicit nesting. I wonder if we really need a DSL for it. Maybe a simple API, documentation and assertions would do :)
Now CodeGen part are using pass managers with Target prefix.