diff options
author | Jeff Law <law@redhat.com> | 2014-02-14 13:26:31 -0700 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 2014-02-14 13:26:31 -0700 |
commit | 059742a47f66ce4511d867486827989ae7bd7391 (patch) | |
tree | 09969290c7ea97e942a1f194ee131355d70fa1cd | |
parent | 88f7c49a8bfe6c9e7ac04da2ef3ba8281d3dba06 (diff) | |
download | gcc-059742a47f66ce4511d867486827989ae7bd7391.zip gcc-059742a47f66ce4511d867486827989ae7bd7391.tar.gz gcc-059742a47f66ce4511d867486827989ae7bd7391.tar.bz2 |
re PR rtl-optimization/60131 (RTL check fail in rhs_regno)
PR rtl-optimization/60131
* ree.c (get_extended_src_reg): New function.
(combine_reaching_defs): Use it rather than assuming location
of REG.
(find_and_remove_re): Verify first operand of extension is
a REG before adding the insns to the copy list.
PR rtl-optimization/60131
* g++.dg/torture/pr60131.C: New test.
From-SVN: r207792
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/ree.c | 37 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/pr60131.C | 23 |
4 files changed, 67 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dd988ce..59d1671 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2014-02-14 Jeff Law <law@redhat.com> + + PR rtl-optimization/60131 + * ree.c (get_extended_src_reg): New function. + (combine_reaching_defs): Use it rather than assuming location + of REG. + (find_and_remove_re): Verify first operand of extension is + a REG before adding the insns to the copy list. + 2014-02-14 Roland McGrath <mcgrathr@google.com> * configure.ac (HAVE_AS_IX86_UD2): New test for 'ud2' mnemonic. @@ -670,6 +670,18 @@ merge_def_and_ext (ext_cand *cand, rtx def_insn, ext_state *state) return false; } +/* Given SRC, which should be one or more extensions of a REG, strip + away the extensions and return the REG. */ + +static inline rtx +get_extended_src_reg (rtx src) +{ + while (GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND) + src = XEXP (src, 0); + gcc_assert (REG_P (src)); + return src; +} + /* This function goes through all reaching defs of the source of the candidate for elimination (CAND) and tries to combine the extension with the definition instruction. The changes @@ -698,17 +710,23 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state) /* If the destination operand of the extension is a different register than the source operand, then additional restrictions - are needed. */ - if ((REGNO (SET_DEST (PATTERN (cand->insn))) - != REGNO (XEXP (SET_SRC (PATTERN (cand->insn)), 0)))) + are needed. Note we have to handle cases where we have nested + extensions in the source operand. */ + if (REGNO (SET_DEST (PATTERN (cand->insn))) + != REGNO (get_extended_src_reg (SET_SRC (PATTERN (cand->insn))))) { /* In theory we could handle more than one reaching def, it just makes the code to update the insn stream more complex. */ if (state->defs_list.length () != 1) return false; - /* We require the candidate not already be modified. This may - be overly conservative. */ + /* We require the candidate not already be modified. It may, + for example have been changed from a (sign_extend (reg)) + into (zero_extend (sign_extend (reg)). + + Handling that case shouldn't be terribly difficult, but the code + here and the code to emit copies would need auditing. Until + we see a need, this is the safe thing to do. */ if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE) return false; @@ -999,8 +1017,13 @@ find_and_remove_re (void) if (dump_file) fprintf (dump_file, "Eliminated the extension.\n"); num_realized++; - if (REGNO (SET_DEST (PATTERN (curr_cand->insn))) - != REGNO (XEXP (SET_SRC (PATTERN (curr_cand->insn)), 0))) + /* If the RHS of the current candidate is not (extend (reg)), then + we do not allow the optimization of extensions where + the source and destination registers do not match. Thus + checking REG_P here is correct. */ + if (REG_P (XEXP (SET_SRC (PATTERN (curr_cand->insn)), 0)) + && (REGNO (SET_DEST (PATTERN (curr_cand->insn))) + != REGNO (XEXP (SET_SRC (PATTERN (curr_cand->insn)), 0)))) { reinsn_copy_list.safe_push (curr_cand->insn); reinsn_copy_list.safe_push (state.defs_list[0]); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a8e72e2..0415b74 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-02-14 Jeff Law <law@redhat.com> + + PR rtl-optimization/60131 + * g++.dg/torture/pr60131.C: New test. + 2014-02-14 Ian Bolton <ian.bolton@arm.com> * gcc.target/arm/pr59858.c: Skip if -mfloat-abi=hard specified diff --git a/gcc/testsuite/g++.dg/torture/pr60131.C b/gcc/testsuite/g++.dg/torture/pr60131.C new file mode 100644 index 0000000..23dde31 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr60131.C @@ -0,0 +1,23 @@ +// { dg-do compile } +struct A { short a; }; +int **b; +unsigned long c; + +bool foo (); +unsigned bar (unsigned i); +extern void baz () __attribute__((noreturn)); + +int * +test (unsigned x, struct A *y) +{ + unsigned v; + if (foo () || y[x].a == -1) + { + c = bar (x); + return 0; + } + v = y[x].a; + if (v >= 23) + baz (); + return b[v]; +} |