@@ -113,6 +113,39 @@ struct HARD_REG_SET
return !operator== (other);
}
+ HARD_REG_SET
+ operator>> (unsigned int shift_amount) const
+ {
+ if (shift_amount == 0)
+ return *this;
+
+ HARD_REG_SET res;
+ unsigned int total_bits = sizeof (HARD_REG_ELT_TYPE) * 8;
+ if (shift_amount >= total_bits)
+ {
+ unsigned int n_elt = shift_amount % total_bits;
+ shift_amount -= n_elt * total_bits;
+ for (unsigned int i = 0; i < ARRAY_SIZE (elts) - n_elt - 1; i += 1)
+ res.elts[i] = elts[i + n_elt];
+ /* clear upper n_elt elements. */
+ for (unsigned int i = 0; i < n_elt; i += 1)
+ res.elts[ARRAY_SIZE (elts) - 1 - i] = 0;
+ }
+
+ if (shift_amount > 0)
+ {
+ /* The left bits of an element be shifted. */
+ HARD_REG_ELT_TYPE left = 0;
+ /* Total bits of an element. */
+ for (int i = ARRAY_SIZE (elts); i >= 0; --i)
+ {
+ res.elts[i] = (elts[i] >> shift_amount) | left;
+ left = elts[i] << (total_bits - shift_amount);
+ }
+ }
+ return res;
+ }
+
HARD_REG_ELT_TYPE elts[HARD_REG_SET_LONGS];
};
typedef const HARD_REG_SET &const_hard_reg_set;
@@ -29,10 +29,12 @@ along with GCC; see the file COPYING3. If not see
#include "insn-config.h"
#include "regs.h"
#include "memmodel.h"
+#include "tm_p.h"
#include "ira.h"
#include "ira-int.h"
#include "sparseset.h"
#include "cfgloop.h"
+#include "subreg-live-range.h"
static ira_copy_t find_allocno_copy (ira_allocno_t, ira_allocno_t, rtx_insn *,
ira_loop_tree_node_t);
@@ -442,13 +444,12 @@ initiate_allocnos (void)
/* Create and return an object corresponding to a new allocno A. */
static ira_object_t
-ira_create_object (ira_allocno_t a, int subword)
+ira_create_object (ira_allocno_t a, int start, int nregs)
{
enum reg_class aclass = ALLOCNO_CLASS (a);
ira_object_t obj = object_pool.allocate ();
OBJECT_ALLOCNO (obj) = a;
- OBJECT_SUBWORD (obj) = subword;
OBJECT_CONFLICT_ID (obj) = ira_objects_num;
OBJECT_CONFLICT_VEC_P (obj) = false;
OBJECT_CONFLICT_ARRAY (obj) = NULL;
@@ -460,12 +461,75 @@ ira_create_object (ira_allocno_t a, int subword)
OBJECT_MIN (obj) = INT_MAX;
OBJECT_MAX (obj) = -1;
OBJECT_LIVE_RANGES (obj) = NULL;
+ OBJECT_START (obj) = start;
+ OBJECT_NREGS (obj) = nregs;
+ OBJECT_INDEX (obj) = ALLOCNO_NUM_OBJECTS (a);
ira_object_id_map_vec.safe_push (obj);
ira_object_id_map
= ira_object_id_map_vec.address ();
ira_objects_num = ira_object_id_map_vec.length ();
+ a->objects.push_back (obj);
+
+ return obj;
+}
+
+/* Return the object in allocno A which match START & NREGS. */
+ira_object_t
+find_object (ira_allocno_t a, int start, int nregs)
+{
+ for (ira_object_t obj : a->objects)
+ {
+ if (OBJECT_START (obj) == start && OBJECT_NREGS (obj) == nregs)
+ return obj;
+ }
+ return NULL;
+}
+
+ira_object_t
+find_object (ira_allocno_t a, poly_int64 offset, poly_int64 size)
+{
+ enum reg_class aclass = ALLOCNO_CLASS (a);
+ machine_mode mode = ALLOCNO_MODE (a);
+ int nregs = ira_reg_class_max_nregs[aclass][mode];
+
+ if (!has_subreg_object_p (a)
+ || maybe_eq (GET_MODE_SIZE (ALLOCNO_MODE (a)), size))
+ return find_object (a, 0, nregs);
+
+ gcc_assert (maybe_lt (size, GET_MODE_SIZE (ALLOCNO_MODE (a)))
+ && maybe_le (offset + size, GET_MODE_SIZE (ALLOCNO_MODE (a))));
+
+ int subreg_start = -1;
+ int subreg_nregs = -1;
+ for (int i = 0; i < nregs; i += 1)
+ {
+ poly_int64 right = ALLOCNO_UNIT_SIZE (a) * (i + 1);
+ if (subreg_start < 0 && maybe_lt (offset, right))
+ {
+ subreg_start = i;
+ }
+ if (subreg_nregs < 0 && maybe_le (offset + size, right))
+ {
+ subreg_nregs = i + 1 - subreg_start;
+ break;
+ }
+ }
+ gcc_assert (subreg_start >= 0 && subreg_nregs > 0);
+ return find_object (a, subreg_start, subreg_nregs);
+}
+
+/* Return the object in allocno A which match START & NREGS. Create when not
+ found. */
+ira_object_t
+find_object_anyway (ira_allocno_t a, int start, int nregs)
+{
+ ira_object_t obj = find_object (a, start, nregs);
+ if (obj == NULL && ALLOCNO_TRACK_SUBREG_P (a))
+ obj = ira_create_object (a, start, nregs);
+
+ gcc_assert (obj != NULL);
return obj;
}
@@ -525,7 +589,8 @@ ira_create_allocno (int regno, bool cap_p,
ALLOCNO_MEMORY_COST (a) = 0;
ALLOCNO_UPDATED_MEMORY_COST (a) = 0;
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) = 0;
- ALLOCNO_NUM_OBJECTS (a) = 0;
+ ALLOCNO_UNIT_SIZE (a) = 0;
+ ALLOCNO_TRACK_SUBREG_P (a) = false;
ALLOCNO_ADD_DATA (a) = NULL;
allocno_vec.safe_push (a);
@@ -549,6 +614,51 @@ ira_set_allocno_class (ira_allocno_t a, enum reg_class aclass)
OBJECT_CONFLICT_HARD_REGS (obj) |= ~reg_class_contents[aclass];
OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= ~reg_class_contents[aclass];
}
+
+ if (aclass == NO_REGS)
+ return;
+ /* SET the unit_size of one register. */
+ machine_mode mode = ALLOCNO_MODE (a);
+ int nregs = ira_reg_class_max_nregs[aclass][mode];
+ if (nregs == 2 && maybe_eq (GET_MODE_SIZE (mode), nregs * UNITS_PER_WORD))
+ {
+ ALLOCNO_UNIT_SIZE (a) = UNITS_PER_WORD;
+ ALLOCNO_TRACK_SUBREG_P (a) = true;
+ return;
+ }
+}
+
+/* Return the subreg range of rtx SUBREG. */
+static subreg_range
+get_range (rtx subreg)
+{
+ gcc_assert (read_modify_subreg_p (subreg));
+ rtx reg = SUBREG_REG (subreg);
+ machine_mode reg_mode = GET_MODE (reg);
+
+ machine_mode subreg_mode = GET_MODE (subreg);
+ int nblocks = get_nblocks (reg_mode);
+ poly_int64 unit_size = REGMODE_NATURAL_SIZE (reg_mode);
+
+ poly_int64 offset = SUBREG_BYTE (subreg);
+ poly_int64 left = offset + GET_MODE_SIZE (subreg_mode);
+
+ int subreg_start = -1;
+ int subreg_nblocks = -1;
+ for (int i = 0; i < nblocks; i += 1)
+ {
+ poly_int64 right = unit_size * (i + 1);
+ if (subreg_start < 0 && maybe_lt (offset, right))
+ subreg_start = i;
+ if (subreg_nblocks < 0 && maybe_le (left, right))
+ {
+ subreg_nblocks = i + 1 - subreg_start;
+ break;
+ }
+ }
+ gcc_assert (subreg_start >= 0 && subreg_nblocks > 0);
+
+ return subreg_range (subreg_start, subreg_start + subreg_nblocks);
}
/* Determine the number of objects we should associate with allocno A
@@ -558,15 +668,37 @@ ira_create_allocno_objects (ira_allocno_t a)
{
machine_mode mode = ALLOCNO_MODE (a);
enum reg_class aclass = ALLOCNO_CLASS (a);
- int n = ira_reg_class_max_nregs[aclass][mode];
- int i;
+ int nregs = ira_reg_class_max_nregs[aclass][mode];
- if (n != 2 || maybe_ne (GET_MODE_SIZE (mode), n * UNITS_PER_WORD))
- n = 1;
+ ira_create_object (a, 0, nregs);
- ALLOCNO_NUM_OBJECTS (a) = n;
- for (i = 0; i < n; i++)
- ALLOCNO_OBJECT (a, i) = ira_create_object (a, i);
+ if (aclass == NO_REGS || !ALLOCNO_TRACK_SUBREG_P (a) || a->subregs.empty ())
+ return;
+
+ int nblocks = get_nblocks (ALLOCNO_MODE (a));
+ int times = nblocks / ALLOCNO_NREGS (a);
+ gcc_assert (times >= 1 && nblocks % ALLOCNO_NREGS (a) == 0);
+
+ for (const auto &range : a->subregs)
+ {
+ int start = range.start / times;
+ int end = CEIL (range.end, times);
+ if (find_object (a, start, end - start) != NULL)
+ continue;
+ ira_create_object (a, start, end - start);
+ }
+
+ a->subregs.clear ();
+}
+
+/* Copy the objects from FROM to TO. */
+void
+ira_copy_allocno_objects (ira_allocno_t to, ira_allocno_t from)
+{
+ ira_allocno_object_iterator oi;
+ ira_object_t obj;
+ FOR_EACH_ALLOCNO_OBJECT (from, obj, oi)
+ ira_create_object (to, OBJECT_START (obj), OBJECT_NREGS (obj));
}
/* For each allocno, set ALLOCNO_NUM_OBJECTS and create the
@@ -590,11 +722,11 @@ merge_hard_reg_conflicts (ira_allocno_t from, ira_allocno_t to,
bool total_only)
{
int i;
- gcc_assert (ALLOCNO_NUM_OBJECTS (to) == ALLOCNO_NUM_OBJECTS (from));
- for (i = 0; i < ALLOCNO_NUM_OBJECTS (to); i++)
+ for (i = 0; i < ALLOCNO_NUM_OBJECTS (from); i++)
{
ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
- ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+ ira_object_t to_obj = find_object_anyway (to, OBJECT_START (from_obj),
+ OBJECT_NREGS (from_obj));
if (!total_only)
OBJECT_CONFLICT_HARD_REGS (to_obj)
@@ -888,7 +1020,7 @@ create_cap_allocno (ira_allocno_t a)
ALLOCNO_WMODE (cap) = ALLOCNO_WMODE (a);
aclass = ALLOCNO_CLASS (a);
ira_set_allocno_class (cap, aclass);
- ira_create_allocno_objects (cap);
+ ira_copy_allocno_objects (cap, a);
ALLOCNO_CAP_MEMBER (cap) = a;
ALLOCNO_CAP (a) = cap;
ALLOCNO_CLASS_COST (cap) = ALLOCNO_CLASS_COST (a);
@@ -1830,6 +1962,26 @@ ira_traverse_loop_tree (bool bb_p, ira_loop_tree_node_t loop_node,
/* The basic block currently being processed. */
static basic_block curr_bb;
+/* Return true if A's subregs has a subreg with same SIZE and OFFSET. */
+static bool
+find_subreg_p (ira_allocno_t a, const subreg_range &r)
+{
+ for (const auto &item : a->subregs)
+ if (item.start == r.start && item.end == r.end)
+ return true;
+ return false;
+}
+
+/* Return start and nregs subregs from DF_LIVE_SUBREG. */
+static void
+add_subregs (ira_allocno_t a, const subreg_ranges &sr)
+{
+ gcc_assert (get_nblocks (ALLOCNO_MODE (a)) == (unsigned) sr.max);
+ for (const subreg_range &r : sr.ranges)
+ if (!find_subreg_p (a, r))
+ a->subregs.push_back (r);
+}
+
/* This recursive function creates allocnos corresponding to
pseudo-registers containing in X. True OUTPUT_P means that X is
an lvalue. OUTER corresponds to the parent expression of X. */
@@ -1859,6 +2011,14 @@ create_insn_allocnos (rtx x, rtx outer, bool output_p)
}
}
+ /* Collect subreg reference. */
+ if (outer != NULL && read_modify_subreg_p (outer))
+ {
+ const subreg_range r = get_range (outer);
+ if (!find_subreg_p (a, r))
+ a->subregs.push_back (r);
+ }
+
ALLOCNO_NREFS (a)++;
ALLOCNO_FREQ (a) += REG_FREQ_FROM_BB (curr_bb);
if (output_p)
@@ -1919,10 +2079,28 @@ create_bb_allocnos (ira_loop_tree_node_t bb_node)
create_insn_allocnos (PATTERN (insn), NULL, false);
/* It might be a allocno living through from one subloop to
another. */
- EXECUTE_IF_SET_IN_REG_SET (DF_LIVE_SUBREG_IN (bb), FIRST_PSEUDO_REGISTER,
+ EXECUTE_IF_SET_IN_REG_SET (DF_LIVE_SUBREG_FULL_IN (bb), FIRST_PSEUDO_REGISTER,
i, bi)
if (ira_curr_regno_allocno_map[i] == NULL)
ira_create_allocno (i, false, ira_curr_loop_tree_node);
+
+ EXECUTE_IF_SET_IN_REG_SET (DF_LIVE_SUBREG_PARTIAL_IN (bb),
+ FIRST_PSEUDO_REGISTER, i, bi)
+ {
+ if (ira_curr_regno_allocno_map[i] == NULL)
+ ira_create_allocno (i, false, ira_curr_loop_tree_node);
+ add_subregs (ira_curr_regno_allocno_map[i],
+ DF_LIVE_SUBREG_RANGE_IN (bb)->lives.at (i));
+ }
+
+ EXECUTE_IF_SET_IN_REG_SET (DF_LIVE_SUBREG_PARTIAL_OUT (bb),
+ FIRST_PSEUDO_REGISTER, i, bi)
+ {
+ if (ira_curr_regno_allocno_map[i] == NULL)
+ ira_create_allocno (i, false, ira_curr_loop_tree_node);
+ add_subregs (ira_curr_regno_allocno_map[i],
+ DF_LIVE_SUBREG_RANGE_OUT (bb)->lives.at (i));
+ }
}
/* Create allocnos corresponding to pseudo-registers living on edge E
@@ -2137,20 +2315,20 @@ move_allocno_live_ranges (ira_allocno_t from, ira_allocno_t to)
int i;
int n = ALLOCNO_NUM_OBJECTS (from);
- gcc_assert (n == ALLOCNO_NUM_OBJECTS (to));
-
for (i = 0; i < n; i++)
{
ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
- ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+ ira_object_t to_obj = find_object_anyway (to, OBJECT_START (from_obj),
+ OBJECT_NREGS (from_obj));
live_range_t lr = OBJECT_LIVE_RANGES (from_obj);
if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL)
{
fprintf (ira_dump_file,
- " Moving ranges of a%dr%d to a%dr%d: ",
+ " Moving ranges of a%dr%d_obj%d to a%dr%d_obj%d: ",
ALLOCNO_NUM (from), ALLOCNO_REGNO (from),
- ALLOCNO_NUM (to), ALLOCNO_REGNO (to));
+ OBJECT_INDEX (from_obj), ALLOCNO_NUM (to),
+ ALLOCNO_REGNO (to), OBJECT_INDEX (to_obj));
ira_print_live_range_list (ira_dump_file, lr);
}
change_object_in_range_list (lr, to_obj);
@@ -2166,12 +2344,11 @@ copy_allocno_live_ranges (ira_allocno_t from, ira_allocno_t to)
int i;
int n = ALLOCNO_NUM_OBJECTS (from);
- gcc_assert (n == ALLOCNO_NUM_OBJECTS (to));
-
for (i = 0; i < n; i++)
{
ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
- ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+ ira_object_t to_obj = find_object_anyway (to, OBJECT_START (from_obj),
+ OBJECT_NREGS (from_obj));
live_range_t lr = OBJECT_LIVE_RANGES (from_obj);
if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL)
@@ -2783,15 +2960,17 @@ setup_min_max_allocno_live_range_point (void)
ira_assert (OBJECT_LIVE_RANGES (obj) == NULL);
OBJECT_MAX (obj) = 0;
OBJECT_MIN (obj) = 1;
- continue;
}
ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
/* Accumulation of range info. */
if (ALLOCNO_CAP (a) != NULL)
{
- for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
+ for (cap = ALLOCNO_CAP (a); cap != NULL;
+ cap = ALLOCNO_CAP (cap))
{
- ira_object_t cap_obj = ALLOCNO_OBJECT (cap, j);
+ ira_object_t cap_obj = find_object (cap, OBJECT_START (obj),
+ OBJECT_NREGS (obj));
+ gcc_assert (cap_obj != NULL);
if (OBJECT_MAX (cap_obj) < OBJECT_MAX (obj))
OBJECT_MAX (cap_obj) = OBJECT_MAX (obj);
if (OBJECT_MIN (cap_obj) > OBJECT_MIN (obj))
@@ -2802,7 +2981,9 @@ setup_min_max_allocno_live_range_point (void)
if ((parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) == NULL)
continue;
parent_a = parent->regno_allocno_map[i];
- parent_obj = ALLOCNO_OBJECT (parent_a, j);
+ parent_obj
+ = find_object (parent_a, OBJECT_START (obj), OBJECT_NREGS (obj));
+ gcc_assert (parent_obj != NULL);
if (OBJECT_MAX (parent_obj) < OBJECT_MAX (obj))
OBJECT_MAX (parent_obj) = OBJECT_MAX (obj);
if (OBJECT_MIN (parent_obj) > OBJECT_MIN (obj))
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_MAP
#include "system.h"
#include "coretypes.h"
#include "backend.h"
@@ -852,18 +853,17 @@ setup_left_conflict_sizes_p (ira_allocno_t a)
node_preorder_num = node->preorder_num;
node_set = node->hard_regs->set;
node_check_tick++;
+ /* Collect conflict objects. */
+ std::map<int, bitmap> allocno_conflict_regs;
for (k = 0; k < nobj; k++)
{
ira_object_t obj = ALLOCNO_OBJECT (a, k);
ira_object_t conflict_obj;
ira_object_conflict_iterator oci;
-
+
FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
{
- int size;
- ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
- allocno_hard_regs_node_t conflict_node, temp_node;
- HARD_REG_SET conflict_node_set;
+ ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
allocno_color_data_t conflict_data;
conflict_data = ALLOCNO_COLOR_DATA (conflict_a);
@@ -872,6 +872,24 @@ setup_left_conflict_sizes_p (ira_allocno_t a)
conflict_data
->profitable_hard_regs))
continue;
+ int num = ALLOCNO_NUM (conflict_a);
+ if (allocno_conflict_regs.count (num) == 0)
+ allocno_conflict_regs.insert ({num, ira_allocate_bitmap ()});
+ bitmap_head temp;
+ bitmap_initialize (&temp, ®_obstack);
+ bitmap_set_range (&temp, OBJECT_START (conflict_obj),
+ OBJECT_NREGS (conflict_obj));
+ bitmap_and_compl_into (&temp, allocno_conflict_regs.at (num));
+ int size = bitmap_count_bits (&temp);
+ bitmap_clear (&temp);
+ if (size == 0)
+ continue;
+
+ bitmap_set_range (allocno_conflict_regs.at (num),
+ OBJECT_START (conflict_obj),
+ OBJECT_NREGS (conflict_obj));
+ allocno_hard_regs_node_t conflict_node, temp_node;
+ HARD_REG_SET conflict_node_set;
conflict_node = conflict_data->hard_regs_node;
conflict_node_set = conflict_node->hard_regs->set;
if (hard_reg_set_subset_p (node_set, conflict_node_set))
@@ -886,14 +904,13 @@ setup_left_conflict_sizes_p (ira_allocno_t a)
temp_node->check = node_check_tick;
temp_node->conflict_size = 0;
}
- size = (ira_reg_class_max_nregs
- [ALLOCNO_CLASS (conflict_a)][ALLOCNO_MODE (conflict_a)]);
- if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1)
- /* We will deal with the subwords individually. */
- size = 1;
temp_node->conflict_size += size;
}
}
+ /* Setup conflict nregs of ALLOCNO. */
+ for (auto &kv : allocno_conflict_regs)
+ ira_free_bitmap (kv.second);
+
for (i = 0; i < data->hard_regs_subnodes_num; i++)
{
allocno_hard_regs_node_t temp_node;
@@ -1031,7 +1048,7 @@ static void
setup_profitable_hard_regs (void)
{
unsigned int i;
- int j, k, nobj, hard_regno, nregs, class_size;
+ int j, k, nobj, hard_regno, class_size;
ira_allocno_t a;
bitmap_iterator bi;
enum reg_class aclass;
@@ -1076,7 +1093,6 @@ setup_profitable_hard_regs (void)
|| (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
continue;
mode = ALLOCNO_MODE (a);
- nregs = hard_regno_nregs (hard_regno, mode);
nobj = ALLOCNO_NUM_OBJECTS (a);
for (k = 0; k < nobj; k++)
{
@@ -1088,24 +1104,39 @@ setup_profitable_hard_regs (void)
{
ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
- /* We can process the conflict allocno repeatedly with
- the same result. */
- if (nregs == nobj && nregs > 1)
+ if (!has_subreg_object_p (a))
{
- int num = OBJECT_SUBWORD (conflict_obj);
-
- if (REG_WORDS_BIG_ENDIAN)
- CLEAR_HARD_REG_BIT
- (ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
- hard_regno + nobj - num - 1);
- else
- CLEAR_HARD_REG_BIT
- (ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
- hard_regno + num);
+ ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs
+ &= ~ira_reg_mode_hard_regset[hard_regno][mode];
+ continue;
+ }
+
+ /* Clear all hard regs occupied by obj. */
+ if (REG_WORDS_BIG_ENDIAN)
+ {
+ int start_regno
+ = hard_regno + ALLOCNO_NREGS (a) - 1 - OBJECT_START (obj);
+ for (int i = 0; i < OBJECT_NREGS (obj); i += 1)
+ {
+ int regno = start_regno - i;
+ if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
+ CLEAR_HARD_REG_BIT (
+ ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
+ regno);
+ }
}
else
- ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs
- &= ~ira_reg_mode_hard_regset[hard_regno][mode];
+ {
+ int start_regno = hard_regno + OBJECT_START (obj);
+ for (int i = 0; i < OBJECT_NREGS (obj); i += 1)
+ {
+ int regno = start_regno + i;
+ if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
+ CLEAR_HARD_REG_BIT (
+ ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
+ regno);
+ }
+ }
}
}
}
@@ -1677,18 +1708,25 @@ update_conflict_hard_regno_costs (int *costs, enum reg_class aclass,
aligned. */
static inline void
get_conflict_and_start_profitable_regs (ira_allocno_t a, bool retry_p,
- HARD_REG_SET *conflict_regs,
+ HARD_REG_SET *start_conflict_regs,
HARD_REG_SET *start_profitable_regs)
{
int i, nwords;
ira_object_t obj;
nwords = ALLOCNO_NUM_OBJECTS (a);
- for (i = 0; i < nwords; i++)
- {
- obj = ALLOCNO_OBJECT (a, i);
- conflict_regs[i] = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj);
- }
+ CLEAR_HARD_REG_SET (*start_conflict_regs);
+ if (has_subreg_object_p (a))
+ for (i = 0; i < nwords; i++)
+ {
+ obj = ALLOCNO_OBJECT (a, i);
+ for (int j = 0; j < OBJECT_NREGS (obj); j += 1)
+ *start_conflict_regs |= OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)
+ >> (OBJECT_START (obj) + j);
+ }
+ else
+ *start_conflict_regs
+ = OBJECT_TOTAL_CONFLICT_HARD_REGS (get_full_object (a));
if (retry_p)
*start_profitable_regs
= (reg_class_contents[ALLOCNO_CLASS (a)]
@@ -1702,9 +1740,9 @@ get_conflict_and_start_profitable_regs (ira_allocno_t a, bool retry_p,
PROFITABLE_REGS and whose objects have CONFLICT_REGS. */
static inline bool
check_hard_reg_p (ira_allocno_t a, int hard_regno,
- HARD_REG_SET *conflict_regs, HARD_REG_SET profitable_regs)
+ HARD_REG_SET start_conflict_regs,
+ HARD_REG_SET profitable_regs)
{
- int j, nwords, nregs;
enum reg_class aclass;
machine_mode mode;
@@ -1716,28 +1754,17 @@ check_hard_reg_p (ira_allocno_t a, int hard_regno,
/* Checking only profitable hard regs. */
if (! TEST_HARD_REG_BIT (profitable_regs, hard_regno))
return false;
- nregs = hard_regno_nregs (hard_regno, mode);
- nwords = ALLOCNO_NUM_OBJECTS (a);
- for (j = 0; j < nregs; j++)
+
+ if (has_subreg_object_p (a))
+ return !TEST_HARD_REG_BIT (start_conflict_regs, hard_regno);
+ else
{
- int k;
- int set_to_test_start = 0, set_to_test_end = nwords;
-
- if (nregs == nwords)
- {
- if (REG_WORDS_BIG_ENDIAN)
- set_to_test_start = nwords - j - 1;
- else
- set_to_test_start = j;
- set_to_test_end = set_to_test_start + 1;
- }
- for (k = set_to_test_start; k < set_to_test_end; k++)
- if (TEST_HARD_REG_BIT (conflict_regs[k], hard_regno + j))
- break;
- if (k != set_to_test_end)
- break;
+ int nregs = hard_regno_nregs (hard_regno, mode);
+ for (int i = 0; i < nregs; i += 1)
+ if (TEST_HARD_REG_BIT (start_conflict_regs, hard_regno + i))
+ return false;
+ return true;
}
- return j == nregs;
}
/* Return number of registers needed to be saved and restored at
@@ -1945,7 +1972,7 @@ spill_soft_conflicts (ira_allocno_t a, bitmap allocnos_to_spill,
static bool
assign_hard_reg (ira_allocno_t a, bool retry_p)
{
- HARD_REG_SET conflicting_regs[2], profitable_hard_regs;
+ HARD_REG_SET start_conflicting_regs, profitable_hard_regs;
int i, j, hard_regno, best_hard_regno, class_size;
int cost, mem_cost, min_cost, full_cost, min_full_cost, nwords, word;
int *a_costs;
@@ -1962,8 +1989,7 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
HARD_REG_SET soft_conflict_regs = {};
ira_assert (! ALLOCNO_ASSIGNED_P (a));
- get_conflict_and_start_profitable_regs (a, retry_p,
- conflicting_regs,
+ get_conflict_and_start_profitable_regs (a, retry_p, &start_conflicting_regs,
&profitable_hard_regs);
aclass = ALLOCNO_CLASS (a);
class_size = ira_class_hard_regs_num[aclass];
@@ -2041,7 +2067,6 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
(hard_regno, ALLOCNO_MODE (conflict_a),
reg_class_contents[aclass])))
{
- int n_objects = ALLOCNO_NUM_OBJECTS (conflict_a);
int conflict_nregs;
mode = ALLOCNO_MODE (conflict_a);
@@ -2076,24 +2101,95 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
note_conflict (r);
}
}
+ else if (has_subreg_object_p (a))
+ {
+ /* Set start_conflicting_regs if that cause obj and
+ conflict_obj overlap. the overlap position:
+ +--------------+
+ | conflict_obj |
+ +--------------+
+
+ +-----------+ +-----------+
+ | obj | ... | obj |
+ +-----------+ +-----------+
+
+ Point: A B C
+
+ the hard regs from A to C point will cause overlap.
+ For REG_WORDS_BIG_ENDIAN:
+ A = hard_regno + ALLOCNO_NREGS (conflict_a) - 1
+ - OBJECT_START (conflict_obj)
+ - OBJECT_NREGS (obj) + 1
+ C = A + OBJECT_NREGS (obj)
+ + OBJECT_NREGS (conflict_obj) - 2
+ For !REG_WORDS_BIG_ENDIAN:
+ A = hard_regno + OBJECT_START (conflict_obj)
+ - OBJECT_NREGS (obj) + 1
+ C = A + OBJECT_NREGS (obj)
+ + OBJECT_NREGS (conflict_obj) - 2
+ */
+ int start_regno;
+ int conflict_allocno_nregs, conflict_object_nregs,
+ conflict_object_start;
+ if (has_subreg_object_p (conflict_a))
+ {
+ conflict_allocno_nregs = ALLOCNO_NREGS (conflict_a);
+ conflict_object_nregs = OBJECT_NREGS (conflict_obj);
+ conflict_object_start = OBJECT_START (conflict_obj);
+ }
+ else
+ {
+ conflict_allocno_nregs = conflict_object_nregs
+ = hard_regno_nregs (hard_regno, mode);
+ conflict_object_start = 0;
+ }
+ if (REG_WORDS_BIG_ENDIAN)
+ {
+ int A = hard_regno + conflict_allocno_nregs - 1
+ - conflict_object_start - OBJECT_NREGS (obj)
+ + 1;
+ start_regno = A + OBJECT_NREGS (obj) - 1
+ + OBJECT_START (obj) - ALLOCNO_NREGS (a)
+ + 1;
+ }
+ else
+ {
+ int A = hard_regno + conflict_object_start
+ - OBJECT_NREGS (obj) + 1;
+ start_regno = A - OBJECT_START (obj);
+ }
+
+ for (int i = 0;
+ i <= OBJECT_NREGS (obj) + conflict_object_nregs - 2;
+ i += 1)
+ {
+ int regno = start_regno + i;
+ if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
+ SET_HARD_REG_BIT (start_conflicting_regs, regno);
+ }
+ if (hard_reg_set_subset_p (profitable_hard_regs,
+ start_conflicting_regs))
+ goto fail;
+ }
else
{
- if (conflict_nregs == n_objects && conflict_nregs > 1)
+ if (has_subreg_object_p (conflict_a))
{
- int num = OBJECT_SUBWORD (conflict_obj);
-
- if (REG_WORDS_BIG_ENDIAN)
- SET_HARD_REG_BIT (conflicting_regs[word],
- hard_regno + n_objects - num - 1);
- else
- SET_HARD_REG_BIT (conflicting_regs[word],
- hard_regno + num);
+ int start_hard_regno
+ = REG_WORDS_BIG_ENDIAN
+ ? hard_regno + ALLOCNO_NREGS (conflict_a)
+ - OBJECT_START (conflict_obj)
+ : hard_regno + OBJECT_START (conflict_obj);
+ for (int i = 0; i < OBJECT_NREGS (conflict_obj);
+ i += 1)
+ SET_HARD_REG_BIT (start_conflicting_regs,
+ start_hard_regno + i);
}
else
- conflicting_regs[word]
+ start_conflicting_regs
|= ira_reg_mode_hard_regset[hard_regno][mode];
if (hard_reg_set_subset_p (profitable_hard_regs,
- conflicting_regs[word]))
+ start_conflicting_regs))
goto fail;
}
}
@@ -2160,8 +2256,8 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
&& FIRST_STACK_REG <= hard_regno && hard_regno <= LAST_STACK_REG)
continue;
#endif
- if (! check_hard_reg_p (a, hard_regno,
- conflicting_regs, profitable_hard_regs))
+ if (!check_hard_reg_p (a, hard_regno, start_conflicting_regs,
+ profitable_hard_regs))
continue;
cost = costs[i];
full_cost = full_costs[i];
@@ -2667,21 +2763,16 @@ push_allocno_to_stack (ira_allocno_t a)
{
enum reg_class aclass;
allocno_color_data_t data, conflict_data;
- int size, i, n = ALLOCNO_NUM_OBJECTS (a);
-
+ int i, n = ALLOCNO_NUM_OBJECTS (a);
+
data = ALLOCNO_COLOR_DATA (a);
data->in_graph_p = false;
allocno_stack_vec.safe_push (a);
aclass = ALLOCNO_CLASS (a);
if (aclass == NO_REGS)
return;
- size = ira_reg_class_max_nregs[aclass][ALLOCNO_MODE (a)];
- if (n > 1)
- {
- /* We will deal with the subwords individually. */
- gcc_assert (size == ALLOCNO_NUM_OBJECTS (a));
- size = 1;
- }
+ /* Already collect conflict objects. */
+ std::map<int, bitmap> allocno_conflict_regs;
for (i = 0; i < n; i++)
{
ira_object_t obj = ALLOCNO_OBJECT (a, i);
@@ -2706,6 +2797,21 @@ push_allocno_to_stack (ira_allocno_t a)
continue;
ira_assert (bitmap_bit_p (coloring_allocno_bitmap,
ALLOCNO_NUM (conflict_a)));
+
+ int num = ALLOCNO_NUM (conflict_a);
+ if (allocno_conflict_regs.count (num) == 0)
+ allocno_conflict_regs.insert ({num, ira_allocate_bitmap ()});
+ bitmap_head temp;
+ bitmap_initialize (&temp, ®_obstack);
+ bitmap_set_range (&temp, OBJECT_START (obj), OBJECT_NREGS (obj));
+ bitmap_and_compl_into (&temp, allocno_conflict_regs.at (num));
+ int size = bitmap_count_bits (&temp);
+ bitmap_clear (&temp);
+ if (size == 0)
+ continue;
+
+ bitmap_set_range (allocno_conflict_regs.at (num), OBJECT_START (obj),
+ OBJECT_NREGS (obj));
if (update_left_conflict_sizes_p (conflict_a, a, size))
{
delete_allocno_from_bucket
@@ -2721,6 +2827,9 @@ push_allocno_to_stack (ira_allocno_t a)
}
}
+
+ for (auto &kv : allocno_conflict_regs)
+ ira_free_bitmap (kv.second);
}
/* Put ALLOCNO onto the coloring stack and remove it from its bucket.
@@ -3154,7 +3263,7 @@ improve_allocation (void)
machine_mode mode;
int *allocno_costs;
int costs[FIRST_PSEUDO_REGISTER];
- HARD_REG_SET conflicting_regs[2], profitable_hard_regs;
+ HARD_REG_SET start_conflicting_regs, profitable_hard_regs;
ira_allocno_t a;
bitmap_iterator bi;
int saved_nregs;
@@ -3193,7 +3302,7 @@ improve_allocation (void)
- allocno_copy_cost_saving (a, hregno));
try_p = false;
get_conflict_and_start_profitable_regs (a, false,
- conflicting_regs,
+ &start_conflicting_regs,
&profitable_hard_regs);
class_size = ira_class_hard_regs_num[aclass];
mode = ALLOCNO_MODE (a);
@@ -3202,8 +3311,8 @@ improve_allocation (void)
for (j = 0; j < class_size; j++)
{
hregno = ira_class_hard_regs[aclass][j];
- if (! check_hard_reg_p (a, hregno,
- conflicting_regs, profitable_hard_regs))
+ if (!check_hard_reg_p (a, hregno, start_conflicting_regs,
+ profitable_hard_regs))
continue;
ira_assert (ira_class_hard_reg_index[aclass][hregno] == j);
k = allocno_costs == NULL ? 0 : j;
@@ -3287,16 +3396,15 @@ improve_allocation (void)
}
conflict_nregs = hard_regno_nregs (conflict_hregno,
ALLOCNO_MODE (conflict_a));
- auto note_conflict = [&](int r)
- {
- if (check_hard_reg_p (a, r,
- conflicting_regs, profitable_hard_regs))
- {
- if (spill_a)
- SET_HARD_REG_BIT (soft_conflict_regs, r);
- costs[r] += spill_cost;
- }
- };
+ auto note_conflict = [&] (int r) {
+ if (check_hard_reg_p (a, r, start_conflicting_regs,
+ profitable_hard_regs))
+ {
+ if (spill_a)
+ SET_HARD_REG_BIT (soft_conflict_regs, r);
+ costs[r] += spill_cost;
+ }
+ };
for (r = conflict_hregno;
r >= 0 && (int) end_hard_regno (mode, r) > conflict_hregno;
r--)
@@ -3314,8 +3422,8 @@ improve_allocation (void)
for (j = 0; j < class_size; j++)
{
hregno = ira_class_hard_regs[aclass][j];
- if (check_hard_reg_p (a, hregno,
- conflicting_regs, profitable_hard_regs)
+ if (check_hard_reg_p (a, hregno, start_conflicting_regs,
+ profitable_hard_regs)
&& min_cost > costs[hregno])
{
best = hregno;
@@ -60,23 +60,8 @@ static IRA_INT_TYPE **conflicts;
static void
record_object_conflict (ira_object_t obj1, ira_object_t obj2)
{
- ira_allocno_t a1 = OBJECT_ALLOCNO (obj1);
- ira_allocno_t a2 = OBJECT_ALLOCNO (obj2);
- int w1 = OBJECT_SUBWORD (obj1);
- int w2 = OBJECT_SUBWORD (obj2);
- int id1, id2;
-
- /* Canonicalize the conflict. If two identically-numbered words
- conflict, always record this as a conflict between words 0. That
- is the only information we need, and it is easier to test for if
- it is collected in each allocno's lowest-order object. */
- if (w1 == w2 && w1 > 0)
- {
- obj1 = ALLOCNO_OBJECT (a1, 0);
- obj2 = ALLOCNO_OBJECT (a2, 0);
- }
- id1 = OBJECT_CONFLICT_ID (obj1);
- id2 = OBJECT_CONFLICT_ID (obj2);
+ int id1 = OBJECT_CONFLICT_ID (obj1);
+ int id2 = OBJECT_CONFLICT_ID (obj2);
SET_MINMAX_SET_BIT (conflicts[id1], id2, OBJECT_MIN (obj1),
OBJECT_MAX (obj1));
@@ -606,8 +591,8 @@ build_object_conflicts (ira_object_t obj)
if (parent_a == NULL)
return;
ira_assert (ALLOCNO_CLASS (a) == ALLOCNO_CLASS (parent_a));
- ira_assert (ALLOCNO_NUM_OBJECTS (a) == ALLOCNO_NUM_OBJECTS (parent_a));
- parent_obj = ALLOCNO_OBJECT (parent_a, OBJECT_SUBWORD (obj));
+ parent_obj
+ = find_object_anyway (parent_a, OBJECT_START (obj), OBJECT_NREGS (obj));
parent_num = OBJECT_CONFLICT_ID (parent_obj);
parent_min = OBJECT_MIN (parent_obj);
parent_max = OBJECT_MAX (parent_obj);
@@ -616,7 +601,6 @@ build_object_conflicts (ira_object_t obj)
{
ira_object_t another_obj = ira_object_id_map[i];
ira_allocno_t another_a = OBJECT_ALLOCNO (another_obj);
- int another_word = OBJECT_SUBWORD (another_obj);
ira_assert (ira_reg_classes_intersect_p
[ALLOCNO_CLASS (a)][ALLOCNO_CLASS (another_a)]);
@@ -627,11 +611,11 @@ build_object_conflicts (ira_object_t obj)
ira_assert (ALLOCNO_NUM (another_parent_a) >= 0);
ira_assert (ALLOCNO_CLASS (another_a)
== ALLOCNO_CLASS (another_parent_a));
- ira_assert (ALLOCNO_NUM_OBJECTS (another_a)
- == ALLOCNO_NUM_OBJECTS (another_parent_a));
SET_MINMAX_SET_BIT (conflicts[parent_num],
- OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (another_parent_a,
- another_word)),
+ OBJECT_CONFLICT_ID (
+ find_object_anyway (another_parent_a,
+ OBJECT_START (another_obj),
+ OBJECT_NREGS (another_obj))),
parent_min, parent_max);
}
}
@@ -659,9 +643,10 @@ build_conflicts (void)
build_object_conflicts (obj);
for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
{
- ira_object_t cap_obj = ALLOCNO_OBJECT (cap, j);
- gcc_assert (ALLOCNO_NUM_OBJECTS (cap) == ALLOCNO_NUM_OBJECTS (a));
- build_object_conflicts (cap_obj);
+ ira_object_t cap_obj
+ = find_object_anyway (cap, OBJECT_START (obj),
+ OBJECT_NREGS (obj));
+ build_object_conflicts (cap_obj);
}
}
}
@@ -736,7 +721,8 @@ print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
}
if (n > 1)
- fprintf (file, "\n;; subobject %d:", i);
+ fprintf (file, "\n;; subobject s%d,n%d,f%d:", OBJECT_START (obj),
+ OBJECT_NREGS (obj), ALLOCNO_NREGS (a));
FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
{
ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
@@ -746,8 +732,10 @@ print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
{
fprintf (file, " a%d(r%d", ALLOCNO_NUM (conflict_a),
ALLOCNO_REGNO (conflict_a));
- if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1)
- fprintf (file, ",w%d", OBJECT_SUBWORD (conflict_obj));
+ if (has_subreg_object_p (conflict_a))
+ fprintf (file, ",s%d,n%d,f%d", OBJECT_START (conflict_obj),
+ OBJECT_NREGS (conflict_obj),
+ ALLOCNO_NREGS (conflict_a));
if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
fprintf (file, ",b%d", bb->index);
else
@@ -854,7 +854,7 @@ modify_move_list (move_t list)
ALLOCNO_MODE (new_allocno) = ALLOCNO_MODE (set_move->to);
ira_set_allocno_class (new_allocno,
ALLOCNO_CLASS (set_move->to));
- ira_create_allocno_objects (new_allocno);
+ ira_copy_allocno_objects (new_allocno, set_move->to);
ALLOCNO_ASSIGNED_P (new_allocno) = true;
ALLOCNO_HARD_REGNO (new_allocno) = -1;
ALLOCNO_EMIT_DATA (new_allocno)->reg
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see
#include "recog.h"
#include "function-abi.h"
+#include <vector>
+#include "subreg-live-range.h"
/* To provide consistency in naming, all IRA external variables,
functions, common typedefs start with prefix ira_. */
@@ -222,11 +224,13 @@ extern int ira_max_point;
extern live_range_t *ira_start_point_ranges, *ira_finish_point_ranges;
/* A structure representing conflict information for an allocno
- (or one of its subwords). */
+ (or one of its subregs). */
struct ira_object
{
/* The allocno associated with this record. */
ira_allocno_t allocno;
+ /* Index in allocno->objects array */
+ unsigned int index;
/* Vector of accumulated conflicting conflict_redords with NULL end
marker (if OBJECT_CONFLICT_VEC_P is true) or conflict bit vector
otherwise. */
@@ -236,10 +240,9 @@ struct ira_object
ranges in the list are not intersected and ordered by decreasing
their program points*. */
live_range_t live_ranges;
- /* The subword within ALLOCNO which is represented by this object.
- Zero means the lowest-order subword (or the entire allocno in case
- it is not being tracked in subwords). */
- int subword;
+ /* Reprensent OBJECT occupied [start, start + nregs) registers of it's
+ ALLOCNO. */
+ int start, nregs;
/* Allocated size of the conflicts array. */
unsigned int conflicts_array_size;
/* A unique number for every instance of this structure, which is used
@@ -295,6 +298,11 @@ struct ira_allocno
reload (at this point pseudo-register has only one allocno) which
did not get stack slot yet. */
signed int hard_regno : 16;
+ /* Unit size of one register that allocate for the allocno. Only use to
+ compute the start and nregs of subreg which be tracked. */
+ poly_int64 unit_size;
+ /* Flag means need track subreg live range for the allocno. */
+ bool track_subreg_p;
/* A bitmask of the ABIs used by calls that occur while the allocno
is live. */
unsigned int crossed_calls_abis : NUM_ABI_IDS;
@@ -353,8 +361,6 @@ struct ira_allocno
register class living at the point than number of hard-registers
of the class available for the allocation. */
int excess_pressure_points_num;
- /* The number of objects tracked in the following array. */
- int num_objects;
/* Accumulated frequency of calls which given allocno
intersects. */
int call_freq;
@@ -387,8 +393,11 @@ struct ira_allocno
/* An array of structures describing conflict information and live
ranges for each object associated with the allocno. There may be
more than one such object in cases where the allocno represents a
- multi-word register. */
- ira_object_t objects[2];
+ multi-hardreg pesudo. */
+ std::vector<ira_object_t> objects;
+ /* An array of structures decribing the subreg mode start and subreg end for
+ this allocno. */
+ std::vector<subreg_range> subregs;
/* Registers clobbered by intersected calls. */
HARD_REG_SET crossed_calls_clobbered_regs;
/* Array of usage costs (accumulated and the one updated during
@@ -468,8 +477,12 @@ struct ira_allocno
#define ALLOCNO_EXCESS_PRESSURE_POINTS_NUM(A) \
((A)->excess_pressure_points_num)
#define ALLOCNO_OBJECT(A,N) ((A)->objects[N])
-#define ALLOCNO_NUM_OBJECTS(A) ((A)->num_objects)
+#define ALLOCNO_NUM_OBJECTS(A) ((int) (A)->objects.size ())
#define ALLOCNO_ADD_DATA(A) ((A)->add_data)
+#define ALLOCNO_UNIT_SIZE(A) ((A)->unit_size)
+#define ALLOCNO_TRACK_SUBREG_P(A) ((A)->track_subreg_p)
+#define ALLOCNO_NREGS(A) \
+ (ira_reg_class_max_nregs[ALLOCNO_CLASS (A)][ALLOCNO_MODE (A)])
/* Typedef for pointer to the subsequent structure. */
typedef struct ira_emit_data *ira_emit_data_t;
@@ -511,7 +524,7 @@ allocno_emit_reg (ira_allocno_t a)
}
#define OBJECT_ALLOCNO(O) ((O)->allocno)
-#define OBJECT_SUBWORD(O) ((O)->subword)
+#define OBJECT_INDEX(O) ((O)->index)
#define OBJECT_CONFLICT_ARRAY(O) ((O)->conflicts_array)
#define OBJECT_CONFLICT_VEC(O) ((ira_object_t *)(O)->conflicts_array)
#define OBJECT_CONFLICT_BITVEC(O) ((IRA_INT_TYPE *)(O)->conflicts_array)
@@ -524,6 +537,8 @@ allocno_emit_reg (ira_allocno_t a)
#define OBJECT_MAX(O) ((O)->max)
#define OBJECT_CONFLICT_ID(O) ((O)->id)
#define OBJECT_LIVE_RANGES(O) ((O)->live_ranges)
+#define OBJECT_START(O) ((O)->start)
+#define OBJECT_NREGS(O) ((O)->nregs)
/* Map regno -> allocnos with given regno (see comments for
allocno member `next_regno_allocno'). */
@@ -1041,6 +1056,12 @@ extern void ira_free_cost_vector (int *, reg_class_t);
extern void ira_flattening (int, int);
extern bool ira_build (void);
extern void ira_destroy (void);
+extern ira_object_t
+find_object (ira_allocno_t, int, int);
+extern ira_object_t find_object (ira_allocno_t, poly_int64, poly_int64);
+ira_object_t
+find_object_anyway (ira_allocno_t a, int start, int nregs);
+extern void ira_copy_allocno_objects (ira_allocno_t, ira_allocno_t);
/* ira-costs.cc */
extern void ira_init_costs_once (void);
@@ -1708,4 +1729,18 @@ ira_caller_save_loop_spill_p (ira_allocno_t a, ira_allocno_t subloop_a,
return call_cost && call_cost >= spill_cost;
}
+/* Return true if allocno A has subreg object. */
+inline bool
+has_subreg_object_p (ira_allocno_t a)
+{
+ return ALLOCNO_NUM_OBJECTS (a) > 1;
+}
+
+/* Return the full object of allocno A. */
+inline ira_object_t
+get_full_object (ira_allocno_t a)
+{
+ return find_object (a, 0, ALLOCNO_NREGS (a));
+}
+
#endif /* GCC_IRA_INT_H */
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "backend.h"
@@ -35,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "sparseset.h"
#include "function-abi.h"
#include "except.h"
+#include "subreg-live-range.h"
/* The code in this file is similar to one in global but the code
works on the allocno basis and creates live ranges instead of
@@ -91,6 +93,9 @@ static alternative_mask preferred_alternatives;
we should not add a conflict with the copy's destination operand. */
static rtx ignore_reg_for_conflicts;
+/* Store def/use point of has_subreg_object_p register. */
+static class subregs_live_points *subreg_live_points;
+
/* Record hard register REGNO as now being live. */
static void
make_hard_regno_live (int regno)
@@ -98,6 +103,33 @@ make_hard_regno_live (int regno)
SET_HARD_REG_BIT (hard_regs_live, regno);
}
+/* Update conflict hard regs of ALLOCNO a for current live part. */
+static void
+add_onflict_hard_regs (ira_allocno_t a, HARD_REG_SET regs)
+{
+ gcc_assert (has_subreg_object_p (a));
+
+ if (subreg_live_points->subreg_live_ranges.count (ALLOCNO_NUM (a)) == 0)
+ return;
+
+ for (const subreg_range &r :
+ subreg_live_points->subreg_live_ranges.at (ALLOCNO_NUM (a)).ranges)
+ {
+ ira_object_t obj = find_object_anyway (a, r.start, r.end - r.start);
+ OBJECT_CONFLICT_HARD_REGS (obj) |= regs;
+ OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= regs;
+ }
+}
+
+static void
+add_onflict_hard_reg (ira_allocno_t a, unsigned int regno)
+{
+ HARD_REG_SET set;
+ CLEAR_HARD_REG_SET (set);
+ SET_HARD_REG_BIT (set, regno);
+ add_onflict_hard_regs (a, set);
+}
+
/* Process the definition of hard register REGNO. This updates
hard_regs_live and hard reg conflict information for living allocnos. */
static void
@@ -113,8 +145,13 @@ make_hard_regno_dead (int regno)
== (unsigned int) ALLOCNO_REGNO (OBJECT_ALLOCNO (obj)))
continue;
- SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
- SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
+ if (has_subreg_object_p (OBJECT_ALLOCNO (obj)))
+ add_onflict_hard_reg (OBJECT_ALLOCNO (obj), regno);
+ else
+ {
+ SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
+ SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
+ }
}
CLEAR_HARD_REG_BIT (hard_regs_live, regno);
}
@@ -127,9 +164,29 @@ make_object_live (ira_object_t obj)
sparseset_set_bit (objects_live, OBJECT_CONFLICT_ID (obj));
live_range_t lr = OBJECT_LIVE_RANGES (obj);
- if (lr == NULL
- || (lr->finish != curr_point && lr->finish + 1 != curr_point))
- ira_add_live_range_to_object (obj, curr_point, -1);
+ if (lr == NULL || (lr->finish != curr_point && lr->finish + 1 != curr_point))
+ {
+ ira_add_live_range_to_object (obj, curr_point, -1);
+ if (internal_flag_ira_verbose > 8 && ira_dump_file != NULL)
+ {
+ fprintf (ira_dump_file,
+ " add new live_range for a%d(r%d): [%d...-1]\n",
+ ALLOCNO_NUM (OBJECT_ALLOCNO (obj)),
+ ALLOCNO_REGNO (OBJECT_ALLOCNO (obj)), curr_point);
+ }
+ }
+ else
+ {
+ if (internal_flag_ira_verbose > 8 && ira_dump_file != NULL)
+ {
+ fprintf (
+ ira_dump_file,
+ " use old live_range for a%d(r%d): [%d...%d], curr: %d\n",
+ ALLOCNO_NUM (OBJECT_ALLOCNO (obj)),
+ ALLOCNO_REGNO (OBJECT_ALLOCNO (obj)), lr->start, lr->finish,
+ curr_point);
+ }
+ }
}
/* Update ALLOCNO_EXCESS_PRESSURE_POINTS_NUM for the allocno
@@ -140,7 +197,6 @@ update_allocno_pressure_excess_length (ira_object_t obj)
ira_allocno_t a = OBJECT_ALLOCNO (obj);
int start, i;
enum reg_class aclass, pclass, cl;
- live_range_t p;
aclass = ALLOCNO_CLASS (a);
pclass = ira_pressure_class_translate[aclass];
@@ -152,10 +208,18 @@ update_allocno_pressure_excess_length (ira_object_t obj)
continue;
if (high_pressure_start_point[cl] < 0)
continue;
- p = OBJECT_LIVE_RANGES (obj);
- ira_assert (p != NULL);
- start = (high_pressure_start_point[cl] > p->start
- ? high_pressure_start_point[cl] : p->start);
+ int start_point;
+ if (has_subreg_object_p (a))
+ start_point = subreg_live_points->get_start_point (ALLOCNO_NUM (a));
+ else
+ {
+ live_range_t p = OBJECT_LIVE_RANGES (obj);
+ ira_assert (p != NULL);
+ start_point = p->start;
+ }
+ start = (high_pressure_start_point[cl] > start_point
+ ? high_pressure_start_point[cl]
+ : start_point);
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) += curr_point - start + 1;
}
}
@@ -201,6 +265,14 @@ make_object_dead (ira_object_t obj)
CLEAR_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
lr = OBJECT_LIVE_RANGES (obj);
+ if (internal_flag_ira_verbose > 8 && ira_dump_file != NULL)
+ {
+ fprintf (ira_dump_file,
+ " finish a live_range a%d(r%d): [%d...%d] => [%d...%d]\n",
+ ALLOCNO_NUM (OBJECT_ALLOCNO (obj)),
+ ALLOCNO_REGNO (OBJECT_ALLOCNO (obj)), lr->start, lr->finish,
+ lr->start, curr_point);
+ }
ira_assert (lr != NULL);
lr->finish = curr_point;
update_allocno_pressure_excess_length (obj);
@@ -295,77 +367,144 @@ pseudo_regno_single_word_and_live_p (int regno)
return sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj));
}
-/* Mark the pseudo register REGNO as live. Update all information about
- live ranges and register pressure. */
+/* Collect the point which the OBJ be def/use. */
static void
-mark_pseudo_regno_live (int regno)
+add_subreg_point (ira_object_t obj, bool is_def, bool is_dec = true)
{
- ira_allocno_t a = ira_curr_regno_allocno_map[regno];
- enum reg_class pclass;
- int i, n, nregs;
-
- if (a == NULL)
- return;
+ ira_allocno_t a = OBJECT_ALLOCNO (obj);
+ if (is_def)
+ {
+ OBJECT_CONFLICT_HARD_REGS (obj) |= hard_regs_live;
+ OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= hard_regs_live;
+ if (is_dec)
+ {
+ enum reg_class pclass
+ = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
+ dec_register_pressure (pclass, ALLOCNO_NREGS (a));
+ }
+ update_allocno_pressure_excess_length (obj);
+ }
+ else
+ {
+ enum reg_class pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
+ inc_register_pressure (pclass, ALLOCNO_NREGS (a));
+ }
- /* Invalidate because it is referenced. */
- allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+ subreg_range r = subreg_range (
+ {OBJECT_START (obj), OBJECT_START (obj) + OBJECT_NREGS (obj)});
+ subreg_live_points->add_point (ALLOCNO_NUM (a), ALLOCNO_NREGS (a), r, is_def,
+ curr_point);
- n = ALLOCNO_NUM_OBJECTS (a);
- pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
- nregs = ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)];
- if (n > 1)
+ if (internal_flag_ira_verbose > 8 && ira_dump_file != NULL)
{
- /* We track every subobject separately. */
- gcc_assert (nregs == n);
- nregs = 1;
+ fprintf (ira_dump_file, " %s a%d(r%d", is_def ? "def" : "use",
+ ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
+ if (ALLOCNO_CLASS (a) != NO_REGS
+ && ALLOCNO_NREGS (a) != OBJECT_NREGS (obj))
+ fprintf (ira_dump_file, " [subreg: start %d, nregs %d]",
+ OBJECT_START (obj), OBJECT_NREGS (obj));
+ else
+ fprintf (ira_dump_file, " [full: nregs %d]", OBJECT_NREGS (obj));
+ fprintf (ira_dump_file, ") at point %d\n", curr_point);
}
- for (i = 0; i < n; i++)
- {
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
+ gcc_assert (has_subreg_object_p (a));
+ gcc_assert (subreg_live_points->subreg_live_ranges.count (ALLOCNO_NUM (a))
+ != 0);
+
+ const subreg_ranges &sr
+ = subreg_live_points->subreg_live_ranges.at (ALLOCNO_NUM (a));
+ ira_object_t main_obj = find_object (a, 0, ALLOCNO_NREGS (a));
+ gcc_assert (main_obj != NULL);
+ if (sr.empty_p ()
+ && sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (main_obj)))
+ sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (main_obj));
+ else if (!sr.empty_p ()
+ && !sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (main_obj)))
+ sparseset_set_bit (objects_live, OBJECT_CONFLICT_ID (main_obj));
+}
+
+/* Mark the object OBJ as live. */
+static void
+mark_pseudo_object_live (ira_allocno_t a, ira_object_t obj)
+{
+ /* Invalidate because it is referenced. */
+ allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+ if (has_subreg_object_p (a))
+ add_subreg_point (obj, false);
+ else
+ {
if (sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
- continue;
+ return;
- inc_register_pressure (pclass, nregs);
+ enum reg_class pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
+ inc_register_pressure (pclass, ALLOCNO_NREGS (a));
make_object_live (obj);
}
}
+/* Mark the pseudo register REGNO as live. Update all information about
+ live ranges and register pressure. */
+static void
+mark_pseudo_regno_live (int regno)
+{
+ ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+
+ if (a == NULL)
+ return;
+
+ int nregs = ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)];
+ ira_object_t obj = find_object (a, 0, nregs);
+ gcc_assert (obj != NULL);
+
+ mark_pseudo_object_live (a, obj);
+}
+
/* Like mark_pseudo_regno_live, but try to only mark one subword of
the pseudo as live. SUBWORD indicates which; a value of 0
indicates the low part. */
static void
-mark_pseudo_regno_subword_live (int regno, int subword)
+mark_pseudo_regno_subreg_live (int regno, rtx subreg)
{
ira_allocno_t a = ira_curr_regno_allocno_map[regno];
- int n;
- enum reg_class pclass;
- ira_object_t obj;
if (a == NULL)
return;
- /* Invalidate because it is referenced. */
- allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+ ira_object_t obj
+ = find_object (a, SUBREG_BYTE (subreg), GET_MODE_SIZE (GET_MODE (subreg)));
+ gcc_assert (obj != NULL);
+
+ mark_pseudo_object_live (a, obj);
+}
- n = ALLOCNO_NUM_OBJECTS (a);
- if (n == 1)
+/* Mark objects in subreg ranges SR as live. Update all information about
+ live ranges and register pressure. */
+static void
+mark_pseudo_regno_subregs_live (int regno, const subreg_ranges &sr)
+{
+ ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+ if (a == NULL)
+ return;
+
+ if (!ALLOCNO_TRACK_SUBREG_P (a))
{
mark_pseudo_regno_live (regno);
return;
}
- pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
- gcc_assert
- (n == ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]);
- obj = ALLOCNO_OBJECT (a, subword);
-
- if (sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
- return;
-
- inc_register_pressure (pclass, 1);
- make_object_live (obj);
+ int times = sr.max / ALLOCNO_NREGS (a);
+ gcc_assert (sr.max >= ALLOCNO_NREGS (a)
+ && times * ALLOCNO_NREGS (a) == sr.max);
+ for (const subreg_range &range : sr.ranges)
+ {
+ int start = range.start / times;
+ int end = CEIL (range.end, times);
+ ira_object_t obj = find_object (a, start, end - start);
+ gcc_assert (obj != NULL);
+ mark_pseudo_object_live (a, obj);
+ }
}
/* Mark the register REG as live. Store a 1 in hard_regs_live for
@@ -403,10 +542,7 @@ static void
mark_pseudo_reg_live (rtx orig_reg, unsigned regno)
{
if (read_modify_subreg_p (orig_reg))
- {
- mark_pseudo_regno_subword_live (regno,
- subreg_lowpart_p (orig_reg) ? 0 : 1);
- }
+ mark_pseudo_regno_subreg_live (regno, orig_reg);
else
mark_pseudo_regno_live (regno);
}
@@ -427,72 +563,59 @@ mark_ref_live (df_ref ref)
mark_hard_reg_live (reg);
}
-/* Mark the pseudo register REGNO as dead. Update all information about
- live ranges and register pressure. */
+/* Mark object as dead. */
static void
-mark_pseudo_regno_dead (int regno)
+mark_pseudo_object_dead (ira_allocno_t a, ira_object_t obj)
{
- ira_allocno_t a = ira_curr_regno_allocno_map[regno];
- int n, i, nregs;
- enum reg_class cl;
-
- if (a == NULL)
- return;
-
/* Invalidate because it is referenced. */
allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
- n = ALLOCNO_NUM_OBJECTS (a);
- cl = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
- nregs = ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)];
- if (n > 1)
- {
- /* We track every subobject separately. */
- gcc_assert (nregs == n);
- nregs = 1;
- }
- for (i = 0; i < n; i++)
+ if (has_subreg_object_p (a))
+ add_subreg_point (obj, true);
+ else
{
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
if (!sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
- continue;
+ return;
- dec_register_pressure (cl, nregs);
+ enum reg_class cl = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
+ dec_register_pressure (cl, ALLOCNO_NREGS (a));
make_object_dead (obj);
}
}
-/* Like mark_pseudo_regno_dead, but called when we know that only part of the
- register dies. SUBWORD indicates which; a value of 0 indicates the low part. */
+/* Mark the pseudo register REGNO as dead. Update all information about
+ live ranges and register pressure. */
static void
-mark_pseudo_regno_subword_dead (int regno, int subword)
+mark_pseudo_regno_dead (int regno)
{
ira_allocno_t a = ira_curr_regno_allocno_map[regno];
- int n;
- enum reg_class cl;
- ira_object_t obj;
if (a == NULL)
return;
- /* Invalidate because it is referenced. */
- allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+ int nregs = ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)];
+ ira_object_t obj = find_object (a, 0, nregs);
+ gcc_assert (obj != NULL);
- n = ALLOCNO_NUM_OBJECTS (a);
- if (n == 1)
- /* The allocno as a whole doesn't die in this case. */
- return;
+ mark_pseudo_object_dead (a, obj);
+}
- cl = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
- gcc_assert
- (n == ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]);
+/* Like mark_pseudo_regno_dead, but called when we know that only part of the
+ register dies. SUBWORD indicates which; a value of 0 indicates the low part.
+ */
+static void
+mark_pseudo_regno_subreg_dead (int regno, rtx subreg)
+{
+ ira_allocno_t a = ira_curr_regno_allocno_map[regno];
- obj = ALLOCNO_OBJECT (a, subword);
- if (!sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
+ if (a == NULL)
return;
- dec_register_pressure (cl, 1);
- make_object_dead (obj);
+ ira_object_t obj
+ = find_object (a, SUBREG_BYTE (subreg), GET_MODE_SIZE (GET_MODE (subreg)));
+ gcc_assert (obj != NULL);
+
+ mark_pseudo_object_dead (a, obj);
}
/* Process the definition of hard register REG. This updates hard_regs_live
@@ -528,10 +651,7 @@ static void
mark_pseudo_reg_dead (rtx orig_reg, unsigned regno)
{
if (read_modify_subreg_p (orig_reg))
- {
- mark_pseudo_regno_subword_dead (regno,
- subreg_lowpart_p (orig_reg) ? 0 : 1);
- }
+ mark_pseudo_regno_subreg_dead (regno, orig_reg);
else
mark_pseudo_regno_dead (regno);
}
@@ -1059,8 +1179,15 @@ process_single_reg_class_operands (bool in_p, int freq)
/* We could increase costs of A instead of making it
conflicting with the hard register. But it works worse
because it will be spilled in reload in anyway. */
- OBJECT_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl];
- OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl];
+ if (has_subreg_object_p (a))
+ add_onflict_hard_regs (OBJECT_ALLOCNO (obj),
+ reg_class_contents[cl]);
+ else
+ {
+ OBJECT_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl];
+ OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)
+ |= reg_class_contents[cl];
+ }
}
}
}
@@ -1198,17 +1325,15 @@ process_out_of_region_eh_regs (basic_block bb)
bi)
{
ira_allocno_t a = ira_curr_regno_allocno_map[i];
- for (int n = ALLOCNO_NUM_OBJECTS (a) - 1; n >= 0; n--)
+ ira_object_t obj = find_object (a, 0, ALLOCNO_NREGS (a));
+ for (int k = 0;; k++)
{
- ira_object_t obj = ALLOCNO_OBJECT (a, n);
- for (int k = 0; ; k++)
- {
- unsigned int regno = EH_RETURN_DATA_REGNO (k);
- if (regno == INVALID_REGNUM)
- break;
- SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
- SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
- }
+ unsigned int regno = EH_RETURN_DATA_REGNO (k);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
+ SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
}
}
}
@@ -1234,8 +1359,13 @@ add_conflict_from_region_landing_pads (eh_region region, ira_object_t obj,
{
HARD_REG_SET new_conflict_regs
= callee_abi.mode_clobbers (ALLOCNO_MODE (a));
- OBJECT_CONFLICT_HARD_REGS (obj) |= new_conflict_regs;
- OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= new_conflict_regs;
+ if (has_subreg_object_p (a))
+ add_onflict_hard_regs (a, new_conflict_regs);
+ else
+ {
+ OBJECT_CONFLICT_HARD_REGS (obj) |= new_conflict_regs;
+ OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= new_conflict_regs;
+ }
return;
}
}
@@ -1260,6 +1390,10 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
bb = loop_tree_node->bb;
if (bb != NULL)
{
+ if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+ fprintf (ira_dump_file, "\n BB exit(l%d): point = %d\n",
+ loop_tree_node->parent->loop_num, curr_point);
+
for (i = 0; i < ira_pressure_classes_num; i++)
{
curr_reg_pressure[ira_pressure_classes[i]] = 0;
@@ -1268,6 +1402,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
curr_bb_node = loop_tree_node;
reg_live_out = DF_LIVE_SUBREG_OUT (bb);
sparseset_clear (objects_live);
+ subreg_live_points->clear_live_ranges ();
REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
hard_regs_live &= ~(eliminable_regset | ira_no_alloc_regs);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -1291,9 +1426,17 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
<= ira_class_hard_regs_num[cl]);
}
}
- EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
+ EXECUTE_IF_SET_IN_BITMAP (DF_LIVE_SUBREG_FULL_OUT (bb),
+ FIRST_PSEUDO_REGISTER, j, bi)
mark_pseudo_regno_live (j);
+ EXECUTE_IF_SET_IN_BITMAP (DF_LIVE_SUBREG_PARTIAL_OUT (bb),
+ FIRST_PSEUDO_REGISTER, j, bi)
+ {
+ mark_pseudo_regno_subregs_live (
+ j, DF_LIVE_SUBREG_RANGE_OUT (bb)->lives.at (j));
+ }
+
#ifdef EH_RETURN_DATA_REGNO
process_out_of_region_eh_regs (bb);
#endif
@@ -1408,8 +1551,18 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
&& (find_reg_note (insn, REG_SETJMP, NULL_RTX)
!= NULL_RTX)))
{
- SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
- SET_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+ if (has_subreg_object_p (a))
+ {
+ HARD_REG_SET regs;
+ SET_HARD_REG_SET (regs);
+ add_onflict_hard_regs (a, regs);
+ }
+ else
+ {
+ SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
+ SET_HARD_REG_SET (
+ OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+ }
}
eh_region r;
if (can_throw_internal (insn)
@@ -1455,7 +1608,14 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
/* Mark each used value as live. */
FOR_EACH_INSN_USE (use, insn)
- mark_ref_live (use);
+ {
+ unsigned regno = DF_REF_REGNO (use);
+ ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+ if (a && has_subreg_object_p (a)
+ && DF_REF_FLAGS (use) & (DF_REF_READ_WRITE | DF_REF_SUBREG))
+ continue;
+ mark_ref_live (use);
+ }
process_single_reg_class_operands (true, freq);
@@ -1485,6 +1645,10 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
}
ignore_reg_for_conflicts = NULL_RTX;
+ if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+ fprintf (ira_dump_file, "\n BB head(l%d): point = %d\n",
+ loop_tree_node->parent->loop_num, curr_point);
+
if (bb_has_eh_pred (bb))
for (j = 0; ; ++j)
{
@@ -1538,10 +1702,15 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
}
EXECUTE_IF_SET_IN_SPARSESET (objects_live, i)
- make_object_dead (ira_object_id_map[i]);
+ {
+ ira_object_t obj = ira_object_id_map[i];
+ if (has_subreg_object_p (OBJECT_ALLOCNO (obj)))
+ add_subreg_point (obj, true, false);
+ else
+ make_object_dead (obj);
+ }
curr_point++;
-
}
/* Propagate register pressure to upper loop tree nodes. */
if (loop_tree_node != ira_loop_tree_root)
@@ -1742,6 +1911,86 @@ ira_debug_live_ranges (void)
print_live_ranges (stderr);
}
+class subreg_live_item
+{
+public:
+ subreg_ranges subreg;
+ int start, finish;
+};
+
+/* Create subreg live ranges from objects def/use point info. */
+static void
+create_subregs_live_ranges ()
+{
+ for (const auto &subreg_point_it : subreg_live_points->subreg_points)
+ {
+ unsigned int allocno_num = subreg_point_it.first;
+ const class live_points &points = subreg_point_it.second;
+ ira_allocno_t a = ira_allocnos[allocno_num];
+ std::vector<subreg_live_item> temps;
+ gcc_assert (has_subreg_object_p (a));
+ for (const auto &point_it : points.points)
+ {
+ int point = point_it.first;
+ const live_point ®s = point_it.second;
+ gcc_assert (temps.empty () || temps.back ().finish <= point);
+ if (!regs.use_reg.empty_p ())
+ {
+ if (temps.empty ())
+ temps.push_back ({regs.use_reg, point, -1});
+ else if (temps.back ().finish == -1)
+ {
+ if (!temps.back ().subreg.same_p (regs.use_reg))
+ {
+ if (temps.back ().start == point)
+ temps.back ().subreg.add_ranges (regs.use_reg);
+ else
+ {
+ temps.back ().finish = point - 1;
+
+ subreg_ranges temp = regs.use_reg;
+ temp.add_ranges (temps.back ().subreg);
+ temps.push_back ({temp, point, -1});
+ }
+ }
+ }
+ else if (temps.back ().subreg.same_p (regs.use_reg)
+ && (temps.back ().finish == point
+ || temps.back ().finish + 1 == point))
+ temps.back ().finish = -1;
+ else
+ temps.push_back ({regs.use_reg, point, -1});
+ }
+ if (!regs.def_reg.empty_p ())
+ {
+ gcc_assert (!temps.empty ());
+ if (regs.def_reg.include_ranges_p (temps.back ().subreg))
+ temps.back ().finish = point;
+ else if (temps.back ().subreg.include_ranges_p (regs.def_reg))
+ {
+ temps.back ().finish = point;
+
+ subreg_ranges diff = temps.back ().subreg;
+ diff.remove_ranges (regs.def_reg);
+ temps.push_back ({diff, point + 1, -1});
+ }
+ else
+ gcc_unreachable ();
+ }
+ }
+ for (const subreg_live_item &item : temps)
+ for (const subreg_range &r : item.subreg.ranges)
+ {
+ ira_object_t obj = find_object_anyway (a, r.start, r.end - r.start);
+ live_range_t lr = OBJECT_LIVE_RANGES (obj);
+ if (lr != NULL && lr->finish + 1 == item.start)
+ lr->finish = item.finish;
+ else
+ ira_add_live_range_to_object (obj, item.start, item.finish);
+ }
+ }
+}
+
/* The main entry function creates live ranges, set up
CONFLICT_HARD_REGS and TOTAL_CONFLICT_HARD_REGS for objects, and
calculate register pressure info. */
@@ -1755,13 +2004,20 @@ ira_create_allocno_live_ranges (void)
allocno_saved_at_call
= (int *) ira_allocate (ira_allocnos_num * sizeof (int));
memset (allocno_saved_at_call, 0, ira_allocnos_num * sizeof (int));
+ subreg_live_points = new subregs_live_points ();
ira_traverse_loop_tree (true, ira_loop_tree_root, NULL,
process_bb_node_lives);
ira_max_point = curr_point;
+ create_subregs_live_ranges ();
create_start_finish_chains ();
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- print_live_ranges (ira_dump_file);
+ {
+ fprintf (ira_dump_file, ";; subreg live points:\n");
+ subreg_live_points->dump (ira_dump_file);
+ print_live_ranges (ira_dump_file);
+ }
/* Clean up. */
+ delete subreg_live_points;
ira_free (allocno_saved_at_call);
sparseset_free (objects_live);
sparseset_free (allocnos_processed);
@@ -2623,7 +2623,7 @@ static void
check_allocation (void)
{
ira_allocno_t a;
- int hard_regno, nregs, conflict_nregs;
+ int hard_regno;
ira_allocno_iterator ai;
FOR_EACH_ALLOCNO (a, ai)
@@ -2634,28 +2634,18 @@ check_allocation (void)
if (ALLOCNO_CAP_MEMBER (a) != NULL
|| (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
continue;
- nregs = hard_regno_nregs (hard_regno, ALLOCNO_MODE (a));
- if (nregs == 1)
- /* We allocated a single hard register. */
- n = 1;
- else if (n > 1)
- /* We allocated multiple hard registers, and we will test
- conflicts in a granularity of single hard regs. */
- nregs = 1;
for (i = 0; i < n; i++)
{
ira_object_t obj = ALLOCNO_OBJECT (a, i);
ira_object_t conflict_obj;
ira_object_conflict_iterator oci;
- int this_regno = hard_regno;
- if (n > 1)
- {
- if (REG_WORDS_BIG_ENDIAN)
- this_regno += n - i - 1;
- else
- this_regno += i;
- }
+ int this_regno;
+ if (REG_WORDS_BIG_ENDIAN)
+ this_regno = hard_regno + ALLOCNO_NREGS (a) - 1 - OBJECT_START (obj)
+ - OBJECT_NREGS (obj) + 1;
+ else
+ this_regno = hard_regno + OBJECT_START (obj);
FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
{
ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
@@ -2665,24 +2655,18 @@ check_allocation (void)
if (ira_soft_conflict (a, conflict_a))
continue;
- conflict_nregs = hard_regno_nregs (conflict_hard_regno,
- ALLOCNO_MODE (conflict_a));
-
- if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1
- && conflict_nregs == ALLOCNO_NUM_OBJECTS (conflict_a))
- {
- if (REG_WORDS_BIG_ENDIAN)
- conflict_hard_regno += (ALLOCNO_NUM_OBJECTS (conflict_a)
- - OBJECT_SUBWORD (conflict_obj) - 1);
- else
- conflict_hard_regno += OBJECT_SUBWORD (conflict_obj);
- conflict_nregs = 1;
- }
+ if (REG_WORDS_BIG_ENDIAN)
+ conflict_hard_regno = conflict_hard_regno
+ + ALLOCNO_NREGS (conflict_a) - 1
+ - OBJECT_START (conflict_obj)
+ - OBJECT_NREGS (conflict_obj) + 1;
+ else
+ conflict_hard_regno
+ = conflict_hard_regno + OBJECT_START (conflict_obj);
- if ((conflict_hard_regno <= this_regno
- && this_regno < conflict_hard_regno + conflict_nregs)
- || (this_regno <= conflict_hard_regno
- && conflict_hard_regno < this_regno + nregs))
+ if (!(this_regno + OBJECT_NREGS (obj) <= conflict_hard_regno
+ || conflict_hard_regno + OBJECT_NREGS (conflict_obj)
+ <= this_regno))
{
fprintf (stderr, "bad allocation for %d and %d\n",
ALLOCNO_REGNO (a), ALLOCNO_REGNO (conflict_a));