Register Allocation issues with microblaze-elf
Vladimir Makarov
vmakarov@redhat.com
Thu Feb 14 01:28:00 GMT 2013
On 13-02-13 6:36 PM, Michael Eager wrote:
> On 02/13/2013 02:38 PM, Vladimir Makarov wrote:
>> On 13-02-13 1:36 AM, Michael Eager wrote:
>>> Hi --
>>>
>>> I'm seeing register allocation problems and code size increases
>>> with gcc-4.6.2 (and gcc-head) compared with older (gcc-4.1.2).
>>> Both are compiled using -O3.
>>>
>>> One test case that I have has a long series of nested if's
>>> each with the same comparison and similar computation.
>>>
>>> if (n<max_no){
>>> n+=*(cp-*p++);
>>> if (n<max_no){
>>> n+=*(cp-*p);
>>> if (n<max_no){
>>> . . . ~20 levels of nesting
>>> <more computations with 'cp' and 'p'>
>>> . . . }}}
>>>
>>> Gcc-4.6.2 generates many blocks like the following:
>>> lwi r28,r1,68 -- load into dead reg
>>> lwi r31,r1,140 -- load p from stack
>>> lbui r28,r31,0
>>> rsubk r31,r28,r19
>>> lbui r31,r31,0
>>> addk r29,r29,r31
>>> swi r31,r1,308
>>> lwi r31,r1,428 -- load of max_no from stack
>>> cmp r28,r31,r29 -- n in r29
>>> bgeid r28,$L46
>>>
>>> gcc-4.1.2 generates the following:
>>> lbui r3,r26,3
>>> rsubk r3,r3,r19
>>> lbui r3,r3,0
>>> addk r30,r30,r3
>>> swi r3,r1,80
>>> cmp r18,r9,r30 -- max_no in r9, n in r30
>>> bgei r18,$L6
>>>
>>> gcc-4.6.2 (and gcc-head) load max_no from the stack in each block.
>>> There also are extra loads into r28 (which is not used) and r31 at
>>> the start of each block. Only r28, r29, and r31 are used.
>>>
>>> I'm having a hard time telling what is happening or why. The
>>> IRA dump has this line:
>>> Ignoring reg 772, has equiv memory
>>> where pseudo 772 is loaded with max_no early in the function.
>>>
>>> The reload dump has
>>> Reloads for insn # 254
>>> Reload 0: reload_in (SI) = (reg/v:SI 722 [ max_no ])
>>> GR_REGS, RELOAD_FOR_INPUT (opnum = 1)
>>> reload_in_reg: (reg/v:SI 722 [ max_no ])
>>> reload_reg_rtx: (reg:SI 31 r31)
>>> and similar for each of the other insns using 722.
>>>
>>> This is followed by
>>> Spilling for insn 254.
>>> Using reg 31 for reload 0
>>> for each insn using pseudo 722.
>>>
>>> Any idea what is going on?
>>>
>> So many changes happened since then (7 years ago), that it is very
>> hard to me to say something
>> definitely. I also have no gcc-4.1 microblaze (as I see microblaze
>> was added to public gcc for 4.6
>> version) and it makes me even more difficult to say something useful.
>>
>> First of all, the new RA was introduced in gcc4.4 (IRA) which uses
>> different heuristics
>> (Chaitin-Briggs graph coloring vs Chow's priority RA).
>>
>> We could blame IRA when we have the same started conditions for it RA
>> gcc4.1 and gcc4.6-gcc-4.8.
>> But I am sure it is not the same. More aggressive optimizations
>> creates higher register pressure. I
>> compared peak reg pressure in the test for gcc4.6 and gcc4.8. It
>> became higher (from 102 to 106).
>> I guess the increase was even bigger since gcc4.1.
>
> I thought about register pressure causing this, but I think that
> should cause
> spilling of one of the registers which were not used in this long
> sequence,
> rather than causing a large number of additional loads.
>
Longer living pseudos has more probability to be spilled as they usually
conflicts with more pseudos during their lives and spilling them frees a
hard reg for many conflicting pseudos. That how RA heuristics work (in
the old RA log (live range span) was used. The bigger the value, the
more probability for spilling).
> Perhaps the cost analysis has a problem.
>
I've checked it and it looks ok to me.
>> RA focused on generation of faster code. Looking at the fragment you
>> provided it, it is hard to say
>> something about it. I tried -Os for gcc4.8 and it generates
>> desirable code for the fragment in
>> question (by the way the peak register pressure decreased to 66 in
>> this case).
>
> It's both larger and slower, since the additional loads take much
> longer. I'll take a
> look at -Os.
>
> It looks like the values of p++ are being pre-calculated and stored on
> the stack. This results in
> a load, rather than an increment of a register.
>
If it is so. It might be another optimization which moves p++
calculations higher. IRA does not do it (more correctly a new IRA
feature implemented by Bernd Schmidt in gcc4.7 can move insns downwards
in CFG graph to decrease reg pressure).
I checked all rtl passes these calcualtions are not created by any RTL
pass. So it is probably some tree-ssa optimization.
>> Any industrial RA uses heuristic algorithms, in some cases better
>> heuristics can work worse than
>> worse heuristics. So you should probably check is there any progress
>> moving from gcc4.1 to gcc4.6
>> with performance point of view for variety benchmarks. Introducing
>> IRA improves code for x86 4% on
>> SPEC2000. Subsequent improving (like using dynamic register classes)
>> made further performance
>> improvements.
>
> My impression is that the performance is worse. Reports I've seen are
> that the code is
> substantially larger, which means more instructions.
>
> I'm skeptical about comparisons between x86 and RISC processors. What
> works well
> for one may not work well for the other.
>
IRA improved code for many RISC processors. Although tetter RA has
smaller effect for these processors as they have more registers.
>> Looking at the test code, I can make some conclusions for myself:
>>
>> o We need a common pass decreasing reg pressure (I already expressed
>> this in the past) as
>> optimizations become more aggressive. Some progress was made to make
>> few optimizations aware about
>> RA (reg-pressure scheduling, loop-invariant motions, and code
>> hoisting) but there are too many
>> passes and it is wrong and impossible to make them all aware of RA.
>> Some register pressure
>> decreasing heuristics are difficult to implement in RA (like insn
>> rearrangements or complex
>> rematerialization) and this pass could focus on them.
>
> That might be useful.
>
>> o Implement RA live range splitting in regions different from loops
>> or BB (now IRA makes splitting
>> only on loop bounds and LRA in BB, the old RA had no live range
>> splitting at all).
>
> Each of the blocks of code is in it's own BB. I haven't checked, but
> I'd guess
> that most of the registers are in use on entry and still live on exit,
> so the
> block has no registers to allocate.
>
Splitting in BB scope this case is not profitable.
>> I'd also recommend to try the following options concerning RA:
>> -fira-loop-pressure,
>> -fsched-pressure, -fira-algorithm=CB|priority,
>> -fira-region=one,all,mixed. Actually
>> -fira-algorithm=priority + -fira-region=one is analog of what the old
>> RA did.
>
More information about the Gcc
mailing list