[fpc-devel] Peephole optimizer tai class change proposals

J. Gareth Moreton gareth at moreton-family.com
Sun Oct 3 14:04:01 CEST 2021

Hi everyone,

So as my optimisations get more and more sophisticated and intelligent, 
I'm realising that I may need ways to store more information than is 
currently possible.  Obviously I want to avoid enlarging the internal 
state too much or making the code unwieldly, but the additions I have in 
mind are for tai objects:

- A connected tai object
- A flags field or some kind of weighting field

The connected tai object would be useful for jumps that branch to labels 
that were created during peephole optimisation, since these can't be 
looked up with "getlabelwithsym" and so lose out on some subsequent 
optimisations that look across jumps.

In regards to the weighting, a flag that indicates "desire to delete" or 
something similar would be very useful in deciding if temporarily making 
the code worse will have a larger payoff later on.  Consider the 
following code snippet (in the Classes unit under -O4 during some of my 
personal experimentation):

     movq    %rdx,%rsi
     movq    %r8,%rdi
     testq    %r8,%r8
     je    .Lj2408
     movq    %rdi,%rdx
     jmp    .Lj2409
     .p2align 4,,10
     .p2align 3
     movq    %rsi,%rdx
     movq    %rbx,%rcx

There's an option to insert "cmoveq %rsi,%rdx", mirroring the "movq 
%rsi,%rdx" instruction (between the two labels), before "je .Lj2408", 
and change that conditional branch to "je .Lj2409".  By itself, this 
wouldn't be a good optimisation because CMOV is slightly slower than MOV 
and it would break the macrofusion betwen the TEST and JE instructions, 
as well as increasing code size and overall instruction count.  However, 
it would cluster the two labels and .Lj2408 only has a single reference; 
if it and the MOV instruction were removed, the entire block between 
"jmp .Lj2409" and its label would collapse, erasing the original MOV, 
and then a subsequent pass will notice that "cmoveq %rsi,%rdx" is 
unnecessary because %rdx = %rsi already at that point in the program 
flow, thus restoring the macrofusion.  At this point, the optimal code 
would be:

     movq    %rdx,%rsi
     movq    %r8,%rdi
     testq    %r8,%r8
     je    .Lj2409
     movq    %rdi,%rdx
     .p2align 4,,10
     .p2align 3
     movq    %rbx,%rcx

Given that .Lj2409 only has a single reference from the nearby 
conditional branch, it may be beneficial to remove the alignment hints 
at this point too, although that one is more up in the air. 
Nevertheless, if the peephole optimizer, while scanning the conditional 
jump, sees that the destination label only has a single reference and 
has been flagged 'desire to delete', it will be more likely to perform 
the optimisation.  However, if the flag is clear, it won't optimise.  As 
for when to set that flag, it will probably be when the peephole 
optimizer scans the original "jmp .Lj2409" instruction and sees how 
close it is to being a zero distance jump, with only alignment fields, 
another label and a single MOV before it finds .Lj2409.

I'm aware that the tai class declares an "optinfo" field, although I'm 
uncertain if this is safe to use or not given it's wrapped by an 
conditional define and is of type Pointer.  I could use optinfo to store 
a reference to the tai_label object in a jump instruction - would this 
be an acceptable use of it?  I'm not sure about using it for a 'desire 
to delete' flag though, especially where there might be situations where 
other tai objects could carry it... maybe even a jump instruction.

This is more of a running commentary of my design thoughts, so I 
apologise for the info dump, but to summarise, could I add a 'connected 
object' and 'flags' field to the tai class, and/or can I use the optinfo 
field for a similar purpose?

Remember I can always refactor later if a feature could be cleaned up or 
restructured in some way.

Gareth aka. Kit

This email has been checked for viruses by Avast antivirus software.

More information about the fpc-devel mailing list