This is another problem uncovered by the generalization of the ZEE pass: when the definition insn of an extension is itself an extension, modifying the insn for the first extension breaks the handling of the second extension. This was silent in ZEE because you never have 2 identical successive extensions, but is now exposed in REE.
The attached patch implements a minimal fix with the associated FIXME. Tested on x86_64-suse-linux, applied on the mainline. 2012-01-22 Eric Botcazou <ebotca...@adacore.com> PR rtl-optimization/51924 * ree.c (combine_set_extension): Improve debugging message. (combine_reaching_defs): Likewise. (get_defs): Rename confusingly named variable. (find_and_remove_re): Skip a candidate if the extension expression has been modified. 2012-01-22 Eric Botcazou <ebotca...@adacore.com> * gcc.dg/ext-elim-1.c: New test. -- Eric Botcazou
Index: ree.c =================================================================== --- ree.c (revision 183348) +++ ree.c (working copy) @@ -346,7 +346,8 @@ combine_set_extension (ext_cand *cand, r { if (dump_file) { - fprintf (dump_file, "Merged instruction with extension:\n"); + fprintf (dump_file, + "Tentatively merged extension with definition:\n"); print_rtl_single (dump_file, curr_insn); } return true; @@ -407,21 +408,21 @@ transform_ifelse (ext_cand *cand, rtx de static struct df_link * get_defs (rtx insn, rtx reg, VEC (rtx,heap) **dest) { - df_ref reg_info, *defs; + df_ref reg_info, *uses; struct df_link *ref_chain, *ref_link; reg_info = NULL; - for (defs = DF_INSN_USES (insn); *defs; defs++) + for (uses = DF_INSN_USES (insn); *uses; uses++) { - reg_info = *defs; + reg_info = *uses; if (GET_CODE (DF_REF_REG (reg_info)) == SUBREG) return NULL; if (REGNO (DF_REF_REG (reg_info)) == REGNO (reg)) break; } - gcc_assert (reg_info != NULL && defs != NULL); + gcc_assert (reg_info != NULL && uses != NULL); ref_chain = DF_REF_CHAIN (reg_info); @@ -686,11 +687,10 @@ combine_reaching_defs (ext_cand *cand, r purposes. This extension cannot be deleted. */ if (dump_file) { - FOR_EACH_VEC_ELT (rtx, vec, i, def_insn) - { - fprintf (dump_file, "Non-mergeable definitions:\n"); - print_rtl_single (dump_file, def_insn); - } + fprintf (dump_file, + "Merge cancelled, non-mergeable definitions:\n"); + FOR_EACH_VEC_ELT (rtx, vec, i, def_insn) + print_rtl_single (dump_file, def_insn); } } } @@ -843,6 +843,12 @@ find_and_remove_re (void) { num_re_opportunities++; + /* If the candidate insn is itself a definition insn for another + candidate, it may have been modified and the UD chain broken. + FIXME: the handling of successive extensions can be improved. */ + if (!reg_mentioned_p (curr_cand->expr, PATTERN (curr_cand->insn))) + continue; + /* Try to combine the extension with the definition. */ if (dump_file) {
/* PR rtl-optimization/51924 */ /* Testcase by Zdenek Sojka <zso...@seznam.cz> */ /* { dg-do run } */ /* { dg-options "-O -free -fno-rename-registers -ftree-vectorize -funroll-loops" } */ typedef __UINT64_TYPE__ uint64_t; uint64_t __attribute__ ((noinline, noclone)) bn_sub_words (uint64_t * r, const uint64_t * a, const uint64_t * b, int n) { uint64_t t1, t2; unsigned c = 0; while (n) { t1 = a[0]; t2 = b[0]; r[0] = (t1 - t2 - c); if (t1 != t2) c = (t1 < t2); a++; b++; r++; n--; } return (c); } int main (void) { uint64_t r[2]; uint64_t a[2] = { -1, -1 }; uint64_t b[2] = { 0, 0 }; if (bn_sub_words (r, a, b, 2) != 0) __builtin_abort (); return 0; }