Functions |
static allocno_hard_regs_t | find_hard_regs () |
static allocno_hard_regs_t | insert_hard_regs () |
static void | init_allocno_hard_regs () |
static allocno_hard_regs_t | add_allocno_hard_regs () |
static void | finish_allocno_hard_regs () |
static int | allocno_hard_regs_compare () |
static allocno_hard_regs_node_t | create_new_allocno_hard_regs_node () |
static void | add_new_allocno_hard_regs_node_to_forest (allocno_hard_regs_node_t *roots, allocno_hard_regs_node_t new_node) |
static void | add_allocno_hard_regs_to_forest (allocno_hard_regs_node_t *roots, allocno_hard_regs_t hv) |
static void | collect_allocno_hard_regs_cover (allocno_hard_regs_node_t first, HARD_REG_SET set) |
static void | setup_allocno_hard_regs_nodes_parent (allocno_hard_regs_node_t first, allocno_hard_regs_node_t parent) |
static allocno_hard_regs_node_t | first_common_ancestor_node (allocno_hard_regs_node_t first, allocno_hard_regs_node_t second) |
static void | print_hard_reg_set () |
static void | print_hard_regs_subforest (FILE *f, allocno_hard_regs_node_t roots, int level) |
static void | print_hard_regs_forest () |
void | ira_debug_hard_regs_forest () |
static void | remove_unused_allocno_hard_regs_nodes () |
static int | enumerate_allocno_hard_regs_nodes (allocno_hard_regs_node_t first, allocno_hard_regs_node_t parent, int start_num) |
static void | setup_allocno_hard_regs_subnode_index () |
static int | get_allocno_hard_regs_subnodes_num () |
static void | form_allocno_hard_regs_nodes_forest () |
static void | finish_allocno_hard_regs_nodes_tree () |
static void | finish_allocno_hard_regs_nodes_forest () |
static bool | setup_left_conflict_sizes_p () |
static bool | update_left_conflict_sizes_p (ira_allocno_t a, ira_allocno_t removed_a, int size) |
static bool | empty_profitable_hard_regs () |
static void | setup_profitable_hard_regs () |
static void | init_update_cost_records () |
static struct update_cost_record * | get_update_cost_record (int hard_regno, int divisor, struct update_cost_record *next) |
static void | free_update_cost_record_list () |
static void | finish_update_cost_records () |
static void | initiate_cost_update () |
static void | finish_cost_update () |
static void | start_update_cost () |
static void | queue_update_cost () |
static bool | get_next_update_cost () |
static bool | update_allocno_cost () |
static void | update_costs_from_allocno (ira_allocno_t allocno, int hard_regno, int divisor, bool decr_p, bool record_p) |
static void | update_costs_from_prefs () |
static void | update_costs_from_copies () |
static void | restore_costs_from_copies () |
static void | update_conflict_hard_regno_costs (int *costs, enum reg_class aclass, bool decr_p) |
static void | get_conflict_and_start_profitable_regs (ira_allocno_t a, bool retry_p, HARD_REG_SET *conflict_regs, HARD_REG_SET *start_profitable_regs) |
static bool | check_hard_reg_p (ira_allocno_t a, int hard_regno, HARD_REG_SET *conflict_regs, HARD_REG_SET profitable_regs) |
static int | calculate_saved_nregs () |
static bool | assign_hard_reg () |
static int | allocno_spill_priority () |
static void | add_allocno_to_bucket () |
static int | bucket_allocno_compare_func () |
static void | sort_bucket (ira_allocno_t *bucket_ptr, int(*compare_func)(const void *, const void *)) |
static void | add_allocno_to_ordered_bucket (ira_allocno_t allocno, ira_allocno_t *bucket_ptr) |
static void | delete_allocno_from_bucket () |
static void | push_allocno_to_stack () |
static void | remove_allocno_from_bucket_and_push () |
static void | push_only_colorable () |
int | ira_loop_edge_freq () |
static int | calculate_allocno_spill_cost () |
static int | allocno_spill_priority_compare () |
static int | allocno_spill_sort_compare () |
static void | push_allocnos_to_stack () |
static void | pop_allocnos_from_stack () |
static void | setup_allocno_available_regs_num () |
static void | put_allocno_into_bucket () |
static void | setup_allocno_priorities () |
static int | allocno_cost_compare_func () |
static void | improve_allocation () |
static int | allocno_priority_compare_func () |
static void | color_allocnos () |
static void | print_loop_title () |
static void | color_pass () |
static void | do_coloring () |
static void | move_spill_restore () |
static void | update_curr_costs () |
void | ira_reassign_conflict_allocnos () |
static bool | allocnos_conflict_by_live_ranges_p () |
static bool | conflict_by_live_ranges_p () |
static int | copy_freq_compare_func () |
static void | merge_allocnos () |
static bool | coalesced_allocno_conflict_p () |
static void | coalesce_allocnos () |
static int | coalesced_pseudo_reg_freq_compare () |
static int | coalesced_pseudo_reg_slot_compare () |
static void | setup_coalesced_allocno_costs_and_nums () |
static int | collect_spilled_coalesced_allocnos (int *pseudo_regnos, int n, ira_allocno_t *spilled_coalesced_allocnos) |
static bool | slot_coalesced_allocno_live_ranges_intersect_p () |
static void | setup_slot_coalesced_allocno_live_ranges () |
static bool | coalesce_spill_slots () |
void | ira_sort_regnos_for_alter_reg (int *pseudo_regnos, int n, unsigned int *reg_max_ref_width) |
void | ira_mark_allocation_change () |
void | ira_mark_memory_move_deletion () |
static bool | allocno_reload_assign () |
static int | pseudo_reg_compare () |
bool | ira_reassign_pseudos (int *spilled_pseudo_regs, int num, HARD_REG_SET bad_spill_regs, HARD_REG_SET *pseudo_forbidden_regs, HARD_REG_SET *pseudo_previous_regs, bitmap spilled) |
rtx | ira_reuse_stack_slot (int regno, unsigned int inherent_size, unsigned int total_size) |
void | ira_mark_new_stack_slot () |
static int | calculate_spill_cost (int *regnos, rtx in, rtx out, rtx insn, int *excess_pressure_live_length, int *nrefs, int *call_used_count, int *first_hard_regno) |
bool | ira_better_spill_reload_regno_p (int *regnos, int *other_regnos, rtx in, rtx out, rtx insn) |
void | ira_initiate_assign () |
void | ira_finish_assign () |
static void | color () |
static void | fast_allocation () |
void | ira_color () |
@verbatim
IRA allocation based on graph coloring. Copyright (C) 2006-2013 Free Software Foundation, Inc. Contributed by Vladimir Makarov vmaka.nosp@m.rov@.nosp@m.redha.nosp@m.t.co.nosp@m.m.
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/.
static bool assign_hard_reg |
( |
| ) |
|
|
static |
Choose a hard register for allocno A. If RETRY_P is TRUE, it means
that the function called from function
`ira_reassign_conflict_allocnos' and `allocno_reload_assign'. In
this case some allocno data are not defined or updated and we
should not touch these data. The function returns true if we
managed to assign a hard register to the allocno.
To assign a hard register, first of all we calculate all conflict
hard registers which can come from conflicting allocnos with
already assigned hard registers. After that we find first free
hard register with the minimal cost. During hard register cost
calculation we take conflict hard register costs into account to
give a chance for conflicting allocnos to get a better hard
register in the future.
If the best hard register cost is bigger than cost of memory usage
for the allocno, we don't assign a hard register to given allocno
at all.
If we assign a hard register to the allocno, we update costs of the
hard register for allocnos connected by copies to improve a chance
to coalesce insns represented by the copies when we assign hard
registers to the allocnos connected by the copies.
Take preferences of conflicting allocnos into account.
Reload can give another class so we need to check all
allocnos.
Don't process the conflict allocno twice.
Take into account preferences of allocnos connected by copies to
the conflict allocnos.
Take preferences of allocnos connected by copies into
account.
We don't care about giving callee saved registers to allocnos no
living through calls because call clobbered registers are
allocated first (it is usual practice to put them first in
REG_ALLOC_ORDER).
We need to save/restore the hard register in
epilogue/prologue. Therefore we increase the cost.
We don't need updated costs anymore:
static int bucket_allocno_compare_func |
( |
| ) |
|
|
static |
Compare two allocnos to define which allocno should be pushed first
into the coloring stack. If the return is a negative number, the
allocno given by the first parameter will be pushed first. In this
case such allocno has less priority than the second one and the
hard register will be assigned to it after assignment to the second
one. As the result of such assignment order, the second allocno
has a better chance to get the best hard register.
Push pseudos requiring less hard registers first. It means that
we will assign pseudos requiring more hard registers first
avoiding creation small holes in free hard register file into
which the pseudos requiring more hard registers can not fit.
References add_allocno_to_ordered_bucket(), bitmap_bit_p(), allocno_color_data::colorable_p, delete_allocno_from_bucket(), hard_reg_set_intersect_p(), allocno_color_data::in_graph_p, internal_flag_ira_verbose, ira_dump_file, ira_print_expanded_allocno(), allocno_color_data::profitable_hard_regs, and update_left_conflict_sizes_p().
Referenced by add_allocno_to_ordered_bucket().
static void coalesce_allocnos |
( |
| ) |
|
|
static |
The major function for aggressive allocno coalescing. We coalesce
only spilled allocnos. If some allocnos have been coalesced, we
set up flag allocno_coalesced_p.
Collect copies.
For priority coloring we coalesce allocnos only with
the same allocno class not with intersected allocno
classes as it were possible. It is done for
simplicity.
Coalesced copies, most frequently executed first.
Collect the rest of copies.
References ira_live_ranges_intersect_p(), and nr.
Referenced by coalesced_pseudo_reg_slot_compare().
static bool coalesce_spill_slots |
( |
| ) |
|
|
static |
We have coalesced allocnos involving in copies. Coalesce allocnos
further in order to share the same memory stack slot. Allocnos
representing sets of allocnos coalesced before the call are given
in array SPILLED_COALESCED_ALLOCNOS of length NUM. Return TRUE if
some allocnos were coalesced in the function.
Coalesce non-conflicting spilled allocnos preferring most
frequently used.
No coalescing: set up number for coalesced allocnos
represented by ALLOCNO.
static void color_pass |
( |
| ) |
|
|
static |
Color the allocnos inside loop (in the extreme case it can be all
of the function) given the corresponding LOOP_TREE_NODE. The
function is called for each loop during top-down traverse of the
loop tree.
Color all mentioned allocnos including transparent ones.
Process caps. They are processed just once.
Remove from processing in the next loop.
We don't need updated costs anymore:
Update costs of the corresponding allocnos (not caps) in the
subloops.
Use hard register class here. ???
??? conflict costs
We don't need updated costs anymore:
We don't need updated costs anymore:
static void improve_allocation |
( |
| ) |
|
|
static |
We used Chaitin-Briggs coloring to assign as many pseudos as
possible to hard registers. Let us try to improve allocation with
cost point of view. This function improves the allocation by
spilling some allocnos and assigning the freed hard registers to
other allocnos if it decreases the overall allocation cost.
Clear counts used to process conflicting allocnos only once for
each allocno.
Process each allocno and try to assign a hard register to it by
spilling some its conflicting allocnos.
It means that assigning a hard register is not profitable
(we don't waste memory for hard register costs in this
case).
Set up cost improvement for usage of each profitable hard
register for allocno A.
There is no chance to improve the allocation cost by
assigning hard register to allocno A even without spilling
conflicting allocnos.
Process each allocno conflicting with A and update the cost
improvement for profitable hard registers of A. To use a
hard register for A we need to spill some conflicting
allocnos and that creates penalty for the cost
improvement.
We already processed this conflicting allocno
because we processed earlier another object of the
conflicting allocno.
Now we choose hard register for A which results in highest
allocation cost improvement.
We are in a situation when assigning any hard register to A
by spilling some conflicting allocnos does not improve the
allocation cost.
Now spill conflicting allocnos which contain a hard register
of A when we assign the best chosen hard register to it.
No intersection.
Assign the best chosen hard register to A.
We spilled some allocnos to assign their hard registers to other
allocnos. The spilled allocnos are now in array
'sorted_allocnos'. There is still a possibility that some of the
spilled allocnos can get hard registers. So let us try assign
them hard registers again (just a reminder -- function
'assign_hard_reg' assigns hard registers only if it is possible
and profitable). We process the spilled allocnos with biggest
benefit to get hard register first -- see function
'allocno_cost_compare_func'.
void ira_reassign_conflict_allocnos |
( |
| ) |
|
Try to assign hard registers to the unassigned allocnos and
allocnos conflicting with them or conflicting with allocnos whose
regno >= START_REGNO. The function is called after ira_flattening,
so more allocnos (including ones created in ira-emit.c) will have a
chance to get a hard register. We use simple assignment algorithm
based on priorities.
References first, last, and coalesce_data::next.
Referenced by move_unallocated_pseudos().
Try to allocate hard registers to SPILLED_PSEUDO_REGS (there are
NUM of them) or spilled pseudos conflicting with pseudos in
SPILLED_PSEUDO_REGS. Return TRUE and update SPILLED, if the
allocation has been changed. The function doesn't use
BAD_SPILL_REGS and hard registers in PSEUDO_FORBIDDEN_REGS and
PSEUDO_PREVIOUS_REGS for the corresponding pseudos. The function
is called by the reload pass at the end of each reload
iteration.
Add pseudos which conflict with pseudos already in
SPILLED_PSEUDO_REGS to SPILLED_PSEUDO_REGS. This is preferable
to allocating in two steps as some of the conflicts might have
a higher priority than the pseudos passed in SPILLED_PSEUDO_REGS.
?!? This seems wrong.
Try to assign hard registers to pseudos from
SPILLED_PSEUDO_REGS.
References find_regno_note(), ira_regno_allocno_map, REG_N_REFS(), and reg_renumber.
rtx ira_reuse_stack_slot |
( |
int |
regno, |
|
|
unsigned int |
inherent_size, |
|
|
unsigned int |
total_size |
|
) |
| |
The function is called by reload and returns already allocated
stack slot (if any) for REGNO with given INHERENT_SIZE and
TOTAL_SIZE. In the case of failure to find a slot which can be
used for REGNO, the function returns NULL.
It means that the pseudo was spilled in the reload pass, try
to reuse a slot.
References initiate_cost_update(), ira_allocate(), ira_allocate_bitmap(), and ira_allocnos_num.
void ira_sort_regnos_for_alter_reg |
( |
int * |
pseudo_regnos, |
|
|
int |
n, |
|
|
unsigned int * |
reg_max_ref_width |
|
) |
| |
Sort pseudo-register numbers in array PSEUDO_REGNOS of length N for
subsequent assigning stack slots to them in the reload pass. To do
this we coalesce spilled allocnos first to decrease the number of
memory-memory move insns. This function is called by the
reload.
Set up allocnos can be coalesced.
Initialize coalesce data for allocnos.
Sort regnos according frequencies of the corresponding coalesced
allocno sets.
Collect allocnos representing the spilled coalesced allocno
sets.
Assign stack slot numbers to spilled allocno sets, use smaller
numbers for most frequently used coalesced allocnos. -1 is
reserved for dynamic search of stack slots for pseudos spilled by
the reload.
Sort regnos according the slot numbers.
static void move_spill_restore |
( |
| ) |
|
|
static |
Move spill/restore code, which are to be generated in ira-emit.c,
to less frequent points (if it is profitable) by reassigning some
allocnos (in loop with subloops containing in another loop) to
memory which results in longer live-range where the corresponding
pseudo-registers will be in memory.
don't do the optimization because it can create
copies and the reload pass can spill the allocno set
by copy although the allocno will not get memory
slot.
We have accumulated cost. To get the real cost of
allocno usage in the loop we should subtract costs of
the subloop allocnos.
static void push_allocnos_to_stack |
( |
| ) |
|
|
static |
Push allocnos to the coloring stack. The order of allocnos in the
stack defines the order for the subsequent coloring.
Calculate uncolorable allocno spill costs.
??? Remove cost of copies between the coalesced
allocnos.
References floor_log2(), and priority().
static void setup_profitable_hard_regs |
( |
| ) |
|
|
static |
Set up profitable hard registers for each allocno being
colored.
Initial set up from allocno classes and explicitly conflicting
hard regs.
Exclude hard regs already assigned for conflicting objects.
We can process the conflict allocno repeatedly with
the same result.
Exclude too costly hard regs.
This page contains code to coalesce memory stack slots used by
spilled allocnos. This results in smaller stack frame, better data
locality, and in smaller code for some architectures like
x86/x86_64 where insn size depends on address displacement value.
On the other hand, it can worsen insn scheduling after the RA but
in practice it is less important than smaller stack frames.
TRUE if we coalesced some allocnos. In other words, if we got
loops formed by members first_coalesced_allocno and
next_coalesced_allocno containing more one allocno.