First, thanks very much for your comments!<br><br><div class="gmail_quote">On Sat, Feb 28, 2009 at 8:05 PM, Evan Cheng <span dir="ltr"><<a href="mailto:evan.cheng@apple.com">evan.cheng@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class="Ih2E3d"><br>
On Feb 26, 2009, at 2:02 PM, John Mosby wrote:<br>
> It is limited to X86 presently since that is the only target I have</div><div class="Ih2E3d">
> access to at the moment.<br>
<br>
</div>What part of this is target dependent? Is this due to emitPrologue /<br>
emitEpilogue being target specific?<br>
<div class="Ih2E3d"></div></blockquote><div><br></div><div>It is target dependent (X86) at present because of the way I developed it, just using the X86 target since that is the only one on which I can test the entire (static) flow: test.c -> llvm-gcc -emit-llvm -> (.ll, .bc) -> llc --shrink-wrap -> .s -> gcc test.s -o test.</div>
<div><br></div><div>I worked with other targets also, but I decided to take it as far as I could on the first go with X86.</div><div><br></div><div>First pass was without debugging info and with simple stack frames, in the interest of getting as much worked out as possible.</div>
<div>I saw the issue concerning how code gen handles placement of spill and restore code outside of entry/return blocks before I had the first test cases running, but I worked through the details using -march=x86 only.</div>
<div><br></div><div>Re: debugging info: I know about the work to change the way debugging info is handled, so I held off trying to make the shrink wrapping work with the current impl.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="Ih2E3d">> The main features are:<br>
>   - Placing callee saved register (CSR) spills and restores in the<br>
> CFG to tightly surround uses<br>
>      so that execution paths that do not use CSRs do not pay the<br>
> spill/restore penalty.<br>
><br>
>   - Avoiding placment of spills/restores in loops: if a CSR is used<br>
> inside a loop(nest), the spills<br>
>      are placed in the loop preheader, and restores are placed in<br>
> the loop exit nodes (the<br>
>      successors of the loop _exiting_ nodes).<br>
><br>
>   - Covering paths without CSR uses: e.g. if a restore is placed in<br>
> a join block, a matching spill<br>
>      is added to the end of all immediate predecessor blocks that<br>
> are not reached by a spill.<br>
>      Similarly for saves placed in branch blocks.<br>
<br>
</div>Sounds great. It would help everyone if you can show some examples code.</blockquote><div><br></div><div>I am putting documented examples together from the test cases in the patch.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="Ih2E3d">> Since I ran into a non-trivial issue in developing this pass, I<br>
> would like to submit my implementation as a "RFC + code/tests"<br>
> rather than a typical contribution, and get people's opinions on how<br>
> to proceed.<br>
><br>
> The issue is that the code generator assumes all spills and restores<br>
> of callee saved registers must be placed in the entry and return<br>
> blocks resp.<br>
> Shink wrapping violates this assumption, with the result that the<br>
> frame offsets computed by PEI for frame-relative operands may be<br>
> incorrect.<br>
<br>
</div>I am not sure how this would happen. Why would frame offsets be<br>
affected by where these instructions are placed?</blockquote><div><br></div><div>The issue is illustrated by a simple example in which a single CSR is used in one branch of a conditional. When the stack frame is laid out, the spill for this CSR is accounted for in the calculation of stack size as it should be. The stack slot for the CSR is correctly computed and everything seems fine when the MO_FrameIndex are replaced. The problem is that since the spill instruction for the CSR (e.g. pushl %esi) is moved from the entry block, the push does not happen, and the value of %esp in the entry block is not what it should be to satisfy the offsets produced by eliminateFrameIndex().</div>
<div>A similar situation exists for the BB into which a spill is "moved" (from the entry block): a push happens  to spill the CSR on entry to the block, and now %esp is not what it should be for that block. The example below illustrates this issue:</div>
<div><br></div><div>assume:</div><div>int F(int a, int b, int c) uses one CSR in conditional branch</div><div><br></div><div>prologue, no shrink wrapping:</div><div><br></div><div><div>_F:</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>pushl<span class="Apple-tab-span" style="white-space:pre">       </span>%esi                   # spill CSR %csi, %esp -= 4 (in this case)</div>
<div><span class="Apple-tab-span" style="white-space:pre">      </span>subl<span class="Apple-tab-span" style="white-space:pre">        </span>$56, %esp           # create frame, %esp = %esp - 56</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>movl<span class="Apple-tab-span" style="white-space:pre">        </span>64(%esp), %eax  # fetch arg 'a' from entry %esp + 4</div>
<div><span class="Apple-tab-span" style="white-space:pre">      </span>movl<span class="Apple-tab-span" style="white-space:pre">        </span>%eax, 52(%esp)</div><div><span class="Apple-tab-span" style="white-space:pre">       </span>movl<span class="Apple-tab-span" style="white-space:pre">        </span>68(%esp), %eax  # fetch arg 'b'</div>
<div><div><span class="Apple-tab-span" style="white-space:pre">   </span>movl<span class="Apple-tab-span" style="white-space:pre">        </span>%eax, 48(%esp)</div><div>...</div><div><br></div><div>prologue with spill shrink-wrapped to basic block bb:</div>
<div><br></div><div><div>_F:</div><div>        # no spill of %esi, moved to bb</div><div><span class="Apple-tab-span" style="white-space:pre">  </span>subl<span class="Apple-tab-span" style="white-space:pre">        </span>$56, %esp          # create frame same as before %esp = %esp - 56</div>
<div><span class="Apple-tab-span" style="white-space:pre">      </span>movl<span class="Apple-tab-span" style="white-space:pre">        </span>64(%esp), %eax  # error: 'a' is not at 64(%esp), it's at 60(%esp)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>movl<span class="Apple-tab-span" style="white-space:pre">        </span>%eax, 52(%esp)</div>
<div>...</div><div><br></div><div>The simple, ugly hack of adjusting the value by which %esp is decremented in the prologue when one or more CSR spills have been placed into other blocks takes care of the issue on this simple code (no dynamic stack realign., nor EH) on x86.</div>
<div><br></div><div>The companion hack for (non entry) MBBs into which spills have been introduced is to adjust the stack size around eliminateFrameIndex()'s for replacement of MO_FrameIndex operands.</div><div><br></div>
<div>Obviously, all of this applies only when spills are done with push/pop, which is the case on x86. I used this issue to start looking at generalizing how spills and restores are handled, before looking too closely at other targets, and developed the workaround for the initial implementation.</div>
<div><br></div></div></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class="Ih2E3d">><br>
> My limited implementation uses a workaround that adjusts the<br>
> generation of prologue code and the frame indices used by<br>
> the target eliminateFrameIndex() when necessary. I am looking at<br>
> several approaches, but I would like input from anyone who<br>
> has an opinion.<br>
><br>
<br>
</div>I think to do this right for every target is a big job. I'd like to<br>
see prologue / epilogue related stuff be moved out of<br>
TargetRegisterInfo. Shrink wrapping will only happen when the targets<br>
buy-in, i.e. providing the right hooks.<br></blockquote><div><br></div><div>Part of what I'm doing now is estimating the work, which requires going through the targets. I am not far enough along to send out a proposal. Moving pro/epi generation out of TRI, perhaps into its own "component" is one architecture I am looking at.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">When is shrink wrapping happening? Is it possible to do it after CSR<br>
spills and restores are inserted but before FI are lowered into sp /<br>
fp +/- offset?</blockquote><div><br></div><div>Shrink wrapping starts after calculateCalleeSavedRegisters(), which creates the list of CSRs used in the function. Shrink wrapping assigns MBB placements for spills and restores based on where they are used. calculateCalleeSavedRegisters() determines stack slots for the CSRs used in the function.</div>
<div>I don't see an interaction between this and shrink wrapping, of have I missed something?</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="Ih2E3d">> Finally, I realize that shrink wrapping is probably not high<br>
> priority in the larger scheme of LLVM development, so I'm not<br>
> expecting<br>
> a huge response, but any ideas are certainly welcome.<br>
<br>
</div>It's actually a fairly useful optimization. It can really help a class<br>
of functions, e.g. functions with early returns.<br>
<div class="Ih2E3d"></div></blockquote><div><br></div><div>Quite right, it is certainly worthwhile. I could have left that comment out :-)</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="Ih2E3d"><br>
><br>
> The patch and a test tarball are attached. I include basic tests<br>
> that are run with the supplied Makefile.<br>
<br>
</div>Some comments:<br>
<br>
1. The code needs some refactoring. :-) It's a big chunk of code so<br>
it's hard to digest.<br>
2. There doesn't seem to be a way to turn off shrink wrapping. Please<br>
make sure it's optional. When it's not being done, PEI should not<br>
require dominator, etc.<br></blockquote><div><br></div><div>I already refactored once, but I knew it would not be enough(!), I'll definitely do another pass. I forgot to put the analysis deps under --shrink-wrap, I will fix that and anything else that I might have left out of the option.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
 From what I can see this is a very good first step. I look forward to<br>
seeing its completion.<br>
<br>
Evan<br></blockquote><div><br></div><div>Thanks! Likewise, and it's a pleasure to work on.</div><div><br></div><div>John</div><div><br></div><div><br></div></div>