https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125788
--- Comment #7 from Drea Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Guoce Feng from comment #6)
> I think the sink-like direction makes sense here. One possible way to start
> would be to handle the all-predecessors common-tail case first:
>
> - scan the tail statements of all unconditional predecessors of a join
> block;
> - require matching statement shape, while allowing operands to differ;
This is what LLVM does (I am not a fan) and I think we should not do that way
as we can handle this better. Having 2 statements swapped causes this way to
fall over very quickly.
Rather based on the incoming phis in the join block. Virtual operand phis will
be used for calls and stores. Non-virtual operands phis will be used for calls,
and normal operands.
is_factor_profitable can be used to check if it is profitable to use the ssa
names in the join block (either as part of a new phi or in the new statement).
This should allow for the order to be sligtly different and even maybe allowing
for say some statements that won't factor at all but others before happening.
Plus this is better than say LLVM handling. And since we are looping, it might
be the case that is_factor_profitable might return false but later on return
true.
> A pre-ifcvt common-sinking pass could turn the common `+ c[i]` and `* 2`
> tail into merged data flow by creating operand PHIs/selects before rebuilding
> the common operations after the join.
So GCC's PRE has a hoisting part to it and will hoist the load from `c[i]` and
`a[i]` rather than sinking it. And the normal part of the sink pass will sink
then past the commonized part. Also the example in comment #6 is a bad example
because it is mostly handled already by other passes.
On trunk before ifcvt we have:
```
if (_4 > 0)
goto <bb 4>; [59.00%]
else
goto <bb 5>; [41.00%]
<bb 4> [local count: 563821836]:
x_25 = pretmp_37 + 1;
y_26 = x_25 + pretmp_39;
goto <bb 6>; [100.00%]
<bb 5> [local count: 391808389]:
x_22 = pretmp_37 + -1;
y_24 = x_22 + pretmp_39;
<bb 6> [local count: 955630226]:
```
Pre hoists a[i] and c[i] as mentioned.
And phiopt already commonizes `y * 2`. Then ifcvt will commonize the other 2.
And we get in ifcvt:
```
_34 = _4 > 0;
_48 = _34 ? 1 : -1;
_47 = pretmp_37 + _48;
_9 = _47 + pretmp_39;
r_16 = _9 * 2;
```
Which is exactly what you expect.
Now ifcvt handled that in GCC 16 already too.
In the scalar part we get:
```
if (_54 > 0)
goto <bb 12>; [59.00%]
else
goto <bb 11>; [41.00%]
<bb 10> [local count: 244402423]:
# _67 = PHI <-1(11), 1(12)>
_69 = pretmp_56 + _67;
_59 = pretmp_58 + _69;
r_60 = _59 * 2;
```
Now too in phiopt4.
Basically hoisting and commonization in phiopt/ifcvt already handles this. Note
hoisting is just as important as sinking when it comes to commonization.
Hoisting helps because then maybe you don't need to allow for a new phi (except
for stores).