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

            Bug ID: 128449
           Summary: Improve gimple select across sequences that differ
                    only in signedness
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: missed-optimization
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: law at gcc dot gnu.org
            Blocks: 26163
  Target Milestone: ---
            Target: riscv

Imagine this code in gimple:

;;   basic block 3, loop depth 0
;;    pred:       2
  _2 = f_13(D) + _18;
  _3 = _2 * mf_14(D);
  _4 = _3 >> 16;
  _16 = (short int) _4;
  goto <bb 5>; [100.00%]
;;    succ:       5

;;   basic block 4, loop depth 0
;;    pred:       2
  _6 = f_13(D) - _18;
  _7 = _6 * mf_14(D);
  _8 = _7 >> 16;
  _9 = (unsigned short) _8;
  _10 = -_9;
  _15 = (short int) _10;
;;    succ:       5

;;   basic block 5, loop depth 0
;;    pred:       3
;;                4
  # _11 = PHI <_16(3), _15(4)>

A bit of work shows that _16 and _15 only differ in signs.  Furthermore, the
RTL if-converter is going to turn that into straightline code with two
multiplies!

        sub     a5,a1,a0        # 47    [c=4 l=4]  subdi3
        mul     t0,a5,a2        # 48    [c=16 l=4]  muldi3
        add     a1,a1,a0        # 43    [c=4 l=4]  *adddi3/0
        slti    a0,a0,1 # 53    [c=4 l=4]  *sle_didi
        mul     t1,a1,a2        # 45    [c=16 l=4]  muldi3
        sraiw   t2,t0,16        # 49    [c=8 l=4]  ashrsi3_extend
        negw    a2,t2   # 50    [c=8 l=4]  negsi2_extended
        sext.h  a3,a2   # 51    [c=4 l=4]  *extendhidi2_bitmanip/0
        czero.eqz       a4,a3,a0        # 54    [c=4 l=4]  *czero.eqz.didi
        sraiw   a6,t1,16        # 46    [c=12 l=4]  *lshrsi3_extend_2
        czero.nez       a7,a6,a0        # 55    [c=4 l=4]  *czero.nez.didi
        add     a0,a7,a4        # 38    [c=4 l=4]  *adddi3/0

That's probably still better than taking a branch mispredict, but it'd be more
profitable if we just did a single multiply.  A quick looksie at the RTL
confirmed my suspicion that this could be quite painful to try and capture in
ifcvt.c  But the gimple might be more feasible.  It's about 19m instructions in
x264.  Small, but with the multiply in there, it's going to have an outsized
impact.


short
f (short x, int f, int mf)
{
  if (x > 0)
    return (f + x) * mf >> 16;
  else
    return -((f - x) * mf >> 16);
}

Note the bigger versions of quant get vectorized and thus don't suffer from
this problem on modern designs.


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26163
[Bug 26163] [meta-bug] missed optimization in SPEC (2026, 2k17, 2k and 2k6 and
95)

Reply via email to