On Sun, Feb 15, 2015 at 9:53 PM, H.J. Lu <hjl.to...@gmail.com> wrote:
> Hi,
>
> This is a backport of the patch for PR middle-end/53623 plus all bug
> fixes caused by it.  Tested on Linux/x86-32, Linux/x86-64 and x32.  OK
> for 4.8 branch?

Ok if nobody objects within 24h (you changed the bug to wrong-code
which is why I am considering it - a missed-optimization fix this big
shouldn't be backported).

Richard.

> Thanks.
>
>
> H.J.
> ---
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 469ee31..44bf322 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,82 @@
> +2015-02-15  H.J. Lu  <hongjiu...@intel.com>
> +
> +       Backport from mainline:
> +       2014-06-13  Jeff Law  <l...@redhat.com>
> +
> +       PR rtl-optimization/61094
> +       PR rtl-optimization/61446
> +       * ree.c (combine_reaching_defs): Get the mode for the copy from
> +       the extension insn rather than the defining insn.
> +
> +       2014-06-02  Jeff Law  <l...@redhat.com>
> +
> +       PR rtl-optimization/61094
> +       * ree.c (combine_reaching_defs): Do not reextend an insn if it
> +       was marked as do_no_reextend.  If a copy is needed to eliminate
> +       an extension, then mark it as do_not_reextend.
> +
> +       2014-02-14  Jeff Law  <l...@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-01-17  Jeff Law  <l...@redhat.com>
> +
> +       * ree.c (combine_set_extension): Temporarily disable test for
> +       changing number of hard registers.
> +
> +       2014-01-15  Jeff Law  <l...@redhat.com>
> +
> +       PR tree-optimization/59747
> +       * ree.c (find_and_remove_re): Properly handle case where a second
> +       eliminated extension requires widening a copy created for elimination
> +       of a prior extension.
> +       (combine_set_extension): Ensure that the number of hard regs needed
> +       for a destination register does not change when we widen it.
> +
> +       2014-01-10  Jeff Law  <l...@redhat.com>
> +
> +       PR middle-end/59743
> +       * ree.c (combine_reaching_defs): Ensure the defining statement
> +       occurs before the extension when optimizing extensions with
> +       different source and destination hard registers.
> +
> +       2014-01-10  Jakub Jelinek  <ja...@redhat.com>
> +
> +       PR rtl-optimization/59754
> +       * ree.c (combine_reaching_defs): Disallow !SCALAR_INT_MODE_P
> +       modes in the REGNO != REGNO case.
> +
> +       2014-01-08  Jeff Law  <l...@redhat.com>
> +
> +       * ree.c (get_sub_rtx): New function, extracted from...
> +       (merge_def_and_ext): Here.
> +       (combine_reaching_defs): Use get_sub_rtx.
> +
> +       2014-01-07  Jeff Law  <l...@redhat.com>
> +
> +       PR middle-end/53623
> +       * ree.c (combine_set_extension): Handle case where source
> +       and destination registers in an extension insn are different.
> +       (combine_reaching_defs): Allow source and destination
> +       registers in extension to be different under limited
> +       circumstances.
> +       (add_removable_extension): Remove restriction that the
> +       source and destination registers in the extension are the
> +       same.
> +       (find_and_remove_re): Emit a copy from the extension's
> +       destination to its source after the defining insn if
> +       the source and destination registers are different.
> +
> +       2013-12-12  Jeff Law  <l...@redhat.com>
> +
> +       * i386.md (simple LEA peephole2): Add missing mode to zero_extend
> +       for zero-extended MULT simple LEA pattern.
> +
>  2015-02-12  Jakub Jelinek  <ja...@redhat.com>
>
>         Backported from mainline
> diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
> index 372ae63..aabd6ec 100644
> --- a/gcc/config/i386/i386.md
> +++ b/gcc/config/i386/i386.md
> @@ -17265,7 +17265,7 @@
>     && REGNO (operands[0]) == REGNO (operands[1])
>     && peep2_regno_dead_p (0, FLAGS_REG)"
>    [(parallel [(set (match_dup 0)
> -                  (zero_extend (ashift:SI (match_dup 1) (match_dup 2))))
> +                  (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))
>               (clobber (reg:CC FLAGS_REG))])]
>    "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[2])));")
>
> diff --git a/gcc/ree.c b/gcc/ree.c
> index c7e106f..bc566ad 100644
> --- a/gcc/ree.c
> +++ b/gcc/ree.c
> @@ -327,8 +327,30 @@ 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;
> +  rtx cand_pat = PATTERN (cand->insn);
> +
> +  /* If the extension's source/destination registers are not the same
> +     then we need to change the original load to reference the destination
> +     of the extension.  Then we need to emit a copy from that destination
> +     to the original destination of the load.  */
> +  rtx new_reg;
> +  bool copy_needed
> +    = (REGNO (SET_DEST (cand_pat)) != REGNO (XEXP (SET_SRC (cand_pat), 0)));
> +  if (copy_needed)
> +    new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (cand_pat)));
> +  else
> +    new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (*orig_set)));
> +
> +#if 0
> +  /* Rethinking test.  Temporarily disabled.  */
> +  /* We're going to be widening the result of DEF_INSN, ensure that doing so
> +     doesn't change the number of hard registers needed for the result.  */
> +  if (HARD_REGNO_NREGS (REGNO (new_reg), cand->mode)
> +      != HARD_REGNO_NREGS (REGNO (SET_DEST (*orig_set)),
> +                          GET_MODE (SET_DEST (*orig_set))))
> +       return false;
> +#endif
>
>    /* Merge constants by directly moving the constant into the register under
>       some conditions.  Recall that RTL constants are sign-extended.  */
> @@ -387,7 +409,8 @@ combine_set_extension (ext_cand *cand, rtx curr_insn, rtx 
> *orig_set)
>        if (dump_file)
>          {
>            fprintf (dump_file,
> -                  "Tentatively merged extension with definition:\n");
> +                  "Tentatively merged extension with definition %s:\n",
> +                  (copy_needed) ? "(copy needed)" : "");
>            print_rtl_single (dump_file, curr_insn);
>          }
>        return true;
> @@ -531,6 +554,8 @@ struct ATTRIBUTE_PACKED ext_modified
>    /* Kind of modification of the insn.  */
>    ENUM_BITFIELD(ext_modified_kind) kind : 2;
>
> +  unsigned int do_not_reextend : 1;
> +
>    /* True if the insn is scheduled to be deleted.  */
>    unsigned int deleted : 1;
>  };
> @@ -614,27 +639,21 @@ make_defs_and_copies_lists (rtx extend_insn, const_rtx 
> set_pat,
>    return ret;
>  }
>
> -/* Merge the DEF_INSN with an extension.  Calls combine_set_extension
> -   on the SET pattern.  */
> -
> -static bool
> -merge_def_and_ext (ext_cand *cand, rtx def_insn, ext_state *state)
> +/* If DEF_INSN has single SET expression, possibly buried inside
> +   a PARALLEL, return the address of the SET expression, else
> +   return NULL.  This is similar to single_set, except that
> +   single_set allows multiple SETs when all but one is dead.  */
> +static rtx *
> +get_sub_rtx (rtx def_insn)
>  {
> -  enum machine_mode ext_src_mode;
> -  enum rtx_code code;
> -  rtx *sub_rtx;
> -  rtx s_expr;
> -  int i;
> -
> -  ext_src_mode = GET_MODE (XEXP (SET_SRC (cand->expr), 0));
> -  code = GET_CODE (PATTERN (def_insn));
> -  sub_rtx = NULL;
> +  enum rtx_code code = GET_CODE (PATTERN (def_insn));
> +  rtx *sub_rtx = NULL;
>
>    if (code == PARALLEL)
>      {
> -      for (i = 0; i < XVECLEN (PATTERN (def_insn), 0); i++)
> +      for (int i = 0; i < XVECLEN (PATTERN (def_insn), 0); i++)
>          {
> -          s_expr = XVECEXP (PATTERN (def_insn), 0, i);
> +          rtx s_expr = XVECEXP (PATTERN (def_insn), 0, i);
>            if (GET_CODE (s_expr) != SET)
>              continue;
>
> @@ -643,7 +662,7 @@ merge_def_and_ext (ext_cand *cand, rtx def_insn, 
> ext_state *state)
>            else
>              {
>                /* PARALLEL with multiple SETs.  */
> -              return false;
> +              return NULL;
>              }
>          }
>      }
> @@ -652,10 +671,27 @@ merge_def_and_ext (ext_cand *cand, rtx def_insn, 
> ext_state *state)
>    else
>      {
>        /* It is not a PARALLEL or a SET, what could it be ? */
> -      return false;
> +      return NULL;
>      }
>
>    gcc_assert (sub_rtx != NULL);
> +  return sub_rtx;
> +}
> +
> +/* Merge the DEF_INSN with an extension.  Calls combine_set_extension
> +   on the SET pattern.  */
> +
> +static bool
> +merge_def_and_ext (ext_cand *cand, rtx def_insn, ext_state *state)
> +{
> +  enum machine_mode ext_src_mode;
> +  rtx *sub_rtx;
> +
> +  ext_src_mode = GET_MODE (XEXP (SET_SRC (cand->expr), 0));
> +  sub_rtx = get_sub_rtx (def_insn);
> +
> +  if (sub_rtx == NULL)
> +    return false;
>
>    if (REG_P (SET_DEST (*sub_rtx))
>        && (GET_MODE (SET_DEST (*sub_rtx)) == ext_src_mode
> @@ -683,6 +719,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
> @@ -709,6 +757,108 @@ combine_reaching_defs (ext_cand *cand, const_rtx 
> set_pat, ext_state *state)
>    if (!outcome)
>      return false;
>
> +  /* If the destination operand of the extension is a different
> +     register than the source operand, then additional restrictions
> +     are needed.  Note we have to handle cases where we have nested
> +     extensions in the source operand.  */
> +  bool copy_needed
> +    = (REGNO (SET_DEST (PATTERN (cand->insn)))
> +       != REGNO (get_extended_src_reg (SET_SRC (PATTERN (cand->insn)))));
> +  if (copy_needed)
> +    {
> +      /* 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.  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;
> +
> +      /* Transformation of
> +        (set (reg1) (expression))
> +        (set (reg2) (any_extend (reg1)))
> +        into
> +        (set (reg2) (any_extend (expression)))
> +        (set (reg1) (reg2))
> +        is only valid for scalar integral modes, as it relies on the low
> +        subreg of reg1 to have the value of (expression), which is not true
> +        e.g. for vector modes.  */
> +      if (!SCALAR_INT_MODE_P (GET_MODE (SET_DEST (PATTERN (cand->insn)))))
> +       return false;
> +
> +      /* There's only one reaching def.  */
> +      rtx def_insn = state->defs_list[0];
> +
> +      /* The defining statement must not have been modified either.  */
> +      if (state->modified[INSN_UID (def_insn)].kind != EXT_MODIFIED_NONE)
> +       return false;
> +
> +      /* The defining statement and candidate insn must be in the same block.
> +        This is merely to keep the test for safety and updating the insn
> +        stream simple.  Also ensure that within the block the candidate
> +        follows the defining insn.  */
> +      if (BLOCK_FOR_INSN (cand->insn) != BLOCK_FOR_INSN (def_insn)
> +         || DF_INSN_LUID (def_insn) > DF_INSN_LUID (cand->insn))
> +       return false;
> +
> +      /* If there is an overlap between the destination of DEF_INSN and
> +        CAND->insn, then this transformation is not safe.  Note we have
> +        to test in the widened mode.  */
> +      rtx *dest_sub_rtx = get_sub_rtx (def_insn);
> +      if (dest_sub_rtx == NULL
> +         || !REG_P (SET_DEST (*dest_sub_rtx)))
> +       return false;
> +
> +      rtx tmp_reg = gen_rtx_REG (GET_MODE (SET_DEST (PATTERN (cand->insn))),
> +                                REGNO (SET_DEST (*dest_sub_rtx)));
> +      if (reg_overlap_mentioned_p (tmp_reg, SET_DEST (PATTERN (cand->insn))))
> +       return false;
> +
> +      /* The destination register of the extension insn must not be
> +        used or set between the def_insn and cand->insn exclusive.  */
> +      if (reg_used_between_p (SET_DEST (PATTERN (cand->insn)),
> +                             def_insn, cand->insn)
> +         || reg_set_between_p (SET_DEST (PATTERN (cand->insn)),
> +                               def_insn, cand->insn))
> +       return false;
> +
> +      /* We must be able to copy between the two registers.   Generate,
> +        recognize and verify constraints of the copy.  Also fail if this
> +        generated more than one insn.
> +
> +         This generates garbage since we throw away the insn when we're
> +        done, only to recreate it later if this test was successful.
> +
> +        Make sure to get the mode from the extension (cand->insn).  This
> +        is different than in the code to emit the copy as we have not
> +        modified the defining insn yet.  */
> +      start_sequence ();
> +      rtx pat = PATTERN (cand->insn);
> +      rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (pat)),
> +                                 REGNO (XEXP (SET_SRC (pat), 0)));
> +      rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (pat)),
> +                                 REGNO (SET_DEST (pat)));
> +      emit_move_insn (new_dst, new_src);
> +
> +      rtx insn = get_insns();
> +      end_sequence ();
> +      if (NEXT_INSN (insn))
> +       return false;
> +      if (recog_memoized (insn) == -1)
> +       return false;
> +      extract_insn (insn);
> +      if (!constrain_operands (1))
> +       return false;
> +    }
> +
> +
>    /* If cand->insn has been already modified, update cand->mode to a wider
>       mode if possible, or punt.  */
>    if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE)
> @@ -772,11 +922,15 @@ combine_reaching_defs (ext_cand *cand, const_rtx 
> set_pat, ext_state *state)
>              fprintf (dump_file, "All merges were successful.\n");
>
>           FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
> -           if (state->modified[INSN_UID (def_insn)].kind == 
> EXT_MODIFIED_NONE)
> -             state->modified[INSN_UID (def_insn)].kind
> -               = (cand->code == ZERO_EXTEND
> -                  ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT);
> +           {
> +             ext_modified *modified = &state->modified[INSN_UID (def_insn)];
> +             if (modified->kind == EXT_MODIFIED_NONE)
> +               modified->kind = (cand->code == ZERO_EXTEND ? 
> EXT_MODIFIED_ZEXT
> +                                                           : 
> EXT_MODIFIED_SEXT);
>
> +             if (copy_needed)
> +               modified->do_not_reextend = 1;
> +           }
>            return true;
>          }
>        else
> @@ -825,8 +979,7 @@ add_removable_extension (const_rtx expr, rtx insn,
>
>    if (REG_P (dest)
>        && (code == SIGN_EXTEND || code == ZERO_EXTEND)
> -      && REG_P (XEXP (src, 0))
> -      && REGNO (dest) == REGNO (XEXP (src, 0)))
> +      && REG_P (XEXP (src, 0)))
>      {
>        struct df_link *defs, *def;
>        ext_cand *cand;
> @@ -910,6 +1063,7 @@ find_and_remove_re (void)
>    int num_re_opportunities = 0, num_realized = 0, i;
>    vec<ext_cand> reinsn_list;
>    vec<rtx> reinsn_del_list;
> +  vec<rtx> reinsn_copy_list;
>    ext_state state;
>
>    /* Construct DU chain to get all reaching definitions of each
> @@ -921,6 +1075,7 @@ find_and_remove_re (void)
>
>    max_insn_uid = get_max_uid ();
>    reinsn_del_list.create (0);
> +  reinsn_copy_list.create (0);
>    reinsn_list = find_removable_extensions ();
>    state.defs_list.create (0);
>    state.copies_list.create (0);
> @@ -947,17 +1102,62 @@ find_and_remove_re (void)
>            if (dump_file)
>              fprintf (dump_file, "Eliminated the extension.\n");
>            num_realized++;
> -          reinsn_del_list.safe_push (curr_cand->insn);
> +         /* 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]);
> +           }
> +         reinsn_del_list.safe_push (curr_cand->insn);
>           state.modified[INSN_UID (curr_cand->insn)].deleted = 1;
>          }
>      }
>
> +  /* The copy list contains pairs of insns which describe copies we
> +     need to insert into the INSN stream.
> +
> +     The first insn in each pair is the extension insn, from which
> +     we derive the source and destination of the copy.
> +
> +     The second insn in each pair is the memory reference where the
> +     extension will ultimately happen.  We emit the new copy
> +     immediately after this insn.
> +
> +     It may first appear that the arguments for the copy are reversed.
> +     Remember that the memory reference will be changed to refer to the
> +     destination of the extention.  So we're actually emitting a copy
> +     from the new destination to the old destination.  */
> +  for (unsigned int i = 0; i < reinsn_copy_list.length (); i += 2)
> +    {
> +      rtx curr_insn = reinsn_copy_list[i];
> +      rtx def_insn = reinsn_copy_list[i + 1];
> +
> +      /* Use the mode of the destination of the defining insn
> +        for the mode of the copy.  This is necessary if the
> +        defining insn was used to eliminate a second extension
> +        that was wider than the first.  */
> +      rtx sub_rtx = *get_sub_rtx (def_insn);
> +      rtx pat = PATTERN (curr_insn);
> +      rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
> +                                REGNO (XEXP (SET_SRC (pat), 0)));
> +      rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
> +                                REGNO (SET_DEST (pat)));
> +      rtx set = gen_rtx_SET (VOIDmode, new_dst, new_src);
> +      emit_insn_after (set, def_insn);
> +    }
> +
>    /* Delete all useless extensions here in one sweep.  */
>    FOR_EACH_VEC_ELT (reinsn_del_list, i, curr_insn)
>      delete_insn (curr_insn);
>
>    reinsn_list.release ();
>    reinsn_del_list.release ();
> +  reinsn_copy_list.release ();
>    state.defs_list.release ();
>    state.copies_list.release ();
>    state.modified_list.release ();
> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
> index ff0934b..a408fed 100644
> --- a/gcc/testsuite/ChangeLog
> +++ b/gcc/testsuite/ChangeLog
> @@ -1,3 +1,32 @@
> +2015-02-15  H.J. Lu  <hongjiu...@intel.com>
> +
> +       Backport from mainline:
> +       2014-06-02  Jeff Law  <l...@redhat.com>
> +
> +       PR rtl-optimization/61094
> +       * g++.dg/pr61094: New test.
> +
> +       2014-02-14  Jeff Law  <l...@redhat.com>
> +
> +       PR rtl-optimization/60131
> +       * g++.dg/torture/pr60131.C: New test.
> +
> +       2014-01-15  Jeff Law  <l...@redhat.com>
> +
> +       PR tree-optimization/59747
> +       * gcc.c-torture/execute/pr59747.c: New test.
> +
> +       2014-01-10  Jeff Law  <l...@redhat.com>
> +
> +       PR middle-end/59743
> +       * gcc.c-torture/compile/pr59743.c: New test.
> +
> +       Backport from mainline:
> +       2014-01-07  Jeff Law  <l...@redhat.com>
> +
> +       PR middle-end/53623
> +       * gcc.target/i386/pr53623.c: New test.
> +
>  2015-02-13  Mikael Morin  <mik...@gcc.gnu.org>
>
>         PR fortran/63744
> diff --git a/gcc/testsuite/g++.dg/pr61094.C b/gcc/testsuite/g++.dg/pr61094.C
> new file mode 100644
> index 0000000..35adc25
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr61094.C
> @@ -0,0 +1,31 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3" }  */
> +
> +template <typename> struct A {
> +  unsigned _width, _height, _depth, _spectrum;
> +  template <typename t> A(t p1) {
> +    int a = p1.size();
> +    if (a) {
> +      _width = p1._width;
> +      _depth = _height = _spectrum = p1._spectrum;
> +    }
> +  }
> +  long size() { return (long)_width * _height * _depth * _spectrum; }
> +};
> +
> +int d;
> +void fn1(void *);
> +A<int> *fn2();
> +void fn3() {
> +  int b;
> +  for (;;) {
> +    A<char> c(*fn2());
> +    fn1(&c);
> +    if (d || !b)
> +      throw;
> +  }
> +}
> +
> +
> +
> +
> 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];
> +}
> diff --git a/gcc/testsuite/gcc.c-torture/compile/pr59743.c 
> b/gcc/testsuite/gcc.c-torture/compile/pr59743.c
> new file mode 100644
> index 0000000..8dadba5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.c-torture/compile/pr59743.c
> @@ -0,0 +1,23 @@
> +/* PR middle-end/59743 */
> +
> +typedef union {
> +  long all;
> +  struct {
> +    int low;
> +    int high;
> +  } s;
> +} udwords;
> +int a, b, c, d;
> +void __udivmoddi4() {
> +  udwords r;
> +  d = __builtin_clz(0);
> +  r.s.low = 0;
> +  for (; d; --d) {
> +    r.s.high = r.s.high << 1 | r.s.low >> a;
> +    r.s.low = r.s.low << b >> 1;
> +    int s = -r.all;
> +    c = s;
> +    r.all--;
> +  }
> +}
> +
> diff --git a/gcc/testsuite/gcc.c-torture/execute/pr59747.c 
> b/gcc/testsuite/gcc.c-torture/execute/pr59747.c
> new file mode 100644
> index 0000000..d45a908
> --- /dev/null
> +++ b/gcc/testsuite/gcc.c-torture/execute/pr59747.c
> @@ -0,0 +1,27 @@
> +extern void abort (void);
> +extern void exit (int);
> +
> +int a[6], b, c = 1, d;
> +short e;
> +
> +int __attribute__ ((noinline))
> +fn1 (int p)
> +{
> +  b = a[p];
> +}
> +
> +int
> +main ()
> +{
> +  if (sizeof (long long) != 8)
> +    exit (0);
> +
> +  a[0] = 1;
> +  if (c)
> +    e--;
> +  d = e;
> +  long long f = e;
> +  if (fn1 ((f >> 56) & 1) != 0)
> +    abort ();
> +  exit (0);
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/pr53623.c 
> b/gcc/testsuite/gcc.target/i386/pr53623.c
> new file mode 100644
> index 0000000..35c578b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr53623.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile { target {! ia32 } } } */
> +/* { dg-options "-O2 -fdump-rtl-ree" } */
> +
> +
> +#include <stdint.h>
> +
> +typedef (*inst_t)(int64_t rdi, int64_t rsi, int64_t rdx);
> +
> +int16_t code[256];
> +inst_t dispatch[256];
> +
> +void an_inst(int64_t rdi, int64_t rsi, int64_t rdx) {
> +  rdx = code[rdx];
> +  uint8_t inst = (uint8_t) rdx;
> +  rdx >>= 8;
> +  dispatch[inst](rdi, rsi, rdx);
> +}
> +
> +int main(void) {
> +  return 0;
> +}
> +
> +/* { dg-final { scan-rtl-dump "copy needed" "ree" } } */
> +/* { dg-final { cleanup-rtl-dump "ree" } } */
> +

Reply via email to