I admit I got carried away with trying to use an extra static link when the arg parameter would've sufficed. Using a static link is probably still a better idea because if there are > 1 loop to parallelize in a function, they would share the same parent frame struct but might have a separate structs describing their parameters.<br>
<br>"you must be the first person to try using nest functions with the JIT :) "<br><br>Well, this is a project in a dynamic optimization course. The JIT lacks a lot of things for this purpose like recompiling, patching old callers to refer to the new code, and deleting old machine code - currently, it just overwrites the old code with a branch to the new code and makes no attempt to patch the callers. We'll probably come up with something more sophisticated and submit it.<br>
<br>"If you look in X86JITInfo.cpp, in the function X86JITInfo::emitFunctionStub,<br>
you will see the code generating the stub and using r10"<br><br>I didn't expect it to be that easy. I thought I needed to add special rules to the register allocator. I'll take a look at it.<br><br><div class="gmail_quote">
On Sat, Nov 1, 2008 at 3:54 AM, Duncan Sands <span dir="ltr"><<a href="mailto:duncan.sands@math.u-psud.fr">duncan.sands@math.u-psud.fr</a>></span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi,<br>
<div><div></div><div class="Wj3C7c"><br>
> I'm parallelizing loops to be called by pthread. The thread body that I pass<br>
> to pthread_create looks like<br>
><br>
> define i8* @loop1({ i32*, i32* }* nest  %parent_frame, i8* %arg)<br>
> parent_frame is pointer to shared variables in original function<br>
><br>
> 0x00007f0de11c41f0:     mov    (%r10),%rax<br>
> 0x00007f0de11c41f3:     cmpl   $0x63,(%rax)<br>
> 0x00007f0de11c41f6:     jg     0x7f0de11c420c<br>
> 0x00007f0de11c41fc:     mov    0x8(%r10),%rax<br>
> 0x00007f0de11c4200:     incl   (%rax)<br>
> 0x00007f0de11c4202:     mov    (%r10),%rax<br>
> 0x00007f0de11c4205:     incl   (%rax)<br>
> 0x00007f0de11c4207:     jmpq   0x7f0de11c41f0<br>
> 0x00007f0de11c420c:     xor    %rax,%rax<br>
> 0x00007f0de11c420f:     retq<br>
><br>
> I use init_trampoline to generate code that sets up the static link:<br>
><br>
> 0x00007fffee982316:     mov    $0x7f48e1a08fb0,%r11<br>
> 0x00007fffee982320:     mov    $0x7fffee982330,%r10               the static<br>
> link<br>
> 0x00007fffee98232a:     rex.WB jmpq   *%r11<br>
><br>
> The program crashes in loop1 on the 2nd instruction. r10, which contained<br>
> the static link was different from the value set by the trampoline.<br>
><br>
> Upon closer inspection, it looks like the trampoline first jumps to a stub<br>
> that compiles loop1:<br>
><br>
> 0x00007f48e1a08fb0:     mov    $0x5c61c0,%r10<br>
> 0x00007f48e1a08fba:     callq  *%r10<br>
> 0x00007f48e1a08fbd:     int    $0x0<br>
><br>
> But that clobbers r10 which loop1 needs. According to the x86-64 ABI, r10<br>
> isn't preserved across functions, but here it needs to be. Is there anyway<br>
> to force LLVM to do that?<br>
<br>
</div></div>you must be the first person to try using nest functions with the JIT :)<br>
If you look in X86JITInfo.cpp, in the function X86JITInfo::emitFunctionStub,<br>
you will see the code generating the stub and using r10.  I think the right<br>
solution is to change r10 to a different call clobbered register.  It would<br>
also be possible to have the trampoline use a different register, but since<br>
the x86-64 ABI explicitly states that r10 should be used for the static chain,<br>
I'd rather not.<br>
<br>
I'm also wondering about the x86-32 case.  There are no comments in the<br>
JIT stub code in this case, so I'm not sure which register it is using.<br>
The problem with x86-32 is that there are so few registers, and for some<br>
calling conventions there is only one spare call clobbered register<br>
available.  This is used by trampolines, so if it's also used by JIT,<br>
which is almost surely the case, that will cause trouble.  Even worse,<br>
it looks like the JIT is wrong even without trampolines, because for<br>
the C and X86_StdCall conventions it is ECX that is spare, while for<br>
X86_FastCall and Fast it is EAX.  Yet the JIT always uses the same<br>
hardwired code, and does not adjust according to the calling convention.<br>
So presumably it is broken for one of these sets of calling conventions.<br>
<br>
Hopefully Anton can comment on this.<br>
<div class="Ih2E3d"><br>
> I tried telling lli to compile the entire program<br>
> (-no-lazy) so that the stub won't be generated, but gives the error:<br>
><br>
> LLVM JIT requested to do lazy compilation of function<br>
> '_Z41__static_initialization_and_destruction_0ii' when lazy compiles are<br>
> disabled!<br>
><br>
> Any ideas?<br>
><br>
> Note, I had to compile lli with -z execstack in order for trampolines on the<br>
> stack to work.<br>
<br>
</div>Maybe lli can be taught to mark itself as having an executable stack when<br>
it sees a trampoline.  I'm not sure how this can best be done.  On linux<br>
I guess it can be done using mmap.<br>
<br>
Ciao,<br>
<font color="#888888"><br>
Duncan.<br>
</font></blockquote></div><br>