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)