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++; > }