<div dir="ltr"><div><div><div>Hi Soren,<br><br></div>Long time no see.<br><br></div>I just finished my master degree and was thinking about to return my contributions to pixman project, exactly in JIT compiler but with LLVM.<br>

<br></div><div>What do you think about? Is it a bad idea to create a dependency with LLVM? Or will we get better results developing another infrastructure?<br></div><div><br></div><div>Best<br><br></div><div>André Tupinambá<br>

</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Jan 17, 2014 at 9:15 PM, Søren Sandmann <span dir="ltr"><<a href="mailto:soren.sandmann@gmail.com" target="_blank">soren.sandmann@gmail.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello,<br>
<br>
<br>
Over the Christmas holidays, I spent some time writing a prototype JIT<br>
compiler for pixman. Since I may not be able to spend much time working<br>
on it in the near future, I thought I'd write up a bit of information<br>
about it, in case someone else wants to play around with it.<br>
<br>
The code is available in this branch:<br>
<br>
    <a href="http://cgit.freedesktop.org/~sandmann/pixman/commit/?h=jit" target="_blank">http://cgit.freedesktop.org/~sandmann/pixman/commit/?h=jit</a><br>
<br>
Some things about it work quite well I think:<br>
<br>
- pixman-jit-x86-asm.[ch]:<br>
<br>
These files are a runtime assembler for x86 (both 64 and 32 bit). It<br>
supports most things that you expect from an assembler, such as labels<br>
and code alignment. It also correctly selects the best encoding whenever<br>
there is a choice (eg., for "add rax, $17" it will pick the short<br>
encoding available for the rax register). It also uses short jumps<br>
whenever possible.<br>
<br>
At the same time, the code is compact and fast. All the instructions are<br>
described in one big ~40Kb table, and the rest of the code (apart from<br>
the table) is just 1600 lines. It doesn't support every x86 instruction,<br>
but it's easy to add anything that is missing (although AVX-512 with its<br>
optional arguments may require a bit of work to support).<br>
<br>
If/when support for other architectures is added, this file would likely<br>
have to be split up in order to share the code for "bookkeeping" (labels<br>
etc.), while allowing different instruction sets.<br>
<br>
A missing feature is the ability to free the generated code, and there<br>
are almost certainly bugs related to out-of-memory conditions.<br>
<br>
The way to use it is like this:<br>
<br>
    fragment1 = assembler_create_fragment (asm);<br>
<br>
    BEGIN_ASM (fragment1)<br>
          DEFINE_LABEL ("begin"),<br>
          I_mov,         rax,       IMM (17),<br>
          I_add,         rbx,       rax,<br>
          I_jne,         LABEL ("done"),<br>
          I_jmp,         LABEL ("begin"),<br>
          DEFINE_LABEL ("done"),<br>
          I_ret,<br>
    END_ASM ();<br>
<br>
    code = assembler_link (asm, fragment1, fragment2, NULL);<br>
<br>
where assembler_link will concatenate the code described in fragment1<br>
and fragment2, resolve labels and jumps, then return a pointer to<br>
executable code.<br>
<br>
- pixman-jit-code-manager.[ch]:<br>
<br>
These files handle memory management for executable memory, ie., mapping<br>
files and marking them writable and executable as needed. When SELinux<br>
and other security features are involved you can't just malloc() some<br>
memory and execute it.<br>
<br>
An interesting potential feature would be to make the allocated files<br>
ELF files so that they would show up in profilers. The main missing<br>
piece here is the ability to free allocated memory.<br>
<br>
(And of course there is no support for Windows or anything else<br>
non-Linux).<br>
<br>
- New pixman infrastructure to deal with jitted compositing functions<br>
<br>
This turned out to be a pretty simple extension of the 'fast path'<br>
mechanism already in place. Instead of implementations exposing a table<br>
of fast paths, they now expose a pair of functions 'create_composite'<br>
and 'destroy_composite' that are passed the flags supported by the<br>
images in questions, where by default create_composite() simply scans<br>
the fast path table looking for a match, and destroy_composite() is a<br>
noop.<br>
<br>
When a fast path is evicted from the cache, destroy_composite() is<br>
called. A jitting implementation can then simply have its<br>
create_composite() jit a compositing function and destroy it in<br>
destroy_composite(). Caching is then handled by the existing<br>
mechanism. (It may be useful to expand the fast path cache if jitting<br>
turns out to be very expensive).<br>
<br>
<br>
The less convincing part is pixman-x86-jit.[ch], which is a jitting<br>
implementation for x86-64 that can generate various blitter-type<br>
compositing functions. This means it isn't all that useful right now<br>
because pixman-sse2.c has those covered pretty well.<br>
<br>
Also, while the code generated isn't totally awful, it isn't really<br>
great either. In particular, it is built on the assumption that<br>
source/mask/destination will be converted to a8r8g8b8/a8/a8r8g8b8 and<br>
then combined. However, in many cases, this isn't optimal:<br>
<br>
- For a8b8g8r8 OVER a8b8g8r8 it is clearly counterproductive to convert<br>
  both source and destination to a8r8g8b8, and then convert back to<br>
  a8b8g8r8.<br>
<br>
- For solid sources we want to do all the source swizzing outside of the<br>
  main loop, and also extract the alpha channel into its own<br>
  register. There is no support for this currently.<br>
<br>
Another less-convincing bit is the register allocator, which is as dumb<br>
as possible. All it does is keeping track of available registers and<br>
hand them out as needed. There is no spilling, and if it runs out of<br>
registers, it will simply abort().<br>
<br>
This is sufficient for generating blitters on x86-64 (provided the<br>
aborting is turned into giving up), where we have 14 general purpose<br>
registers, but won't be good enough for x86-32, nor will it be good<br>
enough if more complicated sources than regular untransformed images are<br>
added.<br>
<br>
There is also no support for dealing with constants. When there is<br>
enough registers, we want to allocate constants in registers; when there<br>
isn't we want to put them ideally in one shared constant pool, but<br>
otherwise, on the stack, or directly embedded in the code (in the case<br>
of x86-64, where we have RIP-relative addressing).<br>
<br>
Right now, certain specific constants are just permanently allocated in<br>
registers, but this is not ideal.<br>
<br>
Finally, there is a large number of boring, but straightforward, tasks,<br>
such as dealing with OOM and fixing memory leaks. Also the patch series<br>
of course would need to be cleaned up.<br>
<br>
Anyway, if anyone is interested in this, I'll be happy to answer<br>
questions either here on the mailing list or on IRC, but as mentioned I<br>
may not be able to do a lot of work on it for a while.<br>
<br>
<br>
Søren<br>
_______________________________________________<br>
Pixman mailing list<br>
<a href="mailto:Pixman@lists.freedesktop.org">Pixman@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/pixman" target="_blank">http://lists.freedesktop.org/mailman/listinfo/pixman</a><br>
</blockquote></div><br></div>