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