On Sun, Oct 28, 2012 at 6:13 PM, Joern Rennecke
<joern.renne...@embecosm.com> wrote:
> Quoting Richard Biener <richard.guent...@gmail.com>:
>
>>> Thus, you can allow the length to vary downwards as well as upwards
>>> across iterations with suitable definitions of the @code{length}
>>> attribute
>>> and/or @code{ADJUST_INSN_LENGTH}.  Care has to be taken that this does
>>> not
>>> lead to infinite loops.
>>
>>
>> I don't see that you can shrink length with just suitable lock_length and
>> length attributes.
>
>
> I disagree there (for certain values of 'just'), but we can just agree
> to disagree on this point because...
>
>>  What seems to be the cruical difference is that you
>> apply ADJUST_INSN_LENGTH after combining lock-length-max and length.
>> But then you _decrease_ length with ADJUST_INSN_LENGHT ...
>>
>> Maybe what you really want is ADJUST_INSN_LENGTH_AFTER which is
>> applied afterwards?  Thus,
>
>
> Well, actually, I found a number of problems with ADJUST_INSN_LENGTH:
> - it is not applied to inner insn is a delay slot sequence.  You can
>   sort of work around this by stitching recursive calls together, but
>   then you are faced with another problem:
> - You don't know what the length prior to ADJUST_INSN_LENGTH was.  That
>   was even worse with the non-unique uids where you didn't knew squat
>   about the instructions in the delay slot.
> - As you said, I want the adjustment happen after the maximum calculation.
>   Well, usually.  There are actually special cases where it would be useful
>   to have some sort of maximum calculation in place, to break up
>   alignment-driven cycles, but only applicable with a lesser priority than
>   for the range-driven branch offset calculations.
>
> But adding yet another macro neither does solve all these problems, nor
> would it align with our goal to move away from target macros.
>
> I found now an alternate way to make the ARC port termiante building its
> insn-attrtab.c - it involves using match_test("get_attr_length (insn) == 2")
> instead of eq_attr("[lock_]length" (const_int 2)) - where I really want to
> know if the instruction was considered short in the previous iteration.
>
> So, I have made a patch to replace the ADJUST_INSN_LENGTH macro in final.c
> with an adjust_insn_length hook, for which a default implementation
> using ADJUST_INSN_LENGTH is provided in targhooks.c to provide for an
> easy transition.
> I've looked at the existing ports that use ADJUST_INSN_LENGTH, and some
> seem to prefer to return an adjustment to be added to the length, while
> others prefer to return the new length.  The latter seemed to be slightly
> more numerous, so I went with that.
>
> The hook has two new parameters:
> - a flag that tells it if the insn in question is a delay sequence.
>   The default hook implementation skips the invocation of ADJUST_INSN_LENGTH
>   in this case for the sake of compatibility.
> - a pointer to int to set the number of iteration loops till the length
>   locking feature is supposed to apply to this instruction length when
>   using the increasing size calculations.  The pointed-to value is
> initialized
>   to zero, which means that length locking is always applied (assuming
> final.c
>   uses the increasing length algorithm).  Setting this to a higher number
>   effectively gives the new instruction length a lower priority to be put
>   into uid_lock_length.
>
>> Note that
>>
>>> Care has to be taken that this does not
>>> lead to infinite loops.
>>
>>
>> doesn't convince me that is properly designed ;)
>
>
> With the hook mechanism, it is much harder to create an infinite loop
> inside shorten_branches.  (It would involve something like setting
>  iteration_threshold to MAX_INT and making length decreasing when niter
>  is at MAX_INT, then letting integer overflow of niter take its course.
>  Making it impossible for a port maintainer to get things wrong is not a
>  meaningful goal for GCC, but making it straightforward to get it right is.)
>
> This patch builds on:
> http://gcc.gnu.org/ml/gcc-patches/2012-10/msg02527.html
>
> Bootstrapped in revision 192879 on i686-pc-linux-gnu.
> Tested with config-list.mk on x86_64-unknown-linux-gnu.

Apart from the iteration_threshold the hookization would be straight-forward.
Now I cannot decipher from the patch what functional change it introduces ;)

There are also ony 10 users of ADJUST_INSN_LENGTH, not enough to
warrant introducing a hook without removing the macro IMHO.

Thanks,
Richard.

> 2012-10-28  Joern Rennecke  <joern.renne...@embecosm.com>
>
>         * doc/tm.texi.in (@hook TARGET_ADJUST_INSN_LENGTH): Add.
>         * doc/tm.texi: Regenerate.
>         * final.c (get_attr_length_1): Use targetm.adjust_insn_length
>         instead of ADJUST_INSN_LENGTH.
>         (adjust_length): New function.
>         (shorten_branches): Use adjust_length instead of ADJUST_INSN_LENGTH.
>         * target.def (adjust_insn_length): New hook.
>         * targhooks.c (default_adjust_insn_length): New function.
>         * targhooks.h (default_adjust_insn_length): Declare.
>
> diff -drup gcc-192879-haveattr/doc/tm.texi gcc/doc/tm.texi
> --- gcc-192879-haveattr/doc/tm.texi     2012-10-28 01:07:38.463469923 +0000
> +++ gcc/doc/tm.texi     2012-10-28 01:31:15.522227927 +0000
> @@ -11341,3 +11341,7 @@ This value should be set if the result w
>  @deftypevrx {Target Hook} {bool} TARGET_HAVE_ATTR_LENGTH
>  These flags are automatically generated;  you should not override them in
> tm.c:
>  @end deftypevr
> +
> +@deftypefn {Target Hook} int TARGET_ADJUST_INSN_LENGTH (rtx @var{insn}, int
> @var{length}, bool @var{in_delay_sequence}, int *@var{iteration_threshold})
> +Return an adjusted length for @var{insn}.  @var{length} is the value that
> has been calculated using the @code{length} instruction attribute.
> @var{in_delay_sequence} if @var{insn} forms part of a delay sequence.
> *@var{iteration_threshold} specifies the number of branch shortening
> iterations before length decreases are inhibited.  The default
> implementation uses @code{ADJUST_INSN_LENGTH}, if defined.
> +@end deftypefn
> diff -drup gcc-192879-haveattr/doc/tm.texi.in gcc/doc/tm.texi.in
> --- gcc-192879-haveattr/doc/tm.texi.in  2012-10-28 01:07:38.489470252 +0000
> +++ gcc/doc/tm.texi.in  2012-10-28 01:31:55.578745701 +0000
> @@ -11175,3 +11175,5 @@ memory model bits are allowed.
>  @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
>
>  @hook TARGET_HAVE_CC0
> +
> +@hook TARGET_ADJUST_INSN_LENGTH
> diff -drup gcc-192879-haveattr/final.c gcc/final.c
> --- gcc-192879-haveattr/final.c 2012-10-28 01:07:38.492470288 +0000
> +++ gcc/final.c 2012-10-28 15:24:49.731169660 +0000
> @@ -424,10 +424,8 @@ get_attr_length_1 (rtx insn, int (*fallb
>         break;
>        }
>
> -#ifdef ADJUST_INSN_LENGTH
> -  ADJUST_INSN_LENGTH (insn, length);
> -#endif
> -  return length;
> +  int dummy = -1;
> +  return targetm.adjust_insn_length (insn, length, false, &dummy);
>  }
>
>  /* Obtain the current length of an insn.  If branch shortening has been
> done,
> @@ -827,6 +825,56 @@ struct rtl_opt_pass pass_compute_alignme
>  };
>
>
> +/* Helper function for shorten_branches, to apply the adjust_insn_length
> +   target hook, and lock in length increases in order to avoid infinite
> +   iteration cycles.
> +   INSN the the instruction being processed, and new_length is the length
> +   that has been calulated for it from its length attribute.  UID is
> +   its UID.  SEQ_P indicates if it is inside a delay slot sequence.
> +   INSN_LENGTHS and UID_LOCK_LENGTH are the arrays holding the current
> lengths
> +   and lockeds-in maximum lengths from the prevuious iterations, and are
> +   updated for UID when appropriate.
> +   *NITER contains the number of iterations since we last made a change
> +   to uid_lock_length.
> +   *SOMETHING_CHANGED will be set if we make a change to INSN_LENGTHS.
> +   The return value is the new length taking the result of the
> +   adjust_insn_length and uid_lock_length into account.
> +   Note that when *NITER is negative, no length locking is effective, and
> +   the new lengths are just assigned.  This is used in the initial pass,
> +   and when only making a single pass to update instruction length
> downward.  */
> +static int
> +adjust_length (rtx insn, int new_length, int uid, int *insn_lengths,
> +              int *uid_lock_length, bool seq_p, int *niter,
> +              bool *something_changed)
> +
> +{
> +  int iter_threshold = 0;
> +  new_length
> +    = targetm.adjust_insn_length (insn, new_length, seq_p,
> &iter_threshold);
> +  if (new_length < 0)
> +    fatal_insn ("negative insn length", insn);
> +  if (iter_threshold < 0)
> +    fatal_insn ("negative shorten_branches iteration threshold", insn);
> +  if (new_length != insn_lengths[uid])
> +    {
> +      if (new_length < uid_lock_length[uid])
> +       new_length = uid_lock_length[uid];
> +      if (new_length == insn_lengths[uid])
> +       ; /* done here.  */
> +      else if (*niter < iter_threshold
> +              || new_length > insn_lengths[uid])
> +       {
> +         if (*niter >= iter_threshold)
> +           uid_lock_length[uid] = new_length, *niter = 0;
> +         insn_lengths[uid] = new_length;
> +         *something_changed = true;
> +       }
> +      else
> +       new_length = insn_lengths[uid];
> +    }
> +  return new_length;
> +}
> +
>  /* Make a pass over all insns and compute their actual lengths by
> shortening
>     any branches of variable length if possible.  */
>
> @@ -848,7 +896,7 @@ shorten_branches (rtx first)
>    int max_skip;
>  #define MAX_CODE_ALIGN 16
>    rtx seq;
> -  int something_changed = 1;
> +  bool something_changed = true;
>    char *varying_length;
>    rtx body;
>    int uid;
> @@ -964,7 +1012,8 @@ shorten_branches (rtx first)
>      return;
>
>    /* Allocate the rest of the arrays.  */
> -  insn_lengths = XNEWVEC (int, max_uid);
> +  insn_lengths = XCNEWVEC (int, max_uid);
> +  int *uid_lock_length = XCNEWVEC (int, max_uid);
>    insn_lengths_max_uid = max_uid;
>    /* Syntax errors can lead to labels being outside of the main insn
> stream.
>       Initialize insn_addresses, so that we get reproducible results.  */
> @@ -1065,6 +1114,7 @@ shorten_branches (rtx first)
>
>    /* Compute initial lengths, addresses, and varying flags for each insn.
> */
>    int (*length_fun) (rtx) = increasing ? insn_min_length :
> insn_default_length;
> +  int niter = increasing ? 0 : -1;
>
>    for (insn_current_address = 0, insn = first;
>         insn != 0;
> @@ -1072,8 +1122,6 @@ shorten_branches (rtx first)
>      {
>        uid = INSN_UID (insn);
>
> -      insn_lengths[uid] = 0;
> -
>        if (LABEL_P (insn))
>         {
>           int log = LABEL_TO_ALIGNMENT (insn);
> @@ -1093,6 +1141,8 @@ shorten_branches (rtx first)
>        if (INSN_DELETED_P (insn))
>         continue;
>
> +      int length = 0;
> +
>        body = PATTERN (insn);
>        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
>         {
> @@ -1100,13 +1150,12 @@ shorten_branches (rtx first)
>              section.  */
>           if (JUMP_TABLES_IN_TEXT_SECTION
>               || readonly_data_section == text_section)
> -           insn_lengths[uid] = (XVECLEN (body,
> -                                         GET_CODE (body) == ADDR_DIFF_VEC)
> -                                * GET_MODE_SIZE (GET_MODE (body)));
> +           length = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
> +                     * GET_MODE_SIZE (GET_MODE (body)));
>           /* Alignment is handled by ADDR_VEC_ALIGN.  */
>         }
>        else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
> -       insn_lengths[uid] = asm_insn_count (body) * insn_default_length
> (insn);
> +       length = asm_insn_count (body) * insn_default_length (insn);
>        else if (GET_CODE (body) == SEQUENCE)
>         {
>           int i;
> @@ -1134,7 +1183,10 @@ shorten_branches (rtx first)
>               else
>                 inner_length = inner_length_fun (inner_insn);
>
> -             insn_lengths[inner_uid] = inner_length;
> +             inner_length
> +               = adjust_length (insn, inner_length, inner_uid,
> insn_lengths,
> +                                uid_lock_length, true, &niter,
> +                                &something_changed);
>               if (const_delay_slots)
>                 {
>                   if ((varying_length[inner_uid]
> @@ -1145,21 +1197,18 @@ shorten_branches (rtx first)
>                 }
>               else
>                 varying_length[inner_uid] = 0;
> -             insn_lengths[uid] += inner_length;
> +             length += inner_length;
>             }
>         }
>        else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
>         {
> -         insn_lengths[uid] = length_fun (insn);
> +         length = length_fun (insn);
>           varying_length[uid] = insn_variable_length_p (insn);
>         }
> -
> +
>        /* If needed, do any adjustment.  */
> -#ifdef ADJUST_INSN_LENGTH
> -      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
> -      if (insn_lengths[uid] < 0)
> -       fatal_insn ("negative insn length", insn);
> -#endif
> +      adjust_length (insn, length, uid, insn_lengths, uid_lock_length,
> +                    false, &niter, &something_changed);
>      }
>
>    /* Now loop over all the insns finding varying length insns.  For each,
> @@ -1168,16 +1217,16 @@ shorten_branches (rtx first)
>
>    while (something_changed)
>      {
> -      something_changed = 0;
> +      if (increasing)
> +       niter++;
> +
> +      something_changed = false;
>        insn_current_align = MAX_CODE_ALIGN - 1;
>        for (insn_current_address = 0, insn = first;
>            insn != 0;
>            insn = NEXT_INSN (insn))
>         {
>           int new_length;
> -#ifdef ADJUST_INSN_LENGTH
> -         int tmp_length;
> -#endif
>           int length_align;
>
>           uid = INSN_UID (insn);
> @@ -1363,17 +1412,13 @@ shorten_branches (rtx first)
>                   if (! varying_length[inner_uid])
>                     inner_length = insn_lengths[inner_uid];
>                   else
> -                   inner_length = insn_current_length (inner_insn);
> -
> -                 if (inner_length != insn_lengths[inner_uid])
>                     {
> -                     if (!increasing || inner_length >
> insn_lengths[inner_uid])
> -                       {
> -                         insn_lengths[inner_uid] = inner_length;
> -                         something_changed = 1;
> -                       }
> -                     else
> -                       inner_length = insn_lengths[inner_uid];
> +                     inner_length = insn_current_length (inner_insn);
> +
> +                     inner_length
> +                       = adjust_length (insn, inner_length, inner_uid,
> +                                        insn_lengths, uid_lock_length,
> true,
> +                                        &niter, &something_changed);
>                     }
>                   insn_current_address += inner_length;
>                   new_length += inner_length;
> @@ -1385,21 +1430,13 @@ shorten_branches (rtx first)
>               insn_current_address += new_length;
>             }
>
> -#ifdef ADJUST_INSN_LENGTH
>           /* If needed, do any adjustment.  */
> -         tmp_length = new_length;
> -         ADJUST_INSN_LENGTH (insn, new_length);
> +         int tmp_length = new_length;
> +         new_length
> +           = adjust_length (insn, new_length, uid, insn_lengths,
> +                            uid_lock_length, false, &niter,
> +                            &something_changed);
>           insn_current_address += (new_length - tmp_length);
> -#endif
> -
> -         if (new_length != insn_lengths[uid]
> -             && (!increasing || new_length > insn_lengths[uid]))
> -           {
> -             insn_lengths[uid] = new_length;
> -             something_changed = 1;
> -           }
> -         else
> -           insn_current_address += insn_lengths[uid] - new_length;
>         }
>        /* For a non-optimizing compile, do only a single pass.  */
>        if (!increasing)
> diff -drup gcc-192879-haveattr/target.def gcc/target.def
> --- gcc-192879-haveattr/target.def      2012-10-28 01:07:38.517470606 +0000
> +++ gcc/target.def      2012-10-28 01:31:15.525227979 +0000
> @@ -2818,6 +2818,17 @@ DEFHOOK
>   enum unwind_info_type, (void),
>   default_debug_unwind_info)
>
> +DEFHOOK
> +(adjust_insn_length,
> + "Return an adjusted length for @var{insn}.  @var{length} is the value
> that\
> + has been calculated using the @code{length} instruction attribute. \
> + @var{in_delay_sequence} if @var{insn} forms part of a delay sequence. \
> + *@var{iteration_threshold} specifies the number of branch shortening\
> + iterations before length decreases are inhibited.  The default\
> + implementation uses @code{ADJUST_INSN_LENGTH}, if defined.",
> + int, (rtx insn, int length, bool in_delay_sequence, int
> *iteration_threshold),
> + default_adjust_insn_length)
> +
>  DEFHOOKPOD
>  (atomic_test_and_set_trueval,
>   "This value should be set if the result written by\
> diff -drup gcc-192879-haveattr/targhooks.c gcc/targhooks.c
> --- gcc-192879-haveattr/targhooks.c     2012-10-25 03:33:26.000000000 +0100
> +++ gcc/targhooks.c     2012-10-28 01:41:35.082931024 +0000
> @@ -1540,4 +1540,20 @@ default_member_type_forces_blk (const_tr
>    return false;
>  }
>
> +/* Default version of adjust_insn_length.  */
> +
> +int
> +default_adjust_insn_length (rtx insn ATTRIBUTE_UNUSED, int length,
> +                           bool in_delay_sequence, int *iter_threshold)
> +{
> +  if (in_delay_sequence)
> +    *iter_threshold = INT_MAX;
> +#ifdef ADJUST_INSN_LENGTH
> +  else
> +    ADJUST_INSN_LENGTH (insn, length);
> +#endif
> +  return length;
> +}
> +
> +
>  #include "gt-targhooks.h"
> diff -drup gcc-192879-haveattr/targhooks.h gcc/targhooks.h
> --- gcc-192879-haveattr/targhooks.h     2012-10-25 03:33:26.000000000 +0100
> +++ gcc/targhooks.h     2012-10-28 01:31:15.479227682 +0000
> @@ -193,3 +193,4 @@ extern const char *default_pch_valid_p (
>  extern void default_asm_output_ident_directive (const char*);
>
>  extern bool default_member_type_forces_blk (const_tree, enum machine_mode);
> +extern int default_adjust_insn_length (rtx, int, bool, int *);
>

Reply via email to