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 <[email protected]>
* 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)