ifcvt vs. expand_binop

Oleg Endo oleg.endo@t-online.de
Tue Sep 22 13:54:00 GMT 2015


On SH, the result of comparisons etc. is stored in the T_REG.  It's a 1
bit reg but described as SImode.  To get the T_REG into another reg,
there's this insn:

(define_insn "movt"
  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
	(match_operand:SI 1 "t_reg_operand"))]
  "TARGET_SH1"
  "movt	%0"
  [(set_attr "type" "arith")])

where "t_reg_operand" accepts various forms of the T_REG via
reg,subreg,sign_extend,zero_extend (to get better combine results).

Now I'd like to extend the "t_reg_operand" predicate to accept something
like

(set (reg:SI) (ne:SI (reg:SI 147 t) (const_int 0)))


For the test case 

int test05 (int a, int b)
{
  return a != b ? 0x7FFFFFFF : 0x80000000;
}

ifcvt (noce_emit_store_flag) tries to emit the store flag insn as

(set (reg:SI 162)
    (ne:SI (reg:SI 147 t)
        (const_int 0 [0])))

It then proceeds with a call to

expand_simple_binop
  op0: (const_int 2147483647 [0x7fffffff])
  op1: (reg:SI 162)          <<< same reg
  target: (reg:SI 162)       <<<

The problem is that expand_binop gets confused, seemingly because
op1 and target are the same.  It tries to emit a 64 bit addition:

(insn 50 49 51 (clobber (reg:DI 173)) -1
     (nil))

(insn 51 50 52 (set (subreg:SI (reg:DI 173) 0)
        (reg:SI 162)) -1
     (nil))

(insn 52 51 53 (set (reg:DI 175)
        (const_int 2147483647 [0x7fffffff])) -1
     (nil))

(insn 53 52 0 (parallel [
            (set (reg:DI 174)
                (plus:DI (reg:DI 173)
                    (reg:DI 175)))
            (clobber (reg:SI 147 t))
        ]) -1
     (nil))

ifcvt (end_ifcvt_sequence) then does a recog for each emitted insn in
the resulting sequence and insn 50 above will not match anything in the
SH md.  It then drops everything and tries something else.

Until now, because SH patterns would not accept the
(set (reg:SI 162)
    (ne:SI (reg:SI 147 t)
        (const_int 0 [0])))

the "fallback path" in noce_emit_store_flag is used.  This uses
emit_store_flag which creates a new pseudo for the result and we get

expand_simple_binop
  op0: (const_int 2147483647 [0x7fffffff])
  op1: (reg:SI 167)          <<< different regs
  target: (reg:SI 162)       <<< 

which works fine (no 64 bit addition).

A simple fix seems to be to create a new pseudo for the "short cut" path
in noce_emit_store_flag:

Index: gcc/ifcvt.c
===================================================================
--- gcc/ifcvt.c	(revision 227970)
+++ gcc/ifcvt.c	(working copy)
@@ -874,6 +874,7 @@
     {
       rtx src = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
 			    XEXP (cond, 1));
+      x = gen_reg_rtx (GET_MODE (x));
       rtx set = gen_rtx_SET (x, src);
 
       start_sequence ();

I haven't done full testing of this, but it fixes the problem for me.
Any opinions?

Cheers,
Oleg



More information about the Gcc-patches mailing list