[llvm] [Draft] Support save/restore point splitting in shrink-wrap (PR #119359)
Elizaveta Noskova via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 27 07:51:23 PST 2026
enoskova-sc wrote:
@asb, @preames,
I’ve been exploring ways to improve the shrink-wrap algorithm and enable it to apply in more cases. During this investigation, I noticed that current implementation (even with both splitting and post-shrink-wrapping enabled) still skips many opportunities, especially in functions with multiple return points. In fact, [post-shrink-wrapping is explicitly disabled in such cases](https://github.com/llvm/llvm-project/blob/c1152f0fb250a8321dbb2aa73e2a8d6c798f2127/llvm/lib/CodeGen/ShrinkWrap.cpp#L598).
To illustrate, consider the following CFG (s0, s1 are callee saved registers):
<img width="338" height="521" alt="initial-graph" src="https://github.com/user-attachments/assets/966c9bf9-d201-4c02-956e-13fff9cc51b6">
With the current algorithm (even with post-shrink-wrapping and my splitting optimization enabled) we get this result:
<img width="338" height="521" alt="current-approach" src="https://github.com/user-attachments/assets/bf89ffab-1172-48e8-b405-3058a11a7e76">
As you can see:
- Current implementation of shrink-wrap splitting fails because s1 is used in BB3 and BB1, nearest common post-dominator for BB1 and BB3 is BB3 and there is an edge between BB0 and BB3.
- Post-shrink-wrapping doesn’t run at all due to the multiple returns.
Yet, we clearly don’t want to save/restore s1 on the BB0 --> BB2 path, since it’s unused there.
To address this, I propose a reworked shrink-wrap algorithm that places saves and restores more precisely. The key differences from the current approach are:
- Each register can have multiple save and multiple restore points (currently, only restores can be duplicated and only in multi-return functions).
- Edge splitting is used for both saves and restores, not just restores. This works even in functions with multiple returns.
- Instead of searching for basic blocks as candidates for save/restore placement, we identify edges where saves or restores are needed, then split those edges and insert new basic blocks containing the required operations. (Some post-processing should follow to merge some blocks.)
- The new algorithm enables splitting and post-shrink-wrapping by default, but will include a fallback option to use the original behavior, at least because multiple save/restore points require explicit backend support.
Applied to the same example, the new algorithm produces this result:
<img width="441" height="521" alt="new-approach" src="https://github.com/user-attachments/assets/9e65e5dc-23bd-49dc-a5d8-dbe7309af726" />
I plan to prototype this approach and share performance results soon. If you have any concerns about new algorithm, please, write here.
https://github.com/llvm/llvm-project/pull/119359
More information about the llvm-commits
mailing list