Hi Jeff,

On 29 August 2017 at 07:07, Jeff Law <l...@redhat.com> wrote:
> This is a two part patchkit to improve DOM's ability to derive constant
> equivalences that arise as a result of traversing a particular edge in
> the CFG.
>
> Until now we only allowed a single NAME = NAME|CONST equivalence to be
> associated with an edge in the CFG.  Patch #1 generalizes that code so
> that we can record multiple simple equivalences on an edge.  Much like
> expression equivalences, we just shove them into a vec and iterate on
> the vec in the appropriate places.
>
> Patch #2 has the interesting bits.
>
> Back in the gcc-7 effort I added the ability to look at the operands of
> a BIT_IOR_EXPR that had a zero result.  In that case each operand of the
> BIT_IOR must have a zero value.  This was to address a missed
> optimization regression bug during stage4.
>
> The plan was always to add analogous BIT_AND support, but I didn't feel
> like handling BIT_AND was appropriate at the time (no bz entry and no
> regressions related to that capability).
>
> I'd also had the sense that further improvements could be made here. For
> example, it is common for the BIT_IOR or BIT_AND to be fed by a
> comparison and we ought to be able to record the result of the
> comparison.  If the comparison happened to be an equality test, then we
> may ultimately derive a constant for on operand of the equality test as
> well.
>
> It also seemed like the NOP/CONVERT_EXPR handling could be incorporated
> into such a change.
>
> So I pulled together some instrumentation.  Lots of things generate
> equivalences -- but a much smaller subset of those equivalences are
> ultimately useful.
>
> Probably the most surprising was BIT_XOR, which allows us to generate
> all kinds of equivalences, but none that were useful for ultimate
> simplification in any of the tests I looked at.
>
>
> The most subtle was COND_EXPRs.  We might have something like
>
> res = (a != 5) ? x : 1;
>
>
> We can't actually derive anything useful for "a" here, even if we know
> the result is one.  That's because "x" could have the value 1.  So you
> end up only being able to derive equivalences for COND_EXPRs when both
> arms have a constant value.  That restriction dramatically reduces the
> utility of handling COND_EXPR -- to the point where I'm not including it.
>
> So what we end up with is BIT_AND/BIT_IOR, conversions, plus/minus,
> comparisons and neg/not.
>
> So when we determine that a particular SSA_NAME has a constant value, we
> look at the defining statement and essentially try to derive a value for
> the input operand(s) based on knowing the result value.  If we can
> derive a constant value for an input operand, we record that value and
> recurse.
>
> In cases where we walk backwards to a condition.  We will record the
> condition into the available expression table.
>
>
> The code is written such that if we find cases where the equivalences
> for other nodes are useful, they're easy to add.
>
>
> These equivalences are most useful to the threader, but I've seen them
> help in other cases as well.  There's a half-dozen or so new tests
> reduced from GCC itself.
>
> Bootstrapped and regression tested on x86_64, lightly tested on ppc64le
> via bootstrapping and running the new tests to verify they do the right
> thing on a !logical_op_short_circuit target.
>
> Installing on the trunk.
>
> Jeff
>
>
> commit 506ac60cacbc4c4e5e166513ea83c1d2e14eaf3b
> Author: law <law@138bc75d-0d04-0410-961f-82ee72b054a4>
> Date:   Tue Aug 29 05:03:22 2017 +0000
>
>             * tree-ssa-dom.c (class edge_info): Changed from a struct
>             to a class.  Add ctor/dtor, methods and data members.
>             (edge_info::edge_info): Renamed from allocate_edge_info.
>             Initialize additional members.
>             (edge_info::~edge_info): New.
>             (free_dom_edge_info): Delete the edge info.
>             (record_edge_info): Use new class & associated member functions.
>             Tighten forms for testing for edge equivalences.
>             (record_temporary_equivalences): Iterate over the simple
>             equivalences rather than assuming there's only one per edge.
>             (cprop_into_successor_phis): Iterate over the simple
>             equivalences rather than assuming there's only one per edge.
>             (optimize_stmt): Use operand_equal_p rather than pointer
>             equality for mini-DSE code.
>
>     git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@251396 
> 138bc75d-0d04-0410-961f-82ee72b054a4
>
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index abe7d855260..258d4242f30 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,20 @@
> +2017-08-28  Jeff Law  <l...@redhat.com>
> +
> +       * tree-ssa-dom.c (class edge_info): Changed from a struct
> +       to a class.  Add ctor/dtor, methods and data members.
> +       (edge_info::edge_info): Renamed from allocate_edge_info.
> +       Initialize additional members.
> +       (edge_info::~edge_info): New.
> +       (free_dom_edge_info): Delete the edge info.
> +       (record_edge_info): Use new class & associated member functions.
> +       Tighten forms for testing for edge equivalences.
> +       (record_temporary_equivalences): Iterate over the simple
> +       equivalences rather than assuming there's only one per edge.
> +       (cprop_into_successor_phis): Iterate over the simple
> +       equivalences rather than assuming there's only one per edge.
> +       (optimize_stmt): Use operand_equal_p rather than pointer
> +       equality for mini-DSE code.
> +
>  2017-08-28  Nathan Sidwell  <nat...@acm.org>
>
>         * gcc.c (execute): Fold SIGPIPE handling into switch
> diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
> index 407a4ef97d2..403485b3c55 100644
> --- a/gcc/tree-ssa-dom.c
> +++ b/gcc/tree-ssa-dom.c
> @@ -58,17 +58,28 @@ along with GCC; see the file COPYING3.  If not see
>     These structures live for a single iteration of the dominator
>     optimizer in the edge's AUX field.  At the end of an iteration we
>     free each of these structures.  */
> -
> -struct edge_info
> +class edge_info
>  {
> -  /* If this edge creates a simple equivalence, the LHS and RHS of
> -     the equivalence will be stored here.  */
> -  tree lhs;
> -  tree rhs;
> + public:
> +  typedef std::pair <tree, tree> equiv_pair;
> +  edge_info (edge);
> +  ~edge_info ();
> +
> +  /* Record a simple LHS = RHS equivalence.  This may trigger
> +     calls to derive_equivalences.  */
> +  void record_simple_equiv (tree, tree);
> +
> +  /* If traversing this edge creates simple equivalences, we store
> +     them as LHS/RHS pairs within this vector.  */
> +  vec<equiv_pair> simple_equivalences;
>
>    /* Traversing an edge may also indicate one or more particular conditions
>       are true or false.  */
>    vec<cond_equivalence> cond_equivalences;
> +
> + private:
> +  /* Derive equivalences by walking the use-def chains.  */
> +  void derive_equivalences (tree, tree, int);
>  };
>
>  /* Track whether or not we have changed the control flow graph.  */
> @@ -109,36 +120,46 @@ static edge single_incoming_edge_ignoring_loop_edges 
> (basic_block);
>  static void dump_dominator_optimization_stats (FILE *file,
>                                                hash_table<expr_elt_hasher> *);
>
> +/* Constructor for EDGE_INFO.  An EDGE_INFO instance is always
> +   associated with an edge E.  */
>
> -/* Free the edge_info data attached to E, if it exists.  */
> -
> -void
> -free_dom_edge_info (edge e)
> +edge_info::edge_info (edge e)
>  {
> -  struct edge_info *edge_info = (struct edge_info *)e->aux;
> +  /* Free the old one associated with E, if it exists and
> +     associate our new object with E.  */
> +  free_dom_edge_info (e);
> +  e->aux = this;
>
> -  if (edge_info)
> -    {
> -      edge_info->cond_equivalences.release ();
> -      free (edge_info);
> -    }
> +  /* And initialize the embedded vectors.  */
> +  simple_equivalences = vNULL;
> +  cond_equivalences = vNULL;
>  }
>
> -/* Allocate an EDGE_INFO for edge E and attach it to E.
> -   Return the new EDGE_INFO structure.  */
> +/* Destructor just needs to release the vectors.  */
> +edge_info::~edge_info (void)
> +{
> +  this->cond_equivalences.release ();
> +  this->simple_equivalences.release ();
> +}
> +
> +/* Record that LHS is known to be equal to RHS at runtime when the
> +   edge associated with THIS is traversed.  */
>
> -static struct edge_info *
> -allocate_edge_info (edge e)
> +void
> +edge_info::record_simple_equiv (tree lhs, tree rhs)
>  {
> -  struct edge_info *edge_info;
> +  simple_equivalences.safe_push (equiv_pair (lhs, rhs));
> +}
>
> -  /* Free the old one, if it exists.  */
> -  free_dom_edge_info (e);
> +/* Free the edge_info data attached to E, if it exists.  */
>
> -  edge_info = XCNEW (struct edge_info);
> +void
> +free_dom_edge_info (edge e)
> +{
> +  class edge_info *edge_info = (struct edge_info *)e->aux;
>
> -  e->aux = edge_info;
> -  return edge_info;
> +  if (edge_info)
> +    delete edge_info;
>  }
>
>  /* Free all EDGE_INFO structures associated with edges in the CFG.
> @@ -171,7 +192,7 @@ static void
>  record_edge_info (basic_block bb)
>  {
>    gimple_stmt_iterator gsi = gsi_last_bb (bb);
> -  struct edge_info *edge_info;
> +  class edge_info *edge_info;
>
>    if (! gsi_end_p (gsi))
>      {
> @@ -212,9 +233,8 @@ record_edge_info (basic_block bb)
>                     {
>                       tree x = fold_convert_loc (loc, TREE_TYPE (index),
>                                                  CASE_LOW (label));
> -                     edge_info = allocate_edge_info (e);
> -                     edge_info->lhs = index;
> -                     edge_info->rhs = x;
> +                     edge_info = new class edge_info (e);
> +                     edge_info->record_simple_equiv (index, x);
>                     }
>                 }
>               free (info);
> @@ -251,28 +271,32 @@ record_edge_info (basic_block bb)
>
>                if (code == EQ_EXPR)
>                  {
> -                  edge_info = allocate_edge_info (true_edge);
> -                  edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1) ? false_val : 
> true_val);
> -
> -                  edge_info = allocate_edge_info (false_edge);
> -                  edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1) ? true_val : 
> false_val);
> +                 edge_info = new class edge_info (true_edge);
> +                 edge_info->record_simple_equiv (op0,
> +                                                 (integer_zerop (op1)
> +                                                  ? false_val : true_val));
> +                 edge_info = new class edge_info (false_edge);
> +                 edge_info->record_simple_equiv (op0,
> +                                                 (integer_zerop (op1)
> +                                                  ? true_val : false_val));
>                  }
>                else
>                  {
> -                  edge_info = allocate_edge_info (true_edge);
> -                  edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1) ? true_val : 
> false_val);
> -
> -                  edge_info = allocate_edge_info (false_edge);
> -                  edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1) ? false_val : 
> true_val);
> +                 edge_info = new class edge_info (true_edge);
> +                 edge_info->record_simple_equiv (op0,
> +                                                 (integer_zerop (op1)
> +                                                  ? true_val : false_val));
> +                 edge_info = new class edge_info (false_edge);
> +                 edge_info->record_simple_equiv (op0,
> +                                                 (integer_zerop (op1)
> +                                                  ? false_val : true_val));
>                  }
>              }
> +         /* This can show up in the IL as a result of copy propagation
> +            it will eventually be canonicalized, but we have to cope
> +            with this case within the pass.  */
>            else if (is_gimple_min_invariant (op0)
> -                   && (TREE_CODE (op1) == SSA_NAME
> -                       || is_gimple_min_invariant (op1)))
> +                   && TREE_CODE (op1) == SSA_NAME)
>              {
>                tree cond = build2 (code, boolean_type_node, op0, op1);
>                tree inverted = invert_truthvalue_loc (loc, cond);
> @@ -281,23 +305,17 @@ record_edge_info (basic_block bb)
>                      && real_zerop (op0));
>                struct edge_info *edge_info;
>
> -              edge_info = allocate_edge_info (true_edge);
> +             edge_info = new class edge_info (true_edge);
>                record_conditions (&edge_info->cond_equivalences, cond, 
> inverted);
>
>                if (can_infer_simple_equiv && code == EQ_EXPR)
> -                {
> -                  edge_info->lhs = op1;
> -                  edge_info->rhs = op0;
> -                }
> +               edge_info->record_simple_equiv (op1, op0);
>
> -              edge_info = allocate_edge_info (false_edge);
> +             edge_info = new class edge_info (false_edge);
>                record_conditions (&edge_info->cond_equivalences, inverted, 
> cond);
>
>                if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR)
> -                {
> -                  edge_info->lhs = op1;
> -                  edge_info->rhs = op0;
> -                }
> +               edge_info->record_simple_equiv (op1, op0);
>              }
>
>            else if (TREE_CODE (op0) == SSA_NAME
> @@ -311,27 +329,19 @@ record_edge_info (basic_block bb)
>                      && (TREE_CODE (op1) == SSA_NAME || real_zerop (op1)));
>                struct edge_info *edge_info;
>
> -              edge_info = allocate_edge_info (true_edge);
> +             edge_info = new class edge_info (true_edge);
>                record_conditions (&edge_info->cond_equivalences, cond, 
> inverted);
>
>                if (can_infer_simple_equiv && code == EQ_EXPR)
> -                {
> -                  edge_info->lhs = op0;
> -                  edge_info->rhs = op1;
> -                }
> +               edge_info->record_simple_equiv (op0, op1);
>
> -              edge_info = allocate_edge_info (false_edge);
> +             edge_info = new class edge_info (false_edge);
>                record_conditions (&edge_info->cond_equivalences, inverted, 
> cond);
>
>                if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR)
> -                {
> -                  edge_info->lhs = op0;
> -                  edge_info->rhs = op1;
> -                }
> +               edge_info->record_simple_equiv (op0, op1);
>              }
>          }
> -
> -      /* ??? TRUTH_NOT_EXPR can create an equivalence too.  */
>      }
>  }
>
> @@ -738,7 +748,7 @@ record_temporary_equivalences (edge e,
>                                class avail_exprs_stack *avail_exprs_stack)
>  {
>    int i;
> -  struct edge_info *edge_info = (struct edge_info *) e->aux;
> +  class edge_info *edge_info = (class edge_info *) e->aux;
>
>    /* If we have info associated with this edge, record it into
>       our equivalence tables.  */
> @@ -771,68 +781,73 @@ record_temporary_equivalences (edge e,
>             }
>         }
>
> -      tree lhs = edge_info->lhs;
> -      if (!lhs || TREE_CODE (lhs) != SSA_NAME)
> -       return;
> +      edge_info::equiv_pair *seq;
> +      for (i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i)
> +       {
> +         tree lhs = seq->first;
> +         if (!lhs || TREE_CODE (lhs) != SSA_NAME)
> +           continue;
>
> -      /* Record the simple NAME = VALUE equivalence.  */
> -      tree rhs = edge_info->rhs;
> +         /* Record the simple NAME = VALUE equivalence.  */
> +         tree rhs = seq->second;
>
> -      /* If this is a SSA_NAME = SSA_NAME equivalence and one operand is
> -        cheaper to compute than the other, then set up the equivalence
> -        such that we replace the expensive one with the cheap one.
> +         /* If this is a SSA_NAME = SSA_NAME equivalence and one operand is
> +            cheaper to compute than the other, then set up the equivalence
> +            such that we replace the expensive one with the cheap one.
>
> -        If they are the same cost to compute, then do not record anything.  
> */
> -      if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME)
> -       {
> -         gimple *rhs_def = SSA_NAME_DEF_STMT (rhs);
> -         int rhs_cost = estimate_num_insns (rhs_def, &eni_size_weights);
> +            If they are the same cost to compute, then do not record
> +            anything.  */
> +         if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME)
> +           {
> +             gimple *rhs_def = SSA_NAME_DEF_STMT (rhs);
> +             int rhs_cost = estimate_num_insns (rhs_def, &eni_size_weights);
>
> -         gimple *lhs_def = SSA_NAME_DEF_STMT (lhs);
> -         int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
> +             gimple *lhs_def = SSA_NAME_DEF_STMT (lhs);
> +             int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
>
> -         if (rhs_cost > lhs_cost)
> -           record_equality (rhs, lhs, const_and_copies);
> -         else if (rhs_cost < lhs_cost)
> +             if (rhs_cost > lhs_cost)
> +               record_equality (rhs, lhs, const_and_copies);
> +             else if (rhs_cost < lhs_cost)
> +               record_equality (lhs, rhs, const_and_copies);
> +           }
> +         else
>             record_equality (lhs, rhs, const_and_copies);
> -       }
> -      else
> -       record_equality (lhs, rhs, const_and_copies);
>
> -      /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
> -        set via a widening type conversion, then we may be able to record
> -        additional equivalences.  */
> -      if (TREE_CODE (rhs) == INTEGER_CST)
> -       {
> -         gimple *defstmt = SSA_NAME_DEF_STMT (lhs);
> -
> -         if (defstmt
> -             && is_gimple_assign (defstmt)
> -             && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt)))
> +         /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
> +            set via a widening type conversion, then we may be able to record
> +            additional equivalences.  */
> +         if (TREE_CODE (rhs) == INTEGER_CST)
>             {
> -             tree old_rhs = gimple_assign_rhs1 (defstmt);
> -
> -             /* If the conversion widens the original value and
> -                the constant is in the range of the type of OLD_RHS,
> -                then convert the constant and record the equivalence.
> -
> -                Note that int_fits_type_p does not check the precision
> -                if the upper and lower bounds are OK.  */
> -             if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs))
> -                 && (TYPE_PRECISION (TREE_TYPE (lhs))
> -                     > TYPE_PRECISION (TREE_TYPE (old_rhs)))
> -                 && int_fits_type_p (rhs, TREE_TYPE (old_rhs)))
> +             gimple *defstmt = SSA_NAME_DEF_STMT (lhs);
> +
> +             if (defstmt
> +                 && is_gimple_assign (defstmt)
> +                 && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt)))
>                 {
> -                 tree newval = fold_convert (TREE_TYPE (old_rhs), rhs);
> -                 record_equality (old_rhs, newval, const_and_copies);
> +                 tree old_rhs = gimple_assign_rhs1 (defstmt);
> +
> +                 /* If the conversion widens the original value and
> +                    the constant is in the range of the type of OLD_RHS,
> +                    then convert the constant and record the equivalence.
> +
> +                    Note that int_fits_type_p does not check the precision
> +                    if the upper and lower bounds are OK.  */
> +                 if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs))
> +                     && (TYPE_PRECISION (TREE_TYPE (lhs))
> +                         > TYPE_PRECISION (TREE_TYPE (old_rhs)))
> +                     && int_fits_type_p (rhs, TREE_TYPE (old_rhs)))
> +                   {
> +                     tree newval = fold_convert (TREE_TYPE (old_rhs), rhs);
> +                     record_equality (old_rhs, newval, const_and_copies);
> +                   }
>                 }
>             }
> -       }
>
> -      /* Any equivalence found for LHS may result in additional
> -        equivalences for other uses of LHS that we have already
> -        processed.  */
> -      back_propagate_equivalences (lhs, e, const_and_copies);
> +         /* Any equivalence found for LHS may result in additional
> +            equivalences for other uses of LHS that we have already
> +            processed.  */
> +         back_propagate_equivalences (lhs, e, const_and_copies);
> +       }
>      }
>  }
>
> @@ -1124,14 +1139,20 @@ cprop_into_successor_phis (basic_block bb,
>
>          Don't bother with [01] = COND equivalences, they're not useful
>          here.  */
> -      struct edge_info *edge_info = (struct edge_info *) e->aux;
> +      class edge_info *edge_info = (class edge_info *) e->aux;
> +
>        if (edge_info)
>         {
> -         tree lhs = edge_info->lhs;
> -         tree rhs = edge_info->rhs;
> +         edge_info::equiv_pair *seq;
> +         for (int i = 0; edge_info->simple_equivalences.iterate (i, &seq); 
> ++i)
> +           {
> +             tree lhs = seq->first;
> +             tree rhs = seq->second;
> +
> +             if (lhs && TREE_CODE (lhs) == SSA_NAME)
> +               const_and_copies->record_const_or_copy (lhs, rhs);
> +           }
>
> -         if (lhs && TREE_CODE (lhs) == SSA_NAME)
> -           const_and_copies->record_const_or_copy (lhs, rhs);
>         }
>
>        indx = e->dest_idx;
> @@ -1701,8 +1722,7 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
>           gimple_set_vuse (new_stmt, gimple_vuse (stmt));
>           cached_lhs = avail_exprs_stack->lookup_avail_expr (new_stmt, false,
>                                                              false);
> -         if (cached_lhs
> -             && rhs == cached_lhs)
> +         if (cached_lhs && operand_equal_p (rhs, cached_lhs, 0))
>             {
>               basic_block bb = gimple_bb (stmt);
>               unlink_stmt_vdef (stmt);
>
> commit a370df2c52074abbb044d1921a0c7df235758050
> Author: law <law@138bc75d-0d04-0410-961f-82ee72b054a4>
> Date:   Tue Aug 29 05:03:36 2017 +0000
>
>             * tree-ssa-dom.c (edge_info::record_simple_equiv): Call
>             derive_equivalences.
>             (derive_equivalences_from_bit_ior, record_temporary_equivalences):
>             Code moved into....
>             (edge_info::derive_equivalences): New private member function
>
>             * gcc.dg/torture/pr57214.c: Fix type of loop counter.
>             * gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM.
>             * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test.
>             * gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test.
>             * gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test.
>             * gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test.
>             * gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test.
>             * gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test.
>             * gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test.
>
>     git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@251397 
> 138bc75d-0d04-0410-961f-82ee72b054a4
>

3 of the new tests fail on arm-none-linux-gnueabihf
--with-cpu=cortex-a15 --with-fpu=vfpv3-d16-fp16

FAIL:    gcc.dg/tree-ssa/ssa-dom-thread-11.c scan-tree-dump-times dom2
"Threaded" 1
FAIL:    gcc.dg/tree-ssa/ssa-dom-thread-14.c scan-tree-dump-times dom2
"Threaded" 1
FAIL:    gcc.dg/tree-ssa/ssa-dom-thread-16.c scan-tree-dump-times dom2
"Threaded" 1

they do pass when configuring for cpu cortex-a9/a15 and fpu neon-fp16/neon-vfpv4

I do not have the dumps since it's automated testing; let me know if
you need me to
reproduce it manually and extract the dumps.

Thanks,

Christophe

> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 258d4242f30..9a60a80b746 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,5 +1,11 @@
>  2017-08-28  Jeff Law  <l...@redhat.com>
>
> +       * tree-ssa-dom.c (edge_info::record_simple_equiv): Call
> +       derive_equivalences.
> +       (derive_equivalences_from_bit_ior, record_temporary_equivalences):
> +       Code moved into....
> +       (edge_info::derive_equivalences): New private member function
> +
>         * tree-ssa-dom.c (class edge_info): Changed from a struct
>         to a class.  Add ctor/dtor, methods and data members.
>         (edge_info::edge_info): Renamed from allocate_edge_info.
> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
> index cfe90904f6d..0ffc4f9a70f 100644
> --- a/gcc/testsuite/ChangeLog
> +++ b/gcc/testsuite/ChangeLog
> @@ -1,3 +1,15 @@
> +2017-08-28  Jeff Law  <l...@redhat.com>
> +
> +       * gcc.dg/torture/pr57214.c: Fix type of loop counter.
> +       * gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test.
> +       * gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test.
> +
>  2017-08-28  Janus Weil  <ja...@gcc.gnu.org>
>
>         PR fortran/81770
> diff --git a/gcc/testsuite/gcc.dg/torture/pr57214.c 
> b/gcc/testsuite/gcc.dg/torture/pr57214.c
> index d51067d95d8..c697f84514e 100644
> --- a/gcc/testsuite/gcc.dg/torture/pr57214.c
> +++ b/gcc/testsuite/gcc.dg/torture/pr57214.c
> @@ -15,7 +15,7 @@ bar (_Bool b)
>        b = 1;
>        baz ();
>        x = 0;
> -      int i;
> +      unsigned int i;
>        while (buf[i] && i)
>         i++;
>        foo ();
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
> new file mode 100644
> index 00000000000..f42d64bed71
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile { target { ! logical_op_short_circuit  } } } */
> +/* { dg-options "-O2 -fdump-tree-dom2-details" } */
> +
> +static int *bb_ticks;
> +extern void frob (void);
> +void
> +mark_target_live_regs (int b, int block, int bb_tick)
> +{
> +  if (b == block && b != -1 && bb_tick == bb_ticks[b])
> +      return;
> +  if (b != -1)
> +    frob ();
> +}
> +
> +/* When the first two conditionals in the first IF are true, but
> +   the third conditional is false, then there's a jump threading
> +   opportunity to bypass the second IF statement.  */
> +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
> new file mode 100644
> index 00000000000..63bd12a06a4
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
> @@ -0,0 +1,36 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
> +typedef long unsigned int size_t;
> +union tree_node;
> +typedef union tree_node *tree;
> +typedef union gimple_statement_d *gimple;
> +typedef const union gimple_statement_d *const_gimple;
> +union gimple_statement_d
> +{
> +  unsigned num_ops;
> +  tree exp;
> +};
> +
> +unsigned int x;
> +static inline tree
> +gimple_op (const_gimple gs, unsigned i)
> +{
> +  if (!(i < gs->num_ops))
> +    abort ();
> +  return gs->exp;
> +}
> +
> +unsigned char
> +scan_function (gimple stmt)
> +{
> +  unsigned i;
> +  for (i = 0; i < stmt->num_ops - 3 ; i++)
> +    gimple_call_arg (stmt, i);
> +  gimple_op (stmt, 1);
> +}
> +
> +/* The test which bypasses the loop is simplified prior to DOM to check
> +   that stmt->num_ops - 3 != 0.  When that test is false, we can derive
> +   a value for stmt->num_ops.  That in turn allows us to thread the jump
> +   for the conditional at the start of the call to gimple_op.  */
> +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
> new file mode 100644
> index 00000000000..209c40d4c95
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
> @@ -0,0 +1,46 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
> +
> +union tree_node;
> +typedef union tree_node *tree;
> +extern unsigned char tree_contains_struct[0xdead][64];
> +struct tree_base
> +{
> +  int code:16;
> +};
> +struct tree_typed
> +{
> +  tree type;
> +};
> +struct tree_type_common
> +{
> +  tree main_variant;
> +};
> +extern tree build_target_option_node (void);
> +union tree_node
> +{
> +  struct tree_base base;
> +  struct tree_typed typed;
> +  struct tree_type_common type_common;
> +};
> +tree
> +convert (tree type, tree expr)
> +{
> +  tree e = expr;
> +  int code = (type)->base.code;
> +  const char *invalid_conv_diag;
> +  tree ret;
> +  if (tree_contains_struct[expr->base.code][(42)] != 1)
> +    abort ();
> +  if (type->type_common.main_variant == 
> expr->typed.type->type_common.main_variant
> +      && (expr->typed.type->base.code != 123
> +         || e->base.code == 456))
> +    return arf ();
> +  if (expr->typed.type->base.code == 42)
> +    error ("void value not ignored as it ought to be");
> +}
> +
> +/* When the *->base.code tests in the second IF statement are false, we
> +   know that expr->typed.base->base.code has the value 123.  That allows
> +   us to thread the test for the final IF statement on that path.  */
> +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
> new file mode 100644
> index 00000000000..2d97f86fa28
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
> @@ -0,0 +1,40 @@
> +/* { dg-do compile { target { ! logical_op_short_circuit  } } } */
> +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
> +
> +enum optab_methods
> +{
> +  OPTAB_DIRECT,
> +  OPTAB_LIB,
> +  OPTAB_WIDEN,
> +  OPTAB_LIB_WIDEN,
> +  OPTAB_MUST_WIDEN
> +};
> +struct optab_d { };
> +typedef struct optab_d *optab;
> +void
> +expand_shift_1 (int code, int unsignedp, int rotate,
> +               optab lshift_optab, optab rshift_arith_optab)
> +{
> +  int left = (code == 42 || code == 0xde);
> +  int attempt;
> +  enum optab_methods methods;
> +  if (attempt == 0)
> +    methods = OPTAB_DIRECT;
> +  else if (attempt == 1)
> +    methods = OPTAB_WIDEN;
> +  if ((!unsignedp || (!left && methods == OPTAB_WIDEN)))
> +    {
> +      enum optab_methods methods1 = methods;
> +      if (unsignedp)
> +       methods1 = OPTAB_MUST_WIDEN;
> +      expand_binop (left ? lshift_optab : rshift_arith_optab,
> +                          unsignedp, methods1);
> +    }
> +}
> +
> +/* When UNSIGNEDP is true, LEFT is false and METHOD == OPTAB_WIDEN
> +   we will enter the TRUE arm of the conditional and we can thread
> +   the test to compute the first first argument of the expand_binop
> +   call if we look backwards through the boolean logicals.  */
> +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
> +
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
> new file mode 100644
> index 00000000000..df6a9b32eb1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
> @@ -0,0 +1,67 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
> +struct rtx_def;
> +typedef struct rtx_def *rtx;
> +struct machine_frame_state
> +{
> +  rtx cfa_reg;
> +  long sp_offset;
> +};
> +struct machine_function {
> +  struct machine_frame_state fs;
> +};
> +enum global_rtl_index
> +{
> +  GR_PC,
> +  GR_CC0,
> +  GR_RETURN,
> +  GR_SIMPLE_RETURN,
> +  GR_STACK_POINTER,
> +  GR_FRAME_POINTER,
> +  GR_HARD_FRAME_POINTER,
> +  GR_ARG_POINTER,
> +  GR_VIRTUAL_INCOMING_ARGS,
> +  GR_VIRTUAL_STACK_ARGS,
> +  GR_VIRTUAL_STACK_DYNAMIC,
> +  GR_VIRTUAL_OUTGOING_ARGS,
> +  GR_VIRTUAL_CFA,
> +  GR_VIRTUAL_PREFERRED_STACK_BOUNDARY,
> +  GR_MAX
> +};
> +struct target_rtl {
> +  rtx x_global_rtl[GR_MAX];
> +};
> +extern struct target_rtl default_target_rtl;
> +struct function {
> +  struct machine_function * machine;
> +};
> +extern struct function *cfun;
> +struct ix86_frame
> +{
> +  long stack_pointer_offset;
> +};
> +void
> +ix86_expand_prologue (void)
> +{
> +  struct machine_function *m = (cfun + 0)->machine;
> +  struct ix86_frame frame;
> +  long allocate;
> +  allocate = frame.stack_pointer_offset - m->fs.sp_offset;
> +  if (allocate == 0)
> +    ;
> +  else if (!ix86_target_stack_probe ())
> +    {
> +      pro_epilogue_adjust_stack 
> ((((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]), 
> (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]),
> +            gen_rtx_CONST_INT ((-allocate)), -1,
> +            m->fs.cfa_reg == 
> (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]));
> +    }
> +  ((void)(!(m->fs.sp_offset == frame.stack_pointer_offset) ? fancy_abort 
> ("../../gcc-4.7.3/gcc/config/i386/i386.c", 10435, __FUNCTION__), 0 : 0));
> +}
> +
> +/* In the case where ALLOCATE is zero, we know that sp_offset and
> +   stack_poitner_offset within their respective structures are the
> +   same.  That allows us to thread the jump from the true arm of the
> +   first IF conditional around the test controlling the call to
> +   fancy_abort.  */
> +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
> +
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
> new file mode 100644
> index 00000000000..e2e0d20fb9f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile { target { ! logical_op_short_circuit  } } } */
> +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
> +unsigned char
> +validate_subreg (unsigned int offset, unsigned int isize, unsigned int 
> osize, int zz, int qq)
> +{
> +if (osize >= (((zz & (1L << 2)) != 0) ? 8 : 4) && isize >= osize)
> +    ;
> +  else if (qq == 99)
> + return 0;
> +  if (osize > isize)
> +    return offset == 0;
> +  return 1;
> +}
> +/* When we test isize >= osize in the first IF conditional and it is
> +   false and qq != 99, then we can thread the osize > isize test of
> +   the second conditional.  */
> +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c
> new file mode 100644
> index 00000000000..2c5c5a6cf94
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c
> @@ -0,0 +1,44 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-dom2 -w" } */
> +
> +struct rtx_def;
> +typedef struct rtx_def *rtx;
> +struct reload
> +{
> +  rtx in;
> +  rtx reg_rtx;
> +};
> +extern struct reload rld[(2 * 30 * (2 + 1))];
> +static rtx find_dummy_reload (rtx);
> +extern int frob ();
> +extern int arf ();
> +int
> +push_reload (rtx in, rtx out
> +)
> +{
> +  int i;
> +  if (out != 0 && in != out)
> +    {
> +      rld[i].reg_rtx = find_dummy_reload (out);
> +      if (rld[i].reg_rtx == out)
> +        rld[i].in = out;
> +    }
> +}
> +rtx
> +find_dummy_reload (rtx real_out)
> +{
> +   unsigned int nwords = frob ();
> +   unsigned int regno = frob ();
> +   unsigned int i;
> +   for (i = 0; i < nwords; i++)
> +     if (arf ())
> +       break;
> +   if (i == nwords)
> +     return real_out;
> +  return 0;
> +}
> +
> +/* In the case where the call to find_dummy_reload returns 0,
> +   the final test in push_reload will never be true and it will
> +   be eliminated.  */
> +/* { dg-final { scan-tree-dump-not "out_\[^\n\r]+ == 0" "dom2"} } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
> index 1b94c336806..610c8d60ebe 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
> @@ -1,6 +1,6 @@
>  /* { dg-do compile } */
> -/* Note PRE rotates the loop and blocks the sinking opportunity.  */
> -/* { dg-options "-O2 -fno-tree-pre -fdump-tree-sink -fdump-tree-optimized" } 
> */
> +/* Note PRE and DOM jump threading rotate the loop and blocks the sinking 
> opportunity.  */
> +/* { dg-options "-O2 -fno-tree-pre -fno-tree-dominator-opts -fdump-tree-sink 
> -fdump-tree-optimized" } */
>
>  int f(int n)
>  {
> diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
> index 403485b3c55..d91766e902e 100644
> --- a/gcc/tree-ssa-dom.c
> +++ b/gcc/tree-ssa-dom.c
> @@ -136,19 +136,240 @@ edge_info::edge_info (edge e)
>  }
>
>  /* Destructor just needs to release the vectors.  */
> +
>  edge_info::~edge_info (void)
>  {
>    this->cond_equivalences.release ();
>    this->simple_equivalences.release ();
>  }
>
> -/* Record that LHS is known to be equal to RHS at runtime when the
> -   edge associated with THIS is traversed.  */
> +/* NAME is known to have the value VALUE, which must be a constant.
> +
> +   Walk through its use-def chain to see if there are other equivalences
> +   we might be able to derive.
> +
> +   RECURSION_LIMIT controls how far back we recurse through the use-def
> +   chains.  */
> +
> +void
> +edge_info::derive_equivalences (tree name, tree value, int recursion_limit)
> +{
> +  if (TREE_CODE (name) != SSA_NAME || TREE_CODE (value) != INTEGER_CST)
> +    return;
> +
> +  /* This records the equivalence for the toplevel object.  Do
> +     this before checking the recursion limit.  */
> +  simple_equivalences.safe_push (equiv_pair (name, value));
> +
> +  /* Limit how far up the use-def chains we are willing to walk.  */
> +  if (recursion_limit == 0)
> +    return;
> +
> +  /* We can walk up the use-def chains to potentially find more
> +     equivalences.  */
> +  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
> +  if (is_gimple_assign (def_stmt))
> +    {
> +      /* We know the result of DEF_STMT was zero.  See if that allows
> +        us to deduce anything about the SSA_NAMEs used on the RHS.  */
> +      enum tree_code code = gimple_assign_rhs_code (def_stmt);
> +      switch (code)
> +       {
> +       case BIT_IOR_EXPR:
> +         if (integer_zerop (value))
> +           {
> +             tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +             tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +
> +             value = build_zero_cst (TREE_TYPE (rhs1));
> +             derive_equivalences (rhs1, value, recursion_limit - 1);
> +             value = build_zero_cst (TREE_TYPE (rhs2));
> +             derive_equivalences (rhs2, value, recursion_limit - 1);
> +           }
> +         break;
> +
> +      /* We know the result of DEF_STMT was one.  See if that allows
> +        us to deduce anything about the SSA_NAMEs used on the RHS.  */
> +       case BIT_AND_EXPR:
> +         if (!integer_zerop (value))
> +           {
> +             tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +             tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +
> +             /* If either operand has a boolean range, then we
> +                know its value must be one, otherwise we just know it
> +                is nonzero.  The former is clearly useful, I haven't
> +                seen cases where the latter is helpful yet.  */
> +             if (TREE_CODE (rhs1) == SSA_NAME)
> +               {
> +                 if (ssa_name_has_boolean_range (rhs1))
> +                   {
> +                     value = build_one_cst (TREE_TYPE (rhs1));
> +                     derive_equivalences (rhs1, value, recursion_limit - 1);
> +                   }
> +               }
> +             if (TREE_CODE (rhs2) == SSA_NAME)
> +               {
> +                 if (ssa_name_has_boolean_range (rhs2))
> +                   {
> +                     value = build_one_cst (TREE_TYPE (rhs2));
> +                     derive_equivalences (rhs2, value, recursion_limit - 1);
> +                   }
> +               }
> +           }
> +         break;
> +
> +       /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
> +          set via a widening type conversion, then we may be able to record
> +          additional equivalences.  */
> +       case NOP_EXPR:
> +       case CONVERT_EXPR:
> +         {
> +           tree rhs = gimple_assign_rhs1 (def_stmt);
> +           tree rhs_type = TREE_TYPE (rhs);
> +           if (INTEGRAL_TYPE_P (rhs_type)
> +               && (TYPE_PRECISION (TREE_TYPE (name))
> +                   >= TYPE_PRECISION (rhs_type))
> +               && int_fits_type_p (value, rhs_type))
> +             derive_equivalences (rhs,
> +                                  fold_convert (rhs_type, value),
> +                                  recursion_limit - 1);
> +           break;
> +         }
> +
> +       /* We can invert the operation of these codes trivially if
> +          one of the RHS operands is a constant to produce a known
> +          value for the other RHS operand.  */
> +       case POINTER_PLUS_EXPR:
> +       case PLUS_EXPR:
> +         {
> +           tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +           tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +
> +           /* If either argument is a constant, then we can compute
> +              a constant value for the nonconstant argument.  */
> +           if (TREE_CODE (rhs1) == INTEGER_CST
> +               && TREE_CODE (rhs2) == SSA_NAME)
> +             derive_equivalences (rhs2,
> +                                  fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
> +                                               value, rhs1),
> +                                  recursion_limit - 1);
> +           else if (TREE_CODE (rhs2) == INTEGER_CST
> +                    && TREE_CODE (rhs1) == SSA_NAME)
> +             derive_equivalences (rhs1,
> +                                  fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
> +                                               value, rhs2),
> +                                  recursion_limit - 1);
> +           break;
> +         }
> +
> +       /* If one of the operands is a constant, then we can compute
> +          the value of the other operand.  If both operands are
> +          SSA_NAMEs, then they must be equal if the result is zero.  */
> +       case MINUS_EXPR:
> +         {
> +           tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +           tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +
> +           /* If either argument is a constant, then we can compute
> +              a constant value for the nonconstant argument.  */
> +           if (TREE_CODE (rhs1) == INTEGER_CST
> +               && TREE_CODE (rhs2) == SSA_NAME)
> +             derive_equivalences (rhs2,
> +                                  fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
> +                                               rhs1, value),
> +                                  recursion_limit - 1);
> +           else if (TREE_CODE (rhs2) == INTEGER_CST
> +                    && TREE_CODE (rhs1) == SSA_NAME)
> +             derive_equivalences (rhs1,
> +                                  fold_binary (PLUS_EXPR, TREE_TYPE (rhs1),
> +                                               value, rhs2),
> +                                  recursion_limit - 1);
> +           else if (integer_zerop (value))
> +             {
> +               tree cond = build2 (EQ_EXPR, boolean_type_node,
> +                                   gimple_assign_rhs1 (def_stmt),
> +                                   gimple_assign_rhs2 (def_stmt));
> +               tree inverted = invert_truthvalue (cond);
> +               record_conditions (&this->cond_equivalences, cond, inverted);
> +             }
> +           break;
> +         }
> +
> +
> +       case EQ_EXPR:
> +       case NE_EXPR:
> +         {
> +           if ((code == EQ_EXPR && integer_onep (value))
> +               || (code == NE_EXPR && integer_zerop (value)))
> +             {
> +               tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +               tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +
> +               /* If either argument is a constant, then record the
> +                  other argument as being the same as that constant.
> +
> +                  If neither operand is a constant, then we have a
> +                  conditional name == name equivalence.  */
> +               if (TREE_CODE (rhs1) == INTEGER_CST)
> +                 derive_equivalences (rhs2, rhs1, recursion_limit - 1);
> +               else if (TREE_CODE (rhs2) == INTEGER_CST)
> +                 derive_equivalences (rhs1, rhs2, recursion_limit - 1);
> +             }
> +           else
> +             {
> +               tree cond = build2 (code, boolean_type_node,
> +                                   gimple_assign_rhs1 (def_stmt),
> +                                   gimple_assign_rhs2 (def_stmt));
> +               tree inverted = invert_truthvalue (cond);
> +               if (integer_zerop (value))
> +                 std::swap (cond, inverted);
> +               record_conditions (&this->cond_equivalences, cond, inverted);
> +             }
> +           break;
> +         }
> +
> +       /* For BIT_NOT and NEGATE, we can just apply the operation to the
> +          VALUE to get the new equivalence.  It will always be a constant
> +          so we can recurse.  */
> +       case BIT_NOT_EXPR:
> +       case NEGATE_EXPR:
> +         {
> +           tree rhs = gimple_assign_rhs1 (def_stmt);
> +           tree res = fold_build1 (code, TREE_TYPE (rhs), value);
> +           derive_equivalences (rhs, res, recursion_limit - 1);
> +           break;
> +         }
> +
> +       default:
> +         {
> +           if (TREE_CODE_CLASS (code) == tcc_comparison)
> +             {
> +               tree cond = build2 (code, boolean_type_node,
> +                                   gimple_assign_rhs1 (def_stmt),
> +                                   gimple_assign_rhs2 (def_stmt));
> +               tree inverted = invert_truthvalue (cond);
> +               if (integer_zerop (value))
> +                 std::swap (cond, inverted);
> +               record_conditions (&this->cond_equivalences, cond, inverted);
> +               break;
> +             }
> +           break;
> +         }
> +       }
> +    }
> +}
>
>  void
>  edge_info::record_simple_equiv (tree lhs, tree rhs)
>  {
> -  simple_equivalences.safe_push (equiv_pair (lhs, rhs));
> +  /* If the RHS is a constant, then we may be able to derive
> +     further equivalences.  Else just record the name = name
> +     equivalence.  */
> +  if (TREE_CODE (rhs) == INTEGER_CST)
> +    derive_equivalences (lhs, rhs, 4);
> +  else
> +    simple_equivalences.safe_push (equiv_pair (lhs, rhs));
>  }
>
>  /* Free the edge_info data attached to E, if it exists.  */
> @@ -702,42 +923,6 @@ back_propagate_equivalences (tree lhs, edge e,
>      BITMAP_FREE (domby);
>  }
>
> -/* Record NAME has the value zero and if NAME was set from a BIT_IOR_EXPR
> -   recurse into both operands recording their values as zero too.
> -   RECURSION_DEPTH controls how far back we recurse through the operands
> -   of the BIT_IOR_EXPR.  */
> -
> -static void
> -derive_equivalences_from_bit_ior (tree name,
> -                                 const_and_copies *const_and_copies,
> -                                 int recursion_limit)
> -{
> -  if (recursion_limit == 0)
> -    return;
> -
> -  if (TREE_CODE (name) == SSA_NAME)
> -    {
> -      tree value = build_zero_cst (TREE_TYPE (name));
> -
> -      /* This records the equivalence for the toplevel object.  */
> -      record_equality (name, value, const_and_copies);
> -
> -      /* And we can recurse into each operand to potentially find more
> -        equivalences.  */
> -      gimple *def_stmt = SSA_NAME_DEF_STMT (name);
> -      if (is_gimple_assign (def_stmt)
> -         && gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
> -       {
> -         derive_equivalences_from_bit_ior (gimple_assign_rhs1 (def_stmt),
> -                                           const_and_copies,
> -                                           recursion_limit - 1);
> -         derive_equivalences_from_bit_ior (gimple_assign_rhs2 (def_stmt),
> -                                           const_and_copies,
> -                                           recursion_limit - 1);
> -       }
> -    }
> -}
> -
>  /* Record into CONST_AND_COPIES and AVAIL_EXPRS_STACK any equivalences 
> implied
>     by traversing edge E (which are cached in E->aux).
>
> @@ -758,28 +943,7 @@ record_temporary_equivalences (edge e,
>        /* If we have 0 = COND or 1 = COND equivalences, record them
>          into our expression hash tables.  */
>        for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i)
> -       {
> -         avail_exprs_stack->record_cond (eq);
> -
> -         /* If the condition is testing that X == 0 is true or X != 0 is 
> false
> -            and X is set from a BIT_IOR_EXPR, then we can record equivalences
> -            for the operands of the BIT_IOR_EXPR (and recurse on those).  */
> -         tree op0 = eq->cond.ops.binary.opnd0;
> -         tree op1 = eq->cond.ops.binary.opnd1;
> -         if (TREE_CODE (op0) == SSA_NAME && integer_zerop (op1))
> -           {
> -             enum tree_code code = eq->cond.ops.binary.op;
> -             if ((code == EQ_EXPR && eq->value == boolean_true_node)
> -                 || (code == NE_EXPR && eq->value == boolean_false_node))
> -               derive_equivalences_from_bit_ior (op0, const_and_copies, 4);
> -
> -             /* TODO: We could handle BIT_AND_EXPR in a similar fashion
> -                recording that the operands have a nonzero value.  */
> -
> -             /* TODO: We can handle more cases here, particularly when OP0 is
> -                known to have a boolean range.  */
> -           }
> -       }
> +       avail_exprs_stack->record_cond (eq);
>
>        edge_info::equiv_pair *seq;
>        for (i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i)
> @@ -806,42 +970,13 @@ record_temporary_equivalences (edge e,
>               int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
>
>               if (rhs_cost > lhs_cost)
> -               record_equality (rhs, lhs, const_and_copies);
> +               record_equality (rhs, lhs, const_and_copies);
>               else if (rhs_cost < lhs_cost)
> -               record_equality (lhs, rhs, const_and_copies);
> +               record_equality (lhs, rhs, const_and_copies);
>             }
>           else
>             record_equality (lhs, rhs, const_and_copies);
>
> -         /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
> -            set via a widening type conversion, then we may be able to record
> -            additional equivalences.  */
> -         if (TREE_CODE (rhs) == INTEGER_CST)
> -           {
> -             gimple *defstmt = SSA_NAME_DEF_STMT (lhs);
> -
> -             if (defstmt
> -                 && is_gimple_assign (defstmt)
> -                 && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt)))
> -               {
> -                 tree old_rhs = gimple_assign_rhs1 (defstmt);
> -
> -                 /* If the conversion widens the original value and
> -                    the constant is in the range of the type of OLD_RHS,
> -                    then convert the constant and record the equivalence.
> -
> -                    Note that int_fits_type_p does not check the precision
> -                    if the upper and lower bounds are OK.  */
> -                 if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs))
> -                     && (TYPE_PRECISION (TREE_TYPE (lhs))
> -                         > TYPE_PRECISION (TREE_TYPE (old_rhs)))
> -                     && int_fits_type_p (rhs, TREE_TYPE (old_rhs)))
> -                   {
> -                     tree newval = fold_convert (TREE_TYPE (old_rhs), rhs);
> -                     record_equality (old_rhs, newval, const_and_copies);
> -                   }
> -               }
> -           }
>
>           /* Any equivalence found for LHS may result in additional
>              equivalences for other uses of LHS that we have already
>

Reply via email to