> Am 17.12.2024 um 14:30 schrieb Alexandre Oliva <ol...@adacore.com>:
> 
> 
> ACATS-4 ca11d02 exposed an error in the logic for recognizing and
> identifying the inner object in decode_field_ref: a view-converting
> load, inserted in a previous successful field merging operation, was
> recognized by gimple_convert_def_p within decode_field_reference, and
> as a result we took its operand as the expression, and failed to take
> note of the load location.
> 
> Without that load, we couldn't compare vuses, and then we ended up
> inserting a wider load before relevant parts of the object were
> initialized.
> 
> This patch makes gimple_convert_def_p recognize loads only when
> requested, and requires that either both or neither parts of a
> potentially merged operand have associated loads.
> 
> As a bonus, it enables additional optimizations by swapping the
> operands of the second compare when that makes left-hand operands
> of both compares match.
> 
> Regstrapped on x86_64-linux-gnu and on ppc64-linux-gnu, along with 3
> other ifcombine patches.  Ok to install?

Ok

Richard 

> 
> for  gcc/ChangeLog
> 
>    * gimple-fold.cc (gimple_convert_def_p): Reject load stmts
>    unless requested.
>    (decode_field_reference): Accept a converting load at the last
>    conversion matcher, subsuming the load identification.
>    (fold_truth_andor_for_ifcombine): Refuse to merge operands
>    when only one of them has an associated load stmt.  Swap
>    operands of one of the compares if that helps them match.
> 
> for  gcc/testsuite/ChangeLog
> 
>    * gcc.dg/field-merge-13.c: New.
> ---
> gcc/gimple-fold.cc                    |   93 ++++++++++++++++++++++++---------
> gcc/testsuite/gcc.dg/field-merge-13.c |   93 +++++++++++++++++++++++++++++++++
> 2 files changed, 162 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/field-merge-13.c
> 
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index 6c11654a2c65b..92f02ddd77408 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -7440,26 +7440,42 @@ maybe_fold_comparisons_from_match_pd (tree type, enum 
> tree_code code,
> }
> 
> /* Return TRUE and set op[0] if T, following all SSA edges, is a type
> -   conversion.  */
> +   conversion.  Reject loads if LOAD is NULL, otherwise set *LOAD if a
> +   converting load is found.  */
> 
> static bool
> -gimple_convert_def_p (tree t, tree op[1])
> +gimple_convert_def_p (tree t, tree op[1], gimple **load = NULL)
> {
> +  bool ret = false;
> +
>   if (TREE_CODE (t) == SSA_NAME
>       && !SSA_NAME_IS_DEFAULT_DEF (t))
>     if (gassign *def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (t)))
> -      switch (gimple_assign_rhs_code (def))
> -    {
> -    CASE_CONVERT:
> -      op[0] = gimple_assign_rhs1 (def);
> -      return true;
> -    case VIEW_CONVERT_EXPR:
> -      op[0] = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
> -      return true;
> -    default:
> -      break;
> -    }
> -  return false;
> +      {
> +    bool load_p = gimple_assign_load_p (def);
> +    if (load_p && !load)
> +      return false;
> +    switch (gimple_assign_rhs_code (def))
> +      {
> +      CASE_CONVERT:
> +        op[0] = gimple_assign_rhs1 (def);
> +        ret = true;
> +        break;
> +
> +      case VIEW_CONVERT_EXPR:
> +        op[0] = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
> +        ret = true;
> +        break;
> +
> +      default:
> +        break;
> +      }
> +
> +    if (ret && load_p)
> +      *load = def;
> +      }
> +
> +  return ret;
> }
> 
> /* Return TRUE and set op[*] if T, following all SSA edges, resolves to a
> @@ -7604,19 +7620,23 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT 
> *pbitsize,
>    return NULL_TREE;
>     }
> 
> -  /* Yet another chance to drop conversions.  */
> -  if (gimple_convert_def_p (exp, res_ops))
> +  /* Yet another chance to drop conversions.  This one is allowed to
> +     match a converting load, subsuming the load identification block
> +     below.  */
> +  if (gimple_convert_def_p (exp, res_ops, load))
>     {
>       if (!outer_type)
>    {
>      outer_type = TREE_TYPE (exp);
>      loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
>    }
> +      if (*load)
> +    loc[3] = gimple_location (*load);
>       exp = res_ops[0];
>     }
> 
>   /* Identify the load, if there is one.  */
> -  if (TREE_CODE (exp) == SSA_NAME
> +  if (!(*load) && TREE_CODE (exp) == SSA_NAME
>       && !SSA_NAME_IS_DEFAULT_DEF (exp))
>     {
>       gimple *def = SSA_NAME_DEF_STMT (exp);
> @@ -8056,13 +8076,37 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>   /* It must be true that the inner operation on the lhs of each
>      comparison must be the same if we are to be able to do anything.
>      Then see if we have constants.  If not, the same must be true for
> -     the rhs's.  */
> +     the rhs's.  If one is a load and the other isn't, we have to be
> +     conservative and avoid the optimization, otherwise we could get
> +     SRAed fields wrong.  */
>   if (volatilep
>       || ll_reversep != rl_reversep
> -      || ll_inner == 0 || rl_inner == 0
> -      || ! operand_equal_p (ll_inner, rl_inner, 0)
> -      || (ll_load && rl_load
> -      && gimple_vuse (ll_load) != gimple_vuse (rl_load)))
> +      || ll_inner == 0 || rl_inner == 0)
> +    return 0;
> +
> +  if (! operand_equal_p (ll_inner, rl_inner, 0))
> +    {
> +      /* Try swapping the operands.  */
> +      if (ll_reversep != rr_reversep
> +      || !rr_inner
> +      || !operand_equal_p (ll_inner, rr_inner, 0))
> +    return 0;
> +
> +      rcode = swap_tree_comparison (rcode);
> +      std::swap (rl_arg, rr_arg);
> +      std::swap (rl_inner, rr_inner);
> +      std::swap (rl_bitsize, rr_bitsize);
> +      std::swap (rl_bitpos, rr_bitpos);
> +      std::swap (rl_unsignedp, rr_unsignedp);
> +      std::swap (rl_reversep, rr_reversep);
> +      std::swap (rl_and_mask, rr_and_mask);
> +      std::swap (rl_load, rr_load);
> +      std::swap (rl_loc, rr_loc);
> +    }
> +
> +  if ((ll_load && rl_load)
> +      ? gimple_vuse (ll_load) != gimple_vuse (rl_load)
> +      : (!ll_load != !rl_load))
>     return 0;
> 
>   if (TREE_CODE (lr_arg) == INTEGER_CST
> @@ -8083,8 +8127,9 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>   else if (lr_reversep != rr_reversep
>       || lr_inner == 0 || rr_inner == 0
>       || ! operand_equal_p (lr_inner, rr_inner, 0)
> -       || (lr_load && rr_load
> -           && gimple_vuse (lr_load) != gimple_vuse (rr_load)))
> +       || ((lr_load && rr_load)
> +           ? gimple_vuse (lr_load) != gimple_vuse (rr_load)
> +           : (!lr_load != !rr_load)))
>     return 0;
> 
>   /* If we found sign tests, finish turning them into bit tests.  */
> diff --git a/gcc/testsuite/gcc.dg/field-merge-13.c 
> b/gcc/testsuite/gcc.dg/field-merge-13.c
> new file mode 100644
> index 0000000000000..7e4f4c499347f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/field-merge-13.c
> @@ -0,0 +1,93 @@
> +/* { dg-do run } */
> +/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +
> +/* Check that we optimize swapped compares, and that we don't load from 
> objects
> +   before they're fully initialized.  */
> +
> +struct pair {
> +  signed char a;
> +  signed char b;
> +} __attribute__ ((aligned (2)));
> +
> +#define make_pair(a,b) { a, b }
> +
> +struct s {
> +  struct pair c;
> +  struct pair d;
> +} __attribute__ ((aligned (4)));
> +
> +struct pair cp = make_pair (127, -1);
> +struct pair dp = make_pair (42, 0xf1);
> +
> +struct pair cq = make_pair (127, -1);
> +struct pair dq = make_pair (42, 0xf1);
> +
> +struct pair cr = make_pair (-127, -1);
> +struct pair dr = make_pair (42, 0xff);
> +
> +static __attribute__ ((noinline, noclone, noipa))
> +struct pair copy_pair (struct pair c)
> +{
> +  return c;
> +}
> +
> +static inline
> +struct s
> +make_s (struct pair c, struct pair d)
> +{
> +  struct s r;
> +  r.c = copy_pair (c);
> +  r.d = copy_pair (d);
> +  return r;
> +}
> +
> +void f (void) {
> +  struct s p = make_s (cp, dp);
> +  struct s q = make_s (cq, dr);
> +
> +  if (0
> +      || p.c.a != q.c.a
> +      || q.c.b != p.c.b
> +      || p.d.b != q.d.b
> +      || q.d.a != p.d.a
> +      )
> +    return;
> +  __builtin_abort ();
> +}
> +
> +void g (void) {
> +  struct s p = make_s (cp, dp);
> +  struct s q = make_s (cr, dq);
> +
> +  if (0
> +      || p.c.a != q.c.a
> +      || q.c.b != p.c.b
> +      || p.d.b != q.d.b
> +      || q.d.a != p.d.a
> +      )
> +    return;
> +  __builtin_abort ();
> +}
> +
> +void h (void) {
> +  struct s p = make_s (cp, dp);
> +  struct s q = make_s (cq, dq);
> +
> +  if (0
> +      || p.c.a != q.c.a
> +      || q.c.b != p.c.b
> +      || p.d.b != q.d.b
> +      || q.d.a != p.d.a
> +      )
> +    __builtin_abort ();
> +  return;
> +}
> +
> +int main () {
> +  f ();
> +  g ();
> +  h ();
> +  return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "optimizing" 9 "ifcombine" } } */
> 
> --
> Alexandre Oliva, happy hacker            https://FSFLA.org/blogs/lxo/
>   Free Software Activist                   GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive

Reply via email to