[PATCH 2/5] completely_scalarize arrays as well as records
Christophe Lyon
christophe.lyon@linaro.org
Fri Aug 28 07:19:00 GMT 2015
On 27 August 2015 at 17:43, Alan Lawrence <alan.lawrence@arm.com> wrote:
> Martin Jambor wrote:
>>
>> First, I would be much
>> happier if you added a proper comment to scalarize_elem function which
>> you forgot completely. The name is not very descriptive and it has
>> quite few parameters too.
>>
>> Second, this patch should also fix PR 67283. It would be great if you
>> could verify that and add it to the changelog when committing if that
>> is indeed the case.
>
> Thanks for pointing both of those out. I've added a comment to scalarize_elem,
> deleted the bogus comment in the new test, and yes I can confirm that the patch
> fixes PR 67283 on x86_64, and also AArch64 if
> --param sra-max-scalarization-size-Ospeed is passed. (I've not added any
> testcase specifically taken from that PR, however.)
>
> Pushed as r277265.
Actually, is r227265.
Since since commit I've noticed that
g++.dg/torture/pr64312.C
fails at -O1 in my config, saying "virtual memory exhaustion" (arm* targets)
I run my validations under ulimit -v 10GB, which seems already large enough.
Do we consider this a bug?
Christophe.
> ---
> gcc/testsuite/gcc.dg/tree-ssa/sra-15.c | 37 ++++++++
> gcc/tree-sra.c | 149 ++++++++++++++++++++++-----------
> 2 files changed, 138 insertions(+), 48 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/sra-15.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sra-15.c b/gcc/testsuite/gcc.dg/tree-ssa/sra-15.c
> new file mode 100644
> index 0000000..a22062e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/sra-15.c
> @@ -0,0 +1,37 @@
> +/* Verify that SRA total scalarization works on records containing arrays. */
> +/* { dg-do run } */
> +/* { dg-options "-O1 -fdump-tree-release_ssa --param sra-max-scalarization-size-Ospeed=32" } */
> +
> +extern void abort (void);
> +
> +struct S
> +{
> + char c;
> + unsigned short f[2][2];
> + int i;
> + unsigned short f3, f4;
> +};
> +
> +
> +int __attribute__ ((noinline))
> +foo (struct S *p)
> +{
> + struct S l;
> +
> + l = *p;
> + l.i++;
> + l.f[1][0] += 3;
> + *p = l;
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> + struct S a = {0, { {5, 7}, {9, 11} }, 4, 0, 0};
> + foo (&a);
> + if (a.i != 5 || a.f[1][0] != 12)
> + abort ();
> + return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "l;" 0 "release_ssa" } } */
> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
> index 8b3a0ad..3caf84a 100644
> --- a/gcc/tree-sra.c
> +++ b/gcc/tree-sra.c
> @@ -915,73 +915,126 @@ create_access (tree expr, gimple stmt, bool write)
> }
>
>
> -/* Return true iff TYPE is a RECORD_TYPE with fields that are either of gimple
> - register types or (recursively) records with only these two kinds of fields.
> - It also returns false if any of these records contains a bit-field. */
> +/* Return true iff TYPE is scalarizable - i.e. a RECORD_TYPE or ARRAY_TYPE with
> + fields that are either of gimple register types (excluding bit-fields)
> + or (recursively) scalarizable types. */
>
> static bool
> -type_consists_of_records_p (tree type)
> +scalarizable_type_p (tree type)
> {
> - tree fld;
> + gcc_assert (!is_gimple_reg_type (type));
>
> - if (TREE_CODE (type) != RECORD_TYPE)
> - return false;
> + switch (TREE_CODE (type))
> + {
> + case RECORD_TYPE:
> + for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
> + if (TREE_CODE (fld) == FIELD_DECL)
> + {
> + tree ft = TREE_TYPE (fld);
>
> - for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
> - if (TREE_CODE (fld) == FIELD_DECL)
> - {
> - tree ft = TREE_TYPE (fld);
> + if (DECL_BIT_FIELD (fld))
> + return false;
>
> - if (DECL_BIT_FIELD (fld))
> - return false;
> + if (!is_gimple_reg_type (ft)
> + && !scalarizable_type_p (ft))
> + return false;
> + }
>
> - if (!is_gimple_reg_type (ft)
> - && !type_consists_of_records_p (ft))
> - return false;
> - }
> + return true;
>
> - return true;
> + case ARRAY_TYPE:
> + {
> + tree elem = TREE_TYPE (type);
> + if (DECL_P (elem) && DECL_BIT_FIELD (elem))
> + return false;
> + if (!is_gimple_reg_type (elem)
> + && !scalarizable_type_p (elem))
> + return false;
> + return true;
> + }
> + default:
> + return false;
> + }
> }
>
> -/* Create total_scalarization accesses for all scalar type fields in DECL that
> - must be of a RECORD_TYPE conforming to type_consists_of_records_p. BASE
> - must be the top-most VAR_DECL representing the variable, OFFSET must be the
> - offset of DECL within BASE. REF must be the memory reference expression for
> - the given decl. */
> +static void scalarize_elem (tree, HOST_WIDE_INT, HOST_WIDE_INT, tree, tree);
> +
> +/* Create total_scalarization accesses for all scalar fields of a member
> + of type DECL_TYPE conforming to scalarizable_type_p. BASE
> + must be the top-most VAR_DECL representing the variable; within that,
> + OFFSET locates the member and REF must be the memory reference expression for
> + the member. */
>
> static void
> -completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
> - tree ref)
> +completely_scalarize (tree base, tree decl_type, HOST_WIDE_INT offset, tree ref)
> {
> - tree fld, decl_type = TREE_TYPE (decl);
> + switch (TREE_CODE (decl_type))
> + {
> + case RECORD_TYPE:
> + for (tree fld = TYPE_FIELDS (decl_type); fld; fld = DECL_CHAIN (fld))
> + if (TREE_CODE (fld) == FIELD_DECL)
> + {
> + HOST_WIDE_INT pos = offset + int_bit_position (fld);
> + tree ft = TREE_TYPE (fld);
> + tree nref = build3 (COMPONENT_REF, ft, ref, fld, NULL_TREE);
>
> - for (fld = TYPE_FIELDS (decl_type); fld; fld = DECL_CHAIN (fld))
> - if (TREE_CODE (fld) == FIELD_DECL)
> + scalarize_elem (base, pos, tree_to_uhwi (DECL_SIZE (fld)), nref,
> + ft);
> + }
> + break;
> + case ARRAY_TYPE:
> {
> - HOST_WIDE_INT pos = offset + int_bit_position (fld);
> - tree ft = TREE_TYPE (fld);
> - tree nref = build3 (COMPONENT_REF, TREE_TYPE (fld), ref, fld,
> - NULL_TREE);
> -
> - if (is_gimple_reg_type (ft))
> + tree elemtype = TREE_TYPE (decl_type);
> + tree elem_size = TYPE_SIZE (elemtype);
> + gcc_assert (elem_size && tree_fits_uhwi_p (elem_size));
> + int el_size = tree_to_uhwi (elem_size);
> + gcc_assert (el_size);
> +
> + tree minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (decl_type));
> + tree maxidx = TYPE_MAX_VALUE (TYPE_DOMAIN (decl_type));
> + gcc_assert (TREE_CODE (minidx) == INTEGER_CST
> + && TREE_CODE (maxidx) == INTEGER_CST);
> + unsigned HOST_WIDE_INT len = tree_to_uhwi (maxidx)
> + + 1 - tree_to_uhwi (minidx);
> + /* 4th operand to ARRAY_REF is size in units of the type alignment. */
> + for (unsigned HOST_WIDE_INT idx = 0; idx < len; idx++)
> {
> - struct access *access;
> - HOST_WIDE_INT size;
> -
> - size = tree_to_uhwi (DECL_SIZE (fld));
> - access = create_access_1 (base, pos, size);
> - access->expr = nref;
> - access->type = ft;
> - access->grp_total_scalarization = 1;
> - /* Accesses for intraprocedural SRA can have their stmt NULL. */
> + tree t_idx = build_int_cst (TYPE_DOMAIN (decl_type), idx);
> + tree nref = build4 (ARRAY_REF, elemtype, ref, t_idx, NULL_TREE,
> + NULL_TREE);
> + int el_off = offset + idx * el_size;
> + scalarize_elem (base, el_off, el_size, nref, elemtype);
> }
> - else
> - completely_scalarize_record (base, fld, pos, nref);
> }
> + break;
> + default:
> + gcc_unreachable ();
> + }
> +}
> +
> +/* Create total_scalarization accesses for a member of type TYPE, which must
> + satisfy either is_gimple_reg_type or scalarizable_type_p. BASE must be the
> + top-most VAR_DECL representing the variable; within that, POS and SIZE locate
> + the member and REF must be the reference expression for it. */
> +
> +static void
> +scalarize_elem (tree base, HOST_WIDE_INT pos, HOST_WIDE_INT size,
> + tree ref, tree type)
> +{
> + if (is_gimple_reg_type (type))
> + {
> + struct access *access = create_access_1 (base, pos, size);
> + access->expr = ref;
> + access->type = type;
> + access->grp_total_scalarization = 1;
> + /* Accesses for intraprocedural SRA can have their stmt NULL. */
> + }
> + else
> + completely_scalarize (base, type, pos, ref);
> }
>
> /* Create a total_scalarization access for VAR as a whole. VAR must be of a
> - RECORD_TYPE conforming to type_consists_of_records_p. */
> + RECORD_TYPE or ARRAY_TYPE conforming to scalarizable_type_p. */
>
> static void
> create_total_scalarization_access (tree var)
> @@ -2521,13 +2574,13 @@ analyze_all_variable_accesses (void)
> tree var = candidate (i);
>
> if (TREE_CODE (var) == VAR_DECL
> - && type_consists_of_records_p (TREE_TYPE (var)))
> + && scalarizable_type_p (TREE_TYPE (var)))
> {
> if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var)))
> <= max_scalarization_size)
> {
> create_total_scalarization_access (var);
> - completely_scalarize_record (var, var, 0, var);
> + completely_scalarize (var, TREE_TYPE (var), 0, var);
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> fprintf (dump_file, "Will attempt to totally scalarize ");
> --
> 1.8.3
>
More information about the Gcc-patches
mailing list