On Sun, Nov 17, 2024 at 4:28 AM Lewis Hyatt <lhy...@gmail.com> wrote:
>
> Currently, when we allocate a gphi object, we round up the capacity for the
> trailing arguments array such that it will make full use of the page size
> that ggc will allocate. While there is also an explicit minimum of 2
> arguments, in practice after rounding to the ggc page size there is always
> room for at least 4.
>
> It seems we have some code that has come to depend on there being this much
> room before reallocation of a PHI is required. For example, the function
> loop_version () used during loop optimization will make sure there is room
> for an additional edge on each PHI that it processes. But there are call
> sites which cache a PHI pointer prior to calling loop_version () and assume
> it remains valid afterward, thus implicitly assuming that the PHI will have
> spare capacity. Examples include split_loop () and gen_parallel_loop ().
>
> This works fine now, but if the size of a gphi becomes larger, e.g. due to
> configuring location_t to be a 64-bit type, then on 32-bit platforms it ends
> up being possible to get a gphi with only 2 arguments of capacity, causing
> the above call sites of loop_version () to fail. (They store a pointer to a
> gphi object that no longer has the same meaning it did before it got
> reallocated.) The testcases gcc.dg/torture/pr113707-2.c and
> gcc.dg/graphite/pr81945.c exhibit that failure mode.
>
> It may be necessary to adjust those call sites to make this more robust, but
> in the meantime, changing the minimum from 2 to 4 does no harm given the
> minimum is practically 4 anyway, and it resolves the issue for 32-bit
> platforms.

We need to fix the users.  Note ideal_phi_node_len rounds up to a power of two
but extra_order_size_table also has MAX_ALIGNMENT * n with n from 1 to 16
buckets, so such extensive rounding up is not needed.

The cache is also quite useless this way (I didn't fix this when last working
there).

Richard.

> gcc/ChangeLog:
>
>         * tree-phinodes.cc (MIN_PHI_ARGS): New constant.
>         (allocate_phi_node): Change from hard-coded value 2 to MIN_PHI_ARGS,
>         which is now 4.
>         (ideal_phi_node_len): Likewise.
>         (release_phi_node): Likewise.
> ---
>  gcc/tree-phinodes.cc | 24 ++++++++++++------------
>  1 file changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/gcc/tree-phinodes.cc b/gcc/tree-phinodes.cc
> index 5a7e4a94e57..9d8e16ac200 100644
> --- a/gcc/tree-phinodes.cc
> +++ b/gcc/tree-phinodes.cc
> @@ -63,11 +63,12 @@ along with GCC; see the file COPYING3.  If not see
>     walking the elements of the last array entry would result in finding less
>     than .1% additional reusable PHI nodes.
>
> -   Note that we can never have less than two PHI argument slots.  Thus,
> -   the -2 on all the calculations below.  */
> +   Note that we can never have less than MIN_PHI_ARGS argument slots.  Thus,
> +   the subtraction of MIN_PHI_ARGS on all the calculations below.  */
>
>  #define NUM_BUCKETS 10
> -static GTY ((deletable (""))) vec<gimple *, va_gc> 
> *free_phinodes[NUM_BUCKETS - 2];
> +#define MIN_PHI_ARGS 4
> +static GTY ((deletable (""))) vec<gimple *, va_gc> 
> *free_phinodes[NUM_BUCKETS - MIN_PHI_ARGS];
>  static unsigned long free_phinode_count;
>
>  static int ideal_phi_node_len (int);
> @@ -94,17 +95,18 @@ static inline gphi *
>  allocate_phi_node (size_t len)
>  {
>    gphi *phi;
> -  size_t bucket = NUM_BUCKETS - 2;
> +  size_t bucket = NUM_BUCKETS - MIN_PHI_ARGS;
>    size_t size = sizeof (struct gphi)
>                 + (len - 1) * sizeof (struct phi_arg_d);
>
>    if (free_phinode_count)
> -    for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
> +    for (bucket = len - MIN_PHI_ARGS; bucket < NUM_BUCKETS - MIN_PHI_ARGS;
> +        bucket++)
>        if (free_phinodes[bucket])
>         break;
>
>    /* If our free list has an element, then use it.  */
> -  if (bucket < NUM_BUCKETS - 2
> +  if (bucket < NUM_BUCKETS - MIN_PHI_ARGS
>        && gimple_phi_capacity ((*free_phinodes[bucket])[0]) >= len)
>      {
>        free_phinode_count--;
> @@ -145,9 +147,8 @@ ideal_phi_node_len (int len)
>    size_t size, new_size;
>    int log2, new_len;
>
> -  /* We do not support allocations of less than two PHI argument slots.  */
> -  if (len < 2)
> -    len = 2;
> +  /* We do not support allocations of less than MIN_PHI_ARGS argument slots. 
>  */
> +  len = MAX (len, MIN_PHI_ARGS);
>
>    /* Compute the number of bytes of the original request.  */
>    size = sizeof (struct gphi)
> @@ -225,14 +226,13 @@ release_phi_node (gimple *phi)
>
>    /* Immediately return the memory to the allocator when we would
>       only ever re-use it for a smaller size allocation.  */
> -  if (len - 2 >= NUM_BUCKETS - 2)
> +  if (len >= NUM_BUCKETS)
>      {
>        ggc_free (phi);
>        return;
>      }
>
> -  bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len;
> -  bucket -= 2;
> +  bucket = len - MIN_PHI_ARGS;
>    vec_safe_push (free_phinodes[bucket], phi);
>    free_phinode_count++;
>  }

Reply via email to