expand_parity attempts to generate popcount operations in wider modes and do a
logical AND afterward, but it overlooks the mode of "target" and just do:
if (temp != 0)
temp = expand_binop (wider_mode, and_optab, temp, const1_rtx,
target, true, OPTAB_DIRECT);
and this ICEs if the mode of "target" is not wider_mode, as for the attached
testcase compiled for Niagara-2 at -Os.
Tested on x86_64-suse-linux and SPARC/Solaris, applied on mainline as obvious.
2016-10-15 Eric Botcazou <ebotca...@adacore.com>
* optabs.c (expand_parity): Fix mode mismatch, add final conversion
and keep looping on failure.
2016-10-15 Eric Botcazou <ebotca...@adacore.com>
* gcc.target/sparc/popc-2.c: New test.
--
Eric Botcazou
Index: optabs.c
===================================================================
--- optabs.c (revision 241147)
+++ optabs.c (working copy)
@@ -2382,18 +2382,26 @@ expand_parity (machine_mode mode, rtx op
last = get_last_insn ();
- if (target == 0)
- target = gen_reg_rtx (mode);
+ if (target == 0 || GET_MODE (target) != wider_mode)
+ target = gen_reg_rtx (wider_mode);
+
xop0 = widen_operand (op0, wider_mode, mode, true, false);
temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX,
true);
if (temp != 0)
temp = expand_binop (wider_mode, and_optab, temp, const1_rtx,
target, true, OPTAB_DIRECT);
- if (temp == 0)
- delete_insns_since (last);
- return temp;
+ if (temp)
+ {
+ if (mclass != MODE_INT
+ || !TRULY_NOOP_TRUNCATION_MODES_P (mode, wider_mode))
+ return convert_to_mode (mode, temp, 0);
+ else
+ return gen_lowpart (mode, temp);
+ }
+ else
+ delete_insns_since (last);
}
}
}
/* { dg-do compile } */
/* { dg-options "-mcpu=niagara2 -Os" } */
int foo (unsigned long long l)
{
return __builtin_parityll (l);
}