The following aims to improve code generation for loops like
those in tree-ssa-alias.c:

  auto_vec<tree, 16> component_refs1;
  auto_vec<tree, 16> component_refs2;

  /* Create the stack of handled components for REF1.  */
  while (handled_component_p (ref1))
    {
      component_refs1.safe_push (ref1);
      ref1 = TREE_OPERAND (ref1, 0);
    }

It does so by making sure the vector itself doesn't necessarily
escape (to vec.c:calculate_allocation) and by simplifying the
way we identify a vector using auto storage.  In the end this
results in us doing better CSE.  But not SRA unfortunately,
as we have

  component_refs1.m_header.m_alloc = 16;
  component_refs1.m_header.m_using_auto_storage = 1;
  component_refs1.m_header.m_num = 0;
  component_refs1.D.56915.m_vec = &component_refs1.m_header;

which is what keeps component_refs1 address-taken (no easy
way out of that I fear).

It also gets rid of the aliasing-suspicious

    this->m_vec = reinterpret_cast<vec<T, va_heap, vl_embed> *> 
(&m_header);

and the friend declaration in class auto_vec.

Bootstrap / regtest ongoing on x86_64-unknown-linux-gnu.  Ok at this
stage if it works ok?

Thanks,
Richard.

2014-02-12  Richard Biener  <rguent...@suse.de>

        * vec.c (vec_prefix::calculate_allocation): Move as
        inline variant to vec.h.
        (vec_prefix::calculate_allocation_1): New out-of-line version.
        * vec.h (vec_prefix::calculate_allocation_1): Declare.
        (vec_prefix::m_has_auto_buf): Rename to ...
        (vec_prefix::m_using_auto_storage): ... this.
        (vec_prefix::calculate_allocation): Inline the easy cases
        and dispatch to calculate_allocation_1 which doesn't need the
        prefix address.
        (va_heap::reserve): Use gcc_checking_assert.
        (vec<T, A, vl_embed>::embedded_init): Add argument to initialize
        m_using_auto_storage.
        (auto_vec): Change m_vecpfx member to a vec<T, va_heap, vl_embed>
        member and adjust.
        (vec<T, va_heap, vl_ptr>::reserve): Remove redundant check.
        (vec<T, va_heap, vl_ptr>::release): Avoid casting.
        (vec<T, va_heap, vl_ptr>::using_auto_storage): Simplify.

Index: gcc/vec.c
===================================================================
*** gcc/vec.c   (revision 207718)
--- gcc/vec.c   (working copy)
*************** vec_prefix::release_overhead (void)
*** 171,216 ****
  
  
  /* Calculate the number of slots to reserve a vector, making sure that
!    RESERVE slots are free.  If EXACT grow exactly, otherwise grow
!    exponentially.  PFX is the control data for the vector.  */
  
  unsigned
! vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve,
!                                 bool exact)
  {
-   unsigned alloc = 0;
-   unsigned num = 0;
- 
-   if (pfx)
-     {
-       alloc = pfx->m_alloc;
-       num = pfx->m_num;
-     }
-   else if (!reserve)
-     gcc_unreachable ();
- 
    /* We must have run out of room.  */
!   gcc_assert (alloc - num < reserve);
  
!   if (exact)
!     /* Exact size.  */
!     alloc = num + reserve;
    else
!     {
!       /* Exponential growth. */
!       if (!alloc)
!       alloc = 4;
!       else if (alloc < 16)
!       /* Double when small.  */
!       alloc = alloc * 2;
!       else
!       /* Grow slower when large.  */
!       alloc = (alloc * 3 / 2);
! 
!       /* If this is still too small, set it to the right size. */
!       if (alloc < num + reserve)
!       alloc = num + reserve;
!     }
    return alloc;
  }
  
--- 171,197 ----
  
  
  /* Calculate the number of slots to reserve a vector, making sure that
!    it is of at least DESIRED size by growing ALLOC exponentially.  */
  
  unsigned
! vec_prefix::calculate_allocation_1 (unsigned alloc, unsigned desired)
  {
    /* We must have run out of room.  */
!   gcc_assert (alloc < desired);
  
!   /* Exponential growth. */
!   if (!alloc)
!     alloc = 4;
!   else if (alloc < 16)
!     /* Double when small.  */
!     alloc = alloc * 2;
    else
!     /* Grow slower when large.  */
!     alloc = (alloc * 3 / 2);
! 
!   /* If this is still too small, set it to the right size. */
!   if (alloc < desired)
!     alloc = desired;
    return alloc;
  }
  
Index: gcc/vec.h
===================================================================
*** gcc/vec.h   (revision 207718)
--- gcc/vec.h   (working copy)
*************** struct vec_prefix
*** 218,223 ****
--- 218,224 ----
    void register_overhead (size_t, const char *, int, const char *);
    void release_overhead (void);
    static unsigned calculate_allocation (vec_prefix *, unsigned, bool);
+   static unsigned calculate_allocation_1 (unsigned, unsigned);
  
    /* Note that vec_prefix should be a base class for vec, but we use
       offsetof() on vector fields of tree structures (e.g.,
*************** struct vec_prefix
*** 233,242 ****
    friend struct va_heap;
  
    unsigned m_alloc : 31;
!   unsigned m_has_auto_buf : 1;
    unsigned m_num;
  };
  
  template<typename, typename, typename> struct vec;
  
  /* Valid vector layouts
--- 234,258 ----
    friend struct va_heap;
  
    unsigned m_alloc : 31;
!   unsigned m_using_auto_storage : 1;
    unsigned m_num;
  };
  
+ /* Calculate the number of slots to reserve a vector, making sure that
+    RESERVE slots are free.  If EXACT grow exactly, otherwise grow
+    exponentially.  PFX is the control data for the vector.  */
+ 
+ inline unsigned
+ vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve,
+                                 bool exact)
+ {
+   if (exact)
+     return (pfx ? pfx->m_num : 0) + reserve;
+   else if (!pfx)
+     return MAX (4, reserve);
+   return calculate_allocation_1 (pfx->m_alloc, pfx->m_num + reserve);
+ }
+ 
  template<typename, typename, typename> struct vec;
  
  /* Valid vector layouts
*************** va_heap::reserve (vec<T, va_heap, vl_emb
*** 283,289 ****
  {
    unsigned alloc
      = vec_prefix::calculate_allocation (v ? &v->m_vecpfx : 0, reserve, exact);
!   gcc_assert (alloc);
  
    if (GATHER_STATISTICS && v)
      v->m_vecpfx.release_overhead ();
--- 299,305 ----
  {
    unsigned alloc
      = vec_prefix::calculate_allocation (v ? &v->m_vecpfx : 0, reserve, exact);
!   gcc_checking_assert (alloc);
  
    if (GATHER_STATISTICS && v)
      v->m_vecpfx.release_overhead ();
*************** public:
*** 479,485 ****
    T *bsearch (const void *key, int (*compar)(const void *, const void *));
    unsigned lower_bound (T, bool (*)(const T &, const T &)) const;
    static size_t embedded_size (unsigned);
!   void embedded_init (unsigned, unsigned = 0);
    void quick_grow (unsigned len);
    void quick_grow_cleared (unsigned len);
  
--- 495,501 ----
    T *bsearch (const void *key, int (*compar)(const void *, const void *));
    unsigned lower_bound (T, bool (*)(const T &, const T &)) const;
    static size_t embedded_size (unsigned);
!   void embedded_init (unsigned, unsigned = 0, unsigned = 0);
    void quick_grow (unsigned len);
    void quick_grow_cleared (unsigned len);
  
*************** vec<T, A, vl_embed>::embedded_size (unsi
*** 1037,1046 ****
  
  template<typename T, typename A>
  inline void
! vec<T, A, vl_embed>::embedded_init (unsigned alloc, unsigned num)
  {
    m_vecpfx.m_alloc = alloc;
!   m_vecpfx.m_has_auto_buf = 0;
    m_vecpfx.m_num = num;
  }
  
--- 1053,1062 ----
  
  template<typename T, typename A>
  inline void
! vec<T, A, vl_embed>::embedded_init (unsigned alloc, unsigned num, unsigned 
aut)
  {
    m_vecpfx.m_alloc = alloc;
!   m_vecpfx.m_using_auto_storage = aut;
    m_vecpfx.m_num = num;
  }
  
*************** class auto_vec : public vec<T, va_heap>
*** 1234,1243 ****
  public:
    auto_vec ()
    {
!     m_header.m_alloc = N;
!     m_header.m_has_auto_buf = 1;
!     m_header.m_num = 0;
!     this->m_vec = reinterpret_cast<vec<T, va_heap, vl_embed> *> (&m_header);
    }
  
    ~auto_vec ()
--- 1250,1257 ----
  public:
    auto_vec ()
    {
!     m_auto.embedded_init (MAX (N, 2), 0, 1);
!     this->m_vec = &m_auto;
    }
  
    ~auto_vec ()
*************** public:
*** 1246,1255 ****
    }
  
  private:
!   friend class vec<T, va_heap, vl_ptr>;
! 
!   vec_prefix m_header;
!   T m_data[N];
  };
  
  /* auto_vec is a sub class of vec whose storage is released when it is
--- 1260,1267 ----
    }
  
  private:
!   vec<T, va_heap, vl_embed> m_auto;
!   T m_data[MAX (N - 1, 1)];
  };
  
  /* auto_vec is a sub class of vec whose storage is released when it is
*************** template<typename T>
*** 1396,1402 ****
  inline bool
  vec<T, va_heap, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL)
  {
!   if (!nelems || space (nelems))
      return false;
  
    /* For now play a game with va_heap::reserve to hide our auto storage if 
any,
--- 1408,1414 ----
  inline bool
  vec<T, va_heap, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL)
  {
!   if (space (nelems))
      return false;
  
    /* For now play a game with va_heap::reserve to hide our auto storage if 
any,
*************** vec<T, va_heap, vl_ptr>::release (void)
*** 1462,1468 ****
  
    if (using_auto_storage ())
      {
!       static_cast<auto_vec<T, 1> *> (this)->m_header.m_num = 0;
        return;
      }
  
--- 1474,1480 ----
  
    if (using_auto_storage ())
      {
!       m_vec->m_vecpfx.m_num = 0;
        return;
      }
  
*************** template<typename T>
*** 1705,1716 ****
  inline bool
  vec<T, va_heap, vl_ptr>::using_auto_storage () const
  {
!   if (!m_vec->m_vecpfx.m_has_auto_buf)
!     return false;
! 
!   const vec_prefix *auto_header
!     = &static_cast<const auto_vec<T, 1> *> (this)->m_header;
!   return reinterpret_cast<vec_prefix *> (m_vec) == auto_header;
  }
  
  #if (GCC_VERSION >= 3000)
--- 1717,1723 ----
  inline bool
  vec<T, va_heap, vl_ptr>::using_auto_storage () const
  {
!   return m_vec->m_vecpfx.m_using_auto_storage;
  }
  
  #if (GCC_VERSION >= 3000)

Reply via email to