On Wed, Nov 08, 2017 at 04:20:15PM +0100, Richard Biener wrote:
> Can't you simply use
> 
>    unsigned ret = 0;
>    FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
>      if (!has_single_use (op))
>        ++ret;
>    return ret;
> 
> ?  Not sure if the bit_not_p handling is required.

Consider the case with most possible statements:
  _1 = load1;
  _2 = load2;
  _3 = ~_1;
  _4 = ~_2;
  _5 = _3 ^ _4;
  store0 = _5;
All these statements construct the value for the store, and if we remove
the old stores and add new stores we'll need similar statements for each
of the new stores.  What the function is attempting to compute how many
of these original statements will be not DCEd.
If _5 has multiple uses, then we'll need all of them, so 5 stmts not
being DCEd.  If _5 has single use, but _3 (and/or _4) has multiple uses,
we'll need the corresponding loads in addition to the BIT_NOT_EXPR
statement(s).  If only _1 (and/or _2) has multiple uses, we'll need
the load(s) but nothing else.
So, there isn't a single stmt I could FOR_EACH_SSA_TREE_OPERAND on.
For BIT_{AND,IOR,XOR}_EXPR doing it just on that stmt would be too rough
approximation and would miss the case when the bitwise binary op result
is used.

> It doesn't seem you handle multi-uses of the BIT_*_EXPR results
> itself?  Or does it only handle multi-uses of the BIT_*_EXPR
> but not the feeding loads?

I believe I handle all those precisely above (the only reason I've talked
about aproximation is that bit field loads/stores are counted as one stmt
and the masking added for handling multiple semi-adjacent bitfield
loads/stores aren't counted either).

Given the above example:
      if (!has_single_use (gimple_assign_rhs1 (stmt)))
        {
          ret += 1 + info->ops[0].bit_not_p;
          if (info->ops[1].base_addr)
            ret += 1 + info->ops[1].bit_not_p;
          return ret + 1;
        }
Above should handle the _5 multiple uses case (the first operand is guaranteed
by the discovery code to be a possibly negated load).
      stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
      /* stmt is now the BIT_*_EXPR.  */
      if (!has_single_use (gimple_assign_rhs1 (stmt)))
        ret += 1 + info->ops[0].bit_not_p;
Above should handle the _3 multiple uses.
      else if (info->ops[0].bit_not_p)
        {
          gimple *stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
          if (!has_single_use (gimple_assign_rhs1 (stmt2)))
            ++ret;
        }
Above should handle multiple uses of _1.
      if (info->ops[1].base_addr == NULL_TREE)
        return ret;
is an early return for the case when second argument to BIT_*_EXPR is
constant.
      if (!has_single_use (gimple_assign_rhs2 (stmt)))
        ret += 1 + info->ops[1].bit_not_p;
Above should handle the _4 multiple uses.
      else if (info->ops[1].bit_not_p)
        {
          gimple *stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
          if (!has_single_use (gimple_assign_rhs1 (stmt2)))
            ++ret;
        }
Above should handle the _2 multiple uses.

And for another example like:
  _6 = load1;
  _7 = ~_6;
  store0 = _7;
      if (!has_single_use (gimple_assign_rhs1 (stmt)))
        return 1 + info->ops[0].bit_not_p;
Above should handle _7 multiple uses
      else if (info->ops[0].bit_not_p)
        {
          stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
          if (!has_single_use (gimple_assign_rhs1 (stmt)))
            return 1;
        }
Above should handle _6 multiple uses.

        Jakub

Reply via email to