> On December 4, 2014 6:34:18 PM CET, Jan Hubicka <hubi...@ucw.cz> wrote:
> >> 
> >> I think you want get_addr_base_and_unit_offset here.  But I really
> >wonder
> >
> >I copied what I found in tree-ssa-alias. The differenc eis that
> >get_addr_base_and_unit_offset won't give a range for variable sized
> >accesses right?
> 
> Yes. But OTOH you could also use non_aliasing_component_refs?

Hmm, nonoverlaping_component_refs tests strict_aliasing at beggining. Does it
depend on alias sets? In that case I think it may not be safe.  One can use 
component ref of one type to check if memory is unused and use it in different 
type
I think.
> 
> >> what cases this code catches that the code in fold_comparison you
> >touched
> >> above does not?  (apart from previously being bogus in different kind
> >of
> >> ways)
> >> 
> >> So I'd rather remove the code in fold_binary.
> >
> >Well, the code in fold_binary only handles comparsions where base
> >addresses are known
> >to be different. I.e. &a==&b returning false.
> >All the other cases are handled here.  I.. &a==&a or &a[5]==&b[7] etc.
> >Perhaps the code should be in fold_comparison?
> 
> Yes, I think it should be in one place.

I think too.  I actually found the fold_comparison code only while constructing 
a testcase.
I think it belongs there, so I will move all the logic there.

Honza

> 
> Richard.
> 
> >Honza
> >> 
> >> Thanks,
> >> Richard.
> >> 
> >> > +         offset_int offset0 = hwi_offset0;
> >> > +         offset_int offset1 = hwi_offset1;
> >> > +
> >> > +         /* Add constant offset of MEM_REF to OFFSET, if possible.
> > */
> >> > +         if (base0 && TREE_CODE (base0) == MEM_REF
> >> > +             && TREE_CODE (TREE_OPERAND (base0, 1)) ==
> >INTEGER_CST)
> >> > +           {
> >> > +             offset0 += wi::lshift (mem_ref_offset (base0),
> >LOG2_BITS_PER_UNIT);
> >> > +             base0 = TREE_OPERAND (base0, 0);
> >> > +           }
> >> > +         if (base1 && TREE_CODE (base1) == MEM_REF
> >> > +             && TREE_CODE (TREE_OPERAND (base1, 1)) ==
> >INTEGER_CST)
> >> > +           {
> >> > +             offset1 += wi::lshift (mem_ref_offset (base1),
> >LOG2_BITS_PER_UNIT);
> >> > +             base1 = TREE_OPERAND (base1, 0);
> >> > +           }
> >> > +         /* If both offsets of MEM_REF are the same, just ignore
> >them.  */
> >> > +         if (base0 && base1
> >> > +             && TREE_CODE (base0) == MEM_REF
> >> > +             && TREE_CODE (base1) == MEM_REF
> >> > +             && operand_equal_p (TREE_OPERAND (base0, 1),
> >TREE_OPERAND (base1, 1), 0))
> >> > +           {
> >> > +             base0 = TREE_OPERAND (base0, 0);
> >> > +             base1 = TREE_OPERAND (base1, 1);
> >> > +           }
> >> > +         /* If we see MEM_REF with variable offset, just modify
> >MAX_SIZE to declare that
> >> > +            sizes are unknown.  We can still prove that bases
> >points to different memory
> >> > +            locations.  */
> >> > +         if (base0 && TREE_CODE (base0) == MEM_REF)
> >> > +           {
> >> > +             base0 = TREE_OPERAND (base0, 0);
> >> > +             max_size0 = -1;
> >> > +           }
> >> > +         if (base1 && TREE_CODE (base1) == MEM_REF)
> >> > +           {
> >> > +             base1 = TREE_OPERAND (base1, 0);
> >> > +             max_size1 = -1;
> >> > +           }
> >> > +
> >> > +         /* If bases are equal or they are both declarations, we
> >can disprove equivalency by
> >> > +            proving that offsets are different.  */
> >> > +         if (base0 && base1 && (base0 == base1 || (DECL_P (base0)
> >&& DECL_P (base1))))
> >> > +           {
> >> > +             if ((wi::ltu_p (offset0 + max_size0 - size0, offset1)
> >> > +                  || (wi::ltu_p (offset1 + max_size1 - size1,
> >offset0)))
> >> > +                 && max_size0 != -1 && max_size1 != -1
> >> > +                 && size0 != -1 && size1 != -1)
> >> > +               return constant_boolean_node (code != EQ_EXPR,
> >type);
> >> > +           }
> >> > +         /* If bases are equal, then addresses are equal if
> >offsets are.
> >> > +            We can work hader here for non-constant offsets.  */
> >> > +         if (base0 && base0 == base1)
> >> > +           {
> >> > +             if (base0 == base1
> >> > +                 && size0 != -1 && size1 != -1
> >> > +                 && (max_size0 == size0) && (max_size1 == size1))
> >> > +               return constant_boolean_node (code == EQ_EXPR,
> >type);
> >> > +           }
> >> > +
> >> > +         if (base0 && base1 && DECL_P (base0) && DECL_P (base1))
> >> > +           {
> >> > +             bool in_symtab0 = decl_in_symtab_p (base0);
> >> > +             bool in_symtab1 = decl_in_symtab_p (base1);
> >> > +
> >> > +             /* Symtab and non-symtab declarations never overlap. 
> >*/
> >> > +             if (in_symtab0 != in_symtab1)
> >> > +               return constant_boolean_node (code != EQ_EXPR,
> >type);
> >> > +             /* Non-symtab nodes never have aliases: different
> >declaration means
> >> > +                different memory object.  */
> >> > +             if (!in_symtab0)
> >> > +               {
> >> > +                 if (base0 != base1 && TREE_CODE (base0) !=
> >TREE_CODE (base1))
> >> > +                   return constant_boolean_node (code != EQ_EXPR,
> >type);
> >> > +               }
> >> > +             else
> >> > +               {
> >> > +                 struct symtab_node *symbol0 =
> >symtab_node::get_create (base0);
> >> > +                 struct symtab_node *symbol1 =
> >symtab_node::get_create (base1);
> >> > +                 int cmp = symbol0->equal_address_to (symbol1);
> >> > +
> >> > +                 if (cmp == 0)
> >> > +                   return constant_boolean_node (code != EQ_EXPR,
> >type);
> >> > +                 if (cmp == 1
> >> > +                     && size0 != -1 && size1 != -1
> >> > +                     && (max_size0 == size0) && (max_size1 ==
> >size1))
> >> > +                   return constant_boolean_node (code == EQ_EXPR,
> >type);
> >> > +               }
> >> > +           }
> >> > +       }
> >> > +
> >> >        /* Transform comparisons of the form X +- Y CMP X to Y CMP
> >0.  */
> >> >        if ((TREE_CODE (arg0) == PLUS_EXPR
> >> >            || TREE_CODE (arg0) == POINTER_PLUS_EXPR
> >> > Index: symtab.c
> >> > ===================================================================
> >> > --- symtab.c    (revision 218286)
> >> > +++ symtab.c    (working copy)
> >> > @@ -1860,3 +1860,90 @@
> >> >      return true;
> >> >    return false;
> >> >  }
> >> > +
> >> > +/* Return 0 if symbol is known to have different address than S2,
> >> > +   Return 1 if symbol is known to have same address as S2,
> >> > +   return 2 otherwise.   */
> >> > +int
> >> > +symtab_node::equal_address_to (symtab_node *s2)
> >> > +{
> >> > +  enum availability avail1, avail2;
> >> > +
> >> > +  /* A Shortcut: equivalent symbols are always equivalent.  */
> >> > +  if (this == s2)
> >> > +    return 1;
> >> > +
> >> > +  /* For non-interposable aliases, lookup and compare their actual
> >definitions.
> >> > +     Also check if the symbol needs to bind to given definition. 
> >*/
> >> > +  symtab_node *rs1 = ultimate_alias_target (&avail1);
> >> > +  symtab_node *rs2 = s2->ultimate_alias_target (&avail2);
> >> > +  bool binds_local1 = rs1->analyzed && decl_binds_to_current_def_p
> >(this->decl);
> >> > +  bool binds_local2 = rs2->analyzed && decl_binds_to_current_def_p
> >(s2->decl);
> >> > +  bool really_binds_local1 = binds_local1;
> >> > +  bool really_binds_local2 = binds_local2;
> >> > +
> >> > +  /* Addresses of vtables and virtual functions can not be used by
> >user
> >> > +     code and are used only within speculation.  In this case we
> >may make
> >> > +     symbol equivalent to its alias even if interposition may
> >break this
> >> > +     rule.  Doing so will allow us to turn speculative inlining
> >into
> >> > +     non-speculative more agressively.  */
> >> > +  if (DECL_VIRTUAL_P (this->decl) && avail1 >= AVAIL_AVAILABLE)
> >> > +    binds_local1 = true;
> >> > +  if (DECL_VIRTUAL_P (s2->decl) && avail2 >= AVAIL_AVAILABLE)
> >> > +    binds_local2 = true;
> >> > +
> >> > +  /* If both definitions are available we know that even if they
> >are bound
> >> > +     to other unit they must be defined same way and therefore we
> >can use
> >> > +     equivalence test.  */
> >> > +  if (rs1 != rs2 && avail1 >= AVAIL_AVAILABLE && avail2 >=
> >AVAIL_AVAILABLE)
> >> > +    binds_local1 = binds_local2 = true;
> >> > +
> >> > +  if ((binds_local1 ? rs1 : this)
> >> > +       == (binds_local2 ? rs2 : s2))
> >> > +    {
> >> > +      /* We made use of the fact that alias is not weak.  */
> >> > +      if (binds_local1 && rs1 != this)
> >> > +        refuse_visibility_changes = true;
> >> > +      if (binds_local2 && rs2 != s2)
> >> > +        s2->refuse_visibility_changes = true;
> >> > +      return 1;
> >> > +    }
> >> > +
> >> > +  /* If both symbols may resolve to NULL, we can not really prove
> >them different.  */
> >> > +  if (!nonzero_address () && !s2->nonzero_address ())
> >> > +    return 2;
> >> > +
> >> > +  /* Except for NULL, functions and variables never overlap.  */
> >> > +  if (TREE_CODE (decl) != TREE_CODE (s2->decl))
> >> > +    return 0;
> >> > +
> >> > +  /* If one of the symbols is unresolved alias, punt.  */
> >> > +  if (rs1->alias || rs2->alias)
> >> > +    return 2;
> >> > +
> >> > +  /* If we have a non-interposale definition of at least one of
> >the symbols
> >> > +     and the other symbol is different, we know other unit can not
> >interpose
> >> > +     it to the first symbol; all aliases of the definition needs
> >to be
> >> > +     present in the current unit.  */
> >> > +  if (((really_binds_local1 || really_binds_local2)
> >> > +      /* If we have both definitions and they are different, we
> >know they
> >> > +        will be different even in units they binds to.  */
> >> > +       || (binds_local1 && binds_local2))
> >> > +      && rs1 != rs2)
> >> > +    {
> >> > +      /* We make use of the fact that one symbol is not alias of
> >the other
> >> > +        and that the definition is non-interposable.  */
> >> > +      refuse_visibility_changes = true;
> >> > +      s2->refuse_visibility_changes = true;
> >> > +      rs1->refuse_visibility_changes = true;
> >> > +      rs2->refuse_visibility_changes = true;
> >> > +      return 0;
> >> > +    }
> >> > +
> >> > +  /* TODO: Alias oracle basically assume that addresses of global
> >variables
> >> > +     are different unless they are declared as alias of one to
> >another.
> >> > +     We probably should be consistent and use this fact here, too,
> >and update
> >> > +     alias oracle to use this predicate.  */
> >> > +
> >> > +  return 2;
> >> > +}
> >> > Index: testsuite/gcc.dg/addr_equal-1.c
> >> > ===================================================================
> >> > --- testsuite/gcc.dg/addr_equal-1.c     (revision 0)
> >> > +++ testsuite/gcc.dg/addr_equal-1.c     (working copy)
> >> > @@ -0,0 +1,107 @@
> >> > +/* { dg-do run } */
> >> > +/* { dg-require-weak "" } */
> >> > +/* { dg-require-alias "" } */
> >> > +/* { dg-options "-O2" } */
> >> > +void abort (void);
> >> > +extern int undef_var0, undef_var1;
> >> > +extern __attribute__ ((weak)) int weak_undef_var0;
> >> > +extern __attribute__ ((weak)) int weak_undef_var1;
> >> > +__attribute__ ((weak)) int weak_def_var0;
> >> > +int def_var0=0, def_var1=0;
> >> > +static int alias_var0 __attribute__ ((alias("def_var0")));
> >> > +extern int weak_alias_var0 __attribute__ ((alias("def_var0")))
> >__attribute__ ((weak));
> >> > +void undef_fn0(void);
> >> > +void undef_fn1(void);
> >> > +void def_fn0(void)
> >> > +{
> >> > +}
> >> > +void def_fn1(void)
> >> > +{
> >> > +}
> >> > +__attribute__ ((weak))
> >> > +void weak_def_fn0(void)
> >> > +{
> >> > +}
> >> > +__attribute__ ((weak))
> >> > +void weak_def_fn1(void)
> >> > +{
> >> > +}
> >> > +__attribute__ ((weak)) void weak_undef_fn0(void);
> >> > +
> >> > +inline
> >> > +void inline_fn0(void)
> >> > +{
> >> > +}
> >> > +inline
> >> > +void inline_fn1(void)
> >> > +{
> >> > +}
> >> > +
> >> > +int
> >> > +main(int argc, char **argv)
> >> > +{
> >> > +  /* Two definitions are always different unless they can be
> >interposed.  */
> >> > +  if (!__builtin_constant_p (def_fn0 == def_fn1))
> >> > +    abort();
> >> > +  if (def_fn0 == def_fn1)
> >> > +    abort();
> >> > +
> >> > +  if (!__builtin_constant_p (&def_var0 == &def_var1))
> >> > +    abort();
> >> > +  if (&def_var0 == &def_var1)
> >> > +    abort();
> >> > +
> >> > +  /* Same symbol is the same no matter on interposition.  */
> >> > +  if (!__builtin_constant_p (undef_fn0 != undef_fn0))
> >> > +    abort ();
> >> > +  if (undef_fn0 != undef_fn0)
> >> > +    abort ();
> >> > +
> >> > +  /* Do not get confused by same offset.  */
> >> > +  if (!__builtin_constant_p (&undef_var0 + argc != &undef_var0 +
> >argc))
> >> > +    abort ();
> >> > +  if (&undef_var0 + argc != &undef_var0 + argc)
> >> > +    abort ();
> >> > +
> >> > +  /* Alias and its target is equivalent unless one of them can be
> >interposed.  */
> >> > +  if (!__builtin_constant_p (&def_var0 != &alias_var0))
> >> > +    abort ();
> >> > +  if (&def_var0 != &alias_var0 )
> >> > +    abort ();
> >> > +
> >> > +  if (__builtin_constant_p (&def_var0 != &weak_alias_var0))
> >> > +    abort ();
> >> > +  if (&def_var0 != &weak_alias_var0)
> >> > +    abort ();
> >> > +
> >> > +  /* Weak definitions may be both NULL.  */
> >> > +  if (__builtin_constant_p ((void *)weak_undef_fn0 == (void
> >*)&weak_undef_var0))
> >> > +    abort ();
> >> > +  if ((void *)weak_undef_fn0 != (void *)&weak_undef_var0)
> >> > +    abort ();
> >> > +
> >> > +  /* Different offsets makes it safe to assume addresses are
> >different.  */
> >> > +  if (!__builtin_constant_p ((char *)weak_undef_fn0 + 4 != (char
> >*)&weak_undef_var1 + 8))
> >> > +    abort ();
> >> > +  if ((char *)weak_undef_fn0 + 4 == (char *)&weak_undef_var1 + 8)
> >> > +    abort ();
> >> > +
> >> > +  /* Variables and functions do not share same memory locations
> >otherwise.  */
> >> > +  if (!__builtin_constant_p ((void *)undef_fn0 == (void
> >*)&undef_var0))
> >> > +    abort ();
> >> > +  if ((void *)undef_fn0 == (void *)&undef_var0)
> >> > +    abort ();
> >> > +
> >> > +  /* This works for cases where one object is just weakly defined,
> >too.  */
> >> > +  if (!__builtin_constant_p ((void *)weak_undef_fn0 == (void
> >*)&weak_def_var0))
> >> > +    abort ();
> >> > +  if ((void *)weak_undef_fn0 == (void *)&weak_def_var0)
> >> > +    abort ();
> >> > +
> >> > +  /* Inline functions are known to be different.  */
> >> > +  if (!__builtin_constant_p (inline_fn0 != inline_fn1))
> >> > +    abort ();
> >> > +  if (inline_fn0 == inline_fn1)
> >> > +    abort ();
> >> > +  return 0;
> >> > +}
> 

Reply via email to