connecting this allocno to the one being allocated. */
int divisor;
+ /* Allocno from which we started chaining costs of connected
+ allocnos. */
+ ira_allocno_t start;
+
/* Allocno from which we are chaining costs of connected allocnos.
It is used not go back in graph of allocnos connected by
copies. */
update_cost_queue = NULL;
}
-/* Add (ALLOCNO, FROM, DIVISOR) to the end of update_cost_queue, unless
+/* Add (ALLOCNO, START, FROM, DIVISOR) to the end of update_cost_queue, unless
ALLOCNO is already in the queue, or has NO_REGS class. */
static inline void
-queue_update_cost (ira_allocno_t allocno, ira_allocno_t from, int divisor)
+queue_update_cost (ira_allocno_t allocno, ira_allocno_t start,
+ ira_allocno_t from, int divisor)
{
struct update_cost_queue_elem *elem;
&& ALLOCNO_CLASS (allocno) != NO_REGS)
{
elem->check = update_cost_check;
+ elem->start = start;
elem->from = from;
elem->divisor = divisor;
elem->next = NULL;
}
/* Try to remove the first element from update_cost_queue. Return
- false if the queue was empty, otherwise make (*ALLOCNO, *FROM,
- *DIVISOR) describe the removed element. */
+ false if the queue was empty, otherwise make (*ALLOCNO, *START,
+ *FROM, *DIVISOR) describe the removed element. */
static inline bool
-get_next_update_cost (ira_allocno_t *allocno, ira_allocno_t *from, int *divisor)
+get_next_update_cost (ira_allocno_t *allocno, ira_allocno_t *start,
+ ira_allocno_t *from, int *divisor)
{
struct update_cost_queue_elem *elem;
*allocno = update_cost_queue;
elem = &update_cost_queue_elems[ALLOCNO_NUM (*allocno)];
+ *start = elem->start;
*from = elem->from;
*divisor = elem->divisor;
update_cost_queue = elem->next;
return true;
}
+/* Return TRUE if allocnos A1 and A2 conflicts. Here we are
+ interesting only in conflicts of allocnos with intersected allocno
+ classes. */
+static bool
+allocnos_conflict_p (ira_allocno_t a1, ira_allocno_t a2)
+{
+ ira_object_t obj, conflict_obj;
+ ira_object_conflict_iterator oci;
+ int word, nwords = ALLOCNO_NUM_OBJECTS (a1);
+
+ for (word = 0; word < nwords; word++)
+ {
+ obj = ALLOCNO_OBJECT (a1, word);
+ /* Take preferences of conflicting allocnos into account. */
+ FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+ if (OBJECT_ALLOCNO (conflict_obj) == a2)
+ return true;
+ }
+ return false;
+}
+
/* Update (decrease if DECR_P) HARD_REGNO cost of allocnos connected
by copies to ALLOCNO to increase chances to remove some copies as
- the result of subsequent assignment. Record cost updates if
- RECORD_P is true. */
+ the result of subsequent assignment. Update conflict costs only
+ for true CONFLICT_COST_UPDATE_P. Record cost updates if RECORD_P is
+ true. */
static void
update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
- int divisor, bool decr_p, bool record_p)
+ int divisor, bool decr_p, bool record_p,
+ bool conflict_cost_update_p)
{
int cost, update_cost, update_conflict_cost;
machine_mode mode;
enum reg_class rclass, aclass;
- ira_allocno_t another_allocno, from = NULL;
+ ira_allocno_t another_allocno, start = allocno, from = NULL;
ira_copy_t cp, next_cp;
rclass = REGNO_REG_CLASS (hard_regno);
else
gcc_unreachable ();
- if (another_allocno == from)
+ if (another_allocno == from
+ || allocnos_conflict_p (another_allocno, start))
continue;
aclass = ALLOCNO_CLASS (another_allocno);
if (decr_p)
cost = -cost;
- update_conflict_cost = update_cost = cp->freq * cost / divisor;
+ update_cost = cp->freq * cost / divisor;
+ update_conflict_cost = conflict_cost_update_p ? update_cost : 0;
if (ALLOCNO_COLOR_DATA (another_allocno) != NULL
&& (ALLOCNO_COLOR_DATA (allocno)->first_thread_allocno
if (! update_allocno_cost (another_allocno, hard_regno,
update_cost, update_conflict_cost))
continue;
- queue_update_cost (another_allocno, allocno, divisor * COST_HOP_DIVISOR);
+ queue_update_cost (another_allocno, start, allocno,
+ divisor * COST_HOP_DIVISOR);
if (record_p && ALLOCNO_COLOR_DATA (another_allocno) != NULL)
ALLOCNO_COLOR_DATA (another_allocno)->update_cost_records
= get_update_cost_record (hard_regno, divisor,
->update_cost_records);
}
}
- while (get_next_update_cost (&allocno, &from, &divisor));
+ while (get_next_update_cost (&allocno, &start, &from, &divisor));
}
/* Decrease preferred ALLOCNO hard register costs and costs of
start_update_cost ();
for (pref = ALLOCNO_PREFS (allocno); pref != NULL; pref = pref->next_pref)
update_costs_from_allocno (allocno, pref->hard_regno,
- COST_HOP_DIVISOR, true, true);
+ COST_HOP_DIVISOR, true, true, false);
}
/* Update (decrease if DECR_P) the cost of allocnos connected to
hard_regno = ALLOCNO_HARD_REGNO (allocno);
ira_assert (hard_regno >= 0 && ALLOCNO_CLASS (allocno) != NO_REGS);
start_update_cost ();
- update_costs_from_allocno (allocno, hard_regno, 1, decr_p, record_p);
+ update_costs_from_allocno (allocno, hard_regno, 1, decr_p, record_p, true);
}
/* Update conflict_allocno_hard_prefs of allocnos conflicting with
start_update_cost ();
for (curr = records; curr != NULL; curr = curr->next)
update_costs_from_allocno (allocno, curr->hard_regno,
- curr->divisor, true, false);
+ curr->divisor, true, false, true);
free_update_cost_record_list (records);
ALLOCNO_COLOR_DATA (allocno)->update_cost_records = NULL;
}
int *conflict_costs;
bool cont_p;
enum reg_class another_aclass;
- ira_allocno_t allocno, another_allocno, from;
+ ira_allocno_t allocno, another_allocno, start, from;
ira_copy_t cp, next_cp;
- while (get_next_update_cost (&allocno, &from, &divisor))
+ while (get_next_update_cost (&allocno, &start, &from, &divisor))
for (cp = ALLOCNO_COPIES (allocno); cp != NULL; cp = next_cp)
{
if (cp->first == allocno)
else
gcc_unreachable ();
- if (another_allocno == from)
+ if (another_allocno == from
+ || allocnos_conflict_p (another_allocno, start))
continue;
another_aclass = ALLOCNO_CLASS (another_allocno);
* COST_HOP_DIVISOR
* COST_HOP_DIVISOR
* COST_HOP_DIVISOR))
- queue_update_cost (another_allocno, allocno, divisor * COST_HOP_DIVISOR);
+ queue_update_cost (another_allocno, start, from, divisor * COST_HOP_DIVISOR);
}
}
continue;
full_costs[j] -= conflict_costs[k];
}
- queue_update_cost (conflict_a, NULL, COST_HOP_DIVISOR);
-
+ queue_update_cost (conflict_a, conflict_a, NULL, COST_HOP_DIVISOR);
}
}
}
if (! retry_p)
{
start_update_cost ();
- queue_update_cost (a, NULL, COST_HOP_DIVISOR);
+ queue_update_cost (a, a, NULL, COST_HOP_DIVISOR);
update_conflict_hard_regno_costs (full_costs, aclass, false);
}
min_cost = min_full_cost = INT_MAX;
best_hard_regno = hard_regno;
ira_assert (hard_regno >= 0);
}
+ if (internal_flag_ira_verbose > 5 && ira_dump_file != NULL)
+ fprintf (ira_dump_file, "(%d=%d,%d) ", hard_regno, cost, full_cost);
}
if (min_full_cost > mem_cost
/* Do not spill static chain pointer pseudo when non-local goto
ira_allocno_t t2 = ALLOCNO_COLOR_DATA (a2)->first_thread_allocno;
int cl1 = ALLOCNO_CLASS (a1), cl2 = ALLOCNO_CLASS (a2);
- /* Push allocnos with minimal hard_reg_prefs first. */
- pref1 = ALLOCNO_COLOR_DATA (a1)->hard_reg_prefs;
- pref2 = ALLOCNO_COLOR_DATA (a2)->hard_reg_prefs;
- if ((diff = pref1 - pref2) != 0)
- return diff;
- /* Push allocnos with minimal conflict_allocno_hard_prefs first. */
- pref1 = ALLOCNO_COLOR_DATA (a1)->conflict_allocno_hard_prefs;
- pref2 = ALLOCNO_COLOR_DATA (a2)->conflict_allocno_hard_prefs;
- if ((diff = pref1 - pref2) != 0)
- return diff;
freq1 = ALLOCNO_COLOR_DATA (t1)->thread_freq;
freq2 = ALLOCNO_COLOR_DATA (t2)->thread_freq;
if ((diff = freq1 - freq2) != 0)
a2_num = ALLOCNO_COLOR_DATA (a2)->available_regs_num;
if ((diff = a2_num - a1_num) != 0)
return diff;
+ /* Push allocnos with minimal conflict_allocno_hard_prefs first. */
+ pref1 = ALLOCNO_COLOR_DATA (a1)->conflict_allocno_hard_prefs;
+ pref2 = ALLOCNO_COLOR_DATA (a2)->conflict_allocno_hard_prefs;
+ if ((diff = pref1 - pref2) != 0)
+ return diff;
return ALLOCNO_NUM (a2) - ALLOCNO_NUM (a1);
}