293 lines
8.2 KiB
C++
293 lines
8.2 KiB
C++
/* RTL iterators
|
|
Copyright (C) 2014-2021 Free Software Foundation, Inc.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* This structure describes the subrtxes of an rtx as follows:
|
|
|
|
- if the rtx has no subrtxes, START and COUNT are both 0.
|
|
|
|
- if all the subrtxes of an rtx are stored in a contiguous block
|
|
of XEXPs ("e"s), START is the index of the first XEXP and COUNT
|
|
is the number of them.
|
|
|
|
- otherwise START is arbitrary and COUNT is UCHAR_MAX.
|
|
|
|
rtx_all_subrtx_bounds applies to all codes. rtx_nonconst_subrtx_bounds
|
|
is like rtx_all_subrtx_bounds except that all constant rtxes are treated
|
|
as having no subrtxes. */
|
|
struct rtx_subrtx_bound_info {
|
|
unsigned char start;
|
|
unsigned char count;
|
|
};
|
|
extern rtx_subrtx_bound_info rtx_all_subrtx_bounds[];
|
|
extern rtx_subrtx_bound_info rtx_nonconst_subrtx_bounds[];
|
|
|
|
/* Return true if CODE has no subrtxes. */
|
|
|
|
static inline bool
|
|
leaf_code_p (enum rtx_code code)
|
|
{
|
|
return rtx_all_subrtx_bounds[code].count == 0;
|
|
}
|
|
|
|
/* Used to iterate over subrtxes of an rtx. T abstracts the type of
|
|
access. */
|
|
template <typename T>
|
|
class generic_subrtx_iterator
|
|
{
|
|
static const size_t LOCAL_ELEMS = 16;
|
|
typedef typename T::value_type value_type;
|
|
typedef typename T::rtx_type rtx_type;
|
|
typedef typename T::rtunion_type rtunion_type;
|
|
|
|
public:
|
|
class array_type
|
|
{
|
|
public:
|
|
array_type ();
|
|
~array_type ();
|
|
value_type stack[LOCAL_ELEMS];
|
|
vec <value_type, va_heap, vl_embed> *heap;
|
|
};
|
|
generic_subrtx_iterator (array_type &, value_type,
|
|
const rtx_subrtx_bound_info *);
|
|
|
|
value_type operator * () const;
|
|
bool at_end () const;
|
|
void next ();
|
|
void skip_subrtxes ();
|
|
void substitute (value_type);
|
|
|
|
private:
|
|
/* The bounds to use for iterating over subrtxes. */
|
|
const rtx_subrtx_bound_info *m_bounds;
|
|
|
|
/* The storage used for the worklist. */
|
|
array_type &m_array;
|
|
|
|
/* The current rtx. */
|
|
value_type m_current;
|
|
|
|
/* The base of the current worklist. */
|
|
value_type *m_base;
|
|
|
|
/* The number of subrtxes in M_BASE. */
|
|
size_t m_end;
|
|
|
|
/* The following booleans shouldn't end up in registers or memory
|
|
but just direct control flow. */
|
|
|
|
/* True if the iteration is over. */
|
|
bool m_done;
|
|
|
|
/* True if we should skip the subrtxes of M_CURRENT. */
|
|
bool m_skip;
|
|
|
|
/* True if M_CURRENT has been replaced with a different rtx. */
|
|
bool m_substitute;
|
|
|
|
static void free_array (array_type &);
|
|
static size_t add_subrtxes_to_queue (array_type &, value_type *, size_t,
|
|
rtx_type);
|
|
static value_type *add_single_to_queue (array_type &, value_type *, size_t,
|
|
value_type);
|
|
};
|
|
|
|
template <typename T>
|
|
inline generic_subrtx_iterator <T>::array_type::array_type () : heap (0) {}
|
|
|
|
template <typename T>
|
|
inline generic_subrtx_iterator <T>::array_type::~array_type ()
|
|
{
|
|
if (__builtin_expect (heap != 0, false))
|
|
free_array (*this);
|
|
}
|
|
|
|
/* Iterate over X and its subrtxes, in arbitrary order. Use ARRAY to
|
|
store the worklist. We use an external array in order to avoid
|
|
capturing the fields of this structure when taking the address of
|
|
the array. Use BOUNDS to find the bounds of simple "e"-string codes. */
|
|
|
|
template <typename T>
|
|
inline generic_subrtx_iterator <T>::
|
|
generic_subrtx_iterator (array_type &array, value_type x,
|
|
const rtx_subrtx_bound_info *bounds)
|
|
: m_bounds (bounds),
|
|
m_array (array),
|
|
m_current (x),
|
|
m_base (m_array.stack),
|
|
m_end (0),
|
|
m_done (false),
|
|
m_skip (false),
|
|
m_substitute (false)
|
|
{
|
|
}
|
|
|
|
/* Return the current subrtx. */
|
|
|
|
template <typename T>
|
|
inline typename T::value_type
|
|
generic_subrtx_iterator <T>::operator * () const
|
|
{
|
|
return m_current;
|
|
}
|
|
|
|
/* Return true if the iteration has finished. */
|
|
|
|
template <typename T>
|
|
inline bool
|
|
generic_subrtx_iterator <T>::at_end () const
|
|
{
|
|
return m_done;
|
|
}
|
|
|
|
/* Move on to the next subrtx. */
|
|
|
|
template <typename T>
|
|
inline void
|
|
generic_subrtx_iterator <T>::next ()
|
|
{
|
|
if (m_substitute)
|
|
{
|
|
m_substitute = false;
|
|
m_skip = false;
|
|
return;
|
|
}
|
|
if (!m_skip)
|
|
{
|
|
/* Add the subrtxes of M_CURRENT. */
|
|
rtx_type x = T::get_rtx (m_current);
|
|
if (__builtin_expect (x != 0, true))
|
|
{
|
|
enum rtx_code code = GET_CODE (x);
|
|
ssize_t count = m_bounds[code].count;
|
|
if (count > 0)
|
|
{
|
|
/* Handle the simple case of a single "e" block that is known
|
|
to fit into the current array. */
|
|
if (__builtin_expect (m_end + count <= LOCAL_ELEMS + 1, true))
|
|
{
|
|
/* Set M_CURRENT to the first subrtx and queue the rest. */
|
|
ssize_t start = m_bounds[code].start;
|
|
rtunion_type *src = &x->u.fld[start];
|
|
if (__builtin_expect (count > 2, false))
|
|
m_base[m_end++] = T::get_value (src[2].rt_rtx);
|
|
if (count > 1)
|
|
m_base[m_end++] = T::get_value (src[1].rt_rtx);
|
|
m_current = T::get_value (src[0].rt_rtx);
|
|
return;
|
|
}
|
|
/* Handle cases which aren't simple "e" sequences or where
|
|
the sequence might overrun M_BASE. */
|
|
count = add_subrtxes_to_queue (m_array, m_base, m_end, x);
|
|
if (count > 0)
|
|
{
|
|
m_end += count;
|
|
if (m_end > LOCAL_ELEMS)
|
|
m_base = m_array.heap->address ();
|
|
m_current = m_base[--m_end];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
m_skip = false;
|
|
if (m_end == 0)
|
|
m_done = true;
|
|
else
|
|
m_current = m_base[--m_end];
|
|
}
|
|
|
|
/* Skip the subrtxes of the current rtx. */
|
|
|
|
template <typename T>
|
|
inline void
|
|
generic_subrtx_iterator <T>::skip_subrtxes ()
|
|
{
|
|
m_skip = true;
|
|
}
|
|
|
|
/* Ignore the subrtxes of the current rtx and look at X instead. */
|
|
|
|
template <typename T>
|
|
inline void
|
|
generic_subrtx_iterator <T>::substitute (value_type x)
|
|
{
|
|
m_substitute = true;
|
|
m_current = x;
|
|
}
|
|
|
|
/* Iterators for const_rtx. */
|
|
struct const_rtx_accessor
|
|
{
|
|
typedef const_rtx value_type;
|
|
typedef const_rtx rtx_type;
|
|
typedef const rtunion rtunion_type;
|
|
static rtx_type get_rtx (value_type x) { return x; }
|
|
static value_type get_value (rtx_type x) { return x; }
|
|
};
|
|
typedef generic_subrtx_iterator <const_rtx_accessor> subrtx_iterator;
|
|
|
|
/* Iterators for non-constant rtx. */
|
|
struct rtx_var_accessor
|
|
{
|
|
typedef rtx value_type;
|
|
typedef rtx rtx_type;
|
|
typedef rtunion rtunion_type;
|
|
static rtx_type get_rtx (value_type x) { return x; }
|
|
static value_type get_value (rtx_type x) { return x; }
|
|
};
|
|
typedef generic_subrtx_iterator <rtx_var_accessor> subrtx_var_iterator;
|
|
|
|
/* Iterators for rtx *. */
|
|
struct rtx_ptr_accessor
|
|
{
|
|
typedef rtx *value_type;
|
|
typedef rtx rtx_type;
|
|
typedef rtunion rtunion_type;
|
|
static rtx_type get_rtx (value_type ptr) { return *ptr; }
|
|
static value_type get_value (rtx_type &x) { return &x; }
|
|
};
|
|
typedef generic_subrtx_iterator <rtx_ptr_accessor> subrtx_ptr_iterator;
|
|
|
|
#define ALL_BOUNDS rtx_all_subrtx_bounds
|
|
#define NONCONST_BOUNDS rtx_nonconst_subrtx_bounds
|
|
|
|
/* Use ITER to iterate over const_rtx X and its recursive subrtxes,
|
|
using subrtx_iterator::array ARRAY as the storage for the worklist.
|
|
ARRAY can be reused for multiple consecutive iterations but shouldn't
|
|
be shared by two concurrent iterations. TYPE is ALL if all subrtxes
|
|
are of interest or NONCONST if it is safe to ignore subrtxes of
|
|
constants. */
|
|
#define FOR_EACH_SUBRTX(ITER, ARRAY, X, TYPE) \
|
|
for (subrtx_iterator ITER (ARRAY, X, TYPE##_BOUNDS); !ITER.at_end (); \
|
|
ITER.next ())
|
|
|
|
/* Like FOR_EACH_SUBRTX, but iterate over subrtxes of an rtx X. */
|
|
#define FOR_EACH_SUBRTX_VAR(ITER, ARRAY, X, TYPE) \
|
|
for (subrtx_var_iterator ITER (ARRAY, X, TYPE##_BOUNDS); !ITER.at_end (); \
|
|
ITER.next ())
|
|
|
|
/* Like FOR_EACH_SUBRTX, but iterate over subrtx pointers of rtx pointer X.
|
|
For example, if X is &PATTERN (insn) and the pattern is a SET, iterate
|
|
over &PATTERN (insn), &SET_DEST (PATTERN (insn)), etc. */
|
|
#define FOR_EACH_SUBRTX_PTR(ITER, ARRAY, X, TYPE) \
|
|
for (subrtx_ptr_iterator ITER (ARRAY, X, TYPE##_BOUNDS); !ITER.at_end (); \
|
|
ITER.next ())
|