From: Jakub Jelinek Date: Fri, 28 Nov 2014 17:03:55 +0000 (+0100) Subject: backport: re PR rtl-optimization/63659 (wrong code at -O2 and -O3 on x86_64-linux... X-Git-Tag: releases/gcc-4.8.4~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fbcf82943d7a8083871e4b44c0b5f2728701b327;p=thirdparty%2Fgcc.git backport: re PR rtl-optimization/63659 (wrong code at -O2 and -O3 on x86_64-linux-gnu) Backported from mainline 2014-10-31 Jakub Jelinek PR rtl-optimization/63659 * ree.c (update_reg_equal_equiv_notes): New function. (combine_set_extension, transform_ifelse): Use it. * gcc.c-torture/execute/pr63659.c: New test. From-SVN: r218166 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 87730ce16ba8..47fefa01be8a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,12 @@ 2014-11-28 Jakub Jelinek Backported from mainline + 2014-10-31 Jakub Jelinek + + PR rtl-optimization/63659 + * ree.c (update_reg_equal_equiv_notes): New function. + (combine_set_extension, transform_ifelse): Use it. + 2014-10-03 Jakub Jelinek PR libgomp/61200 diff --git a/gcc/ree.c b/gcc/ree.c index ff96df8a016b..c7e106f96269 100644 --- a/gcc/ree.c +++ b/gcc/ree.c @@ -261,6 +261,50 @@ typedef struct ext_cand static int max_insn_uid; +/* Update or remove REG_EQUAL or REG_EQUIV notes for INSN. */ + +static bool +update_reg_equal_equiv_notes (rtx insn, enum machine_mode new_mode, + enum machine_mode old_mode, enum rtx_code code) +{ + rtx *loc = ®_NOTES (insn); + while (*loc) + { + enum reg_note kind = REG_NOTE_KIND (*loc); + if (kind == REG_EQUAL || kind == REG_EQUIV) + { + rtx orig_src = XEXP (*loc, 0); + /* Update equivalency constants. Recall that RTL constants are + sign-extended. */ + if (GET_CODE (orig_src) == CONST_INT + && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (new_mode)) + { + if (INTVAL (orig_src) >= 0 || code == SIGN_EXTEND) + /* Nothing needed. */; + else + { + /* Zero-extend the negative constant by masking out the + bits outside the source mode. */ + rtx new_const_int + = gen_int_mode (INTVAL (orig_src) + & GET_MODE_MASK (old_mode), + new_mode); + if (!validate_change (insn, &XEXP (*loc, 0), + new_const_int, true)) + return false; + } + loc = &XEXP (*loc, 1); + } + /* Drop all other notes, they assume a wrong mode. */ + else if (!validate_change (insn, loc, XEXP (*loc, 1), true)) + return false; + } + else + loc = &XEXP (*loc, 1); + } + return true; +} + /* Given a insn (CURR_INSN), an extension candidate for removal (CAND) and a pointer to the SET rtx (ORIG_SET) that needs to be modified, this code modifies the SET rtx to a new SET rtx that extends the @@ -282,6 +326,7 @@ static bool combine_set_extension (ext_cand *cand, rtx curr_insn, rtx *orig_set) { rtx orig_src = SET_SRC (*orig_set); + enum machine_mode orig_mode = GET_MODE (SET_DEST (*orig_set)); rtx new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (*orig_set))); rtx new_set; @@ -296,9 +341,8 @@ combine_set_extension (ext_cand *cand, rtx curr_insn, rtx *orig_set) { /* Zero-extend the negative constant by masking out the bits outside the source mode. */ - enum machine_mode src_mode = GET_MODE (SET_DEST (*orig_set)); rtx new_const_int - = GEN_INT (INTVAL (orig_src) & GET_MODE_MASK (src_mode)); + = GEN_INT (INTVAL (orig_src) & GET_MODE_MASK (orig_mode)); new_set = gen_rtx_SET (VOIDmode, new_reg, new_const_int); } } @@ -336,7 +380,9 @@ combine_set_extension (ext_cand *cand, rtx curr_insn, rtx *orig_set) /* This change is a part of a group of changes. Hence, validate_change will not try to commit the change. */ - if (validate_change (curr_insn, orig_set, new_set, true)) + if (validate_change (curr_insn, orig_set, new_set, true) + && update_reg_equal_equiv_notes (curr_insn, cand->mode, orig_mode, + cand->code)) { if (dump_file) { @@ -385,7 +431,9 @@ transform_ifelse (ext_cand *cand, rtx def_insn) ifexpr = gen_rtx_IF_THEN_ELSE (cand->mode, cond, map_srcreg, map_srcreg2); new_set = gen_rtx_SET (VOIDmode, map_dstreg, ifexpr); - if (validate_change (def_insn, &PATTERN (def_insn), new_set, true)) + if (validate_change (def_insn, &PATTERN (def_insn), new_set, true) + && update_reg_equal_equiv_notes (def_insn, cand->mode, GET_MODE (dstreg), + cand->code)) { if (dump_file) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7b57f1222c7c..38d5c102bce6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,11 @@ 2014-11-28 Jakub Jelinek Backported from mainline + 2014-10-31 Jakub Jelinek + + PR rtl-optimization/63659 + * gcc.c-torture/execute/pr63659.c: New test. + 2014-10-03 Jakub Jelinek PR libgomp/61200 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr63659.c b/gcc/testsuite/gcc.c-torture/execute/pr63659.c new file mode 100644 index 000000000000..780dc8a7e218 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr63659.c @@ -0,0 +1,29 @@ +/* PR rtl-optimization/63659 */ + +int a, b, c, *d = &b, g, h, i; +unsigned char e; +char f; + +int +main () +{ + while (a) + { + for (a = 0; a; a++) + for (; c; c++) + ; + if (i) + break; + } + + char j = c, k = -1, l; + l = g = j >> h; + f = l == 0 ? k : k % l; + e = 0 ? 0 : f; + *d = e; + + if (b != 255) + __builtin_abort (); + + return 0; +}