The first if-conversion pass causes performance drop on arm. For
example on this code:

int f(int c)
{
       int z = 0;
       if( c )
               z = 0x66667777;
       else
               z = 0x99998888;
       return z;
}

It tries to transform the conditional code to if_then_else using the
emit_conditional_move function. But emit_conditional_move decides that
doing it directly is a bad idea (because the constants are big for arm
and movsicc cannot accept them) so it creates two additional pseudos
and moves the assignments of constants out of the block producing the
following sequence of instructions:

  45 r137:SI=0xffffffff99998888
  46 r138:SI=0x66667777
  47 cc:CC=cmp(r135:SI,0x0)
  48 r133:SI={(cc:CC==0x0)?r137:SI:r138:SI}

Then split2 converts if_then_else to cond_exec:

  46 r3:SI=0x66667777
     REG_EQUIV: 0x66667777
  52 r2:SI=0xffffffff99998888
     REG_EQUIV: 0xffffffff99998888
  56 cc:CC=cmp(r0:SI,0x0)
  57 (!cc:CC) r0:SI=r2:SI
  58 (cc:CC) r0:SI=r3:SI

Then the assignments of constants are converted to ldr's (or movt and
movw on cortex-a8) that will be executed unconditionally. And there is
no pass to put them back under conditional execution (and on cortex-a8
it's even harder to do since there will be two instructions for each
load of a constant).

RTL after split2 on cortex-a8:

  53 r2:SI=0x8888
     REG_EQUAL: 0x8888
  56 r3:SI=0x7777
     REG_EQUAL: 0x7777
  54 zero_extract(r2:SI,0x10,0x10)=0x9999
  57 zero_extract(r3:SI,0x10,0x10)=0x6666
  63 cc:CC=cmp(r0:SI,0x0)
  64 (!cc:CC) r0:SI=r2:SI
  65 (cc:CC) r0:SI=r3:SI

So what can we do? We can make the if-conversion pass avoid emitting
conditional moves when it results in using additional registers. But
although we know it's good on arm, we cannot say the same for other
architectures. However we can add a flag and enable it on arm by
default. Alternatively we can add some peephole optimization. (Or may
be modify some pass  to put a pair of instructions under cond_exec).
So what would be the best solution?

--
Sergey.

Reply via email to