<div dir="ltr"><div>Hi,</div><div><br></div><div>I have a question about the way sub-registers are spilled and restored that is related to the changes I made in r192119.</div><div><br></div><div>Suppose I have the following piece of code with four instructions. %vreg0 and %vreg1 consist of two sub-registers indexed by sub_lo and sub_hi.</div>

<div><br></div>instr0 %vreg0<def><div>instr1 %vreg1:sub_lo<def<span style="font-family:arial,sans-serif;font-size:13px">,read-undef</span>><br></div><div>instr2 %vreg0<use></div><div><div>instr3 %vreg1:sub_hi<def></div>

</div><div><br></div><div>If register allocator decides to insert spill and restore instructions for %vreg0, will it spill the whole register that includes sub-registers lo and hi?</div><div><br></div><div>instr0 %vreg0<def></div>

<div>spill0 %vreg0<br><div>instr1 %vreg1:sub_lo<def<span style="font-family:arial,sans-serif;font-size:13px">,read-undef</span>><br></div>spill1 %vreg1:sub_lo<br>restore0 %vreg0<br><div>instr2 %vreg0<use></div>

restore1 %vreg1:sub_lo<br><div>instr3 %vreg1:sub_hi<def></div></div><div><br></div><div>Or will it spill just the lo sub-register?</div><div><br></div><div><div>instr0 %vreg0<def></div><div>spill0 %vreg0:sub_lo<br>

<div>instr1 %vreg1:sub_lo<def<span style="font-family:arial,sans-serif;font-size:13px">,read-undef</span>><br></div>spill1 %vreg1:sub_lo<br>restore0 %vreg0:sub_lo<br><div>instr2 %vreg0<use></div>restore1 %vreg1:sub_lo<br>

<div>instr3 %vreg1:sub_hi<def></div></div></div><div><br></div><div>If it spills the whole register (both sub-registers lo and hi), the changes I made should be fine. Otherwise, I will have to find another way to prevent the problems I mentioned in r192119's commit log.</div>

<div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Oct 7, 2013 at 1:11 PM, Matthias Braun <span dir="ltr"><<a href="mailto:matze@braunis.de" target="_blank">matze@braunis.de</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I've been working on patches to improve subregister liveness tracking on llvm and I wanted to inform the llvm community about the overal design/motivation for them. I will send the patches to llvm-commits later today.<br>

<br>
Greetings<br>
    Matthias Braun<br>
<br>
<br>
Subregisters in llvm<br>
====================<br>
<br>
Some targets can access registers in different ways resulting in wider or<br>
narrower accesses. For example on ARM NEON one of the single precision<br>
floating point registers is called 'S0'. You may also access 'D0' on arm which<br>
is the combination of 'S0' and 'S1' and can store a double prevision number or<br>
2 single precision floats. 'Q0' is the combination of 'S0', 'S1', 'S2' and<br>
'S3' (or 'D0' and 'D1') and so on.<br>
<br>
Before register allocation llvm machine code accesses values through virtual<br>
registers, these get assigned to physical registers later. Each virtual<br>
register has an assigned register class which is a set of physical registers.<br>
So for example on ARM you have a register class containing all the 'SXX'<br>
registers and another one containing all the 'DXX' registers, ...<br>
<br>
But sometimes you want to mix narrow and wide accesses to values. Like loading<br>
the 'D0' register but later reading the 'S0' and 'S1' components separately.<br>
This is modeled with subregister operands which specify that only parts of a<br>
wider value are accessed. For example the register class of the 'DXX'<br>
registers supports subregisters calls 'ssub_0' and 'ssub_1' which would<br>
result in 'S4' and 'S5' getting used if 'D2' is assigned to the virtual<br>
register later.<br>
<br>
Typical operations are decomposing wider values or composing wide values with<br>
multiple smaller defs:<br>
<br>
Decomposing:<br>
%vreg1<def> = produce a 'D' value<br>
            = use 'S' value %vreg1:ssub_0<br>
            = use 'S' value %vreg1:ssub_1<br>
<br>
Composing:<br>
%vreg1:ssub_0<def,read-undef> = produce an 'S' value<br>
%vreg1:ssub_1<def>            = produce an 'S' value<br>
           = use a 'D' value %vreg1<br>
<br>
Problems / Motivation<br>
=====================<br>
<br>
Currently the llvm register allocator tracks liveness for whole virtual<br>
registers. This can lead to suboptimal code:<br>
<br>
%vreg0:ssub_0<def,read-undef> = produce an 'S' value<br>
%vreg0:ssub_1<def> = produce an 'S' value<br>
       = use a 'D' value %vreg0<br>
%vreg1 = produce an 'S' value<br>
       = use an 'S' value %vreg1<br>
       = use an 'S' value %vreg0:ssub_0<br>
<br>
The current code will realize that vreg0 and vreg1 interfere and assign them<br>
to different registers like D0+S2 aka S0+S1+S2; while in reality after the<br>
full use of %vreg0 only %vreg0::ssub_0 must remain in a register while the<br>
subregister used for %vreg0:ssub_1 can be reassigned to %vreg1. An ideal<br>
assignment would be D0+S1 aka S0+S1.<br>
<br>
A even more pressing problem are artificial dependencies in the schedule<br>
graph. This is a side effect of llvms live range information being represented<br>
in a static single assignment like fashion: Every definition of a vreg starts<br>
a new interval with a new value number. This means that partial register<br>
writes must be modeled as an implicit use of the unwritten parts of a register<br>
and force the creating of a new value number. This in turn leads to artificial<br>
dependencies in the schedule graph for code like the following where all defs<br>
should be independent:<br>
<br>
%vreg0:ssub_0<def,read-undef> = produce an 'S' value<br>
%vreg0:ssub_1<def>            = produce an 'S' value<br>
%vreg0:ssub_2<def>            = produce an 'S' value<br>
%vreg0:ssub_3<def>            = produce an 'S' value<br>
<br>
<br>
Subegister liveness tracking<br>
============================<br>
<br>
I developed a set of patches which enable liveness tracking on the subregister<br>
level, to overcome the problems mentioned above. After these changes you can<br>
have separate live ranges for subregisters of a virtual register. With these<br>
patches the following code:<br>
<br>
  16B  %vreg0:ssub_0<def,read-undef> = ...<br>
  32B  %vreg0:ssub_1<def>            = ...<br>
  48B               = %vreg0<br>
  64B               = %vreg0:ssub_0<br>
  80B  %vreg0 = ...<br>
  96B         = %vreg0:ssub_1<br>
<br>
will be represented as the following live range(s):<br>
<br>
  Common LiveRange: [16r,32r)[32r,64r),[80r,96r)<br>
  SubRange with Mask 0x0004 (=ssub_0): [16r,64r)[80r,80d)<br>
  SubRange with Mask 0x0008 (=ssub_1): [32r,48r)[80r,96r)<br>
<br>
Patches/Changes:<br>
* Moves live range management code in the LiveInterval class to a new<br>
  class LiveRange, move the previous LiveRange class (which was just a single<br>
  interval inside a live range) to LiveRange::Segment.<br>
  LiveInterval is made a subclass of LiveRange, other code paths like<br>
  register units liveness use LiveRange instead of LiveInterval now.<br>
* Introduce a linked list of SubRange objects to the LiveInterval class.<br>
  A SubRange is a subclass of LiveRange and contains a LaneMask indicating<br>
  which subregisters are represented.<br>
* Various algorithms have been adapted to calculate/preserve subregister<br>
  liveness.<br>
* The register allocator has been adapted to track interference at the<br>
  subregister level (LaneMasks are mapped to register units)<br>
<br>
Note that SubRegister liveness tracking has to be explicitely enabled by the<br>
target architecture, as it does not provide enough benefits for the costs on<br>
some targets (e.g. having subregister liveness for the lower/upper 8bit regs<br>
on x86 provided nearly no benefits in the llvm-testsuite, so you can't justify<br>
more computations/memory usage for that.<br>
______________________________<u></u>_________________<br>
LLVM Developers mailing list<br>
<a href="mailto:LLVMdev@cs.uiuc.edu" target="_blank">LLVMdev@cs.uiuc.edu</a>         <a href="http://llvm.cs.uiuc.edu" target="_blank">http://llvm.cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/llvmdev</a><br>
</blockquote></div><br></div>