https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86106

--- Comment #4 from Kishan Parmar <kishan at gcc dot gnu.org> ---
Hello @Surya

For the above case, the gimple looks like:

unsigned int g (unsigned int val)
{
  _1 = val_5(D) & 2139062143u;
  _2 = _1 + 2139062143u;
  _3 = _2 | val_5(D);
  _4 = _3 | 2139062143u;
  _6 = ~_4;
  return _6;
}

I’ve attached the RTL generated by expand with both vanilla GCC and the patched
GCC.
In vanilla GCC, expand sees the constant 2139062143 and checks what operation
is being done. It compares the operation’s cost with the cost of a set
(materializing the constant into a register). If the operation’s cost is lower,
it uses the constant directly as the RHS. Otherwise, it loads the constant into
a register first.
For AND, the cost was 8, so GCC loaded the constant into a register before
doing the operation. But for PLUS and IOR, the cost was 4, equal to set, so GCC
used the constant directly as RHS. Later in expand, that constant gets split
into two 16-bit halves and emitted piece by piece. The end result in RTL has
those “half and half” constants, which the later optimization passes can’t make
much use of.
Looking at the md files, I saw that for IOR, PLUS, and XOR, if the constant is
larger than 16 bits, we always end up splitting it anyway — so the cost
effectively becomes 8 in practice.
My patch adjusts the costing in expand for these ops:
(1) If the constant fits in 16 bits, keep using it directly as RHS.
COSTS_N_INSNS(1)
(2) If it’s larger than 16 bits, treat it as COSTS_N_INSNS (2) 

For e.x. after the change constant above is being optimised in CSE1, fwprop1..
pass leaving shorter asm.

Reply via email to