Hi!

add_equal_note has special code to handle properly doubleword POPCOUNT and
similar builtins, e.g. for POPCOUNT if we don't have DImode POPCOUNT, it can
be expanded as 2 SImode POPCOUNTs added together, but for the REG_EQUAL note
we want lowpart SImode SUBREG of DImode POPCOUNT.

Unfortunately, this doesn't really work if the operand is constant and we
are unlucky enough that it hasn't been folded during GIMPLE optimizations
- we still need to use DImode POPCOUNT and take subreg of it.

The following patch fixes it by padding the op0's mode to the function too
and use it everywhere instead of GET_MODE (op0).  For op1 we don't really
need that, that is for binary operations where both arguments have the same
mode or we don't really care about the mode of the last operand (shifts).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-01-21  Jakub Jelinek  <ja...@redhat.com>

        PR target/88905
        * optabs.c (add_equal_note): Add op0_mode argument, use it instead of
        GET_MODE (op0).
        (expand_binop_directly, expand_doubleword_clz,
        expand_doubleword_popcount, expand_ctz, expand_ffs,
        expand_unop_direct, maybe_emit_unop_insn): Adjust callers.

        * gcc.dg/pr88905.c: New test.

--- gcc/optabs.c.jj     2019-01-01 12:37:17.711965861 +0100
+++ gcc/optabs.c        2019-01-21 13:56:18.263446049 +0100
@@ -55,7 +55,7 @@ void debug_optab_libfuncs (void);
 
 /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
-   operation).
+   operation).  OP0_MODE is OP0's mode.
 
    If the last insn does not set TARGET, don't do anything, but return 1.
 
@@ -64,7 +64,8 @@ void debug_optab_libfuncs (void);
    try again, ensuring that TARGET is not one of the operands.  */
 
 static int
-add_equal_note (rtx_insn *insns, rtx target, enum rtx_code code, rtx op0, rtx 
op1)
+add_equal_note (rtx_insn *insns, rtx target, enum rtx_code code, rtx op0,
+               rtx op1, machine_mode op0_mode)
 {
   rtx_insn *last_insn;
   rtx set;
@@ -136,16 +137,16 @@ add_equal_note (rtx_insn *insns, rtx tar
       case POPCOUNT:
       case PARITY:
       case BSWAP:
-       if (GET_MODE (op0) != VOIDmode && GET_MODE (target) != GET_MODE (op0))
+       if (op0_mode != VOIDmode && GET_MODE (target) != op0_mode)
          {
-           note = gen_rtx_fmt_e (code, GET_MODE (op0), copy_rtx (op0));
-           if (GET_MODE_UNIT_SIZE (GET_MODE (op0))
+           note = gen_rtx_fmt_e (code, op0_mode, copy_rtx (op0));
+           if (GET_MODE_UNIT_SIZE (op0_mode)
                > GET_MODE_UNIT_SIZE (GET_MODE (target)))
              note = simplify_gen_unary (TRUNCATE, GET_MODE (target),
-                                        note, GET_MODE (op0));
+                                        note, op0_mode);
            else
              note = simplify_gen_unary (ZERO_EXTEND, GET_MODE (target),
-                                        note, GET_MODE (op0));
+                                        note, op0_mode);
            break;
          }
        /* FALLTHRU */
@@ -1127,7 +1128,7 @@ expand_binop_directly (enum insn_code ic
       if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
          && ! add_equal_note (pat, ops[0].value,
                               optab_to_code (binoptab),
-                              ops[1].value, ops[2].value))
+                              ops[1].value, ops[2].value, mode0))
        {
          delete_insns_since (last);
          return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
@@ -2298,7 +2299,7 @@ expand_doubleword_clz (scalar_int_mode m
   seq = get_insns ();
   end_sequence ();
 
-  add_equal_note (seq, target, CLZ, xop0, 0);
+  add_equal_note (seq, target, CLZ, xop0, NULL_RTX, mode);
   emit_insn (seq);
   return target;
 
@@ -2340,7 +2341,7 @@ expand_doubleword_popcount (scalar_int_m
   seq = get_insns ();
   end_sequence ();
 
-  add_equal_note (seq, t, POPCOUNT, op0, 0);
+  add_equal_note (seq, t, POPCOUNT, op0, NULL_RTX, mode);
   emit_insn (seq);
   return t;
 }
@@ -2511,7 +2512,7 @@ expand_ctz (scalar_int_mode mode, rtx op
   seq = get_insns ();
   end_sequence ();
 
-  add_equal_note (seq, temp, CTZ, op0, 0);
+  add_equal_note (seq, temp, CTZ, op0, NULL_RTX, mode);
   emit_insn (seq);
   return temp;
 }
@@ -2589,7 +2590,7 @@ expand_ffs (scalar_int_mode mode, rtx op
   seq = get_insns ();
   end_sequence ();
 
-  add_equal_note (seq, temp, FFS, op0, 0);
+  add_equal_note (seq, temp, FFS, op0, NULL_RTX, mode);
   emit_insn (seq);
   return temp;
 
@@ -2736,7 +2737,7 @@ expand_unop_direct (machine_mode mode, o
          if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
              && ! add_equal_note (pat, ops[0].value,
                                   optab_to_code (unoptab),
-                                  ops[1].value, NULL_RTX))
+                                  ops[1].value, NULL_RTX, mode))
            {
              delete_insns_since (last);
              return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp);
@@ -3588,7 +3589,8 @@ maybe_emit_unop_insn (enum insn_code ico
 
   if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
       && code != UNKNOWN)
-    add_equal_note (pat, ops[0].value, code, ops[1].value, NULL_RTX);
+    add_equal_note (pat, ops[0].value, code, ops[1].value, NULL_RTX,
+                   GET_MODE (op0));
 
   emit_insn (pat);
 
--- gcc/testsuite/gcc.dg/pr88905.c.jj   2019-01-21 14:19:17.279746531 +0100
+++ gcc/testsuite/gcc.dg/pr88905.c      2019-01-21 14:18:56.264091537 +0100
@@ -0,0 +1,21 @@
+/* PR target/88905 */
+/* { dg-do compile } */
+/* { dg-options "-Og -fno-tree-ccp" } */
+/* { dg-additional-options "-mabm" { target { i?86-*-* x86_64-*-* } } } */
+
+int a, b, c;
+extern void baz (int);
+
+static inline int
+bar (unsigned u)
+{
+  int i = __builtin_popcountll (-(unsigned long long) u);
+  baz (i & c);
+  return a + b + c;
+}
+
+void
+foo (void)
+{
+  bar (2376498292ULL);
+}

        Jakub

Reply via email to