Nagurne, James via llvm-dev
2021-Dec-13 20:59 UTC
[llvm-dev] Looking for guidance/examples/docs related to "Super Passes"
Hi all, I'm working on a downstream target and have been coming across times where I would like to run a pass during another pass. Specifically, the MachinePipeliner is a pass that can be somewhat reliant on prior optimizations, and may greatly affect future optimizations. Case-in-point, register allocation: 2019 EuroLLVM Developers' Meeting: L. Saba "Swinging Modulo Scheduling together with Register ..." - YouTube<https://www.youtube.com/watch?v=o4R3SqyNbqU> This presentation brings two things to light that I am not well-versed in: * Passes that run other passes * Communication between passes At this point I'd be interested in information on both the Legacy and New pass managers, but my implementation and expertise is only at the "Machine" IR level at the moment, so I will be using the Legacy pass manager in examples. -- 1. Is there a best-practices way to creating a 'super' pass? The first bullet concerns the concept that there exists some pass that runs the allocator and pipeliner in a loop. One relevant example is this pull request for a MachineInstr-level unroller for MachinePipeliner. https://reviews.llvm.org/D53005 In this change set, the implementer creates an 'Unroller', an object that is somewhat pass-like, and calls its unroll function during the information-gathering phase of the pipeliner. Should it succeed, analysis and data is rebuilt, and the pipeliner proceeds with the new loop body. This seems messy: * The loop is completely rewritten in-place by the unroller before knowing that pipelining will succeed * The pipeliner effectively needs to 'reset' and recalculate all of the relevant data, such as MII But is there a better way? Perhaps a MachineFunctionPass that calls BasicBlock or MachineLoop helpers in both the Unroller and MachinePipeliner in turn? This leads to my next question.. -- 1. How do passes communicate to one another? The communication in the presentation above is whether the register allocator was capable of allocating the pipelined loop. In the case that it can't, the pipeliner is called again with a bumped ii or different heuristic. How would this be implemented in an LLVM-like way? The presenter mentions ImmutablePass, but I'm not very familiar with how those are accessible in, say, the MachinePipeliner pass. More generally, is there an LLVM-standard way to forward information from one pass to an arbitrary future pass, or a way to annotate blocks? I've thought it might be useful in places to know that a MachineBasicBlock is pipelined (such as during scheduling), but have not found an obvious way to do so. -- As a conclusion/summary of what I'm trying to do, I'm considering that MachinePipeliner could be a MachineFunction superpass that calls various MachineLoopPasses prior to creating the modulo schedule. One of these could be unrolling, while another could be unroll-related optimizations such as MachineInstr-level loop vectorization or condensing address post-increments into the final operation in a chain to reduce the RecMII of the loop. In essence, this will give the ability for targets to seamlessly insert their own heuristics and optimizations to the pipeliner. Regards, J.B Nagurne Code Generation Texas Instruments -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20211213/9c09e0d9/attachment-0001.html>