On 8 August 2016 at 19:33, Martin Jambor <mjam...@suse.cz> wrote:
> Hi,
>
> thanks for following through.  You'll need an approval from Honza, but
> I think the code looks good (I have looked at the places that I
> believe have changed since the last week).  However, I have discovered
> one new thing I don't like and still believe you need to handle
> different precisions in lattice need:
>
> On Mon, Aug 08, 2016 at 03:08:35AM +0530, Prathamesh Kulkarni wrote:
>> On 5 August 2016 at 18:06, Martin Jambor <mjam...@suse.cz> wrote:
>>
>> ...
>>
>> >> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
>> >> index 5b6cb9a..b770f6a 100644
>> >> --- a/gcc/ipa-cp.c
>> >> +++ b/gcc/ipa-cp.c
>> >> @@ -120,6 +120,7 @@ along with GCC; see the file COPYING3.  If not see
>> >>  #include "params.h"
>> >>  #include "ipa-inline.h"
>> >>  #include "ipa-utils.h"
>> >> +#include "tree-ssa-ccp.h"
>> >>
>> >>  template <typename valtype> class ipcp_value;
>> >>
>> >> @@ -266,6 +267,40 @@ private:
>> >>    bool meet_with_1 (unsigned new_align, unsigned new_misalign);
>> >>  };
>> >>
>> >> +/* Lattice of known bits, only capable of holding one value.
>> >> +   Similar to ccp_prop_value_t, mask represents which bits of value are 
>> >> constant.
>> >> +   If a bit in mask is set to 0, then the corresponding bit in
>> >> +   value is known to be constant.  */
>> >> +
>> >> +class ipcp_bits_lattice
>> >> +{
>> >> +public:
>> >> +  bool bottom_p () { return lattice_val == IPA_BITS_VARYING; }
>> >> +  bool top_p () { return lattice_val == IPA_BITS_UNDEFINED; }
>> >> +  bool constant_p () { return lattice_val == IPA_BITS_CONSTANT; }
>> >> +  bool set_to_bottom ();
>> >> +  bool set_to_constant (widest_int, widest_int, signop, unsigned);
>> >> +
>> >> +  widest_int get_value () { return value; }
>> >> +  widest_int get_mask () { return mask; }
>> >> +  signop get_sign () { return sgn; }
>> >> +  unsigned get_precision () { return precision; }
>> >> +
>> >> +  bool meet_with (ipcp_bits_lattice& other, enum tree_code, tree);
>> >> +  bool meet_with (widest_int, widest_int, signop, unsigned);
>> >> +
>> >> +  void print (FILE *);
>> >> +
>> >> +private:
>> >> +  enum { IPA_BITS_UNDEFINED, IPA_BITS_CONSTANT, IPA_BITS_VARYING } 
>> >> lattice_val;
>> >> +  widest_int value, mask;
>> >> +  signop sgn;
>> >> +  unsigned precision;
>
> I know that the existing code in ipa-cp.c does not do this, but please
> prefix member variables with "m_" like our coding style guidelines
> suggest (or even require?).  You routinely reuse those same names in
> names of parameters of meet_with and I believe that is a practice that
> will sooner or later lead to confusing the two and bugs.
Sorry about this, will change to m_ prefix in followup patch.
>
>> >> +
>> >> +  bool meet_with_1 (widest_int, widest_int);
>> >> +  void get_value_and_mask (tree, widest_int *, widest_int *);
>> >> +};
>> >> +
>> >>  /* Structure containing lattices for a parameter itself and for pieces of
>> >>     aggregates that are passed in the parameter or by a reference in a 
>> >> parameter
>> >>     plus some other useful flags.  */
>> >> @@ -281,6 +316,8 @@ public:
>> >>    ipcp_agg_lattice *aggs;
>> >>    /* Lattice describing known alignment.  */
>> >>    ipcp_alignment_lattice alignment;
>> >> +  /* Lattice describing known bits.  */
>> >> +  ipcp_bits_lattice bits_lattice;
>> >>    /* Number of aggregate lattices */
>> >>    int aggs_count;
>> >>    /* True if aggregate data were passed by reference (as opposed to by
>> >> @@ -458,6 +495,21 @@ ipcp_alignment_lattice::print (FILE * f)
>> >>      fprintf (f, "         Alignment %u, misalignment %u\n", align, 
>> >> misalign);
>> >>  }
>> >>
>>
>> ...
>>
>> >> +/* Convert operand to value, mask form.  */
>> >> +
>> >> +void
>> >> +ipcp_bits_lattice::get_value_and_mask (tree operand, widest_int *valuep, 
>> >> widest_int *maskp)
>> >> +{
>> >> +  wide_int get_nonzero_bits (const_tree);
>> >> +
>> >> +  if (TREE_CODE (operand) == INTEGER_CST)
>> >> +    {
>> >> +      *valuep = wi::to_widest (operand);
>> >> +      *maskp = 0;
>> >> +    }
>> >> +  else if (TREE_CODE (operand) == SSA_NAME)
>> >
>> > IIUC, operand is the operand from pass-through jump function and that
>> > should never be an SSA_NAME.  I have even looked at how we generate
>> > them and it seems fairly safe to say that they never are.  If you have
>> > seen an SSA_NAME here, it is a bug and please let me know because
>> > sooner or later it will cause an assert.
>> >
>> >> +    {
>> >> +      *valuep = 0;
>> >> +      *maskp = widest_int::from (get_nonzero_bits (operand), UNSIGNED);
>> >> +    }
>> >> +  else
>> >> +    gcc_unreachable ();
>> >
>> > The operand however can be any any other is_gimple_ip_invariant tree.
>> > I assume that you could hit this gcc_unreachable only in a program
>> > with undefined behavior (or with a Fortran CONST_DECL?) but you should
>> > not ICE here.
>> Changed to:
>> if (TREE_CODE (operand) == INTEGER_CST)
>>     {
>>       *valuep = wi::to_widest (operand);
>>       *maskp = 0;
>>     }
>>   else
>>     {
>>       *valuep = 0;
>>       *maskp = -1;
>>     }
>>
>> I am not sure how to extract nonzero bits for gimple_ip_invariant if
>> it's not INTEGER_CST,
>
> I don't think that you reasonably can.
>
>> so setting to unknown (value = 0, mask = -1).
>> Does this look OK ?
>
> Yes.
>
>> >
>> >
>> >> +}
>> >> +
>> >> +/* Meet operation, similar to ccp_lattice_meet, we xor values
>> >> +   if this->value, value have different values at same bit positions, we 
>> >> want
>> >> +   to drop that bit to varying. Return true if mask is changed.
>> >> +   This function assumes that the lattice value is in CONSTANT state  */
>> >> +
>> >> +bool
>> >> +ipcp_bits_lattice::meet_with_1 (widest_int value, widest_int mask)
>> >> +{
>> >> +  gcc_assert (constant_p ());
>> >> +
>> >> +  widest_int old_mask = this->mask;
>> >> +  this->mask = (this->mask | mask) | (this->value ^ value);
>> >> +
>> >> +  if (wi::sext (this->mask, this->precision) == -1)
>> >> +    return set_to_bottom ();
>> >> +
>> >> +  bool changed = this->mask != old_mask;
>> >> +  return changed;
>> >> +}
>> >> +
>> >> +/* Meet the bits lattice with operand
>> >> +   described by <value, mask, sgn, precision.  */
>> >> +
>> >> +bool
>> >> +ipcp_bits_lattice::meet_with (widest_int value, widest_int mask,
>> >> +                           signop sgn, unsigned precision)
>> >> +{
>> >> +  if (bottom_p ())
>> >> +    return false;
>> >> +
>> >> +  if (top_p ())
>> >> +    {
>> >> +      if (wi::sext (mask, precision) == -1)
>> >> +     return set_to_bottom ();
>> >> +      return set_to_constant (value, mask, sgn, precision);
>> >> +    }
>> >> +
>> >> +  return meet_with_1 (value, mask);
>> >
>> > What if precisions do not match?
>> Sorry I don't understand. Since we extend to widest_int, precision
>> would be same ?
>
> I meant what if:
>
>   this->precision != precision /* the parameter value */
>
> (you see, giving both the same name is error-prone).  You are
> propagating the recorded precision gathered from types of the actual
> arguments in calls, those can be different.  For example, one caller
> can pass a direct integer value with full integer precision, another
> caller can pass in that same argument an enum value with a very
> limited precision.  Your code ignores that difference and the
> resulting precision is the one that arrives first.  If it is the enum,
> it might be too small for the integer value from the other call-site?
Ah indeed the patch incorrectly propagates precision of argument.
So IIUC in ipcp_bits_lattice, we want m_precision to be the precision
of parameter's type and _not_ of argument's type.

The patch incorrectly propagates precision in following case:

__attribute__((noinline))
static int f2(short z)
{
  return z;
}

__attribute__((noinline))
static int f1(int y)
{
  return f2 (y & 0xff);
}

__attribute__((noinline))
int f(int x)
{
  return f1 (x);
}

Precision for 'z' should be 16 while the patch propagates 32, which
is precision of type of the argument passed by the caller.
We only set m_precision when changing from TOP to CONSTANT
state.

Instead of storing arg's precision and sign, we should store
parameter's precision and sign in ipa_compute_jump_functions_for_edge ().
Diff with respect to previous patch:

@@ -1688,9 +1690,9 @@ ipa_compute_jump_functions_for_edge (struct
ipa_func_body_info *fbi,
   && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
  {
   jfunc->bits.known = true;
-  jfunc->bits.sgn = TYPE_SIGN (TREE_TYPE (arg));
-  jfunc->bits.precision = TYPE_PRECISION (TREE_TYPE (arg));
-
+  jfunc->bits.sgn = TYPE_SIGN (param_type);
+  jfunc->bits.precision = TYPE_PRECISION (param_type);
+
   if (TREE_CODE (arg) == SSA_NAME)
     {
       jfunc->bits.value = 0;

So in ipcp_bits_lattice::meet_with(value, mask, signop, precision)
when we propagate into
parameter's lattice for first time, we will set m_precision ==
precision of it's own type.
rather than precision of the argument

For eg, consider following test-case:
int f(int x)
{
  return some_operation (x);
}

int f1(short y)
{
  return f (y & 0xf);
}

int f2(char z)
{
  return f (z & 0xff);
}

Assume we first propagate from f2->f.
In this case, jump_function from f2->f is unknown (but bits.known is true),
so we call meet_with (0, 0xff, SIGNED, 32).
The precision and sign are of param's type because we extract them
from param_type as shown above.

(I suppose the reason this is not pass-thru is because result y & 0xf
is wrapped by convert_expr,
which is actually passed to f(), so the parameter y isn't really
involved in the call to f ?)

Since lattice of x is TOP, it will change to CONSTANT,
and m_precision will get assigned 32.

Next propagate from f1->f
jump_function from f1->f is unknown (but bits.known is true)
so we call meet_with (0, 0xf, 32, SIGNED).
Since lattice of x is already CONSTANT, it doesn't change m_precision anymore
on this call or any subsequent calls.

So when we propagate into callee for first time, only then do we set
the precision.
Does this look reasonable ?
>
>> bit_value_binop_1 requires original precision for few cases (shifts,
>> rotates, plus, mult), so
>
> Yeah, so wrong precision could only be used if it got fed into the
> binary operation routines, making the bug much harder to trigger.  But
> it would still be a bug (or you do not need to care for original
> precisions at all).
>
>> I was preserving the original precision in jump function.
>> Later in ipcp_update_bits(), the mask is set after narrowing to the
>> precision of the parameter.
>> >
>> >> +}
>> >> +
>> >> +/* Meet bits lattice with the result of bit_value_binop_1 (other, 
>> >> operand)
>> >> +   if code is binary operation or bit_value_unop_1 (other) if code is 
>> >> unary op.
>> >> +   In the case when code is nop_expr, no adjustment is required. */
>> >> +
>> >> +bool
>> >> +ipcp_bits_lattice::meet_with (ipcp_bits_lattice& other, enum tree_code 
>> >> code, tree operand)
>> >> +{
>> >> +  if (other.bottom_p ())
>> >> +    return set_to_bottom ();
>> >> +
>> >> +  if (bottom_p () || other.top_p ())
>> >> +    return false;
>> >> +
>> >> +  widest_int adjusted_value, adjusted_mask;
>> >> +
>> >> +  if (TREE_CODE_CLASS (code) == tcc_binary)
>> >> +    {
>> >> +      tree type = TREE_TYPE (operand);
>> >> +      gcc_assert (INTEGRAL_TYPE_P (type));
>> >> +      widest_int o_value, o_mask;
>> >> +      get_value_and_mask (operand, &o_value, &o_mask);
>> >> +
>> >> +      signop sgn = other.get_sign ();
>> >> +      unsigned prec = other.get_precision ();
>> >> +
>> >> +      bit_value_binop_1 (code, sgn, prec, &adjusted_value, 
>> >> &adjusted_mask,
>> >> +                      sgn, prec, other.get_value (), other.get_mask (),
>> >> +                      TYPE_SIGN (type), TYPE_PRECISION (type), o_value, 
>> >> o_mask);
>> >
>> > It is probably just me not being particularly sharp on a Friday
>> > afternoon and I might not understand the semantics of mask well (also,
>> > you did not document it :-), but... assume that we are looking at a
>> > binary and operation, other comes from an SSA pointer and its mask
>> > would be binary 100 and its value 0 because that's what you set for
>> > ssa names in ipa-prop.h, and the operand is binary value 101, which
>> > means that get_value_and_mask returns mask 0 and value 101.  Now,
>> > bit_value_binop_1 would return value 0 & 101 = 0 and mask according to
>> >
>> > (m1 | m2) & ((v1 | m1) & (v2 | m2))
>> >
>> > so in our case
>> >
>> > (100b & 0) & ((0 | 100b) & (101b | 0)) = 0 & 100b = 0.
>> Shouldn't this be:
>> (100b | 0) & ((0 | 100b) & (101b | 0)) = 100 & 100 = 100 -;)
>
> Eh, right, sorry.  I just find the term mask confusing when we do not
> actually mask anything with it (but I guess it is good to be
> consistent so let's keep it).
>
>> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
>> index e32d078..1b9d0ef 100644
>> --- a/gcc/ipa-prop.h
>> +++ b/gcc/ipa-prop.h
>> @@ -154,6 +154,23 @@ struct GTY(()) ipa_alignment
>>    unsigned misalign;
>>  };
>>
>> +/* Information about zero/non-zero bits.  */
>> +struct GTY(()) ipa_bits
>> +{
>> +  /* The propagated value.  */
>> +  widest_int value;
>> +  /* Mask corresponding to the value.
>> +     Similar to ccp_prop_t, if xth bit of mask is 0,
>
> Is ccp_prop_t a typo? I did not find it anywhere when I grepped for it.
ah, it's ccp_lattice_t -;)

Thanks,
Prathamesh
>
> Thanks,
>
> Martin
>

Reply via email to