[initial ira-improv merge in r171649 ] gcc/ 2011-03-28 Vladimir Makarov * ira-color.c (update_left_conflict_sizes_p): Don't assume that conflict object hard regset nodes have intersecting hard reg sets. * regmove.c (regmove_optimize): Move ira_set_pseudo_classes call after regstat_init_n_sets_and_refs. * ira.c: Add more comments at the top. (setup_stack_reg_pressure_class, setup_pressure_classes): Add comments how we compute the register pressure classes. (setup_allocno_and_important_classes): Add more comments. (setup_class_translate_array, reorder_important_classes) (setup_reg_class_relations): Add comments. * ira-emit.c: Add 2011 to the Copyright line. Add comments at the start of the file. * ira-color.c: Add 2011 to the Copyright line. (assign_hard_reg): Add more comments. (improve_allocation): Ditto. * ira-costs.c: Add 2011 to the Copyright line. (setup_cost_classes, setup_regno_cost_classes_by_aclass): Add more comments. (setup_regno_cost_classes_by_mode): Ditto. Initial patches from ira-improv branch: 2010-08-13 Vladimir Makarov * ira-build.c: (ira_create_object): Remove initialization of OBJECT_PROFITABLE_HARD_REGS. Initialize OBJECT_ADD_DATA. (ira_create_allocno): Remove initialization of ALLOCNO_MEM_OPTIMIZED_DEST, ALLOCNO_MEM_OPTIMIZED_DEST_P, ALLOCNO_SOMEWHERE_RENAMED_P, ALLOCNO_CHILD_RENAMED_P, ALLOCNO_IN_GRAPH_P, ALLOCNO_MAY_BE_SPILLED_P, ALLOCNO_COLORABLE_P, ALLOCNO_NEXT_BUCKET_ALLOCNO, ALLOCNO_PREV_BUCKET_ALLOCNO, ALLOCNO_FIRST_COALESCED_ALLOCNO, ALLOCNO_NEXT_COALESCED_ALLOCNO. Initialize ALLOCNO_ADD_DATA. (copy_info_to_removed_store_destinations): Use ALLOCNO_EMIT_DATA and allocno_emit_reg instead of ALLOCNO_MEM_OPTIMIZED_DEST_P and ALLOCNO_REG. (ira_flattening): Ditto. Use ALLOCNO_EMIT_DATA instead of ALLOCNO_MEM_OPTIMIZED_DEST and ALLOCNO_SOMEWHERE_RENAMED_P. * ira.c (ira_reallocate): Remove. (setup_pressure_classes): Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost instead of ira_get_register_move_cost. (setup_allocno_assignment_flags): Use ALLOCNO_EMIT_DATA. (ira): Call ira_initiate_emit_data and ira_finish_emit_data. * ira-color.c: Use ALLOCNO_COLOR_DATA instead of ALLOCNO_IN_GRAPH_P, ALLOCNO_MAY_BE_SPILLED_P, ALLOCNO_COLORABLE_P, ALLOCNO_AVAILABLE_REGS_NUM, ALLOCNO_NEXT_BUCKET_ALLOCNO, ALLOCNO_PREV_BUCKET_ALLOCNO. ALLOCNO_TEMP. Use OBJECT_COLOR_DATA instead of OBJECT_PROFITABLE_HARD_REGS, OBJECT_HARD_REGS_NODE, OBJECT_HARD_REGS_SUBNODES_START, OBJECT_HARD_REGS_SUBNODES_NUM. Fix formatting. (object_hard_regs_t, object_hard_regs_node_t): Move from ira-int.h. (struct object_hard_regs, struct object_hard_regs_node): Ditto. (struct allocno_color_data): New. (allocno_color_data_t): New typedef. (allocno_color_data): New definition. (ALLOCNO_COLOR_DATA): New macro. (struct object_color_data): New. (object_color_data_t): New typedef. (object_color_data): New definition. (OBJECT_COLOR_DATA): New macro. (update_copy_costs, calculate_allocno_spill_cost): Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost instead of ira_get_register_move_cost. (move_spill_restore, update_curr_costs): Ditto. (allocno_spill_priority): Make it inline. (color_pass): Allocate and free allocno_color_dat and object_color_data. (struct coalesce_data, coalesce_data_t): New. (allocno_coalesce_data): New definition. (ALLOCNO_COALESCE_DATA): New macro. (merge_allocnos, coalesced_allocno_conflict_p): Use ALLOCNO_COALESCED_DATA instead of ALLOCNO_FIRST_COALESCED_ALLOCNO, ALLOCNO_NEXT_COALESCED_ALLOCNO, ALLOCNO_TEMP. (coalesce_allocnos): Ditto. (setup_coalesced_allocno_costs_and_nums): Ditto. (collect_spilled_coalesced_allocnos): Ditto. (slot_coalesced_allocno_live_ranges_intersect_p): Ditto. (setup_slot_coalesced_allocno_live_ranges): Ditto. (coalesce_spill_slots): Ditto. (ira_sort_regnos_for_alter_reg): Ditto. Allocate, initialize and free allocno_coalesce_data. * ira-conflicts.c: Fix formatting. (process_regs_for_copy): Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost instead of ira_get_register_move_cost. (build_object_conflicts): Optimize. * ira-costs.c (record_reg_classes): Optimize. Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost, ira_may_move_in_cost, and ira_may_move_out_cost instead of ira_get_register_move_cost and ira_get_may_move_cost. (record_address_regs): Ditto. (scan_one_insn): Optimize. (find_costs_and_classes): Optimize. (process_bb_node_for_hard_reg_moves): Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost instead of ira_get_register_move_cost. * ira-emit.c: Use allocno_emit_reg, ALLOCNO_EMIT_DATA instead of ALLOCNO_REG, ALLOCNO_CHILD_RENAMED_P, ALLOCNO_MEM_OPTIMIZED_DEST, ALLOCNO_MEM_OPTIMIZED_DEST_P, and ALLOCNO_SOMEWHERE_RENAMED_P. (ira_allocno_emit_data, void_p, new_allocno_emit_data_vec): New definitions. (ira_initiate_emit_data, ira_finish_emit_data) (create_new_allocno): New functions. (modify_move_list): Call create_new_alloc instead of ira_create_allocno. (emit_move_list): Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost instead of ira_get_register_move_cost. * ira-int.h: Fix some comments. (object_hard_regs_t, object_hard_regs_node_t): Move to ira-color.c. (struct object_hard_regs, struct object_hard_regs_node): Ditto. (struct ira_object): Remove profitable_hard_regs, hard_regs_node, hard_regs_subnodes_start, hard_regs_subnodes_num. Add new member add_data. (struct ira_allocno): Make mode and aclass a bitfield. Move other bitfield after mode. Make hard_regno a short int. Make hard_regno short. Remove first_coalesced_allocno and next_coalesced_allocno. Move mem_optimized_dest_p, somewhere_renamed_p, child_renamed_p, reg, and mem_optimized_dest into struct ira_emit_data. Remove in_graph_p, may_be_spilled_p, available_regs_num, next_bucket_allocno, prev_bucket_allocno, temp, colorable_p. Add new member add_data. (ALLOCNO_IN_GRAPH_P, ALLOCNO_MAY_BE_SPILLED_P): Remove. (ALLOCNO_COLORABLE_P, ALLOCNO_AVAILABLE_REGS_NUM): Remove. (ALLOCNO_NEXT_BUCKET_ALLOCNO, ALLOCNO_PREV_BUCKET_ALLOCNO): Remove. (ALLOCNO_TEMP, ALLOCNO_FIRST_COALESCED_ALLOCNO): Remove. (ALLOCNO_NEXT_COALESCED_ALLOCNO): Remove. (ALLOCNO_ADD_DATA): New macro. (ira_emit_data_t): New typedef. (struct ira_emit_data): New. Move mem_optimized_dest_p, somewhere_renamed_p, child_renamed_p, reg, mem_optimized_dest from struct ira_allocno. (ALLOCNO_EMIT_DATA): New macro. (ira_allocno_emit_data, allocno_emit_reg): New. (ALLOCNO_PROFITABLE_HARD_REGS, OBJECT_HARD_REGS_NODE): Remove. (OBJECT_HARD_REGS_SUBNODES_STAR, OBJECT_HARD_REGS_SUBNODES_NUM): Remove. (OBJECT_ADD_DATA): New macro. (ira_reallocate): Remove. (ira_initiate_emit_data, ira_finish_emit_data): New. (ira_get_register_move_cost, ira_get_may_move_cost): Remove. (ira_init_register_move_cost_if_necessary): New. (ira_object_conflict_iter_next): Merge into ira_object_conflict_iter_cond. (FOR_EACH_OBJECT_CONFLICT): Don't use ira_object_conflict_iter_next. * ira-live.c: (process_single_reg_class_operands): Call ira_init_register_move_cost_if_necessary. Use ira_register_move_cost instead of ira_get_register_move_cost. 2010-08-13 Vladimir Makarov * ira-int.h (struct target_ira_int): Remove x_cost_classes. * ira-costs.c: Fix formatting. (cost_classes, cost_classes_num): Remove. (struct cost_classes, cost_classes_t, const_cost_classes_t): New. (regno_cost_classes, cost_classes_hash, cost_classes_eq): New. (cost_classes_del, cost_classes_htab): New. (cost_classes_aclass_cache, cost_classes_mode_cache): New. (initiate_regno_cost_classes, setup_cost_classes): New. (setup_regno_cost_classes_by_aclass): New. (setup_regno_cost_classes_by_mode, finish_regno_cost_classes): New. (record_reg_classes): Use regno_cost_classes instead of cost_classes. Move checking opposite operand up. (record_address_regs): Use regno_cost_classes instead of cost_classes. (scan_one_insn): Ditto. Use always general register. (print_allocno_costs): Use regno_cost_classes instead of cost_classes. (print_pseudo_costs): Ditto. Use Reg_N_REFS. (find_costs_and_classes): Set up cost classes for each registers. Use also their mode for this. Use regno_cost_classes instead of cost_classes. (setup_allocno_class_and_costs): Use regno_cost_classes instead of cost_classes. (free_ira_costs, ira_init_costs): Don't use cost_classes. (ira_costs, ira_set_pseudo_classes): Call initiate_regno_cost_classes and finish_regno_cost_classes. 2010-10-04 Vladimir Makarov * target-def.h (TARGET_IRA_COVER_CLASSES): Remove. * target.def (ira_cover_classes): Remove. * doc/tm.texi: Remove TARGET_IRA_COVER_CLASSES and IRA_COVER_CLASSES. * doc/tm.texi.in: Ditto. * ira-conflicts.c: Remove mentioning cover classes from the file. Use ALLOCNO_CLASS instead of ALLOCNO_COVER_CLASS. Use ALLOCNO_COVER_CLASS_COST instead of ALLOCNO_CLASS_COST. Fix formatting. * targhooks.c (default_ira_cover_classes): Remove. * targhooks.h (default_ira_cover_classes): Ditto. * haifa-sched.c: Remove mentioning cover classes from the file. Use ira_reg_pressure_cover instead of ira_reg_class_cover. Use ira_pressure_classes and ira_pressure_classes_num instead of ira_reg_class_cover_size and ira_reg_class_cover. Use sched_regno_pressure_class instead of sched_regno_cover_class. (mark_regno_birth_or_death, setup_insn_reg_pressure_info): Use ira_reg_class_max_nregs instead of ira_reg_class_nregs. * ira-int.h: Add 2010 to Copyright. Remove mentioning cover classes from the file. (object_hard_regs_t, object_hard_regs_node_t): New typedefs. (struct object_hard_regs, struct object_hard_regs_node): New. (struct ira_object): New members profitable_hard_regs, hard_regs_node, hard_regs_subnodes_start, hard_regs_subnodes_num. (struct ira_allocno): Rename cover_class to aclass. Rename cover_class_cost and updated_cover_class_cost to class_cost and updated_class_cost. Remove splay_removed_p and left_conflict_size. Add new members colorable_p. (ALLOCNO_SPLAY_REMOVED_P, ALLOCNO_LEFT_CONFLICTS_SIZE): Remove. (ALLOCNO_COLORABLE_P): New macro. (ALLOCNO_COVER_CLASS): Rename to ALLOCNO_CLASS. (ALLOCNO_COVER_CLASS_COST, ALLOCNO_UPDATED_COVER_CLASS_COST): Rename to ALLOCNO_CLASS_COST and ALLOCNO_UPDATED__CLASS_COST. (OBJECT_...): Rename parameter C to O. (OBJECT_PROFITABLE_HARD_REGS): New macro. (OBJECT_HARD_REGS_NODE, OBJECT_HARD_REGS_SUBNODES_START) (OBJECT_HARD_REGS_SUBNODES_NUM): New macros. (struct target_ira_int): New members x_ira_max_memory_move_cost, x_ira_max_register_move_cost, x_ira_max_may_move_in_cost, x_ira_max_may_move_out_cost, x_ira_reg_allocno_class_p, x_ira_reg_pressure_class_p, x_ira_important_class_nums, x_ira_reg_class_superunion. Rename x_prohibited_class_mode_reg to x_ira_prohibited_class_mode_reg. Rename x_ira_reg_class_union to x_ira_reg_class_subunion. (ira_max_memory_move_cost, ira_max_register_move_cost) (ira_max_may_move_in_cost, ira_max_may_move_out_cost) (ira_reg_allocno_class_p, ira_reg_pressure_class_p) (ira_important_class_nums, ira_reg_class_superunion): New macros. (prohibited_class_mode_regs): Rename to ira_prohibited_class_mode_regs. (ira_reg_class_union): Rename to ira_reg_class_subunion. (ira_debug_class_cover): Rename to ira_debug_allocno_classes. (ira_set_allocno_cover_class): Rename to ira_set_allocno_class. (ira_tune_allocno_costs_and_cover_classes): Rename to ira_tune_allocno_costs. (ira_debug_hard_regs_forest): New. (ira_object_conflict_iter_init, ira_object_conflict_iter_cond) (ira_object_conflict_iter_next): Fix comments. (ira_hard_reg_set_intersection_p, hard_reg_set_size): New functions. (ira_allocate_and_set_costs, ira_allocate_and_copy_costs): Rename cover_class to aclass. (ira_allocate_and_accumulate_costs): Ditto. (ira_allocate_and_set_or_copy_costs): Ditto. * opts.c (decode_options): Remove ira_cover_class check. * ira-color.c: Remove mentioning cover classes from the file. Use ALLOCNO_CLASS, ALLOCNO_CLASS_COST, and ALLOCNO_UPDATED_CLASS_COST instead of ALLOCNO_COVER_CLASS, ALLOCNO_COVER_CLASS_COST, and ALLOCNO_UPDATED_COVER_CLASS_COST. Fix formatting. (splay-tree.h): Remove include. (allocno_coalesced_p, processed_coalesced_allocno_bitmap): Move before copy_freq_compare_func. (allocnos_for_spilling, removed_splay_allocno_vec): Remove. (object_hard_regs_vec, object_hard_regs_htab, node_check_tick): New definitions. (hard_regs_roots, hard_regs_node_vec): Ditto. (object_hard_regs_hash, object_hard_regs_eq, find_hard_regs): Ditto. (insert_hard_regs, init_object_hard_regs, add_object_hard_regs): Ditto. (finish_object_hard_regs, object_hard_regs_compare): Ditto. (create_new_object_hard_regs_node): Ditto. (add_new_object_hard_regs_node_to_forest): Ditto. (add_object_hard_regs_to_forest, collect_object_hard_regs_cover): Ditto. (setup_object_hard_regs_nodes_parent, first_common_ancestor_node): Ditto. (print_hard_reg_set, print_hard_regs_subforest): Ditto. (print_hard_regs_forest, ira_debug_hard_regs_forest): Ditto. (remove_unused_object_hard_regs_nodes): Ditto. (enumerate_object_hard_regs_nodes): Ditto. (object_hard_regs_nodes_num, object_hard_regs_nodes): Ditto. (object_hard_regs_subnode_t): Ditto. (struct object_hard_regs_subnode): Ditto. (object_hard_regs_subnodes, object_hard_regs_subnode_index): Ditto. (setup_object_hard_regs_subnode_index): Ditto. (get_object_hard_regs_subnodes_num): Ditto. (form_object_hard_regs_nodes_forest): Ditto. (finish_object_hard_regs_nodes_tree): Ditto. (finish_object_hard_regs_nodes_forest): Ditto. (allocnos_have_intersected_live_ranges_p): Rename to allocnos_conflict_by_live_ranges_p. Move before copy_freq_compare_func. (pseudos_have_intersected_live_ranges_p): Rename to conflict_by_live_ranges_p. Move before copy_freq_compare_func. (setup_left_conflict_sizes_p, update_left_conflict_sizes_p): Ditto. (empty_profitable_hard_regs, setup_profitable_hard_regs): Ditto. (update_copy_costs): Remove assert. Skip cost update if the hard reg does not belong the class. (assign_hard_reg): Process only profitable hard regs. (uncolorable_allocnos_num): Make it scalar. (allocno_spill_priority): Use ALLOCNO_EXCESS_PRESSURE_POINTS_NUM and ira_reg_class_max_nregs instead of ALLOCNO_LEFT_CONFLICTS_SIZE and ira_reg_class_max_nregs. (bucket_allocno_compare_func): Check frequency first. (sort_bucket): Add compare function as a parameter. (add_allocno_to_ordered_bucket): Assume no coalesced allocnos. (uncolorable_allocnos_splay_tree, USE_SPLAY_P): Remove. (push_allocno_to_stack): Rewrite for checking new allocno colorability. (remove_allocno_from_bucket_and_push): Print cost too. Remove assert. (push_only_colorable): Pass new parameter to sort_bucket. (push_allocno_to_spill): Remove. (allocno_spill_priority_compare): Make it inline and rewrite. (splay_tree_allocate, splay_tree_free): Remove. (allocno_spill_sort_compare): New function. (push_allocnos_to_stack): Sort allocnos for spilling once. Don't build and use splay tree. Choose first allocno in uncolorable allocno bucket to spill. Remove setting spill cost. (all_conflicting_hard_regs): Remove. (setup_allocno_available_regs_num): Check only profitable hard regs. Print info about hard regs nodes. (setup_allocno_left_conflicts_size): Remove. (put_allocno_into_bucket): Don't call setup_allocno_left_conflicts_size. Use setup_left_conflict_sizes_p. (improve_allocation): New. (color_allocnos): Call setup_profitable_hard_regs, form_object_hard_regs_nodes_forest, improve_allocation, finish_object_hard_regs_nodes_forest. Setup spill cost. (print_loop_title): Use pressure classes. (color_allocnso): Ditto. (do_coloring): Remove allocation and freeing splay_tree_node_pool and allocnos_for_spilling. (ira_sort_regnos_for_alter_reg): Don't setup members {first,next}_coalesced_allocno. (color): Remove allocating and freeing removed_splay_allocno_vec. (fast_allocation): Use ira_prohibited_class_mode_regs instead of prohibited_class_mode_regs. * ira-lives.c: Remove mentioning cover classes from the file. Fix formatting. (update_allocno_pressure_excess_length): Use pressure classes. (inc_register_pressure, dec_register_pressure): Check for pressure class. (mark_pseudo_regno_live, mark_pseudo_regno_subword_live): Use pressure class. Use ira_reg_class_nregs instead of ira_reg_class_max_nregs. (mark_pseudo_regno_dead, mark_pseudo_regno_subword_dead): Ditto. (mark_hard_reg_live, mark_hard_reg_dead): Use pressure class. (single_reg_class): Use ira_reg_class_nregs instead of ira_reg_class_max_nregs. (process_bb_node_lives): Use pressure classes. * ira-emit.c: Remove mentioning cover classes from the file. Use ALLOCNO_CLASS instead of ALLOCNO_COVER_CLASS. Fix formatting. (change_loop): Use pressure classes. (modify_move_list): Call ira_set_allocno_class instead of ira_set_allocno_cover_class. * ira-build.c: Remove mentioning cover classes from the file. Use ALLOCNO_CLASS and ALLOCNO_CLASS_COST instead of ALLOCNO_COVER_CLASS and ALLOCNO_COVER_CLASS_COST. Use ALLOCNO_UPDATED_CLASS_COST instead of ALLOCNO_UPDATED_COVER_CLASS_COST. Fix formatting. (ira_create_object): Initiate OBJECT_PROFITABLE_HARD_REGS. (ira_create_allocno): Remove initialization of ALLOCNO_SPLAY_REMOVED_P, ALLOCNO_LEFT_CONFLICT_SIZE. Initialize ALLOCNO_COLORABLE_P. (ira_set_allocno_cover_class): Rename to ira_set_allocno_class. Update conflict regs for the objects. (create_cap_allocno): Remove assert. Don't propagate ALLOCNO_AVAILABLE_REGS_NUM. (ira_free_allocno_costs): New function. (finish_allocno): Change a part of code into call of ira_free_allocno_costs. (low_pressure_loop_node_p): Use pressure classes. (object_range_compare_func): Don't compare classes. (setup_min_max_conflict_allocno_ids): Ditto. * loop-invariant.c: Remove mentioning cover classes from the file. Use ira_pressure_classes and ira_pressure_classes_num instead of ira_reg_class_cover_size and ira_reg_class_cover. Fix formatting. (get_cover_class_and_nregs): Rename to get_cover_pressure_and_nregs. Use ira_reg_class_max_nregs instead of ira_reg_class_nregs. Use reg_allocno_class instead of reg_cover_class. (get_inv_cost): Use instead ira_stack_reg_pressure_class of STACK_REG_COVER_CLASS. (get_regno_cover_class): Rename to get_regno_pressure_class. (move_loop_invariants): Initialize and finalize regstat. * ira.c: Remove mentioning cover classes from the file. Add comments about coloring without cover classes. Use ALLOCNO_CLASS instead of ALLOCNO_COVER_CLASS. Fix formatting. (alloc_reg_class_subclasses, setup_reg_subclasses): Move it before setup_class_subset_and_memory_move_costs. (setup_stack_reg_pressure_class, setup_pressure_classes): New. (setup_cover_and_important_classes): Rename to setup_allocno_and_important_classes. (setup_class_translate_array): New. (setup_class_translate): Call it for allocno and pressure classes. (cover_class_order): Rename to allocno_class_order. (comp_reg_classes_func): Use ira_allocno_class_translate instead of ira_class_translate. (reorder_important_classes): Set up ira_important_class_nums. (setup_reg_class_relations): Set up ira_reg_class_superunion. (print_class_cover): Rename to print_classes. Add parameter. (ira_debug_class_cover): Rename to ira_debug_allocno_classes. Print pressure classes too. (find_reg_class_closure): Rename to find_reg_classes. Don't call setup_reg_subclasses. (ira_hard_regno_cover_class): Rename to ira_hard_regno_allocno_class. (ira_reg_class_nregs): Rename to ira_reg_class_max_nregs. (setup_prohibited_class_mode_regs): Use ira_prohibited_class_mode_regs instead of prohibited_class_mode_regs. (clarify_prohibited_class_mode_regs): New function. (ira_init_register_move_cost): Set up ira_max_register_move_cost, ira_max_may_move_in_cost, and ira_max_may_move_out_cost. (ira_init_once): Initialize them. (free_register_move_costs): Process them. (ira_init): Move calls of find_reg_classes and setup_hard_regno_aclass after setup_prohibited_class_mode_regs. Call clarify_prohibited_class_mode_regs. (ira_no_alloc_reg): Remove. (too_high_register_pressure_p): Use pressure classes. * sched-deps.c: Remove mentioning cover classes from the file. Use ira_reg_pressure_cover instead of ira_reg_class_cover. Use ira_pressure_classes and ira_pressure_classes_num instead of ira_reg_class_cover_size and ira_reg_class_cover. (mark_insn_hard_regno_birth, mark_hard_regno_death): Use sched_regno_pressure_class instead of sched_regno_cover_class. (mark_insn_pseudo_birth, mark_pseudo_death): Ditto. Use ira_reg_class_max_nregs instead of ira_reg_class_nregs. * ira.h: Add 2010 to Copyright. (ira_no_alloc_reg): Remove external. (struct target_ira): Rename x_ira_hard_regno_cover_class, x_ira_reg_class_cover_size, x_ira_reg_class_cover, and x_ira_class_translate to x_ira_hard_regno_allocno_class, x_ira_allocno_classes_num, x_ira_allocno_classes, and x_ira_allocno_class_translate. Add x_ira_pressure_classes_num, x_ira_pressure_classes, x_ira_pressure_class_translate, and x_ira_stack_reg_pressure_class. Rename x_ira_reg_class_nregs to x_ira_reg_class_max_nregs. Add x_ira_reg_class_min_nregs and x_ira_no_alloc_regs. (ira_hard_regno_cover_class): Rename to ira_hard_regno_allocno_class. (ira_reg_class_cover_size, ira_reg_class_cover): Rename to ira_allocno_classes_num and ira_allocno_classes. (ira_class_translate): Rename to ira_allocno_class_translate. (ira_pressure_classes_num, ira_pressure_classes): New definitions. (ira_pressure_class_translate, ira_stack_reg_pressure_class): Ditto. (ira_reg_class_nregs): Rename to ira_reg_class_max_nregs. (ira_reg_class_min_nregs, ira_stack_reg_pressure_class): New (ira_no_alloc_regs): New. * ira-costs.c: Add 2010 to Copyright. Remove mentioning cover classes from the file. Use ALLOCNO_CLASS instead of ALLOCNO_COVER_CLASS. Use ALLOCNO_CLASS_COST instead of ALLOCNO_COVER_CLASS_COST. (regno_cover_class): Rename to regno_aclass. (record_reg_classes): Use ira_reg_class_subunion instead of ira_reg_class_union. (record_address_regs): Check overflow. (scan_one_insn): Ditto. (print_allocno_costs): Print total mem cost fore regional allocation. (print_pseudo_costs): Use REG_N_REFS. (find_costs_and_classes): Use classes intersected with them on the 1st pass. Check overflow. Use ira_reg_class_subunion instead of ira_reg_class_union. Use ira_allocno_class_translate and regno_aclass instead of ira_class_translate and regno_cover_class. Modify code for finding regno_aclass. Setup preferred classes for the next pass. (setup_allocno_cover_class_and_costs): Rename to setup_allocno_class_and_costs. Use regno_aclass instead of regno_cover_class. Use ira_set_allocno_class instead of ira_set_allocno_cover_class. (init_costs, finish_costs): Use regno_aclass instead of regno_cover_class. (ira_costs): Use setup_allocno_class_and_costs instead of setup_allocno_cover_class_and_costs. (ira_tune_allocno_costs_and_cover_classes): Rename to ira_tune_allocno_costs. Check overflow. Skip conflict hard regs by processing objects. Use ira_reg_class_max_nregs instead of ira_reg_class_nregs. * rtl.h (reg_cover_class): Rename to reg_allocno_class. * sched-int.h: Remove mentioning cover classes from the file. (sched_regno_cover_class): Rename to sched_regno_pressure_class. * reginfo.c: Add 2010 to Copyright. Remove mentioning cover classes from the file. (struct reg_pref): Rename coverclass into allocnoclass. (reg_cover_class): Rename to reg_allocno_class. * Makefile.in (ira-color.o): Remove SPLAY_TREE_H from dependencies. * config/alpha/alpha.h (IRA_COVER_CLASSES): Remove. * config/arm/arm.h (IRA_COVER_CLASSES): Ditto. * config/avr/avr.h (IRA_COVER_CLASSES): Ditto. * config/bfin/bfin.h (IRA_COVER_CLASSES): Ditto. * config/cris/cris.h (IRA_COVER_CLASSES): Ditto. * config/fr30/fr30.h (IRA_COVER_CLASSES): Ditto. * config/frv/frv.h (IRA_COVER_CLASSES): Ditto. * config/h8300/h8300.h (IRA_COVER_CLASSES): Ditto. * config/i386/i386.h (STACK_REG_COVER_CLASS): Ditto. * config/i386/i386.c (TARGET_IRA_COVER_CLASSES) (i386_ira_cover_classes): Ditto. * config/ia64/ia64.h (IRA_COVER_CLASSES): Ditto. * config/iq2000/iq2000.h (IRA_COVER_CLASSES): Ditto. * config/m32r/m32r.h (IRA_COVER_CLASSES): Ditto. * config/m68k/m68k.h (IRA_COVER_CLASSES): Ditto. * config/mcore/mcore.h (IRA_COVER_CLASSES): Ditto. * config/mep/mep.h (IRA_COVER_CLASSES): Ditto. * config/mips/mips.c (TARGET_IRA_COVER_CLASSES) (mips_ira_cover_classes): Ditto. * config/mn10300/mn10300.h (IRA_COVER_CLASSES): Ditto. * config/moxie/moxie.h (IRA_COVER_CLASSES): Ditto. * config/pa/pa64-regs.h (IRA_COVER_CLASSES): Ditto. * config/pa/pa32-regs.h (IRA_COVER_CLASSES): Ditto. * config/picochip/picochip.h (IRA_COVER_CLASSES): Ditto. * config/rs6000/rs6000.h (IRA_COVER_CLASSES_PRE_VSX) (IRA_COVER_CLASSES_VSX): Ditto. * config/rs6000/rs6000.c (TARGET_IRA_COVER_CLASSES) (rs6000_ira_cover_classes): Ditto. * config/rx/rx.h (IRA_COVER_CLASSES): Ditto. * config/s390/s390.h (IRA_COVER_CLASSES): Ditto. * config/score/score.h (IRA_COVER_CLASSES): Ditto. * config/sh/sh.h (IRA_COVER_CLASSES): Ditto. * config/sparc/sparc.h (IRA_COVER_CLASSES): Ditto. * config/spu/spu.h (IRA_COVER_CLASSES): Ditto. * config/stormy16/stormy16.h (IRA_COVER_CLASSES): Ditto. * config/v850/v850.h (IRA_COVER_CLASSES): Ditto. * config/vax/vax.h (IRA_COVER_CLASSES): Ditto. * config/xtensa/xtensa.h (IRA_COVER_CLASSES): Ditto. Index: gcc-4.7-r171648/gcc/doc/tm.texi =================================================================== --- gcc-4.7-r171648/gcc/doc/tm.texi (revision 171648) +++ gcc-4.7-r171648/gcc/doc/tm.texi (revision 171649) @@ -2854,36 +2854,6 @@ as below: @end smallexample @end defmac -@deftypefn {Target Hook} {const reg_class_t *} TARGET_IRA_COVER_CLASSES (void) -Return an array of cover classes for the Integrated Register Allocator -(@acronym{IRA}). Cover classes are a set of non-intersecting register -classes covering all hard registers used for register allocation -purposes. If a move between two registers in the same cover class is -possible, it should be cheaper than a load or store of the registers. -The array is terminated by a @code{LIM_REG_CLASSES} element. - -The order of cover classes in the array is important. If two classes -have the same cost of usage for a pseudo, the class occurred first in -the array is chosen for the pseudo. - -This hook is called once at compiler startup, after the command-line -options have been processed. It is then re-examined by every call to -@code{target_reinit}. - -The default implementation returns @code{IRA_COVER_CLASSES}, if defined, -otherwise there is no default implementation. You must define either this -macro or @code{IRA_COVER_CLASSES} in order to use the integrated register -allocator with Chaitin-Briggs coloring. If the macro is not defined, -the only available coloring algorithm is Chow's priority coloring. - -This hook must not be modified from @code{NULL} to non-@code{NULL} or -vice versa by command-line option processing. -@end deftypefn - -@defmac IRA_COVER_CLASSES -See the documentation for @code{TARGET_IRA_COVER_CLASSES}. -@end defmac - @node Old Constraints @section Obsolete Macros for Defining Constraints @cindex defining constraints, obsolete method Index: gcc-4.7-r171648/gcc/doc/tm.texi.in =================================================================== --- gcc-4.7-r171648/gcc/doc/tm.texi.in (revision 171648) +++ gcc-4.7-r171648/gcc/doc/tm.texi.in (revision 171649) @@ -2842,36 +2842,6 @@ as below: @end smallexample @end defmac -@hook TARGET_IRA_COVER_CLASSES -Return an array of cover classes for the Integrated Register Allocator -(@acronym{IRA}). Cover classes are a set of non-intersecting register -classes covering all hard registers used for register allocation -purposes. If a move between two registers in the same cover class is -possible, it should be cheaper than a load or store of the registers. -The array is terminated by a @code{LIM_REG_CLASSES} element. - -The order of cover classes in the array is important. If two classes -have the same cost of usage for a pseudo, the class occurred first in -the array is chosen for the pseudo. - -This hook is called once at compiler startup, after the command-line -options have been processed. It is then re-examined by every call to -@code{target_reinit}. - -The default implementation returns @code{IRA_COVER_CLASSES}, if defined, -otherwise there is no default implementation. You must define either this -macro or @code{IRA_COVER_CLASSES} in order to use the integrated register -allocator with Chaitin-Briggs coloring. If the macro is not defined, -the only available coloring algorithm is Chow's priority coloring. - -This hook must not be modified from @code{NULL} to non-@code{NULL} or -vice versa by command-line option processing. -@end deftypefn - -@defmac IRA_COVER_CLASSES -See the documentation for @code{TARGET_IRA_COVER_CLASSES}. -@end defmac - @node Old Constraints @section Obsolete Macros for Defining Constraints @cindex defining constraints, obsolete method Index: gcc-4.7-r171648/gcc/ira-conflicts.c =================================================================== --- gcc-4.7-r171648/gcc/ira-conflicts.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira-conflicts.c (revision 171649) @@ -97,7 +97,7 @@ build_conflict_bit_table (void) { int i; unsigned int j; - enum reg_class cover_class; + enum reg_class aclass; int object_set_words, allocated_words_num, conflict_bit_vec_words_num; live_range_t r; ira_allocno_t allocno; @@ -170,15 +170,15 @@ build_conflict_bit_table (void) gcc_assert (id < ira_objects_num); - cover_class = ALLOCNO_COVER_CLASS (allocno); + aclass = ALLOCNO_CLASS (allocno); sparseset_set_bit (objects_live, id); EXECUTE_IF_SET_IN_SPARSESET (objects_live, j) { ira_object_t live_obj = ira_object_id_map[j]; ira_allocno_t live_a = OBJECT_ALLOCNO (live_obj); - enum reg_class live_cover_class = ALLOCNO_COVER_CLASS (live_a); + enum reg_class live_aclass = ALLOCNO_CLASS (live_a); - if (ira_reg_classes_intersect_p[cover_class][live_cover_class] + if (ira_reg_classes_intersect_p[aclass][live_aclass] /* Don't set up conflict for the allocno with itself. */ && live_a != allocno) { @@ -205,6 +205,7 @@ allocnos_conflict_for_copy_p (ira_allocn the lowest order words. */ ira_object_t obj1 = ALLOCNO_OBJECT (a1, 0); ira_object_t obj2 = ALLOCNO_OBJECT (a2, 0); + return OBJECTS_CONFLICT_P (obj1, obj2); } @@ -389,7 +390,7 @@ process_regs_for_copy (rtx reg1, rtx reg int allocno_preferenced_hard_regno, cost, index, offset1, offset2; bool only_regs_p; ira_allocno_t a; - enum reg_class rclass, cover_class; + enum reg_class rclass, aclass; enum machine_mode mode; ira_copy_t cp; @@ -426,35 +427,37 @@ process_regs_for_copy (rtx reg1, rtx reg return false; } - if (! IN_RANGE (allocno_preferenced_hard_regno, 0, FIRST_PSEUDO_REGISTER - 1)) + if (! IN_RANGE (allocno_preferenced_hard_regno, + 0, FIRST_PSEUDO_REGISTER - 1)) /* Can not be tied. */ return false; rclass = REGNO_REG_CLASS (allocno_preferenced_hard_regno); mode = ALLOCNO_MODE (a); - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); if (only_regs_p && insn != NULL_RTX && reg_class_size[rclass] <= (unsigned) CLASS_MAX_NREGS (rclass, mode)) /* It is already taken into account in ira-costs.c. */ return false; - index = ira_class_hard_reg_index[cover_class][allocno_preferenced_hard_regno]; + index = ira_class_hard_reg_index[aclass][allocno_preferenced_hard_regno]; if (index < 0) - /* Can not be tied. It is not in the cover class. */ + /* Can not be tied. It is not in the allocno class. */ return false; + ira_init_register_move_cost_if_necessary (mode); if (HARD_REGISTER_P (reg1)) - cost = ira_get_register_move_cost (mode, cover_class, rclass) * freq; + cost = ira_register_move_cost[mode][aclass][rclass] * freq; else - cost = ira_get_register_move_cost (mode, rclass, cover_class) * freq; + cost = ira_register_move_cost[mode][rclass][aclass] * freq; do { ira_allocate_and_set_costs - (&ALLOCNO_HARD_REG_COSTS (a), cover_class, - ALLOCNO_COVER_CLASS_COST (a)); + (&ALLOCNO_HARD_REG_COSTS (a), aclass, + ALLOCNO_CLASS_COST (a)); ira_allocate_and_set_costs - (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), cover_class, 0); + (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), aclass, 0); ALLOCNO_HARD_REG_COSTS (a)[index] -= cost; ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[index] -= cost; - if (ALLOCNO_HARD_REG_COSTS (a)[index] < ALLOCNO_COVER_CLASS_COST (a)) - ALLOCNO_COVER_CLASS_COST (a) = ALLOCNO_HARD_REG_COSTS (a)[index]; + if (ALLOCNO_HARD_REG_COSTS (a)[index] < ALLOCNO_CLASS_COST (a)) + ALLOCNO_CLASS_COST (a) = ALLOCNO_HARD_REG_COSTS (a)[index]; a = ira_parent_or_cap_allocno (a); } while (a != NULL); @@ -507,7 +510,8 @@ add_insn_allocno_copies (rtx insn) ? SET_SRC (set) : SUBREG_REG (SET_SRC (set))) != NULL_RTX) { - process_regs_for_copy (SET_DEST (set), SET_SRC (set), false, insn, freq); + process_regs_for_copy (SET_DEST (set), SET_SRC (set), + false, insn, freq); return; } /* Fast check of possibility of constraint or shuffle copies. If @@ -608,6 +612,7 @@ build_object_conflicts (ira_object_t obj ira_allocno_t a = OBJECT_ALLOCNO (obj); IRA_INT_TYPE *object_conflicts; minmax_set_iterator asi; + int parent_min, parent_max; object_conflicts = conflicts[OBJECT_CONFLICT_ID (obj)]; px = 0; @@ -616,8 +621,9 @@ build_object_conflicts (ira_object_t obj { ira_object_t another_obj = ira_object_id_map[i]; ira_allocno_t another_a = OBJECT_ALLOCNO (obj); + ira_assert (ira_reg_classes_intersect_p - [ALLOCNO_COVER_CLASS (a)][ALLOCNO_COVER_CLASS (another_a)]); + [ALLOCNO_CLASS (a)][ALLOCNO_CLASS (another_a)]); collected_conflict_objects[px++] = another_obj; } if (ira_conflict_vector_profitable_p (obj, px)) @@ -632,6 +638,7 @@ build_object_conflicts (ira_object_t obj else { int conflict_bit_vec_words_num; + OBJECT_CONFLICT_ARRAY (obj) = object_conflicts; if (OBJECT_MAX (obj) < OBJECT_MIN (obj)) conflict_bit_vec_words_num = 0; @@ -646,10 +653,12 @@ build_object_conflicts (ira_object_t obj parent_a = ira_parent_or_cap_allocno (a); if (parent_a == NULL) return; - ira_assert (ALLOCNO_COVER_CLASS (a) == ALLOCNO_COVER_CLASS (parent_a)); + 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_num = OBJECT_CONFLICT_ID (parent_obj); + parent_min = OBJECT_MIN (parent_obj); + parent_max = OBJECT_MAX (parent_obj); FOR_EACH_BIT_IN_MINMAX_SET (object_conflicts, OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi) { @@ -658,21 +667,20 @@ build_object_conflicts (ira_object_t obj int another_word = OBJECT_SUBWORD (another_obj); ira_assert (ira_reg_classes_intersect_p - [ALLOCNO_COVER_CLASS (a)][ALLOCNO_COVER_CLASS (another_a)]); + [ALLOCNO_CLASS (a)][ALLOCNO_CLASS (another_a)]); another_parent_a = ira_parent_or_cap_allocno (another_a); if (another_parent_a == NULL) continue; ira_assert (ALLOCNO_NUM (another_parent_a) >= 0); - ira_assert (ALLOCNO_COVER_CLASS (another_a) - == ALLOCNO_COVER_CLASS (another_parent_a)); + 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_MIN (parent_obj), - OBJECT_MAX (parent_obj)); + another_word)), + parent_min, parent_max); } } @@ -792,14 +800,14 @@ print_allocno_conflicts (FILE * file, bo COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)); AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs); AND_HARD_REG_SET (conflicting_hard_regs, - reg_class_contents[ALLOCNO_COVER_CLASS (a)]); + reg_class_contents[ALLOCNO_CLASS (a)]); print_hard_reg_set (file, "\n;; total conflict hard regs:", conflicting_hard_regs); COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_CONFLICT_HARD_REGS (obj)); AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs); AND_HARD_REG_SET (conflicting_hard_regs, - reg_class_contents[ALLOCNO_COVER_CLASS (a)]); + reg_class_contents[ALLOCNO_CLASS (a)]); print_hard_reg_set (file, ";; conflict hard regs:", conflicting_hard_regs); putc ('\n', file); @@ -876,6 +884,7 @@ ira_build_conflicts (void) FOR_EACH_ALLOCNO (a, ai) { int i, n = ALLOCNO_NUM_OBJECTS (a); + for (i = 0; i < n; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); Index: gcc-4.7-r171648/gcc/targhooks.c =================================================================== --- gcc-4.7-r171648/gcc/targhooks.c (revision 171648) +++ gcc-4.7-r171648/gcc/targhooks.c (revision 171649) @@ -841,15 +841,6 @@ default_branch_target_register_class (vo return NO_REGS; } -#ifdef IRA_COVER_CLASSES -const reg_class_t * -default_ira_cover_classes (void) -{ - static reg_class_t classes[] = IRA_COVER_CLASSES; - return classes; -} -#endif - reg_class_t default_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED, reg_class_t reload_class_i ATTRIBUTE_UNUSED, Index: gcc-4.7-r171648/gcc/targhooks.h =================================================================== --- gcc-4.7-r171648/gcc/targhooks.h (revision 171648) +++ gcc-4.7-r171648/gcc/targhooks.h (revision 171649) @@ -124,9 +124,6 @@ extern rtx default_static_chain (const_t extern void default_trampoline_init (rtx, tree, rtx); extern int default_return_pops_args (tree, tree, int); extern reg_class_t default_branch_target_register_class (void); -#ifdef IRA_COVER_CLASSES -extern const reg_class_t *default_ira_cover_classes (void); -#endif extern reg_class_t default_secondary_reload (bool, rtx, reg_class_t, enum machine_mode, secondary_reload_info *); Index: gcc-4.7-r171648/gcc/target.def =================================================================== --- gcc-4.7-r171648/gcc/target.def (revision 171648) +++ gcc-4.7-r171648/gcc/target.def (revision 171649) @@ -2224,13 +2224,6 @@ DEFHOOK tree, (tree type, tree expr), hook_tree_tree_tree_null) -/* Return the array of IRA cover classes for the current target. */ -DEFHOOK -(ira_cover_classes, - "", - const reg_class_t *, (void), - default_ira_cover_classes) - /* Return the class for a secondary reload, and fill in extra information. */ DEFHOOK (secondary_reload, Index: gcc-4.7-r171648/gcc/haifa-sched.c =================================================================== --- gcc-4.7-r171648/gcc/haifa-sched.c (revision 171648) +++ gcc-4.7-r171648/gcc/haifa-sched.c (revision 171649) @@ -573,11 +573,11 @@ schedule_insns (void) up. */ bool sched_pressure_p; -/* Map regno -> its cover class. The map defined only when +/* Map regno -> its pressure class. The map defined only when SCHED_PRESSURE_P is true. */ -enum reg_class *sched_regno_cover_class; +enum reg_class *sched_regno_pressure_class; -/* The current register pressure. Only elements corresponding cover +/* The current register pressure. Only elements corresponding pressure classes are defined. */ static int curr_reg_pressure[N_REG_CLASSES]; @@ -607,39 +607,41 @@ sched_init_region_reg_pressure_info (voi static void mark_regno_birth_or_death (int regno, bool birth_p) { - enum reg_class cover_class; + enum reg_class pressure_class; - cover_class = sched_regno_cover_class[regno]; + pressure_class = sched_regno_pressure_class[regno]; if (regno >= FIRST_PSEUDO_REGISTER) { - if (cover_class != NO_REGS) + if (pressure_class != NO_REGS) { if (birth_p) { bitmap_set_bit (curr_reg_live, regno); - curr_reg_pressure[cover_class] - += ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; + curr_reg_pressure[pressure_class] + += (ira_reg_class_max_nregs + [pressure_class][PSEUDO_REGNO_MODE (regno)]); } else { bitmap_clear_bit (curr_reg_live, regno); - curr_reg_pressure[cover_class] - -= ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; + curr_reg_pressure[pressure_class] + -= (ira_reg_class_max_nregs + [pressure_class][PSEUDO_REGNO_MODE (regno)]); } } } - else if (cover_class != NO_REGS + else if (pressure_class != NO_REGS && ! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)) { if (birth_p) { bitmap_set_bit (curr_reg_live, regno); - curr_reg_pressure[cover_class]++; + curr_reg_pressure[pressure_class]++; } else { bitmap_clear_bit (curr_reg_live, regno); - curr_reg_pressure[cover_class]--; + curr_reg_pressure[pressure_class]--; } } } @@ -653,8 +655,8 @@ initiate_reg_pressure_info (bitmap live) unsigned int j; bitmap_iterator bi; - for (i = 0; i < ira_reg_class_cover_size; i++) - curr_reg_pressure[ira_reg_class_cover[i]] = 0; + for (i = 0; i < ira_pressure_classes_num; i++) + curr_reg_pressure[ira_pressure_classes[i]] = 0; bitmap_clear (curr_reg_live); EXECUTE_IF_SET_IN_BITMAP (live, 0, j, bi) if (current_nr_blocks == 1 || bitmap_bit_p (region_ref_regs, j)) @@ -723,9 +725,9 @@ save_reg_pressure (void) { int i; - for (i = 0; i < ira_reg_class_cover_size; i++) - saved_reg_pressure[ira_reg_class_cover[i]] - = curr_reg_pressure[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + saved_reg_pressure[ira_pressure_classes[i]] + = curr_reg_pressure[ira_pressure_classes[i]]; bitmap_copy (saved_reg_live, curr_reg_live); } @@ -735,9 +737,9 @@ restore_reg_pressure (void) { int i; - for (i = 0; i < ira_reg_class_cover_size; i++) - curr_reg_pressure[ira_reg_class_cover[i]] - = saved_reg_pressure[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + curr_reg_pressure[ira_pressure_classes[i]] + = saved_reg_pressure[ira_pressure_classes[i]]; bitmap_copy (curr_reg_live, saved_reg_live); } @@ -755,7 +757,7 @@ dying_use_p (struct reg_use_data *use) } /* Print info about the current register pressure and its excess for - each cover class. */ + each pressure class. */ static void print_curr_reg_pressure (void) { @@ -763,9 +765,9 @@ print_curr_reg_pressure (void) enum reg_class cl; fprintf (sched_dump, ";;\t"); - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cl = ira_reg_class_cover[i]; + cl = ira_pressure_classes[i]; gcc_assert (curr_reg_pressure[cl] >= 0); fprintf (sched_dump, " %s:%d(%d)", reg_class_names[cl], curr_reg_pressure[cl], @@ -1108,23 +1110,24 @@ setup_insn_reg_pressure_info (rtx insn) gcc_checking_assert (!DEBUG_INSN_P (insn)); excess_cost_change = 0; - for (i = 0; i < ira_reg_class_cover_size; i++) - death[ira_reg_class_cover[i]] = 0; + for (i = 0; i < ira_pressure_classes_num; i++) + death[ira_pressure_classes[i]] = 0; for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) if (dying_use_p (use)) { - cl = sched_regno_cover_class[use->regno]; + cl = sched_regno_pressure_class[use->regno]; if (use->regno < FIRST_PSEUDO_REGISTER) death[cl]++; else - death[cl] += ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (use->regno)]; + death[cl] + += ira_reg_class_max_nregs[cl][PSEUDO_REGNO_MODE (use->regno)]; } pressure_info = INSN_REG_PRESSURE (insn); max_reg_pressure = INSN_MAX_REG_PRESSURE (insn); gcc_assert (pressure_info != NULL && max_reg_pressure != NULL); - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cl = ira_reg_class_cover[i]; + cl = ira_pressure_classes[i]; gcc_assert (curr_reg_pressure[cl] >= 0); change = (int) pressure_info[i].set_increase - death[cl]; before = MAX (0, max_reg_pressure[i] - ira_available_class_regs[cl]); @@ -1569,9 +1572,9 @@ setup_insn_max_reg_pressure (rtx after, static int max_reg_pressure[N_REG_CLASSES]; save_reg_pressure (); - for (i = 0; i < ira_reg_class_cover_size; i++) - max_reg_pressure[ira_reg_class_cover[i]] - = curr_reg_pressure[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + max_reg_pressure[ira_pressure_classes[i]] + = curr_reg_pressure[ira_pressure_classes[i]]; for (insn = NEXT_INSN (after); insn != NULL_RTX && ! BARRIER_P (insn) && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (after); @@ -1579,24 +1582,24 @@ setup_insn_max_reg_pressure (rtx after, if (NONDEBUG_INSN_P (insn)) { eq_p = true; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - p = max_reg_pressure[ira_reg_class_cover[i]]; + p = max_reg_pressure[ira_pressure_classes[i]]; if (INSN_MAX_REG_PRESSURE (insn)[i] != p) { eq_p = false; INSN_MAX_REG_PRESSURE (insn)[i] - = max_reg_pressure[ira_reg_class_cover[i]]; + = max_reg_pressure[ira_pressure_classes[i]]; } } if (update_p && eq_p) break; update_register_pressure (insn); - for (i = 0; i < ira_reg_class_cover_size; i++) - if (max_reg_pressure[ira_reg_class_cover[i]] - < curr_reg_pressure[ira_reg_class_cover[i]]) - max_reg_pressure[ira_reg_class_cover[i]] - = curr_reg_pressure[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + if (max_reg_pressure[ira_pressure_classes[i]] + < curr_reg_pressure[ira_pressure_classes[i]]) + max_reg_pressure[ira_pressure_classes[i]] + = curr_reg_pressure[ira_pressure_classes[i]]; } restore_reg_pressure (); } @@ -1610,13 +1613,13 @@ update_reg_and_insn_max_reg_pressure (rt int i; int before[N_REG_CLASSES]; - for (i = 0; i < ira_reg_class_cover_size; i++) - before[i] = curr_reg_pressure[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + before[i] = curr_reg_pressure[ira_pressure_classes[i]]; update_register_pressure (insn); - for (i = 0; i < ira_reg_class_cover_size; i++) - if (curr_reg_pressure[ira_reg_class_cover[i]] != before[i]) + for (i = 0; i < ira_pressure_classes_num; i++) + if (curr_reg_pressure[ira_pressure_classes[i]] != before[i]) break; - if (i < ira_reg_class_cover_size) + if (i < ira_pressure_classes_num) setup_insn_max_reg_pressure (insn, true); } @@ -1662,9 +1665,9 @@ schedule_insn (rtx insn) if (pressure_info != NULL) { fputc (':', sched_dump); - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) fprintf (sched_dump, "%s%+d(%d)", - reg_class_names[ira_reg_class_cover[i]], + reg_class_names[ira_pressure_classes[i]], pressure_info[i].set_increase, pressure_info[i].change); } fputc ('\n', sched_dump); @@ -3509,13 +3512,13 @@ sched_init (void) int i, max_regno = max_reg_num (); ira_set_pseudo_classes (sched_verbose ? sched_dump : NULL); - sched_regno_cover_class + sched_regno_pressure_class = (enum reg_class *) xmalloc (max_regno * sizeof (enum reg_class)); for (i = 0; i < max_regno; i++) - sched_regno_cover_class[i] + sched_regno_pressure_class[i] = (i < FIRST_PSEUDO_REGISTER - ? ira_class_translate[REGNO_REG_CLASS (i)] - : reg_cover_class (i)); + ? ira_pressure_class_translate[REGNO_REG_CLASS (i)] + : ira_pressure_class_translate[reg_allocno_class (i)]); curr_reg_live = BITMAP_ALLOC (NULL); saved_reg_live = BITMAP_ALLOC (NULL); region_ref_regs = BITMAP_ALLOC (NULL); @@ -3620,7 +3623,7 @@ sched_finish (void) haifa_finish_h_i_d (); if (sched_pressure_p) { - free (sched_regno_cover_class); + free (sched_regno_pressure_class); BITMAP_FREE (region_ref_regs); BITMAP_FREE (saved_reg_live); BITMAP_FREE (curr_reg_live); Index: gcc-4.7-r171648/gcc/ira-int.h =================================================================== --- gcc-4.7-r171648/gcc/ira-int.h (revision 171648) +++ gcc-4.7-r171648/gcc/ira-int.h (revision 171649) @@ -43,9 +43,9 @@ along with GCC; see the file COPYING3. profile driven feedback is available and the function is never executed, frequency is always equivalent. Otherwise rescale the edge frequency. */ -#define REG_FREQ_FROM_EDGE_FREQ(freq) \ - (optimize_size || (flag_branch_probabilities && !ENTRY_BLOCK_PTR->count) \ - ? REG_FREQ_MAX : (freq * REG_FREQ_MAX / BB_FREQ_MAX) \ +#define REG_FREQ_FROM_EDGE_FREQ(freq) \ + (optimize_size || (flag_branch_probabilities && !ENTRY_BLOCK_PTR->count) \ + ? REG_FREQ_MAX : (freq * REG_FREQ_MAX / BB_FREQ_MAX) \ ? (freq * REG_FREQ_MAX / BB_FREQ_MAX) : 1) /* All natural loops. */ @@ -122,7 +122,7 @@ struct ira_loop_tree_node bool entered_from_non_parent_p; /* Maximal register pressure inside loop for given register class - (defined only for the cover classes). */ + (defined only for the pressure classes). */ int reg_pressure[N_REG_CLASSES]; /* Numbers of allocnos referred or living in the loop node (except @@ -193,11 +193,8 @@ extern ira_loop_tree_node_t ira_loop_nod /* The structure describes program points where a given allocno lives. - To save memory we store allocno conflicts only for the same cover - class allocnos which is enough to assign hard registers. To find - conflicts for other allocnos (e.g. to assign stack memory slot) we - use the live ranges. If the live ranges of two allocnos are - intersected, the allocnos are in conflict. */ + If the live ranges of two allocnos are intersected, the allocnos + are in conflict. */ struct live_range { /* Object whose live range is described by given structure. */ @@ -232,8 +229,7 @@ struct ira_object ira_allocno_t allocno; /* Vector of accumulated conflicting conflict_redords with NULL end marker (if OBJECT_CONFLICT_VEC_P is true) or conflict bit vector - otherwise. Only ira_objects belonging to allocnos with the - same cover class are in the vector or in the bit vector. */ + otherwise. */ void *conflicts_array; /* Pointer to structures describing at what program point the object lives. We always maintain the list in such way that *the @@ -256,7 +252,7 @@ struct ira_object int min, max; /* Initial and accumulated hard registers conflicting with this object and as a consequences can not be assigned to the allocno. - All non-allocatable hard regs and hard regs of cover classes + All non-allocatable hard regs and hard regs of register classes different from given allocno one are included in the sets. */ HARD_REG_SET conflict_hard_regs, total_conflict_hard_regs; /* Number of accumulated conflicts in the vector of conflicting @@ -266,6 +262,9 @@ struct ira_object ira_object structures. Otherwise, we use a bit vector indexed by conflict ID numbers. */ unsigned int conflict_vec_p : 1; + /* Different additional data. It is used to decrease size of + allocno data footprint. */ + void *add_data; }; /* A structure representing an allocno (allocation entity). Allocno @@ -285,16 +284,40 @@ struct ira_allocno int regno; /* Mode of the allocno which is the mode of the corresponding pseudo-register. */ - enum machine_mode mode; + ENUM_BITFIELD (machine_mode) mode : 8; + /* Register class which should be used for allocation for given + allocno. NO_REGS means that we should use memory. */ + ENUM_BITFIELD (reg_class) aclass : 16; + /* During the reload, value TRUE means that we should not reassign a + hard register to the allocno got memory earlier. It is set up + when we removed memory-memory move insn before each iteration of + the reload. */ + unsigned int dont_reassign_p : 1; +#ifdef STACK_REGS + /* Set to TRUE if allocno can't be assigned to the stack hard + register correspondingly in this region and area including the + region and all its subregions recursively. */ + unsigned int no_stack_reg_p : 1, total_no_stack_reg_p : 1; +#endif + /* TRUE value means that there is no sense to spill the allocno + during coloring because the spill will result in additional + reloads in reload pass. */ + unsigned int bad_spill_p : 1; + /* TRUE if a hard register or memory has been assigned to the + allocno. */ + unsigned int assigned_p : 1; + /* TRUE if conflicts for given allocno are represented by vector of + pointers to the conflicting allocnos. Otherwise, we use a bit + vector where a bit with given index represents allocno with the + same number. */ + unsigned int conflict_vec_p : 1; /* Hard register assigned to given allocno. Negative value means that memory was allocated to the allocno. During the reload, spilled allocno has value equal to the corresponding stack slot number (0, ...) - 2. Value -1 is used for allocnos spilled by the reload (at this point pseudo-register has only one allocno) which did not get stack slot yet. */ - int hard_regno; - /* Final rtx representation of the allocno. */ - rtx reg; + short int hard_regno; /* Allocnos with the same regno are linked by the following member. Allocnos corresponding to inner loops are first in the list (it corresponds to depth-first traverse of the loops). */ @@ -312,12 +335,9 @@ struct ira_allocno int nrefs; /* Accumulated frequency of usage of the allocno. */ int freq; - /* Register class which should be used for allocation for given - allocno. NO_REGS means that we should use memory. */ - enum reg_class cover_class; /* Minimal accumulated and updated costs of usage register of the - cover class for the allocno. */ - int cover_class_cost, updated_cover_class_cost; + allocno class. */ + int class_cost, updated_class_cost; /* Minimal accumulated, and updated costs of memory for the allocno. At the allocation start, the original and updated costs are equal. The updated cost may be changed after finishing @@ -342,11 +362,6 @@ struct ira_allocno /* It is a link to allocno (cap) on lower loop level represented by given cap. Null if given allocno is not a cap. */ ira_allocno_t cap_member; - /* Coalesced allocnos form a cyclic list. One allocno given by - FIRST_COALESCED_ALLOCNO represents all coalesced allocnos. The - list is chained by NEXT_COALESCED_ALLOCNO. */ - ira_allocno_t first_coalesced_allocno; - ira_allocno_t next_coalesced_allocno; /* The number of objects tracked in the following array. */ int num_objects; /* An array of structures describing conflict information and live @@ -359,86 +374,34 @@ struct ira_allocno int call_freq; /* Accumulated number of the intersected calls. */ int calls_crossed_num; - /* TRUE if the allocno assigned to memory was a destination of - removed move (see ira-emit.c) at loop exit because the value of - the corresponding pseudo-register is not changed inside the - loop. */ - unsigned int mem_optimized_dest_p : 1; - /* TRUE if the corresponding pseudo-register has disjoint live - ranges and the other allocnos of the pseudo-register except this - one changed REG. */ - unsigned int somewhere_renamed_p : 1; - /* TRUE if allocno with the same REGNO in a subregion has been - renamed, in other words, got a new pseudo-register. */ - unsigned int child_renamed_p : 1; - /* During the reload, value TRUE means that we should not reassign a - hard register to the allocno got memory earlier. It is set up - when we removed memory-memory move insn before each iteration of - the reload. */ - unsigned int dont_reassign_p : 1; -#ifdef STACK_REGS - /* Set to TRUE if allocno can't be assigned to the stack hard - register correspondingly in this region and area including the - region and all its subregions recursively. */ - unsigned int no_stack_reg_p : 1, total_no_stack_reg_p : 1; -#endif - /* TRUE value means that there is no sense to spill the allocno - during coloring because the spill will result in additional - reloads in reload pass. */ - unsigned int bad_spill_p : 1; - /* TRUE value means that the allocno was not removed yet from the - conflicting graph during colouring. */ - unsigned int in_graph_p : 1; - /* TRUE if a hard register or memory has been assigned to the - allocno. */ - unsigned int assigned_p : 1; - /* TRUE if it is put on the stack to make other allocnos - colorable. */ - unsigned int may_be_spilled_p : 1; - /* TRUE if the allocno was removed from the splay tree used to - choose allocn for spilling (see ira-color.c::. */ - unsigned int splay_removed_p : 1; - /* Non NULL if we remove restoring value from given allocno to - MEM_OPTIMIZED_DEST at loop exit (see ira-emit.c) because the - allocno value is not changed inside the loop. */ - ira_allocno_t mem_optimized_dest; /* Array of usage costs (accumulated and the one updated during - coloring) for each hard register of the allocno cover class. The + coloring) for each hard register of the allocno class. The member value can be NULL if all costs are the same and equal to - COVER_CLASS_COST. For example, the costs of two different hard + CLASS_COST. For example, the costs of two different hard registers can be different if one hard register is callee-saved and another one is callee-used and the allocno lives through calls. Another example can be case when for some insn the corresponding pseudo-register value should be put in specific register class (e.g. AREG for x86) which is a strict subset of - the allocno cover class (GENERAL_REGS for x86). We have updated - costs to reflect the situation when the usage cost of a hard - register is decreased because the allocno is connected to another - allocno by a copy and the another allocno has been assigned to - the hard register. */ + the allocno class (GENERAL_REGS for x86). We have updated costs + to reflect the situation when the usage cost of a hard register + is decreased because the allocno is connected to another allocno + by a copy and the another allocno has been assigned to the hard + register. */ int *hard_reg_costs, *updated_hard_reg_costs; /* Array of decreasing costs (accumulated and the one updated during coloring) for allocnos conflicting with given allocno for hard - regno of the allocno cover class. The member value can be NULL - if all costs are the same. These costs are used to reflect - preferences of other allocnos not assigned yet during assigning - to given allocno. */ + regno of the allocno class. The member value can be NULL if all + costs are the same. These costs are used to reflect preferences + of other allocnos not assigned yet during assigning to given + allocno. */ int *conflict_hard_reg_costs, *updated_conflict_hard_reg_costs; - /* Size (in hard registers) of the same cover class allocnos with - TRUE in_graph_p value and conflicting with given allocno during - each point of graph coloring. */ - int left_conflicts_size; - /* Number of hard registers of the allocno cover class really - available for the allocno allocation. */ - int available_regs_num; - /* Allocnos in a bucket (used in coloring) chained by the following - two members. */ - ira_allocno_t next_bucket_allocno; - ira_allocno_t prev_bucket_allocno; - /* Used for temporary purposes. */ - int temp; + /* Different additional data. It is used to decrease size of + allocno data footprint. */ + void *add_data; }; + /* All members of the allocno structures should be accessed only through the following macros. */ #define ALLOCNO_NUM(A) ((A)->num) @@ -463,10 +426,7 @@ struct ira_allocno #define ALLOCNO_TOTAL_NO_STACK_REG_P(A) ((A)->total_no_stack_reg_p) #endif #define ALLOCNO_BAD_SPILL_P(A) ((A)->bad_spill_p) -#define ALLOCNO_IN_GRAPH_P(A) ((A)->in_graph_p) #define ALLOCNO_ASSIGNED_P(A) ((A)->assigned_p) -#define ALLOCNO_MAY_BE_SPILLED_P(A) ((A)->may_be_spilled_p) -#define ALLOCNO_SPLAY_REMOVED_P(A) ((A)->splay_removed_p) #define ALLOCNO_MODE(A) ((A)->mode) #define ALLOCNO_COPIES(A) ((A)->allocno_copies) #define ALLOCNO_HARD_REG_COSTS(A) ((A)->hard_reg_costs) @@ -475,36 +435,71 @@ struct ira_allocno ((A)->conflict_hard_reg_costs) #define ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS(A) \ ((A)->updated_conflict_hard_reg_costs) -#define ALLOCNO_LEFT_CONFLICTS_SIZE(A) ((A)->left_conflicts_size) -#define ALLOCNO_COVER_CLASS(A) ((A)->cover_class) -#define ALLOCNO_COVER_CLASS_COST(A) ((A)->cover_class_cost) -#define ALLOCNO_UPDATED_COVER_CLASS_COST(A) ((A)->updated_cover_class_cost) +#define ALLOCNO_CLASS(A) ((A)->aclass) +#define ALLOCNO_CLASS_COST(A) ((A)->class_cost) +#define ALLOCNO_UPDATED_CLASS_COST(A) ((A)->updated_class_cost) #define ALLOCNO_MEMORY_COST(A) ((A)->memory_cost) #define ALLOCNO_UPDATED_MEMORY_COST(A) ((A)->updated_memory_cost) -#define ALLOCNO_EXCESS_PRESSURE_POINTS_NUM(A) ((A)->excess_pressure_points_num) -#define ALLOCNO_AVAILABLE_REGS_NUM(A) ((A)->available_regs_num) -#define ALLOCNO_NEXT_BUCKET_ALLOCNO(A) ((A)->next_bucket_allocno) -#define ALLOCNO_PREV_BUCKET_ALLOCNO(A) ((A)->prev_bucket_allocno) -#define ALLOCNO_TEMP(A) ((A)->temp) -#define ALLOCNO_FIRST_COALESCED_ALLOCNO(A) ((A)->first_coalesced_allocno) -#define ALLOCNO_NEXT_COALESCED_ALLOCNO(A) ((A)->next_coalesced_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_ADD_DATA(A) ((A)->add_data) -#define OBJECT_ALLOCNO(C) ((C)->allocno) -#define OBJECT_SUBWORD(C) ((C)->subword) -#define OBJECT_CONFLICT_ARRAY(C) ((C)->conflicts_array) -#define OBJECT_CONFLICT_VEC(C) ((ira_object_t *)(C)->conflicts_array) -#define OBJECT_CONFLICT_BITVEC(C) ((IRA_INT_TYPE *)(C)->conflicts_array) -#define OBJECT_CONFLICT_ARRAY_SIZE(C) ((C)->conflicts_array_size) -#define OBJECT_CONFLICT_VEC_P(C) ((C)->conflict_vec_p) -#define OBJECT_NUM_CONFLICTS(C) ((C)->num_accumulated_conflicts) -#define OBJECT_CONFLICT_HARD_REGS(C) ((C)->conflict_hard_regs) -#define OBJECT_TOTAL_CONFLICT_HARD_REGS(C) ((C)->total_conflict_hard_regs) -#define OBJECT_MIN(C) ((C)->min) -#define OBJECT_MAX(C) ((C)->max) -#define OBJECT_CONFLICT_ID(C) ((C)->id) -#define OBJECT_LIVE_RANGES(A) ((A)->live_ranges) +/* Typedef for pointer to the subsequent structure. */ +typedef struct ira_emit_data *ira_emit_data_t; + +/* Allocno bound data used for emit pseudo live range split insns and + to flattening IR. */ +struct ira_emit_data +{ + /* TRUE if the allocno assigned to memory was a destination of + removed move (see ira-emit.c) at loop exit because the value of + the corresponding pseudo-register is not changed inside the + loop. */ + unsigned int mem_optimized_dest_p : 1; + /* TRUE if the corresponding pseudo-register has disjoint live + ranges and the other allocnos of the pseudo-register except this + one changed REG. */ + unsigned int somewhere_renamed_p : 1; + /* TRUE if allocno with the same REGNO in a subregion has been + renamed, in other words, got a new pseudo-register. */ + unsigned int child_renamed_p : 1; + /* Final rtx representation of the allocno. */ + rtx reg; + /* Non NULL if we remove restoring value from given allocno to + MEM_OPTIMIZED_DEST at loop exit (see ira-emit.c) because the + allocno value is not changed inside the loop. */ + ira_allocno_t mem_optimized_dest; +}; + +#define ALLOCNO_EMIT_DATA(a) ((ira_emit_data_t) ALLOCNO_ADD_DATA (a)) + +/* Data used to emit live range split insns and to flattening IR. */ +extern ira_emit_data_t ira_allocno_emit_data; + +/* Abbreviation for frequent emit data access. */ +static inline rtx +allocno_emit_reg (ira_allocno_t a) +{ + return ALLOCNO_EMIT_DATA (a)->reg; +} + +#define OBJECT_ALLOCNO(O) ((O)->allocno) +#define OBJECT_SUBWORD(O) ((O)->subword) +#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) +#define OBJECT_CONFLICT_ARRAY_SIZE(O) ((O)->conflicts_array_size) +#define OBJECT_CONFLICT_VEC_P(O) ((O)->conflict_vec_p) +#define OBJECT_NUM_CONFLICTS(O) ((O)->num_accumulated_conflicts) +#define OBJECT_CONFLICT_HARD_REGS(O) ((O)->conflict_hard_regs) +#define OBJECT_TOTAL_CONFLICT_HARD_REGS(O) ((O)->total_conflict_hard_regs) +#define OBJECT_MIN(O) ((O)->min) +#define OBJECT_MAX(O) ((O)->max) +#define OBJECT_CONFLICT_ID(O) ((O)->id) +#define OBJECT_LIVE_RANGES(O) ((O)->live_ranges) +#define OBJECT_ADD_DATA(O) ((O)->add_data) /* Map regno -> allocnos with given regno (see comments for allocno member `next_regno_allocno'). */ @@ -590,6 +585,7 @@ extern int ira_overall_cost; extern int ira_reg_cost, ira_mem_cost; extern int ira_load_cost, ira_store_cost, ira_shuffle_cost; extern int ira_move_loops_num, ira_additional_jumps_num; + /* This page contains a bitset implementation called 'min/max sets' used to record conflicts in IRA. @@ -757,11 +753,6 @@ struct target_ira_int { struct costs *x_op_costs[MAX_RECOG_OPERANDS]; struct costs *x_this_op_costs[MAX_RECOG_OPERANDS]; - /* Classes used for cost calculation. They may be different on - different iterations of the cost calculations or in different - optimization modes. */ - enum reg_class *x_cost_classes; - /* Hard registers that can not be used for the register allocator for all functions of the current compilation unit. */ HARD_REG_SET x_no_unit_alloc_regs; @@ -776,6 +767,12 @@ struct target_ira_int { ira_get_may_move_cost instead. */ move_table *x_ira_register_move_cost[MAX_MACHINE_MODE]; + /* Array analogs of the macros MEMORY_MOVE_COST and + REGISTER_MOVE_COST but they contain maximal cost not minimal as + the previous two ones do. */ + short int x_ira_max_memory_move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][2]; + move_table *x_ira_max_register_move_cost[MAX_MACHINE_MODE]; + /* Similar to may_move_in_cost but it is calculated in IRA instead of regclass. Another difference we take only available hard registers into account to figure out that one register class is a subset of @@ -790,6 +787,18 @@ struct target_ira_int { ira_get_may_move_cost instead. */ move_table *x_ira_may_move_out_cost[MAX_MACHINE_MODE]; +/* Similar to ira_may_move_in_cost and ira_may_move_out_cost but they + return maximal cost. */ + move_table *x_ira_max_may_move_in_cost[MAX_MACHINE_MODE]; + move_table *x_ira_max_may_move_out_cost[MAX_MACHINE_MODE]; + + /* Map class->true if class is a possible allocno class, false + otherwise. */ + bool x_ira_reg_allocno_class_p[N_REG_CLASSES]; + + /* Map class->true if class is a pressure class, false otherwise. */ + bool x_ira_reg_pressure_class_p[N_REG_CLASSES]; + /* Register class subset relation: TRUE if the first class is a subset of the second one considering only hard registers available for the allocation. */ @@ -809,16 +818,20 @@ struct target_ira_int { /* Array whose values are hard regset of hard registers available for the allocation of given register class whose HARD_REGNO_MODE_OK values for given mode are zero. */ - HARD_REG_SET x_prohibited_class_mode_regs[N_REG_CLASSES][NUM_MACHINE_MODES]; + HARD_REG_SET x_ira_prohibited_class_mode_regs[N_REG_CLASSES][NUM_MACHINE_MODES]; /* The value is number of elements in the subsequent array. */ int x_ira_important_classes_num; - /* The array containing non-empty classes (including non-empty cover - classes; which are subclasses of cover classes. Such classes is + /* The array containing all non-empty classes. Such classes is important for calculation of the hard register usage costs. */ enum reg_class x_ira_important_classes[N_REG_CLASSES]; + /* The array containing indexes of important classes in the previous + array. The array elements are defined only for important + classes. */ + int x_ira_important_class_nums[N_REG_CLASSES]; + /* The biggest important class inside of intersection of the two classes (that is calculated taking only hard registers available for allocation into account;. If the both classes contain no hard @@ -837,14 +850,15 @@ struct target_ira_int { allocation into account. */ enum reg_class x_ira_reg_class_super_classes[N_REG_CLASSES][N_REG_CLASSES]; - /* The biggest important class inside of union of the two classes - (that is calculated taking only hard registers available for - allocation into account;. If the both classes contain no hard - registers available for allocation, the value is calculated with - taking all hard-registers including fixed ones into account. In - other words, the value is the corresponding reg_class_subunion - value. */ - enum reg_class x_ira_reg_class_union[N_REG_CLASSES][N_REG_CLASSES]; + /* The biggest (smallest) important class inside of (covering) union + of the two classes (that is calculated taking only hard registers + available for allocation into account). If the both classes + contain no hard registers available for allocation, the value is + calculated with taking all hard-registers including fixed ones + into account. In other words, the value is the corresponding + reg_class_subunion (reg_class_superunion) value. */ + enum reg_class x_ira_reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES]; + enum reg_class x_ira_reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES]; /* For each reg class, table listing all the classes contained in it (excluding the class itself. Non-allocatable registers are @@ -871,43 +885,58 @@ extern struct target_ira_int *this_targe (this_target_ira_int->x_ira_reg_mode_hard_regset) #define ira_register_move_cost \ (this_target_ira_int->x_ira_register_move_cost) +#define ira_max_memory_move_cost \ + (this_target_ira_int->x_ira_max_memory_move_cost) +#define ira_max_register_move_cost \ + (this_target_ira_int->x_ira_max_register_move_cost) #define ira_may_move_in_cost \ (this_target_ira_int->x_ira_may_move_in_cost) #define ira_may_move_out_cost \ (this_target_ira_int->x_ira_may_move_out_cost) +#define ira_max_may_move_in_cost \ + (this_target_ira_int->x_ira_max_may_move_in_cost) +#define ira_max_may_move_out_cost \ + (this_target_ira_int->x_ira_max_may_move_out_cost) +#define ira_reg_allocno_class_p \ + (this_target_ira_int->x_ira_reg_allocno_class_p) +#define ira_reg_pressure_class_p \ + (this_target_ira_int->x_ira_reg_pressure_class_p) #define ira_class_subset_p \ (this_target_ira_int->x_ira_class_subset_p) #define ira_non_ordered_class_hard_regs \ (this_target_ira_int->x_ira_non_ordered_class_hard_regs) #define ira_class_hard_reg_index \ (this_target_ira_int->x_ira_class_hard_reg_index) -#define prohibited_class_mode_regs \ - (this_target_ira_int->x_prohibited_class_mode_regs) +#define ira_prohibited_class_mode_regs \ + (this_target_ira_int->x_ira_prohibited_class_mode_regs) #define ira_important_classes_num \ (this_target_ira_int->x_ira_important_classes_num) #define ira_important_classes \ (this_target_ira_int->x_ira_important_classes) +#define ira_important_class_nums \ + (this_target_ira_int->x_ira_important_class_nums) #define ira_reg_class_intersect \ (this_target_ira_int->x_ira_reg_class_intersect) #define ira_reg_classes_intersect_p \ (this_target_ira_int->x_ira_reg_classes_intersect_p) #define ira_reg_class_super_classes \ (this_target_ira_int->x_ira_reg_class_super_classes) -#define ira_reg_class_union \ - (this_target_ira_int->x_ira_reg_class_union) +#define ira_reg_class_subunion \ + (this_target_ira_int->x_ira_reg_class_subunion) +#define ira_reg_class_superunion \ + (this_target_ira_int->x_ira_reg_class_superunion) #define ira_prohibited_mode_move_regs \ (this_target_ira_int->x_ira_prohibited_mode_move_regs) /* ira.c: */ extern void *ira_allocate (size_t); -extern void *ira_reallocate (void *, size_t); extern void ira_free (void *addr); extern bitmap ira_allocate_bitmap (void); extern void ira_free_bitmap (bitmap); extern void ira_print_disposition (FILE *); extern void ira_debug_disposition (void); -extern void ira_debug_class_cover (void); +extern void ira_debug_allocno_classes (void); extern void ira_init_register_move_cost (enum machine_mode); /* The length of the two following arrays. */ @@ -938,7 +967,7 @@ extern ira_allocno_t ira_parent_allocno extern ira_allocno_t ira_parent_or_cap_allocno (ira_allocno_t); extern ira_allocno_t ira_create_allocno (int, bool, ira_loop_tree_node_t); extern void ira_create_allocno_objects (ira_allocno_t); -extern void ira_set_allocno_cover_class (ira_allocno_t, enum reg_class); +extern void ira_set_allocno_class (ira_allocno_t, enum reg_class); extern bool ira_conflict_vector_profitable_p (ira_object_t, int); extern void ira_allocate_conflict_vec (ira_object_t, int); extern void ira_allocate_object_conflicts (ira_object_t, int); @@ -972,7 +1001,7 @@ extern void ira_init_costs_once (void); extern void ira_init_costs (void); extern void ira_finish_costs_once (void); extern void ira_costs (void); -extern void ira_tune_allocno_costs_and_cover_classes (void); +extern void ira_tune_allocno_costs (void); /* ira-lives.c */ @@ -990,6 +1019,7 @@ extern void ira_debug_conflicts (bool); extern void ira_build_conflicts (void); /* ira-color.c */ +extern void ira_debug_hard_regs_forest (void); extern int ira_loop_edge_freq (ira_loop_tree_node_t, int, bool); extern void ira_reassign_conflict_allocnos (int); extern void ira_initiate_assign (void); @@ -997,34 +1027,18 @@ extern void ira_finish_assign (void); extern void ira_color (void); /* ira-emit.c */ +extern void ira_initiate_emit_data (void); +extern void ira_finish_emit_data (void); extern void ira_emit (bool); -/* Return cost of moving value of MODE from register of class FROM to - register of class TO. */ -static inline int -ira_get_register_move_cost (enum machine_mode mode, - enum reg_class from, enum reg_class to) -{ - if (ira_register_move_cost[mode] == NULL) - ira_init_register_move_cost (mode); - return ira_register_move_cost[mode][from][to]; -} - -/* Return cost of moving value of MODE from register of class FROM to - register of class TO. Return zero if IN_P is true and FROM is - subset of TO or if IN_P is false and FROM is superset of TO. */ -static inline int -ira_get_may_move_cost (enum machine_mode mode, - enum reg_class from, enum reg_class to, - bool in_p) +/* Initialize register costs for MODE if necessary. */ +static inline void +ira_init_register_move_cost_if_necessary (enum machine_mode mode) { if (ira_register_move_cost[mode] == NULL) ira_init_register_move_cost (mode); - return (in_p - ? ira_may_move_in_cost[mode][from][to] - : ira_may_move_out_cost[mode][from][to]); } @@ -1237,14 +1251,17 @@ ira_object_conflict_iter_cond (ira_objec if (i->conflict_vec_p) { - obj = ((ira_object_t *) i->vec)[i->word_num]; + obj = ((ira_object_t *) i->vec)[i->word_num++]; if (obj == NULL) return false; } else { + unsigned IRA_INT_TYPE word = i->word; + unsigned int bit_num = i->bit_num; + /* Skip words that are zeros. */ - for (; i->word == 0; i->word = ((IRA_INT_TYPE *) i->vec)[i->word_num]) + for (; word == 0; word = ((IRA_INT_TYPE *) i->vec)[i->word_num]) { i->word_num++; @@ -1252,43 +1269,59 @@ ira_object_conflict_iter_cond (ira_objec if (i->word_num * sizeof (IRA_INT_TYPE) >= i->size) return false; - i->bit_num = i->word_num * IRA_INT_BITS; + bit_num = i->word_num * IRA_INT_BITS; } /* Skip bits that are zero. */ - for (; (i->word & 1) == 0; i->word >>= 1) - i->bit_num++; + for (; (word & 1) == 0; word >>= 1) + bit_num++; - obj = ira_object_id_map[i->bit_num + i->base_conflict_id]; + obj = ira_object_id_map[bit_num + i->base_conflict_id]; + i->bit_num = bit_num + 1; + i->word = word >> 1; } *pobj = obj; return true; } -/* Advance to the next conflicting allocno. */ -static inline void -ira_object_conflict_iter_next (ira_object_conflict_iterator *i) -{ - if (i->conflict_vec_p) - i->word_num++; - else - { - i->word >>= 1; - i->bit_num++; - } -} - /* Loop over all objects conflicting with OBJ. In each iteration, CONF is set to the next conflicting object. ITER is an instance of ira_object_conflict_iterator used to iterate the conflicts. */ #define FOR_EACH_OBJECT_CONFLICT(OBJ, CONF, ITER) \ for (ira_object_conflict_iter_init (&(ITER), (OBJ)); \ - ira_object_conflict_iter_cond (&(ITER), &(CONF)); \ - ira_object_conflict_iter_next (&(ITER))) + ira_object_conflict_iter_cond (&(ITER), &(CONF));) +/* The function returns TRUE if at least one hard register from ones + starting with HARD_REGNO and containing value of MODE are in set + HARD_REGSET. */ +static inline bool +ira_hard_reg_set_intersection_p (int hard_regno, enum machine_mode mode, + HARD_REG_SET hard_regset) +{ + int i; + + gcc_assert (hard_regno >= 0); + for (i = hard_regno_nregs[hard_regno][mode] - 1; i >= 0; i--) + if (TEST_HARD_REG_BIT (hard_regset, hard_regno + i)) + return true; + return false; +} + +/* Return number of hard registers in hard register SET. */ +static inline int +hard_reg_set_size (HARD_REG_SET set) +{ + int i, size; + + for (size = i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (TEST_HARD_REG_BIT (set, i)) + size++; + return size; +} + /* The function returns TRUE if hard registers starting with HARD_REGNO and containing value of MODE are not in set HARD_REGSET. */ @@ -1311,61 +1344,60 @@ ira_hard_reg_not_in_set_p (int hard_regn initialization of the cost vectors. We do this only when it is really necessary. */ -/* Allocate cost vector *VEC for hard registers of COVER_CLASS and +/* Allocate cost vector *VEC for hard registers of ACLASS and initialize the elements by VAL if it is necessary */ static inline void -ira_allocate_and_set_costs (int **vec, enum reg_class cover_class, int val) +ira_allocate_and_set_costs (int **vec, enum reg_class aclass, int val) { int i, *reg_costs; int len; if (*vec != NULL) return; - *vec = reg_costs = ira_allocate_cost_vector (cover_class); - len = ira_class_hard_regs_num[cover_class]; + *vec = reg_costs = ira_allocate_cost_vector (aclass); + len = ira_class_hard_regs_num[aclass]; for (i = 0; i < len; i++) reg_costs[i] = val; } -/* Allocate cost vector *VEC for hard registers of COVER_CLASS and - copy values of vector SRC into the vector if it is necessary */ +/* Allocate cost vector *VEC for hard registers of ACLASS and copy + values of vector SRC into the vector if it is necessary */ static inline void -ira_allocate_and_copy_costs (int **vec, enum reg_class cover_class, int *src) +ira_allocate_and_copy_costs (int **vec, enum reg_class aclass, int *src) { int len; if (*vec != NULL || src == NULL) return; - *vec = ira_allocate_cost_vector (cover_class); - len = ira_class_hard_regs_num[cover_class]; + *vec = ira_allocate_cost_vector (aclass); + len = ira_class_hard_regs_num[aclass]; memcpy (*vec, src, sizeof (int) * len); } -/* Allocate cost vector *VEC for hard registers of COVER_CLASS and - add values of vector SRC into the vector if it is necessary */ +/* Allocate cost vector *VEC for hard registers of ACLASS and add + values of vector SRC into the vector if it is necessary */ static inline void -ira_allocate_and_accumulate_costs (int **vec, enum reg_class cover_class, - int *src) +ira_allocate_and_accumulate_costs (int **vec, enum reg_class aclass, int *src) { int i, len; if (src == NULL) return; - len = ira_class_hard_regs_num[cover_class]; + len = ira_class_hard_regs_num[aclass]; if (*vec == NULL) { - *vec = ira_allocate_cost_vector (cover_class); + *vec = ira_allocate_cost_vector (aclass); memset (*vec, 0, sizeof (int) * len); } for (i = 0; i < len; i++) (*vec)[i] += src[i]; } -/* Allocate cost vector *VEC for hard registers of COVER_CLASS and - copy values of vector SRC into the vector or initialize it by VAL - (if SRC is null). */ +/* Allocate cost vector *VEC for hard registers of ACLASS and copy + values of vector SRC into the vector or initialize it by VAL (if + SRC is null). */ static inline void -ira_allocate_and_set_or_copy_costs (int **vec, enum reg_class cover_class, +ira_allocate_and_set_or_copy_costs (int **vec, enum reg_class aclass, int val, int *src) { int i, *reg_costs; @@ -1373,8 +1405,8 @@ ira_allocate_and_set_or_copy_costs (int if (*vec != NULL) return; - *vec = reg_costs = ira_allocate_cost_vector (cover_class); - len = ira_class_hard_regs_num[cover_class]; + *vec = reg_costs = ira_allocate_cost_vector (aclass); + len = ira_class_hard_regs_num[aclass]; if (src != NULL) memcpy (reg_costs, src, sizeof (int) * len); else Index: gcc-4.7-r171648/gcc/ira-color.c =================================================================== --- gcc-4.7-r171648/gcc/ira-color.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira-color.c (revision 171649) @@ -1,5 +1,5 @@ /* IRA allocation based on graph coloring. - Copyright (C) 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Vladimir Makarov . @@ -37,9 +37,119 @@ along with GCC; see the file COPYING3. #include "reload.h" #include "params.h" #include "df.h" -#include "splay-tree.h" #include "ira-int.h" +typedef struct object_hard_regs *object_hard_regs_t; + +/* The structure contains information about hard registers can be + assigned to objects. Usually it is allocno profitable hard + registers but in some cases this set can be a bit different. Major + reason of the difference is a requirement to use hard register sets + that form a tree or a forest (set of trees), i.e. hard register set + of a node should contain hard register sets of its subnodes. */ +struct object_hard_regs +{ + /* Hard registers can be assigned to an allocno. */ + HARD_REG_SET set; + /* Overall (spilling) cost of all allocnos with given register + set. */ + long long int cost; +}; + +typedef struct object_hard_regs_node *object_hard_regs_node_t; + +/* A node representing object hard registers. Such nodes form a + forest (set of trees). Each subnode of given node in the forest + refers for hard register set (usually object profitable hard + register set) which is a subset of one referred from given + node. */ +struct object_hard_regs_node +{ + /* Set up number of the node in preorder traversing of the forest. */ + int preorder_num; + /* Used for different calculation like finding conflict size of an + allocno. */ + int check; + /* Used for calculation of conflict size of an allocno. The + conflict size of the allocno is maximal number of given object + hard registers needed for allocation of the conflicting allocnos. + Given allocno is trivially colored if this number plus the number + of hard registers needed for given allocno is not greater than + the number of given allocno hard register set. */ + int conflict_size; + /* The number of hard registers given by member hard_regs. */ + int hard_regs_num; + /* The following member is used to form the final forest. */ + bool used_p; + /* Pointer to the corresponding profitable hard registers. */ + object_hard_regs_t hard_regs; + /* Parent, first subnode, previous and next node with the same + parent in the forest. */ + object_hard_regs_node_t parent, first, prev, next; +}; + +/* To decrease footprint of ira_allocno structure we store all data + needed only for coloring in the following structure. */ +struct allocno_color_data +{ + /* TRUE value means that the allocno was not removed yet from the + conflicting graph during colouring. */ + unsigned int in_graph_p : 1; + /* TRUE if it is put on the stack to make other allocnos + colorable. */ + unsigned int may_be_spilled_p : 1; + /* TRUE if the object is trivially colorable. */ + unsigned int colorable_p : 1; + /* Number of hard registers of the allocno class really + available for the allocno allocation. It is number of the + profitable hard regs. */ + int available_regs_num; + /* Allocnos in a bucket (used in coloring) chained by the following + two members. */ + ira_allocno_t next_bucket_allocno; + ira_allocno_t prev_bucket_allocno; + /* Used for temporary purposes. */ + int temp; +}; + +/* See above. */ +typedef struct allocno_color_data *allocno_color_data_t; + +/* Container for storing allocno data concerning coloring. */ +static allocno_color_data_t allocno_color_data; + +/* Macro to access the data concerning coloring. */ +#define ALLOCNO_COLOR_DATA(a) ((allocno_color_data_t) ALLOCNO_ADD_DATA (a)) + +/* To decrease footprint of ira_object structure we store all data + needed only for coloring in the following structure. */ +struct object_color_data +{ + /* Profitable hard regs available for this pseudo allocation. It + means that the set excludes unavailable hard regs and hard regs + conflicting with given pseudo. They should be of the allocno + class. */ + HARD_REG_SET profitable_hard_regs; + /* The object hard registers node. */ + object_hard_regs_node_t hard_regs_node; + /* Array of structures object_hard_regs_subnode representing + given object hard registers node (the 1st element in the array) + and all its subnodes in the tree (forest) of object hard + register nodes (see comments above). */ + int hard_regs_subnodes_start; + /* The length of the previous array. */ + int hard_regs_subnodes_num; +}; + +/* See above. */ +typedef struct object_color_data *object_color_data_t; + +/* Container for storing object data concerning coloring. */ +static object_color_data_t object_color_data; + +/* Macro to access the data concerning coloring. */ +#define OBJECT_COLOR_DATA(o) ((object_color_data_t) OBJECT_ADD_DATA (o)) + /* This file contains code for regional graph coloring, spill/restore code placement optimization, and code helping the reload pass to do a better job. */ @@ -59,20 +169,6 @@ static ira_allocno_t *sorted_allocnos; /* Vec representing the stack of allocnos used during coloring. */ static VEC(ira_allocno_t,heap) *allocno_stack_vec; -/* Array used to choose an allocno for spilling. */ -static ira_allocno_t *allocnos_for_spilling; - -/* Pool for splay tree nodes. */ -static alloc_pool splay_tree_node_pool; - -/* When an allocno is removed from the splay tree, it is put in the - following vector for subsequent inserting it into the splay tree - after putting all colorable allocnos onto the stack. The allocno - could be removed from and inserted to the splay tree every time - when its spilling priority is changed but such solution would be - more costly although simpler. */ -static VEC(ira_allocno_t,heap) *removed_splay_allocno_vec; - /* Helper for qsort comparison callbacks - return a positive integer if X > Y, or a negative value otherwise. Use a conditional expression instead of a difference computation to insulate from possible overflow @@ -81,61 +177,1004 @@ static VEC(ira_allocno_t,heap) *removed_ -/* This page contains functions used to find conflicts using allocno - live ranges. */ +/* Definition of vector of object hard registers. */ +DEF_VEC_P(object_hard_regs_t); +DEF_VEC_ALLOC_P(object_hard_regs_t, heap); -/* Return TRUE if live ranges of allocnos A1 and A2 intersect. It is - used to find a conflict for new allocnos or allocnos with the - different cover classes. */ -static bool -allocnos_have_intersected_live_ranges_p (ira_allocno_t a1, ira_allocno_t a2) +/* Vector of unique object hard registers. */ +static VEC(object_hard_regs_t, heap) *object_hard_regs_vec; + +/* Returns hash value for object hard registers V. */ +static hashval_t +object_hard_regs_hash (const void *v) { - int i, j; - int n1 = ALLOCNO_NUM_OBJECTS (a1); - int n2 = ALLOCNO_NUM_OBJECTS (a2); + const struct object_hard_regs *hv = (const struct object_hard_regs *) v; - if (a1 == a2) - return false; - if (ALLOCNO_REG (a1) != NULL && ALLOCNO_REG (a2) != NULL - && (ORIGINAL_REGNO (ALLOCNO_REG (a1)) - == ORIGINAL_REGNO (ALLOCNO_REG (a2)))) - return false; + return iterative_hash (&hv->set, sizeof (HARD_REG_SET), 0); +} - for (i = 0; i < n1; i++) +/* Compares object hard registers V1 and V2. */ +static int +object_hard_regs_eq (const void *v1, const void *v2) +{ + const struct object_hard_regs *hv1 = (const struct object_hard_regs *) v1; + const struct object_hard_regs *hv2 = (const struct object_hard_regs *) v2; + + return hard_reg_set_equal_p (hv1->set, hv2->set); +} + +/* Hash table of unique object hard registers. */ +static htab_t object_hard_regs_htab; + +/* Return object hard registers in the hash table equal to HV. */ +static object_hard_regs_t +find_hard_regs (object_hard_regs_t hv) +{ + return (object_hard_regs_t) htab_find (object_hard_regs_htab, hv); +} + +/* Insert allocno hard registers HV in the hash table (if it is not + there yet) and return the value which in the table. */ +static object_hard_regs_t +insert_hard_regs (object_hard_regs_t hv) +{ + PTR *slot = htab_find_slot (object_hard_regs_htab, hv, INSERT); + + if (*slot == NULL) + *slot = hv; + return (object_hard_regs_t) *slot; +} + +/* Initialize data concerning object hard registers. */ +static void +init_object_hard_regs (void) +{ + object_hard_regs_vec = VEC_alloc (object_hard_regs_t, heap, 200); + object_hard_regs_htab + = htab_create (200, object_hard_regs_hash, object_hard_regs_eq, NULL); +} + +/* Add (or update info about) object hard registers with SET and + COST. */ +static object_hard_regs_t +add_object_hard_regs (HARD_REG_SET set, long long int cost) +{ + struct object_hard_regs temp; + object_hard_regs_t hv; + + gcc_assert (! hard_reg_set_empty_p (set)); + COPY_HARD_REG_SET (temp.set, set); + if ((hv = find_hard_regs (&temp)) != NULL) + hv->cost += cost; + else { - ira_object_t c1 = ALLOCNO_OBJECT (a1, i); - for (j = 0; j < n2; j++) + hv = ((struct object_hard_regs *) + ira_allocate (sizeof (struct object_hard_regs))); + COPY_HARD_REG_SET (hv->set, set); + hv->cost = cost; + VEC_safe_push (object_hard_regs_t, heap, object_hard_regs_vec, hv); + insert_hard_regs (hv); + } + return hv; +} + +/* Finalize data concerning allocno hard registers. */ +static void +finish_object_hard_regs (void) +{ + int i; + object_hard_regs_t hv; + + for (i = 0; + VEC_iterate (object_hard_regs_t, object_hard_regs_vec, i, hv); + i++) + ira_free (hv); + htab_delete (object_hard_regs_htab); + VEC_free (object_hard_regs_t, heap, object_hard_regs_vec); +} + +/* Sort hard regs according to their frequency of usage. */ +static int +object_hard_regs_compare (const void *v1p, const void *v2p) +{ + object_hard_regs_t hv1 = *(const object_hard_regs_t *) v1p; + object_hard_regs_t hv2 = *(const object_hard_regs_t *) v2p; + + if (hv2->cost > hv1->cost) + return 1; + else if (hv2->cost < hv1->cost) + return -1; + else + return 0; +} + + + +/* Used for finding a common ancestor of two allocno hard registers + nodes in the forest. We use the current value of + 'node_check_tick' to mark all nodes from one node to the top and + then walking up from another node until we find a marked node. + + It is also used to figure out allocno colorability as a mark that + we already reset value of member 'conflict_size' for the forest + node corresponding to the processed allocno. */ +static int node_check_tick; + +/* Roots of the forest containing hard register sets can be assigned + to objects. */ +static object_hard_regs_node_t hard_regs_roots; + +/* Definition of vector of object hard register nodes. */ +DEF_VEC_P(object_hard_regs_node_t); +DEF_VEC_ALLOC_P(object_hard_regs_node_t, heap); + +/* Vector used to create the forest. */ +static VEC(object_hard_regs_node_t, heap) *hard_regs_node_vec; + +/* Create and return object hard registers node containing object + hard registers HV. */ +static object_hard_regs_node_t +create_new_object_hard_regs_node (object_hard_regs_t hv) +{ + object_hard_regs_node_t new_node; + + new_node = ((struct object_hard_regs_node *) + ira_allocate (sizeof (struct object_hard_regs_node))); + new_node->check = 0; + new_node->hard_regs = hv; + new_node->hard_regs_num = hard_reg_set_size (hv->set); + new_node->first = NULL; + new_node->used_p = false; + return new_node; +} + +/* Add object hard registers node NEW_NODE to the forest on its level + given by ROOTS. */ +static void +add_new_object_hard_regs_node_to_forest (object_hard_regs_node_t *roots, + object_hard_regs_node_t new_node) +{ + new_node->next = *roots; + if (new_node->next != NULL) + new_node->next->prev = new_node; + new_node->prev = NULL; + *roots = new_node; +} + +/* Add object hard registers HV (or its best approximation if it is + not possible) to the forest on its level given by ROOTS. */ +static void +add_object_hard_regs_to_forest (object_hard_regs_node_t *roots, + object_hard_regs_t hv) +{ + unsigned int i, start; + object_hard_regs_node_t node, prev, new_node; + HARD_REG_SET temp_set; + object_hard_regs_t hv2; + + start = VEC_length (object_hard_regs_node_t, hard_regs_node_vec); + for (node = *roots; node != NULL; node = node->next) + { + if (hard_reg_set_equal_p (hv->set, node->hard_regs->set)) + return; + if (hard_reg_set_subset_p (hv->set, node->hard_regs->set)) { - ira_object_t c2 = ALLOCNO_OBJECT (a2, j); - if (ira_live_ranges_intersect_p (OBJECT_LIVE_RANGES (c1), - OBJECT_LIVE_RANGES (c2))) - return true; + add_object_hard_regs_to_forest (&node->first, hv); + return; + } + if (hard_reg_set_subset_p (node->hard_regs->set, hv->set)) + VEC_safe_push (object_hard_regs_node_t, heap, + hard_regs_node_vec, node); + else if (hard_reg_set_intersect_p (hv->set, node->hard_regs->set)) + { + COPY_HARD_REG_SET (temp_set, hv->set); + AND_HARD_REG_SET (temp_set, node->hard_regs->set); + hv2 = add_object_hard_regs (temp_set, hv->cost); + add_object_hard_regs_to_forest (&node->first, hv2); + } + } + if (VEC_length (object_hard_regs_node_t, hard_regs_node_vec) + > start + 1) + { + /* Create a new node which contains nodes in hard_regs_node_vec. */ + CLEAR_HARD_REG_SET (temp_set); + for (i = start; + i < VEC_length (object_hard_regs_node_t, hard_regs_node_vec); + i++) + { + node = VEC_index (object_hard_regs_node_t, hard_regs_node_vec, i); + IOR_HARD_REG_SET (temp_set, node->hard_regs->set); + } + hv = add_object_hard_regs (temp_set, hv->cost); + new_node = create_new_object_hard_regs_node (hv); + prev = NULL; + for (i = start; + i < VEC_length (object_hard_regs_node_t, hard_regs_node_vec); + i++) + { + node = VEC_index (object_hard_regs_node_t, hard_regs_node_vec, i); + if (node->prev == NULL) + *roots = node->next; + else + node->prev->next = node->next; + if (node->next != NULL) + node->next->prev = node->prev; + if (prev == NULL) + new_node->first = node; + else + prev->next = node; + node->prev = prev; + node->next = NULL; + prev = node; } + add_new_object_hard_regs_node_to_forest (roots, new_node); } - return false; + VEC_truncate (object_hard_regs_node_t, hard_regs_node_vec, start); } -#ifdef ENABLE_IRA_CHECKING +/* Add object hard registers nodes starting with the forest level + given by FIRST which contains biggest set inside SET. */ +static void +collect_object_hard_regs_cover (object_hard_regs_node_t first, + HARD_REG_SET set) +{ + object_hard_regs_node_t node; -/* Return TRUE if live ranges of pseudo-registers REGNO1 and REGNO2 - intersect. This should be used when there is only one region. - Currently this is used during reload. */ + ira_assert (first != NULL); + for (node = first; node != NULL; node = node->next) + if (hard_reg_set_subset_p (node->hard_regs->set, set)) + VEC_safe_push (object_hard_regs_node_t, heap, hard_regs_node_vec, + node); + else if (hard_reg_set_intersect_p (set, node->hard_regs->set)) + collect_object_hard_regs_cover (node->first, set); +} + +/* Set up field parent as PARENT in all object hard registers nodes + in forest given by FIRST. */ +static void +setup_object_hard_regs_nodes_parent (object_hard_regs_node_t first, + object_hard_regs_node_t parent) +{ + object_hard_regs_node_t node; + + for (node = first; node != NULL; node = node->next) + { + node->parent = parent; + setup_object_hard_regs_nodes_parent (node->first, node); + } +} + +/* Return object hard registers node which is a first common ancestor + node of FIRST and SECOND in the forest. */ +static object_hard_regs_node_t +first_common_ancestor_node (object_hard_regs_node_t first, + object_hard_regs_node_t second) +{ + object_hard_regs_node_t node; + + node_check_tick++; + for (node = first; node != NULL; node = node->parent) + node->check = node_check_tick; + for (node = second; node != NULL; node = node->parent) + if (node->check == node_check_tick) + return node; + return first_common_ancestor_node (second, first); +} + +/* Print hard reg set SET to F. */ +static void +print_hard_reg_set (FILE *f, HARD_REG_SET set, bool new_line_p) +{ + int i, start; + + for (start = -1, i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (TEST_HARD_REG_BIT (set, i)) + { + if (i == 0 || ! TEST_HARD_REG_BIT (set, i - 1)) + start = i; + } + if (start >= 0 + && (i == FIRST_PSEUDO_REGISTER - 1 || ! TEST_HARD_REG_BIT (set, i))) + { + if (start == i - 1) + fprintf (f, " %d", start); + else if (start == i - 2) + fprintf (f, " %d %d", start, start + 1); + else + fprintf (f, " %d-%d", start, i - 1); + start = -1; + } + } + if (new_line_p) + fprintf (f, "\n"); +} + +/* Print object hard register subforest given by ROOTS and its LEVEL + to F. */ +static void +print_hard_regs_subforest (FILE *f, object_hard_regs_node_t roots, + int level) +{ + int i; + object_hard_regs_node_t node; + + for (node = roots; node != NULL; node = node->next) + { + fprintf (f, " "); + for (i = 0; i < level * 2; i++) + fprintf (f, " "); + fprintf (f, "%d:(", node->preorder_num); + print_hard_reg_set (f, node->hard_regs->set, false); + fprintf (f, ")@%lld\n", node->hard_regs->cost); + print_hard_regs_subforest (f, node->first, level + 1); + } +} + +/* Print the object hard register forest to F. */ +static void +print_hard_regs_forest (FILE *f) +{ + fprintf (f, " Hard reg set forest:\n"); + print_hard_regs_subforest (f, hard_regs_roots, 1); +} + +/* Print the object hard register forest to stderr. */ +void +ira_debug_hard_regs_forest (void) +{ + print_hard_regs_forest (stderr); +} + +/* Remove unused object hard registers nodes from forest given by its + *ROOTS. */ +static void +remove_unused_object_hard_regs_nodes (object_hard_regs_node_t *roots) +{ + object_hard_regs_node_t node, prev, next, last; + + for (prev = NULL, node = *roots; node != NULL; node = next) + { + next = node->next; + if (node->used_p) + { + remove_unused_object_hard_regs_nodes (&node->first); + prev = node; + } + else + { + for (last = node->first; + last != NULL && last->next != NULL; + last = last->next) + ; + if (last != NULL) + { + if (prev == NULL) + *roots = node->first; + else + prev->next = node->first; + if (next != NULL) + next->prev = last; + last->next = next; + next = node->first; + } + else + { + if (prev == NULL) + *roots = next; + else + prev->next = next; + if (next != NULL) + next->prev = prev; + } + ira_free (node); + } + } +} + +/* Set up fields preorder_num starting with START_NUM in all object + hard registers nodes in forest given by FIRST. Return biggest set + PREORDER_NUM increased by 1. */ +static int +enumerate_object_hard_regs_nodes (object_hard_regs_node_t first, + object_hard_regs_node_t parent, + int start_num) +{ + object_hard_regs_node_t node; + + for (node = first; node != NULL; node = node->next) + { + node->preorder_num = start_num++; + node->parent = parent; + start_num = enumerate_object_hard_regs_nodes (node->first, node, + start_num); + } + return start_num; +} + +/* Number of object hard registers nodes in the forest. */ +static int object_hard_regs_nodes_num; + +/* Table preorder number of object hard registers node in the forest + -> the object hard registers node. */ +static object_hard_regs_node_t *object_hard_regs_nodes; + +/* See below. */ +typedef struct object_hard_regs_subnode *object_hard_regs_subnode_t; + +/* The structure is used to describes all subnodes (not only immediate + ones) in the mentioned above tree for given object hard register + node. The usage of such data accelerates calculation of + colorability of given allocno. */ +struct object_hard_regs_subnode +{ + /* The conflict size of conflicting allocnos whose hard register + sets are equal sets (plus supersets if given node is given + object hard registers node) of one in the given node. */ + int left_conflict_size; + /* The summary conflict size of conflicting allocnos whose hard + register sets are strict subsets of one in the given node. + Overall conflict size is + left_conflict_subnodes_size + + MIN (max_node_impact - left_conflict_subnodes_size, + left_conflict_size) + */ + short left_conflict_subnodes_size; + short max_node_impact; +}; + +/* Container for hard regs subnodes of all objects. */ +static object_hard_regs_subnode_t object_hard_regs_subnodes; + +/* Table (preorder number of object hard registers node in the + forest, preorder number of object hard registers subnode) -> index + of the subnode relative to the node. -1 if it is not a + subnode. */ +static int *object_hard_regs_subnode_index; + +/* Setup arrays OBJECT_HARD_REGS_NODES and + OBJECT_HARD_REGS_SUBNODE_INDEX. */ +static void +setup_object_hard_regs_subnode_index (object_hard_regs_node_t first) +{ + object_hard_regs_node_t node, parent; + int index; + + for (node = first; node != NULL; node = node->next) + { + object_hard_regs_nodes[node->preorder_num] = node; + for (parent = node; parent != NULL; parent = parent->parent) + { + index = parent->preorder_num * object_hard_regs_nodes_num; + object_hard_regs_subnode_index[index + node->preorder_num] + = node->preorder_num - parent->preorder_num; + } + setup_object_hard_regs_subnode_index (node->first); + } +} + +/* Count all object hard registers nodes in tree ROOT. */ +static int +get_object_hard_regs_subnodes_num (object_hard_regs_node_t root) +{ + int len = 1; + + for (root = root->first; root != NULL; root = root->next) + len += get_object_hard_regs_subnodes_num (root); + return len; +} + +/* Build the forest of object hard registers nodes and assign each + allocno a node from the forest. */ +static void +form_object_hard_regs_nodes_forest (void) +{ + unsigned int i, j, size, len; + int start, k; + ira_allocno_t a; + object_hard_regs_t hv; + bitmap_iterator bi; + HARD_REG_SET temp; + object_hard_regs_node_t node, object_hard_regs_node; + + node_check_tick = 0; + init_object_hard_regs (); + hard_regs_roots = NULL; + hard_regs_node_vec = VEC_alloc (object_hard_regs_node_t, heap, 100); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, i)) + { + CLEAR_HARD_REG_SET (temp); + SET_HARD_REG_BIT (temp, i); + hv = add_object_hard_regs (temp, 0); + node = create_new_object_hard_regs_node (hv); + add_new_object_hard_regs_node_to_forest (&hard_regs_roots, node); + } + start = VEC_length (object_hard_regs_t, object_hard_regs_vec); + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + for (k = 0; k < ALLOCNO_NUM_OBJECTS (a); k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + if (hard_reg_set_empty_p (obj_data->profitable_hard_regs)) + continue; + hv = (add_object_hard_regs + (obj_data->profitable_hard_regs, + ALLOCNO_MEMORY_COST (a) - ALLOCNO_CLASS_COST (a))); + } + } + SET_HARD_REG_SET (temp); + AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs); + add_object_hard_regs (temp, 0); + qsort (VEC_address (object_hard_regs_t, object_hard_regs_vec) + start, + VEC_length (object_hard_regs_t, object_hard_regs_vec) - start, + sizeof (object_hard_regs_t), object_hard_regs_compare); + for (i = start; + VEC_iterate (object_hard_regs_t, object_hard_regs_vec, i, hv); + i++) + { + add_object_hard_regs_to_forest (&hard_regs_roots, hv); + ira_assert (VEC_length (object_hard_regs_node_t, + hard_regs_node_vec) == 0); + } + /* We need to set up parent fields for right work of + first_common_ancestor_node. */ + setup_object_hard_regs_nodes_parent (hard_regs_roots, NULL); + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + for (k = 0; k < ALLOCNO_NUM_OBJECTS (a); k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + if (hard_reg_set_empty_p (obj_data->profitable_hard_regs)) + continue; + VEC_truncate (object_hard_regs_node_t, hard_regs_node_vec, 0); + collect_object_hard_regs_cover (hard_regs_roots, + obj_data->profitable_hard_regs); + object_hard_regs_node = NULL; + for (j = 0; + VEC_iterate (object_hard_regs_node_t, hard_regs_node_vec, + j, node); + j++) + object_hard_regs_node + = (j == 0 + ? node + : first_common_ancestor_node (node, object_hard_regs_node)); + /* That is a temporary storage. */ + object_hard_regs_node->used_p = true; + obj_data->hard_regs_node = object_hard_regs_node; + } + } + ira_assert (hard_regs_roots->next == NULL); + hard_regs_roots->used_p = true; + remove_unused_object_hard_regs_nodes (&hard_regs_roots); + object_hard_regs_nodes_num + = enumerate_object_hard_regs_nodes (hard_regs_roots, NULL, 0); + object_hard_regs_nodes + = ((object_hard_regs_node_t *) + ira_allocate (object_hard_regs_nodes_num + * sizeof (object_hard_regs_node_t))); + size = object_hard_regs_nodes_num * object_hard_regs_nodes_num; + object_hard_regs_subnode_index + = (int *) ira_allocate (size * sizeof (int)); + for (i = 0; i < size; i++) + object_hard_regs_subnode_index[i] = -1; + setup_object_hard_regs_subnode_index (hard_regs_roots); + start = 0; + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + for (k = 0; k < ALLOCNO_NUM_OBJECTS (a); k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + if (hard_reg_set_empty_p (obj_data->profitable_hard_regs)) + continue; + len = get_object_hard_regs_subnodes_num (obj_data->hard_regs_node); + obj_data->hard_regs_subnodes_start = start; + obj_data->hard_regs_subnodes_num = len; + start += len; + } + } + object_hard_regs_subnodes + = ((object_hard_regs_subnode_t) + ira_allocate (sizeof (struct object_hard_regs_subnode) * start)); + VEC_free (object_hard_regs_node_t, heap, hard_regs_node_vec); +} + +/* Free tree of object hard registers nodes given by its ROOT. */ +static void +finish_object_hard_regs_nodes_tree (object_hard_regs_node_t root) +{ + object_hard_regs_node_t child, next; + + for (child = root->first; child != NULL; child = next) + { + next = child->next; + finish_object_hard_regs_nodes_tree (child); + } + ira_free (root); +} + +/* Finish work with the forest of object hard registers nodes. */ +static void +finish_object_hard_regs_nodes_forest (void) +{ + object_hard_regs_node_t node, next; + + ira_free (object_hard_regs_subnodes); + for (node = hard_regs_roots; node != NULL; node = next) + { + next = node->next; + finish_object_hard_regs_nodes_tree (node); + } + ira_free (object_hard_regs_nodes); + ira_free (object_hard_regs_subnode_index); + finish_object_hard_regs (); +} + +/* Set up left conflict sizes and left conflict subnodes sizes of hard + registers subnodes of allocno A. Return TRUE if allocno A is + trivially colorable. */ static bool -pseudos_have_intersected_live_ranges_p (int regno1, int regno2) +setup_left_conflict_sizes_p (ira_allocno_t a) { - ira_allocno_t a1, a2; + int k, nobj, conflict_size; + allocno_color_data_t data; - ira_assert (regno1 >= FIRST_PSEUDO_REGISTER - && regno2 >= FIRST_PSEUDO_REGISTER); - /* Reg info caclulated by dataflow infrastructure can be different - from one calculated by regclass. */ - if ((a1 = ira_loop_tree_root->regno_allocno_map[regno1]) == NULL - || (a2 = ira_loop_tree_root->regno_allocno_map[regno2]) == NULL) - return false; - return allocnos_have_intersected_live_ranges_p (a1, a2); + nobj = ALLOCNO_NUM_OBJECTS (a); + conflict_size = 0; + data = ALLOCNO_COLOR_DATA (a); + for (k = 0; k < nobj; k++) + { + int i, node_preorder_num, start, left_conflict_subnodes_size; + HARD_REG_SET profitable_hard_regs; + object_hard_regs_subnode_t subnodes; + object_hard_regs_node_t node; + HARD_REG_SET node_set; + ira_object_t obj = ALLOCNO_OBJECT (a, k); + ira_object_t conflict_obj; + ira_object_conflict_iterator oci; + object_color_data_t obj_data; + + node_check_tick++; + obj_data = OBJECT_COLOR_DATA (obj); + subnodes = object_hard_regs_subnodes + obj_data->hard_regs_subnodes_start; + COPY_HARD_REG_SET (profitable_hard_regs, obj_data->profitable_hard_regs); + node = obj_data->hard_regs_node; + node_preorder_num = node->preorder_num; + COPY_HARD_REG_SET (node_set, node->hard_regs->set); + FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) + { + int size; + ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); + object_hard_regs_node_t conflict_node, temp_node; + HARD_REG_SET conflict_node_set; + object_color_data_t conflict_obj_data; + + conflict_obj_data = OBJECT_COLOR_DATA (conflict_obj); + if (! ALLOCNO_COLOR_DATA (conflict_a)->in_graph_p + || ! hard_reg_set_intersect_p (profitable_hard_regs, + conflict_obj_data + ->profitable_hard_regs)) + continue; + conflict_node = conflict_obj_data->hard_regs_node; + COPY_HARD_REG_SET (conflict_node_set, conflict_node->hard_regs->set); + if (hard_reg_set_subset_p (node_set, conflict_node_set)) + temp_node = node; + else + { + ira_assert (hard_reg_set_subset_p (conflict_node_set, node_set)); + temp_node = conflict_node; + } + if (temp_node->check != node_check_tick) + { + 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; + } + for (i = 0; i < obj_data->hard_regs_subnodes_num; i++) + { + object_hard_regs_node_t temp_node; + + temp_node = object_hard_regs_nodes[i + node_preorder_num]; + ira_assert (temp_node->preorder_num == i + node_preorder_num); + subnodes[i].left_conflict_size = (temp_node->check != node_check_tick + ? 0 : temp_node->conflict_size); + if (hard_reg_set_subset_p (temp_node->hard_regs->set, + profitable_hard_regs)) + subnodes[i].max_node_impact = temp_node->hard_regs_num; + else + { + HARD_REG_SET temp_set; + int j, n; + enum reg_class aclass; + + COPY_HARD_REG_SET (temp_set, temp_node->hard_regs->set); + AND_HARD_REG_SET (temp_set, profitable_hard_regs); + aclass = ALLOCNO_CLASS (a); + for (n = 0, j = ira_class_hard_regs_num[aclass] - 1; j >= 0; j--) + if (TEST_HARD_REG_BIT (temp_set, ira_class_hard_regs[aclass][j])) + n++; + subnodes[i].max_node_impact = n; + } + subnodes[i].left_conflict_subnodes_size = 0; + } + start = node_preorder_num * object_hard_regs_nodes_num; + for (i = obj_data->hard_regs_subnodes_num - 1; i >= 0; i--) + { + int size, parent_i; + object_hard_regs_node_t parent; + + size = (subnodes[i].left_conflict_subnodes_size + + MIN (subnodes[i].max_node_impact + - subnodes[i].left_conflict_subnodes_size, + subnodes[i].left_conflict_size)); + parent = object_hard_regs_nodes[i + node_preorder_num]->parent; + if (parent == NULL) + continue; + parent_i + = object_hard_regs_subnode_index[start + parent->preorder_num]; + if (parent_i < 0) + continue; + subnodes[parent_i].left_conflict_subnodes_size += size; + } + left_conflict_subnodes_size = subnodes[0].left_conflict_subnodes_size; + conflict_size + += (left_conflict_subnodes_size + + MIN (subnodes[0].max_node_impact - left_conflict_subnodes_size, + subnodes[0].left_conflict_size)); + } + conflict_size += ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]; + data->colorable_p = conflict_size <= data->available_regs_num; + return data->colorable_p; +} + +/* Update left conflict sizes of hard registers subnodes of allocno A + after removing allocno containing object REMOVED_OBJ with SIZE from + the conflict graph. Return TRUE if A is trivially colorable. */ +static bool +update_left_conflict_sizes_p (ira_allocno_t a, + ira_object_t removed_obj, int size) +{ + int i, k, conflict_size, before_conflict_size, diff, start; + int node_preorder_num, parent_i; + object_hard_regs_node_t node, removed_node, parent; + object_hard_regs_subnode_t subnodes; + allocno_color_data_t data = ALLOCNO_COLOR_DATA (a); + bool colorable_p = true; + + ira_assert (! data->colorable_p); + for (k = 0; k < ALLOCNO_NUM_OBJECTS (a); k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + node = obj_data->hard_regs_node; + node_preorder_num = node->preorder_num; + removed_node = OBJECT_COLOR_DATA (removed_obj)->hard_regs_node; + if (! hard_reg_set_subset_p (removed_node->hard_regs->set, + node->hard_regs->set) + && ! hard_reg_set_subset_p (node->hard_regs->set, + removed_node->hard_regs->set)) + /* It is a rare case which can happen for conflicting + multi-object allocnos where only one pair of objects might + conflict. */ + continue; + start = node_preorder_num * object_hard_regs_nodes_num; + i = object_hard_regs_subnode_index[start + removed_node->preorder_num]; + if (i < 0) + i = 0; + subnodes = object_hard_regs_subnodes + obj_data->hard_regs_subnodes_start; + before_conflict_size + = (subnodes[i].left_conflict_subnodes_size + + MIN (subnodes[i].max_node_impact + - subnodes[i].left_conflict_subnodes_size, + subnodes[i].left_conflict_size)); + subnodes[i].left_conflict_size -= size; + for (;;) + { + conflict_size + = (subnodes[i].left_conflict_subnodes_size + + MIN (subnodes[i].max_node_impact + - subnodes[i].left_conflict_subnodes_size, + subnodes[i].left_conflict_size)); + if ((diff = before_conflict_size - conflict_size) == 0) + break; + ira_assert (conflict_size < before_conflict_size); + parent = object_hard_regs_nodes[i + node_preorder_num]->parent; + if (parent == NULL) + break; + parent_i + = object_hard_regs_subnode_index[start + parent->preorder_num]; + if (parent_i < 0) + break; + i = parent_i; + before_conflict_size + = (subnodes[i].left_conflict_subnodes_size + + MIN (subnodes[i].max_node_impact + - subnodes[i].left_conflict_subnodes_size, + subnodes[i].left_conflict_size)); + subnodes[i].left_conflict_subnodes_size -= diff; + } + if (i != 0 + || (conflict_size + + ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)] + > data->available_regs_num)) + { + colorable_p = false; + break; + } + } + if (colorable_p) + { + data->colorable_p = true; + return true; + } + return false; } -#endif +/* Return true if allocno A has an object with empty profitable hard + regs. */ +static bool +empty_profitable_hard_regs (ira_allocno_t a) +{ + int k, nobj; + + nobj = ALLOCNO_NUM_OBJECTS (a); + for (k = 0; k < nobj; k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + if (hard_reg_set_empty_p (obj_data->profitable_hard_regs)) + return true; + } + return false; +} + +/* Set up profitable hard registers for each allocno being + colored. */ +static void +setup_profitable_hard_regs (void) +{ + unsigned int i; + int j, k, nobj, hard_regno, nregs, class_size; + ira_allocno_t a; + bitmap_iterator bi; + enum reg_class aclass; + enum machine_mode mode; + + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + if ((aclass = ALLOCNO_CLASS (a)) == NO_REGS) + continue; + mode = ALLOCNO_MODE (a); + nobj = ALLOCNO_NUM_OBJECTS (a); + for (k = 0; k < nobj; k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + if (ALLOCNO_UPDATED_HARD_REG_COSTS (a) == NULL + && ALLOCNO_CLASS_COST (a) > ALLOCNO_MEMORY_COST (a)) + CLEAR_HARD_REG_SET (obj_data->profitable_hard_regs); + else + { + COPY_HARD_REG_SET (obj_data->profitable_hard_regs, + reg_class_contents[aclass]); + AND_COMPL_HARD_REG_SET + (obj_data->profitable_hard_regs, + ira_prohibited_class_mode_regs[aclass][mode]); + AND_COMPL_HARD_REG_SET (obj_data->profitable_hard_regs, + ira_no_alloc_regs); + AND_COMPL_HARD_REG_SET (obj_data->profitable_hard_regs, + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)); + } + } + } + EXECUTE_IF_SET_IN_BITMAP (consideration_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + if ((aclass = ALLOCNO_CLASS (a)) == NO_REGS + || ! ALLOCNO_ASSIGNED_P (a) + || (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++) + { + 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) + { + if (nregs == nobj && nregs > 1) + { + int num = OBJECT_SUBWORD (conflict_obj); + + if (WORDS_BIG_ENDIAN) + CLEAR_HARD_REG_BIT + (OBJECT_COLOR_DATA (conflict_obj)->profitable_hard_regs, + hard_regno + nobj - num - 1); + else + CLEAR_HARD_REG_BIT + (OBJECT_COLOR_DATA (conflict_obj)->profitable_hard_regs, + hard_regno + num); + } + else + AND_COMPL_HARD_REG_SET + (OBJECT_COLOR_DATA (conflict_obj)->profitable_hard_regs, + ira_reg_mode_hard_regset[hard_regno][mode]); + } + } + } + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + int min_cost = INT_MAX; + int *costs; + + a = ira_allocnos[i]; + if ((aclass = ALLOCNO_CLASS (a)) == NO_REGS + || empty_profitable_hard_regs (a)) + continue; + mode = ALLOCNO_MODE (a); + nobj = ALLOCNO_NUM_OBJECTS (a); + for (k = 0; k < nobj; k++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); + + if ((costs = ALLOCNO_UPDATED_HARD_REG_COSTS (a)) != NULL + || (costs = ALLOCNO_HARD_REG_COSTS (a)) != NULL) + { + class_size = ira_class_hard_regs_num[aclass]; + for (j = 0; j < class_size; j++) + { + hard_regno = ira_class_hard_regs[aclass][j]; + nregs = hard_regno_nregs[hard_regno][mode]; + if (nregs == nobj && nregs > 1) + { + int num = OBJECT_SUBWORD (obj); + + if (WORDS_BIG_ENDIAN) + hard_regno += nobj - num - 1; + else + hard_regno += num; + } + if (! TEST_HARD_REG_BIT (obj_data->profitable_hard_regs, + hard_regno)) + continue; + if (ALLOCNO_UPDATED_MEMORY_COST (a) < costs[j]) + CLEAR_HARD_REG_BIT (obj_data->profitable_hard_regs, + hard_regno); + else if (min_cost > costs[j]) + min_cost = costs[j]; + } + } + else if (ALLOCNO_UPDATED_MEMORY_COST (a) + < ALLOCNO_UPDATED_CLASS_COST (a)) + CLEAR_HARD_REG_SET (obj_data->profitable_hard_regs); + } + if (ALLOCNO_UPDATED_CLASS_COST (a) > min_cost) + ALLOCNO_UPDATED_CLASS_COST (a) = min_cost; + } +} @@ -147,7 +1186,8 @@ pseudos_have_intersected_live_ranges_p ( static bool allocated_hardreg_p[FIRST_PSEUDO_REGISTER]; /* Describes one element in a queue of allocnos whose costs need to be - updated. Each allocno in the queue is known to have a cover class. */ + updated. Each allocno in the queue is known to have an allocno + class. */ struct update_cost_queue_elem { /* This element is in the queue iff CHECK == update_cost_check. */ @@ -210,8 +1250,8 @@ start_update_cost (void) update_cost_queue = NULL; } -/* Add (ALLOCNO, DIVISOR) to the end of update_cost_queue, - unless ALLOCNO is already in the queue, or has no cover class. */ +/* Add (ALLOCNO, 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, int divisor) { @@ -219,7 +1259,7 @@ queue_update_cost (ira_allocno_t allocno elem = &update_cost_queue_elems[ALLOCNO_NUM (allocno)]; if (elem->check != update_cost_check - && ALLOCNO_COVER_CLASS (allocno) != NO_REGS) + && ALLOCNO_CLASS (allocno) != NO_REGS) { elem->check = update_cost_check; elem->divisor = divisor; @@ -257,17 +1297,17 @@ update_copy_costs (ira_allocno_t allocno { int i, cost, update_cost, hard_regno, divisor; enum machine_mode mode; - enum reg_class rclass, cover_class; + enum reg_class rclass, aclass; ira_allocno_t another_allocno; ira_copy_t cp, next_cp; hard_regno = ALLOCNO_HARD_REGNO (allocno); ira_assert (hard_regno >= 0); - cover_class = ALLOCNO_COVER_CLASS (allocno); - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (allocno); + if (aclass == NO_REGS) return; - i = ira_class_hard_reg_index[cover_class][hard_regno]; + i = ira_class_hard_reg_index[aclass][hard_regno]; ira_assert (i >= 0); rclass = REGNO_REG_CLASS (hard_regno); @@ -276,6 +1316,7 @@ update_copy_costs (ira_allocno_t allocno do { mode = ALLOCNO_MODE (allocno); + ira_init_register_move_cost_if_necessary (mode); for (cp = ALLOCNO_COPIES (allocno); cp != NULL; cp = next_cp) { if (cp->first == allocno) @@ -291,15 +1332,15 @@ update_copy_costs (ira_allocno_t allocno else gcc_unreachable (); - cover_class = ALLOCNO_COVER_CLASS (another_allocno); - if (! TEST_HARD_REG_BIT (reg_class_contents[cover_class], + aclass = ALLOCNO_CLASS (another_allocno); + if (! TEST_HARD_REG_BIT (reg_class_contents[aclass], hard_regno) || ALLOCNO_ASSIGNED_P (another_allocno)) continue; cost = (cp->second == allocno - ? ira_get_register_move_cost (mode, rclass, cover_class) - : ira_get_register_move_cost (mode, cover_class, rclass)); + ? ira_register_move_cost[mode][rclass][aclass] + : ira_register_move_cost[mode][aclass][rclass]); if (decr_p) cost = -cost; @@ -308,15 +1349,15 @@ update_copy_costs (ira_allocno_t allocno continue; ira_allocate_and_set_or_copy_costs - (&ALLOCNO_UPDATED_HARD_REG_COSTS (another_allocno), cover_class, - ALLOCNO_UPDATED_COVER_CLASS_COST (another_allocno), + (&ALLOCNO_UPDATED_HARD_REG_COSTS (another_allocno), aclass, + ALLOCNO_UPDATED_CLASS_COST (another_allocno), ALLOCNO_HARD_REG_COSTS (another_allocno)); ira_allocate_and_set_or_copy_costs (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno), - cover_class, 0, - ALLOCNO_CONFLICT_HARD_REG_COSTS (another_allocno)); - i = ira_class_hard_reg_index[cover_class][hard_regno]; - ira_assert (i >= 0); + aclass, 0, ALLOCNO_CONFLICT_HARD_REG_COSTS (another_allocno)); + i = ira_class_hard_reg_index[aclass][hard_regno]; + if (i < 0) + continue; ALLOCNO_UPDATED_HARD_REG_COSTS (another_allocno)[i] += update_cost; ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno)[i] += update_cost; @@ -328,18 +1369,18 @@ update_copy_costs (ira_allocno_t allocno } /* This function updates COSTS (decrease if DECR_P) for hard_registers - of COVER_CLASS by conflict costs of the unassigned allocnos + of ACLASS by conflict costs of the unassigned allocnos connected by copies with allocnos in update_cost_queue. This update increases chances to remove some copies. */ static void -update_conflict_hard_regno_costs (int *costs, enum reg_class cover_class, +update_conflict_hard_regno_costs (int *costs, enum reg_class aclass, bool decr_p) { int i, cost, class_size, freq, mult, div, divisor; int index, hard_regno; int *conflict_costs; bool cont_p; - enum reg_class another_cover_class; + enum reg_class another_aclass; ira_allocno_t allocno, another_allocno; ira_copy_t cp, next_cp; @@ -358,16 +1399,15 @@ update_conflict_hard_regno_costs (int *c } else gcc_unreachable (); - another_cover_class = ALLOCNO_COVER_CLASS (another_allocno); - if (! ira_reg_classes_intersect_p[cover_class][another_cover_class] + another_aclass = ALLOCNO_CLASS (another_allocno); + if (! ira_reg_classes_intersect_p[aclass][another_aclass] || ALLOCNO_ASSIGNED_P (another_allocno) - || ALLOCNO_MAY_BE_SPILLED_P (another_allocno)) + || ALLOCNO_COLOR_DATA (another_allocno)->may_be_spilled_p) continue; - class_size = ira_class_hard_regs_num[another_cover_class]; + class_size = ira_class_hard_regs_num[another_aclass]; ira_allocate_and_copy_costs (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno), - another_cover_class, - ALLOCNO_CONFLICT_HARD_REG_COSTS (another_allocno)); + another_aclass, ALLOCNO_CONFLICT_HARD_REG_COSTS (another_allocno)); conflict_costs = ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno); if (conflict_costs == NULL) @@ -382,9 +1422,9 @@ update_conflict_hard_regno_costs (int *c cont_p = false; for (i = class_size - 1; i >= 0; i--) { - hard_regno = ira_class_hard_regs[another_cover_class][i]; + hard_regno = ira_class_hard_regs[another_aclass][i]; ira_assert (hard_regno >= 0); - index = ira_class_hard_reg_index[cover_class][hard_regno]; + index = ira_class_hard_reg_index[aclass][hard_regno]; if (index < 0) continue; cost = conflict_costs [i] * mult / div; @@ -406,17 +1446,96 @@ update_conflict_hard_regno_costs (int *c } } +/* Set up conflicting and profitable regs (through CONFLICT_REGS and + PROFITABLE_REGS) for each object of allocno A. */ +static inline void +setup_conflict_profitable_regs (ira_allocno_t a, bool retry_p, + HARD_REG_SET *conflict_regs, + HARD_REG_SET *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); + COPY_HARD_REG_SET (conflict_regs[i], + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)); + if (retry_p) + COPY_HARD_REG_SET (profitable_regs[i], + reg_class_contents[ALLOCNO_CLASS (a)]); + else + COPY_HARD_REG_SET (profitable_regs[i], + OBJECT_COLOR_DATA (obj)->profitable_hard_regs); + } +} + +/* Return true if HARD_REGNO is ok for assigning to allocno A whose + objects have corresponding CONFLICT_REGS and PROFITABLE_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) +{ + int j, nwords, nregs; + + nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (a)]; + nwords = ALLOCNO_NUM_OBJECTS (a); + for (j = 0; j < nregs; j++) + { + int k; + int set_to_test_start = 0, set_to_test_end = nwords; + + if (nregs == nwords) + { + if (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++) + /* Checking only profitable hard regs. */ + if (TEST_HARD_REG_BIT (conflict_regs[k], hard_regno + j) + || ! TEST_HARD_REG_BIT (profitable_regs[k], hard_regno + j)) + break; + if (k != set_to_test_end) + break; + } + return j == nregs; +} + /* 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'. */ + `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. */ static bool assign_hard_reg (ira_allocno_t a, bool retry_p) { - HARD_REG_SET conflicting_regs[2]; - int i, j, hard_regno, nregs, best_hard_regno, class_size; + HARD_REG_SET conflicting_regs[2], profitable_hard_regs[2]; + 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; - enum reg_class cover_class; + enum reg_class aclass; enum machine_mode mode; static int costs[FIRST_PSEUDO_REGISTER], full_costs[FIRST_PSEUDO_REGISTER]; #ifndef HONOR_REG_ALLOC_ORDER @@ -427,13 +1546,11 @@ assign_hard_reg (ira_allocno_t a, bool r bool no_stack_reg_p; #endif - nwords = ALLOCNO_NUM_OBJECTS (a); ira_assert (! ALLOCNO_ASSIGNED_P (a)); - cover_class = ALLOCNO_COVER_CLASS (a); - class_size = ira_class_hard_regs_num[cover_class]; - mode = ALLOCNO_MODE (a); - for (i = 0; i < nwords; i++) - CLEAR_HARD_REG_SET (conflicting_regs[i]); + setup_conflict_profitable_regs (a, retry_p, + conflicting_regs, profitable_hard_regs); + aclass = ALLOCNO_CLASS (a); + class_size = ira_class_hard_regs_num[aclass]; best_hard_regno = -1; memset (full_costs, 0, sizeof (int) * class_size); mem_cost = 0; @@ -442,16 +1559,17 @@ assign_hard_reg (ira_allocno_t a, bool r #ifdef STACK_REGS no_stack_reg_p = false; #endif - start_update_cost (); + if (! retry_p) + start_update_cost (); mem_cost += ALLOCNO_UPDATED_MEMORY_COST (a); ira_allocate_and_copy_costs (&ALLOCNO_UPDATED_HARD_REG_COSTS (a), - cover_class, ALLOCNO_HARD_REG_COSTS (a)); + aclass, ALLOCNO_HARD_REG_COSTS (a)); a_costs = ALLOCNO_UPDATED_HARD_REG_COSTS (a); #ifdef STACK_REGS no_stack_reg_p = no_stack_reg_p || ALLOCNO_TOTAL_NO_STACK_REG_P (a); #endif - cost = ALLOCNO_UPDATED_COVER_CLASS_COST (a); + cost = ALLOCNO_UPDATED_CLASS_COST (a); for (i = 0; i < class_size; i++) if (a_costs != NULL) { @@ -463,38 +1581,44 @@ assign_hard_reg (ira_allocno_t a, bool r costs[i] += cost; full_costs[i] += cost; } + nwords = ALLOCNO_NUM_OBJECTS (a); for (word = 0; word < nwords; word++) { ira_object_t conflict_obj; ira_object_t obj = ALLOCNO_OBJECT (a, word); ira_object_conflict_iterator oci; - IOR_HARD_REG_SET (conflicting_regs[word], - OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)); /* Take preferences of conflicting allocnos into account. */ FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) - { + { ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); - enum reg_class conflict_cover_class; - + enum reg_class conflict_aclass; + /* Reload can give another class so we need to check all allocnos. */ - if (!retry_p && !bitmap_bit_p (consideration_allocno_bitmap, - ALLOCNO_NUM (conflict_a))) + if (!retry_p + && (!bitmap_bit_p (consideration_allocno_bitmap, + ALLOCNO_NUM (conflict_a)) + || ((!ALLOCNO_ASSIGNED_P (conflict_a) + || ALLOCNO_HARD_REGNO (conflict_a) < 0) + && !(hard_reg_set_intersect_p + (profitable_hard_regs[word], + OBJECT_COLOR_DATA + (conflict_obj)->profitable_hard_regs))))) continue; - conflict_cover_class = ALLOCNO_COVER_CLASS (conflict_a); + conflict_aclass = ALLOCNO_CLASS (conflict_a); ira_assert (ira_reg_classes_intersect_p - [cover_class][conflict_cover_class]); + [aclass][conflict_aclass]); if (ALLOCNO_ASSIGNED_P (conflict_a)) { hard_regno = ALLOCNO_HARD_REGNO (conflict_a); if (hard_regno >= 0 - && ira_class_hard_reg_index[cover_class][hard_regno] >= 0) + && ira_class_hard_reg_index[aclass][hard_regno] >= 0) { enum machine_mode mode = ALLOCNO_MODE (conflict_a); int conflict_nregs = hard_regno_nregs[hard_regno][mode]; int n_objects = ALLOCNO_NUM_OBJECTS (conflict_a); - + if (conflict_nregs == n_objects && conflict_nregs > 1) { int num = OBJECT_SUBWORD (conflict_obj); @@ -510,28 +1634,28 @@ assign_hard_reg (ira_allocno_t a, bool r IOR_HARD_REG_SET (conflicting_regs[word], ira_reg_mode_hard_regset[hard_regno][mode]); - if (hard_reg_set_subset_p (reg_class_contents[cover_class], + if (hard_reg_set_subset_p (profitable_hard_regs[word], conflicting_regs[word])) goto fail; } } - else if (! ALLOCNO_MAY_BE_SPILLED_P (conflict_a)) + else if (! retry_p + && ! ALLOCNO_COLOR_DATA (conflict_a)->may_be_spilled_p) { int k, *conflict_costs; ira_allocate_and_copy_costs (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (conflict_a), - conflict_cover_class, + conflict_aclass, ALLOCNO_CONFLICT_HARD_REG_COSTS (conflict_a)); conflict_costs = ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (conflict_a); if (conflict_costs != NULL) for (j = class_size - 1; j >= 0; j--) { - hard_regno = ira_class_hard_regs[cover_class][j]; + hard_regno = ira_class_hard_regs[aclass][j]; ira_assert (hard_regno >= 0); - k = (ira_class_hard_reg_index - [conflict_cover_class][hard_regno]); + k = ira_class_hard_reg_index[conflict_aclass][hard_regno]; if (k < 0) continue; full_costs[j] -= conflict_costs[k]; @@ -540,52 +1664,36 @@ assign_hard_reg (ira_allocno_t a, bool r } } } - /* Take into account preferences of allocnos connected by copies to - the conflict allocnos. */ - update_conflict_hard_regno_costs (full_costs, cover_class, true); + if (! retry_p) + /* Take into account preferences of allocnos connected by copies to + the conflict allocnos. */ + update_conflict_hard_regno_costs (full_costs, aclass, true); /* Take preferences of allocnos connected by copies into account. */ - start_update_cost (); - queue_update_cost (a, COST_HOP_DIVISOR); - update_conflict_hard_regno_costs (full_costs, cover_class, false); + if (! retry_p) + { + start_update_cost (); + queue_update_cost (a, COST_HOP_DIVISOR); + update_conflict_hard_regno_costs (full_costs, aclass, false); + } min_cost = min_full_cost = INT_MAX; /* 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). */ + mode = ALLOCNO_MODE (a); for (i = 0; i < class_size; i++) { - hard_regno = ira_class_hard_regs[cover_class][i]; - nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (a)]; + hard_regno = ira_class_hard_regs[aclass][i]; #ifdef STACK_REGS if (no_stack_reg_p && FIRST_STACK_REG <= hard_regno && hard_regno <= LAST_STACK_REG) continue; #endif - if (TEST_HARD_REG_BIT (prohibited_class_mode_regs[cover_class][mode], - hard_regno)) - continue; - for (j = 0; j < nregs; j++) - { - int k; - int set_to_test_start = 0, set_to_test_end = nwords; - if (nregs == nwords) - { - if (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 (conflicting_regs[k], hard_regno + j)) - break; - if (k != set_to_test_end) - break; - } - if (j != nregs) + if (! check_hard_reg_p (a, hard_regno, + conflicting_regs, profitable_hard_regs)) continue; cost = costs[i]; full_cost = full_costs[i]; @@ -627,6 +1735,7 @@ assign_hard_reg (ira_allocno_t a, bool r ALLOCNO_ASSIGNED_P (a) = true; if (best_hard_regno >= 0) update_copy_costs (a, true); + ira_assert (ALLOCNO_CLASS (a) == aclass); /* We don't need updated costs anymore: */ ira_free_allocno_updated_costs (a); return best_hard_regno >= 0; @@ -643,41 +1752,43 @@ static ira_allocno_t colorable_allocno_b spilling. */ static ira_allocno_t uncolorable_allocno_bucket; -/* Each element of the array contains the current number of allocnos - of given *cover* class in the uncolorable_bucket. */ -static int uncolorable_allocnos_num[N_REG_CLASSES]; +/* The current number of allocnos in the uncolorable_bucket. */ +static int uncolorable_allocnos_num; /* Return the current spill priority of allocno A. The less the number, the more preferable the allocno for spilling. */ -static int +static inline int allocno_spill_priority (ira_allocno_t a) { - return (ALLOCNO_TEMP (a) - / (ALLOCNO_LEFT_CONFLICTS_SIZE (a) - * ira_reg_class_nregs[ALLOCNO_COVER_CLASS (a)][ALLOCNO_MODE (a)] + allocno_color_data_t data = ALLOCNO_COLOR_DATA (a); + + return (data->temp + / (ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) + * ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)] + 1)); } -/* Add ALLOCNO to bucket *BUCKET_PTR. ALLOCNO should be not in a bucket +/* Add allocno A to bucket *BUCKET_PTR. A should be not in a bucket before the call. */ static void -add_allocno_to_bucket (ira_allocno_t allocno, ira_allocno_t *bucket_ptr) +add_allocno_to_bucket (ira_allocno_t a, ira_allocno_t *bucket_ptr) { - ira_allocno_t first_allocno; - enum reg_class cover_class; + ira_allocno_t first_a; + allocno_color_data_t data; if (bucket_ptr == &uncolorable_allocno_bucket - && (cover_class = ALLOCNO_COVER_CLASS (allocno)) != NO_REGS) + && ALLOCNO_CLASS (a) != NO_REGS) { - uncolorable_allocnos_num[cover_class]++; - ira_assert (uncolorable_allocnos_num[cover_class] > 0); + uncolorable_allocnos_num++; + ira_assert (uncolorable_allocnos_num > 0); } - first_allocno = *bucket_ptr; - ALLOCNO_NEXT_BUCKET_ALLOCNO (allocno) = first_allocno; - ALLOCNO_PREV_BUCKET_ALLOCNO (allocno) = NULL; - if (first_allocno != NULL) - ALLOCNO_PREV_BUCKET_ALLOCNO (first_allocno) = allocno; - *bucket_ptr = allocno; + first_a = *bucket_ptr; + data = ALLOCNO_COLOR_DATA (a); + data->next_bucket_allocno = first_a; + data->prev_bucket_allocno = NULL; + if (first_a != NULL) + ALLOCNO_COLOR_DATA (first_a)->prev_bucket_allocno = a; + *bucket_ptr = a; } /* Compare two allocnos to define which allocno should be pushed first @@ -694,15 +1805,15 @@ bucket_allocno_compare_func (const void ira_allocno_t a2 = *(const ira_allocno_t *) v2p; int diff, a1_freq, a2_freq, a1_num, a2_num; - if ((diff = (int) ALLOCNO_COVER_CLASS (a2) - ALLOCNO_COVER_CLASS (a1)) != 0) + if ((diff = (int) ALLOCNO_CLASS (a2) - ALLOCNO_CLASS (a1)) != 0) return diff; a1_freq = ALLOCNO_FREQ (a1); - a1_num = ALLOCNO_AVAILABLE_REGS_NUM (a1); a2_freq = ALLOCNO_FREQ (a2); - a2_num = ALLOCNO_AVAILABLE_REGS_NUM (a2); - if ((diff = a2_num - a1_num) != 0) + if ((diff = a1_freq - a2_freq) != 0) return diff; - else if ((diff = a1_freq - a2_freq) != 0) + a1_num = ALLOCNO_COLOR_DATA (a1)->available_regs_num; + a2_num = ALLOCNO_COLOR_DATA (a2)->available_regs_num; + if ((diff = a2_num - a1_num) != 0) return diff; return ALLOCNO_NUM (a2) - ALLOCNO_NUM (a1); } @@ -710,25 +1821,27 @@ bucket_allocno_compare_func (const void /* Sort bucket *BUCKET_PTR and return the result through BUCKET_PTR. */ static void -sort_bucket (ira_allocno_t *bucket_ptr) +sort_bucket (ira_allocno_t *bucket_ptr, + int (*compare_func) (const void *, const void *)) { ira_allocno_t a, head; int n; - for (n = 0, a = *bucket_ptr; a != NULL; a = ALLOCNO_NEXT_BUCKET_ALLOCNO (a)) + for (n = 0, a = *bucket_ptr; + a != NULL; + a = ALLOCNO_COLOR_DATA (a)->next_bucket_allocno) sorted_allocnos[n++] = a; if (n <= 1) return; - qsort (sorted_allocnos, n, sizeof (ira_allocno_t), - bucket_allocno_compare_func); + qsort (sorted_allocnos, n, sizeof (ira_allocno_t), compare_func); head = NULL; for (n--; n >= 0; n--) { a = sorted_allocnos[n]; - ALLOCNO_NEXT_BUCKET_ALLOCNO (a) = head; - ALLOCNO_PREV_BUCKET_ALLOCNO (a) = NULL; + ALLOCNO_COLOR_DATA (a)->next_bucket_allocno = head; + ALLOCNO_COLOR_DATA (a)->prev_bucket_allocno = NULL; if (head != NULL) - ALLOCNO_PREV_BUCKET_ALLOCNO (head) = a; + ALLOCNO_COLOR_DATA (head)->prev_bucket_allocno = a; head = a; } *bucket_ptr = head; @@ -742,27 +1855,27 @@ add_allocno_to_ordered_bucket (ira_alloc ira_allocno_t *bucket_ptr) { ira_allocno_t before, after; - enum reg_class cover_class; if (bucket_ptr == &uncolorable_allocno_bucket - && (cover_class = ALLOCNO_COVER_CLASS (allocno)) != NO_REGS) + && ALLOCNO_CLASS (allocno) != NO_REGS) { - uncolorable_allocnos_num[cover_class]++; - ira_assert (uncolorable_allocnos_num[cover_class] > 0); + uncolorable_allocnos_num++; + ira_assert (uncolorable_allocnos_num > 0); } for (before = *bucket_ptr, after = NULL; before != NULL; - after = before, before = ALLOCNO_NEXT_BUCKET_ALLOCNO (before)) + after = before, + before = ALLOCNO_COLOR_DATA (before)->next_bucket_allocno) if (bucket_allocno_compare_func (&allocno, &before) < 0) break; - ALLOCNO_NEXT_BUCKET_ALLOCNO (allocno) = before; - ALLOCNO_PREV_BUCKET_ALLOCNO (allocno) = after; + ALLOCNO_COLOR_DATA (allocno)->next_bucket_allocno = before; + ALLOCNO_COLOR_DATA (allocno)->prev_bucket_allocno = after; if (after == NULL) *bucket_ptr = allocno; else - ALLOCNO_NEXT_BUCKET_ALLOCNO (after) = allocno; + ALLOCNO_COLOR_DATA (after)->next_bucket_allocno = allocno; if (before != NULL) - ALLOCNO_PREV_BUCKET_ALLOCNO (before) = allocno; + ALLOCNO_COLOR_DATA (before)->prev_bucket_allocno = allocno; } /* Delete ALLOCNO from bucket *BUCKET_PTR. It should be there before @@ -771,42 +1884,26 @@ static void delete_allocno_from_bucket (ira_allocno_t allocno, ira_allocno_t *bucket_ptr) { ira_allocno_t prev_allocno, next_allocno; - enum reg_class cover_class; if (bucket_ptr == &uncolorable_allocno_bucket - && (cover_class = ALLOCNO_COVER_CLASS (allocno)) != NO_REGS) + && ALLOCNO_CLASS (allocno) != NO_REGS) { - uncolorable_allocnos_num[cover_class]--; - ira_assert (uncolorable_allocnos_num[cover_class] >= 0); + uncolorable_allocnos_num--; + ira_assert (uncolorable_allocnos_num >= 0); } - prev_allocno = ALLOCNO_PREV_BUCKET_ALLOCNO (allocno); - next_allocno = ALLOCNO_NEXT_BUCKET_ALLOCNO (allocno); + prev_allocno = ALLOCNO_COLOR_DATA (allocno)->prev_bucket_allocno; + next_allocno = ALLOCNO_COLOR_DATA (allocno)->next_bucket_allocno; if (prev_allocno != NULL) - ALLOCNO_NEXT_BUCKET_ALLOCNO (prev_allocno) = next_allocno; + ALLOCNO_COLOR_DATA (prev_allocno)->next_bucket_allocno = next_allocno; else { ira_assert (*bucket_ptr == allocno); *bucket_ptr = next_allocno; } if (next_allocno != NULL) - ALLOCNO_PREV_BUCKET_ALLOCNO (next_allocno) = prev_allocno; + ALLOCNO_COLOR_DATA (next_allocno)->prev_bucket_allocno = prev_allocno; } -/* Splay tree for each cover class. The trees are indexed by the - corresponding cover classes. Splay trees contain uncolorable - allocnos. */ -static splay_tree uncolorable_allocnos_splay_tree[N_REG_CLASSES]; - -/* If the following macro is TRUE, splay tree is used to choose an - allocno of the corresponding cover class for spilling. When the - number uncolorable allocnos of given cover class decreases to some - threshold, linear array search is used to find the best allocno for - spilling. This threshold is actually pretty big because, although - splay trees asymptotically is much faster, each splay tree - operation is sufficiently costly especially taking cache locality - into account. */ -#define USE_SPLAY_P(CLASS) (uncolorable_allocnos_num[CLASS] > 4000) - /* Put allocno A onto the coloring stack without removing it from its bucket. Pushing allocno to the coloring stack can result in moving conflicting allocnos from the uncolorable bucket to the colorable @@ -814,17 +1911,18 @@ static splay_tree uncolorable_allocnos_s static void push_allocno_to_stack (ira_allocno_t a) { - int size; - enum reg_class cover_class; - int i, n = ALLOCNO_NUM_OBJECTS (a); - - ALLOCNO_IN_GRAPH_P (a) = false; + enum reg_class aclass; + allocno_color_data_t data, conflict_data; + int size, i, n = ALLOCNO_NUM_OBJECTS (a); + + data = ALLOCNO_COLOR_DATA (a); + data->in_graph_p = false; VEC_safe_push (ira_allocno_t, heap, allocno_stack_vec, a); - cover_class = ALLOCNO_COVER_CLASS (a); - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (a); + if (aclass == NO_REGS) return; - size = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)]; - if (ALLOCNO_NUM_OBJECTS (a) > 1) + 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)); @@ -833,64 +1931,37 @@ push_allocno_to_stack (ira_allocno_t a) for (i = 0; i < n; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); - int conflict_size; ira_object_t conflict_obj; ira_object_conflict_iterator oci; FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) { ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); - int left_conflicts_size; - conflict_a = conflict_a; - if (!bitmap_bit_p (coloring_allocno_bitmap, - ALLOCNO_NUM (conflict_a))) + conflict_data = ALLOCNO_COLOR_DATA (conflict_a); + if (conflict_data->colorable_p + || ! conflict_data->in_graph_p + || ALLOCNO_ASSIGNED_P (conflict_a) + || !(hard_reg_set_intersect_p + (OBJECT_COLOR_DATA (obj)->profitable_hard_regs, + OBJECT_COLOR_DATA (conflict_obj)->profitable_hard_regs))) continue; - - ira_assert (cover_class - == ALLOCNO_COVER_CLASS (conflict_a)); - if (!ALLOCNO_IN_GRAPH_P (conflict_a) - || ALLOCNO_ASSIGNED_P (conflict_a)) - continue; - - left_conflicts_size = ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_a); - conflict_size - = (ira_reg_class_nregs - [cover_class][ALLOCNO_MODE (conflict_a)]); - ira_assert (left_conflicts_size >= size); - if (left_conflicts_size + conflict_size - <= ALLOCNO_AVAILABLE_REGS_NUM (conflict_a)) - { - ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_a) -= size; - continue; - } - left_conflicts_size -= size; - if (uncolorable_allocnos_splay_tree[cover_class] != NULL - && !ALLOCNO_SPLAY_REMOVED_P (conflict_a) - && USE_SPLAY_P (cover_class)) - { - ira_assert - (splay_tree_lookup - (uncolorable_allocnos_splay_tree[cover_class], - (splay_tree_key) conflict_a) != NULL); - splay_tree_remove - (uncolorable_allocnos_splay_tree[cover_class], - (splay_tree_key) conflict_a); - ALLOCNO_SPLAY_REMOVED_P (conflict_a) = true; - VEC_safe_push (ira_allocno_t, heap, - removed_splay_allocno_vec, - conflict_a); - } - ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_a) - = left_conflicts_size; - if (left_conflicts_size + conflict_size - <= ALLOCNO_AVAILABLE_REGS_NUM (conflict_a)) + ira_assert (bitmap_bit_p (coloring_allocno_bitmap, + ALLOCNO_NUM (conflict_a))); + if (update_left_conflict_sizes_p (conflict_a, obj, size)) { delete_allocno_from_bucket - (conflict_a, &uncolorable_allocno_bucket); + (conflict_a, &uncolorable_allocno_bucket); add_allocno_to_ordered_bucket (conflict_a, &colorable_allocno_bucket); + if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL) + { + fprintf (ira_dump_file, " Making"); + ira_print_expanded_allocno (conflict_a); + fprintf (ira_dump_file, " colorable\n"); + } } + } } } @@ -900,8 +1971,6 @@ push_allocno_to_stack (ira_allocno_t a) static void remove_allocno_from_bucket_and_push (ira_allocno_t allocno, bool colorable_p) { - enum reg_class cover_class; - if (colorable_p) delete_allocno_from_bucket (allocno, &colorable_allocno_bucket); else @@ -911,24 +1980,16 @@ remove_allocno_from_bucket_and_push (ira fprintf (ira_dump_file, " Pushing"); ira_print_expanded_allocno (allocno); if (colorable_p) - fprintf (ira_dump_file, "\n"); + fprintf (ira_dump_file, "(cost %d)\n", + ALLOCNO_COLOR_DATA (allocno)->temp); else fprintf (ira_dump_file, "(potential spill: %spri=%d, cost=%d)\n", ALLOCNO_BAD_SPILL_P (allocno) ? "bad spill, " : "", - allocno_spill_priority (allocno), ALLOCNO_TEMP (allocno)); + allocno_spill_priority (allocno), + ALLOCNO_COLOR_DATA (allocno)->temp); } - cover_class = ALLOCNO_COVER_CLASS (allocno); - ira_assert ((colorable_p - && (ALLOCNO_LEFT_CONFLICTS_SIZE (allocno) - + ira_reg_class_nregs[cover_class][ALLOCNO_MODE (allocno)] - <= ALLOCNO_AVAILABLE_REGS_NUM (allocno))) - || (! colorable_p - && (ALLOCNO_LEFT_CONFLICTS_SIZE (allocno) - + ira_reg_class_nregs[cover_class][ALLOCNO_MODE - (allocno)] - > ALLOCNO_AVAILABLE_REGS_NUM (allocno)))); if (! colorable_p) - ALLOCNO_MAY_BE_SPILLED_P (allocno) = true; + ALLOCNO_COLOR_DATA (allocno)->may_be_spilled_p = true; push_allocno_to_stack (allocno); } @@ -936,24 +1997,11 @@ remove_allocno_from_bucket_and_push (ira static void push_only_colorable (void) { - sort_bucket (&colorable_allocno_bucket); + sort_bucket (&colorable_allocno_bucket, bucket_allocno_compare_func); for (;colorable_allocno_bucket != NULL;) remove_allocno_from_bucket_and_push (colorable_allocno_bucket, true); } -/* Puts ALLOCNO chosen for potential spilling onto the coloring - stack. */ -static void -push_allocno_to_spill (ira_allocno_t allocno) -{ - delete_allocno_from_bucket (allocno, &uncolorable_allocno_bucket); - ALLOCNO_MAY_BE_SPILLED_P (allocno) = true; - if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) - fprintf (ira_dump_file, " Pushing p%d(%d) (spill for NO_REGS)\n", - ALLOCNO_NUM (allocno), ALLOCNO_REGNO (allocno)); - push_allocno_to_stack (allocno); -} - /* Return the frequency of exit edges (if EXIT_P) or entry from/to the loop given by its LOOP_NODE. */ int @@ -1001,7 +2049,7 @@ calculate_allocno_spill_cost (ira_allocn ira_loop_tree_node_t parent_node, loop_node; regno = ALLOCNO_REGNO (a); - cost = ALLOCNO_UPDATED_MEMORY_COST (a) - ALLOCNO_UPDATED_COVER_CLASS_COST (a); + cost = ALLOCNO_UPDATED_MEMORY_COST (a) - ALLOCNO_UPDATED_CLASS_COST (a); if (ALLOCNO_CAP (a) != NULL) return cost; loop_node = ALLOCNO_LOOP_TREE_NODE (a); @@ -1010,76 +2058,54 @@ calculate_allocno_spill_cost (ira_allocn if ((parent_allocno = parent_node->regno_allocno_map[regno]) == NULL) return cost; mode = ALLOCNO_MODE (a); - rclass = ALLOCNO_COVER_CLASS (a); + rclass = ALLOCNO_CLASS (a); if (ALLOCNO_HARD_REGNO (parent_allocno) < 0) cost -= (ira_memory_move_cost[mode][rclass][0] * ira_loop_edge_freq (loop_node, regno, true) + ira_memory_move_cost[mode][rclass][1] * ira_loop_edge_freq (loop_node, regno, false)); else - cost += ((ira_memory_move_cost[mode][rclass][1] - * ira_loop_edge_freq (loop_node, regno, true) - + ira_memory_move_cost[mode][rclass][0] - * ira_loop_edge_freq (loop_node, regno, false)) - - (ira_get_register_move_cost (mode, rclass, rclass) - * (ira_loop_edge_freq (loop_node, regno, false) - + ira_loop_edge_freq (loop_node, regno, true)))); + { + ira_init_register_move_cost_if_necessary (mode); + cost += ((ira_memory_move_cost[mode][rclass][1] + * ira_loop_edge_freq (loop_node, regno, true) + + ira_memory_move_cost[mode][rclass][0] + * ira_loop_edge_freq (loop_node, regno, false)) + - (ira_register_move_cost[mode][rclass][rclass] + * (ira_loop_edge_freq (loop_node, regno, false) + + ira_loop_edge_freq (loop_node, regno, true)))); + } return cost; } -/* Compare keys in the splay tree used to choose best allocno for - spilling. The best allocno has the minimal key. */ -static int -allocno_spill_priority_compare (splay_tree_key k1, splay_tree_key k2) +/* Used for sorting allocnos for spilling. */ +static inline int +allocno_spill_priority_compare (ira_allocno_t a1, ira_allocno_t a2) { int pri1, pri2, diff; - ira_allocno_t a1 = (ira_allocno_t) k1, a2 = (ira_allocno_t) k2; - pri1 = (ALLOCNO_TEMP (a1) - / (ALLOCNO_LEFT_CONFLICTS_SIZE (a1) - * ira_reg_class_nregs[ALLOCNO_COVER_CLASS (a1)][ALLOCNO_MODE (a1)] - + 1)); - pri2 = (ALLOCNO_TEMP (a2) - / (ALLOCNO_LEFT_CONFLICTS_SIZE (a2) - * ira_reg_class_nregs[ALLOCNO_COVER_CLASS (a2)][ALLOCNO_MODE (a2)] - + 1)); + if (ALLOCNO_BAD_SPILL_P (a1) && ! ALLOCNO_BAD_SPILL_P (a2)) + return 1; + if (ALLOCNO_BAD_SPILL_P (a2) && ! ALLOCNO_BAD_SPILL_P (a1)) + return -1; + pri1 = allocno_spill_priority (a1); + pri2 = allocno_spill_priority (a2); if ((diff = pri1 - pri2) != 0) return diff; - if ((diff = ALLOCNO_TEMP (a1) - ALLOCNO_TEMP (a2)) != 0) + if ((diff + = ALLOCNO_COLOR_DATA (a1)->temp - ALLOCNO_COLOR_DATA (a2)->temp) != 0) return diff; return ALLOCNO_NUM (a1) - ALLOCNO_NUM (a2); } -/* Allocate data of SIZE for the splay trees. We allocate only spay - tree roots or splay tree nodes. If you change this, please rewrite - the function. */ -static void * -splay_tree_allocate (int size, void *data ATTRIBUTE_UNUSED) -{ - if (size != sizeof (struct splay_tree_node_s)) - return ira_allocate (size); - return pool_alloc (splay_tree_node_pool); -} - -/* Free data NODE for the splay trees. We allocate and free only spay - tree roots or splay tree nodes. If you change this, please rewrite - the function. */ -static void -splay_tree_free (void *node, void *data ATTRIBUTE_UNUSED) +/* Used for sorting allocnos for spilling. */ +static int +allocno_spill_sort_compare (const void *v1p, const void *v2p) { - int i; - enum reg_class cover_class; + ira_allocno_t p1 = *(const ira_allocno_t *) v1p; + ira_allocno_t p2 = *(const ira_allocno_t *) v2p; - for (i = 0; i < ira_reg_class_cover_size; i++) - { - cover_class = ira_reg_class_cover[i]; - if (node == uncolorable_allocnos_splay_tree[cover_class]) - { - ira_free (node); - return; - } - } - pool_free (splay_tree_node_pool, node); + return allocno_spill_priority_compare (p1, p2); } /* Push allocnos to the coloring stack. The order of allocnos in the @@ -1087,165 +2113,32 @@ splay_tree_free (void *node, void *data static void push_allocnos_to_stack (void) { - ira_allocno_t allocno, i_allocno, *allocno_vec; - enum reg_class cover_class, rclass; - int allocno_pri, i_allocno_pri, allocno_cost, i_allocno_cost; - int i, j, num, cover_class_allocnos_num[N_REG_CLASSES]; - ira_allocno_t *cover_class_allocnos[N_REG_CLASSES]; + ira_allocno_t a; int cost; - /* Initialize. */ - VEC_truncate(ira_allocno_t, removed_splay_allocno_vec, 0); - for (i = 0; i < ira_reg_class_cover_size; i++) - { - cover_class = ira_reg_class_cover[i]; - cover_class_allocnos_num[cover_class] = 0; - cover_class_allocnos[cover_class] = NULL; - uncolorable_allocnos_splay_tree[cover_class] = NULL; - } /* Calculate uncolorable allocno spill costs. */ - for (allocno = uncolorable_allocno_bucket; - allocno != NULL; - allocno = ALLOCNO_NEXT_BUCKET_ALLOCNO (allocno)) - if ((cover_class = ALLOCNO_COVER_CLASS (allocno)) != NO_REGS) + for (a = uncolorable_allocno_bucket; + a != NULL; + a = ALLOCNO_COLOR_DATA (a)->next_bucket_allocno) + if (ALLOCNO_CLASS (a) != NO_REGS) { - cover_class_allocnos_num[cover_class]++; - cost = calculate_allocno_spill_cost (allocno); - ALLOCNO_TEMP (allocno) = cost; - } - /* Define place where to put uncolorable allocnos of the same cover - class. */ - for (num = i = 0; i < ira_reg_class_cover_size; i++) - { - cover_class = ira_reg_class_cover[i]; - ira_assert (cover_class_allocnos_num[cover_class] - == uncolorable_allocnos_num[cover_class]); - if (cover_class_allocnos_num[cover_class] != 0) - { - cover_class_allocnos[cover_class] = allocnos_for_spilling + num; - num += cover_class_allocnos_num[cover_class]; - cover_class_allocnos_num[cover_class] = 0; - } - if (USE_SPLAY_P (cover_class)) - uncolorable_allocnos_splay_tree[cover_class] - = splay_tree_new_with_allocator (allocno_spill_priority_compare, - NULL, NULL, splay_tree_allocate, - splay_tree_free, NULL); - } - ira_assert (num <= ira_allocnos_num); - /* Collect uncolorable allocnos of each cover class. */ - for (allocno = uncolorable_allocno_bucket; - allocno != NULL; - allocno = ALLOCNO_NEXT_BUCKET_ALLOCNO (allocno)) - if ((cover_class = ALLOCNO_COVER_CLASS (allocno)) != NO_REGS) - { - cover_class_allocnos - [cover_class][cover_class_allocnos_num[cover_class]++] = allocno; - if (uncolorable_allocnos_splay_tree[cover_class] != NULL) - splay_tree_insert (uncolorable_allocnos_splay_tree[cover_class], - (splay_tree_key) allocno, - (splay_tree_value) allocno); + cost = calculate_allocno_spill_cost (a); + /* ??? Remove cost of copies between the coalesced + allocnos. */ + ALLOCNO_COLOR_DATA (a)->temp = cost; } + sort_bucket (&uncolorable_allocno_bucket, allocno_spill_sort_compare); for (;;) { push_only_colorable (); - allocno = uncolorable_allocno_bucket; - if (allocno == NULL) + a = uncolorable_allocno_bucket; + if (a == NULL) break; - cover_class = ALLOCNO_COVER_CLASS (allocno); - if (cover_class == NO_REGS) - { - push_allocno_to_spill (allocno); - continue; - } - /* Potential spilling. */ - ira_assert - (ira_reg_class_nregs[cover_class][ALLOCNO_MODE (allocno)] > 0); - if (USE_SPLAY_P (cover_class)) - { - for (;VEC_length (ira_allocno_t, removed_splay_allocno_vec) != 0;) - { - allocno = VEC_pop (ira_allocno_t, removed_splay_allocno_vec); - ALLOCNO_SPLAY_REMOVED_P (allocno) = false; - rclass = ALLOCNO_COVER_CLASS (allocno); - if (ALLOCNO_LEFT_CONFLICTS_SIZE (allocno) - + ira_reg_class_nregs [rclass][ALLOCNO_MODE (allocno)] - > ALLOCNO_AVAILABLE_REGS_NUM (allocno)) - splay_tree_insert - (uncolorable_allocnos_splay_tree[rclass], - (splay_tree_key) allocno, (splay_tree_value) allocno); - } - allocno = ((ira_allocno_t) - splay_tree_min - (uncolorable_allocnos_splay_tree[cover_class])->key); - splay_tree_remove (uncolorable_allocnos_splay_tree[cover_class], - (splay_tree_key) allocno); - } - else - { - num = cover_class_allocnos_num[cover_class]; - ira_assert (num > 0); - allocno_vec = cover_class_allocnos[cover_class]; - allocno = NULL; - allocno_pri = allocno_cost = 0; - /* Sort uncolorable allocno to find the one with the lowest - spill cost. */ - for (i = 0, j = num - 1; i <= j;) - { - i_allocno = allocno_vec[i]; - if (! ALLOCNO_IN_GRAPH_P (i_allocno) - && ALLOCNO_IN_GRAPH_P (allocno_vec[j])) - { - i_allocno = allocno_vec[j]; - allocno_vec[j] = allocno_vec[i]; - allocno_vec[i] = i_allocno; - } - if (ALLOCNO_IN_GRAPH_P (i_allocno)) - { - i++; - ira_assert (ALLOCNO_TEMP (i_allocno) != INT_MAX); - i_allocno_cost = ALLOCNO_TEMP (i_allocno); - i_allocno_pri = allocno_spill_priority (i_allocno); - if (allocno == NULL - || (! ALLOCNO_BAD_SPILL_P (i_allocno) - && ALLOCNO_BAD_SPILL_P (allocno)) - || (! (ALLOCNO_BAD_SPILL_P (i_allocno) - && ! ALLOCNO_BAD_SPILL_P (allocno)) - && (allocno_pri > i_allocno_pri - || (allocno_pri == i_allocno_pri - && (allocno_cost > i_allocno_cost - || (allocno_cost == i_allocno_cost - && (ALLOCNO_NUM (allocno) - > ALLOCNO_NUM (i_allocno)))))))) - { - allocno = i_allocno; - allocno_cost = i_allocno_cost; - allocno_pri = i_allocno_pri; - } - } - if (! ALLOCNO_IN_GRAPH_P (allocno_vec[j])) - j--; - } - ira_assert (allocno != NULL && j >= 0); - cover_class_allocnos_num[cover_class] = j + 1; - } - ira_assert (ALLOCNO_IN_GRAPH_P (allocno) - && ALLOCNO_COVER_CLASS (allocno) == cover_class - && (ALLOCNO_LEFT_CONFLICTS_SIZE (allocno) - + ira_reg_class_nregs[cover_class][ALLOCNO_MODE - (allocno)] - > ALLOCNO_AVAILABLE_REGS_NUM (allocno))); - remove_allocno_from_bucket_and_push (allocno, false); + remove_allocno_from_bucket_and_push (a, false); } ira_assert (colorable_allocno_bucket == NULL && uncolorable_allocno_bucket == NULL); - for (i = 0; i < ira_reg_class_cover_size; i++) - { - cover_class = ira_reg_class_cover[i]; - ira_assert (uncolorable_allocnos_num[cover_class] == 0); - if (uncolorable_allocnos_splay_tree[cover_class] != NULL) - splay_tree_delete (uncolorable_allocnos_splay_tree[cover_class]); - } + ira_assert (uncolorable_allocnos_num == 0); } /* Pop the coloring stack and assign hard registers to the popped @@ -1254,19 +2147,19 @@ static void pop_allocnos_from_stack (void) { ira_allocno_t allocno; - enum reg_class cover_class; + enum reg_class aclass; for (;VEC_length (ira_allocno_t, allocno_stack_vec) != 0;) { allocno = VEC_pop (ira_allocno_t, allocno_stack_vec); - cover_class = ALLOCNO_COVER_CLASS (allocno); + aclass = ALLOCNO_CLASS (allocno); if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) { fprintf (ira_dump_file, " Popping"); ira_print_expanded_allocno (allocno); fprintf (ira_dump_file, " -- "); } - if (cover_class == NO_REGS) + if (aclass == NO_REGS) { ALLOCNO_HARD_REGNO (allocno) = -1; ALLOCNO_ASSIGNED_P (allocno) = true; @@ -1287,23 +2180,7 @@ pop_allocnos_from_stack (void) if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) fprintf (ira_dump_file, "spill\n"); } - ALLOCNO_IN_GRAPH_P (allocno) = true; - } -} - -/* Loop over all subobjects of allocno A, collecting total hard - register conflicts in PSET (which the caller must initialize). */ -static void -all_conflicting_hard_regs (ira_allocno_t a, HARD_REG_SET *pset) -{ - int i; - int n = ALLOCNO_NUM_OBJECTS (a); - - for (i = 0; i < n; i++) - { - ira_object_t obj = ALLOCNO_OBJECT (a, i); - - IOR_HARD_REG_SET (*pset, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)); + ALLOCNO_COLOR_DATA (allocno)->in_graph_p = true; } } @@ -1311,107 +2188,86 @@ all_conflicting_hard_regs (ira_allocno_t static void setup_allocno_available_regs_num (ira_allocno_t a) { - int i, n, hard_regs_num, hard_regno; + int i, j, n, hard_regno, hard_regs_num, nwords, nregs; + enum reg_class aclass; enum machine_mode mode; - enum reg_class cover_class; - HARD_REG_SET temp_set; + allocno_color_data_t data; - cover_class = ALLOCNO_COVER_CLASS (a); - ALLOCNO_AVAILABLE_REGS_NUM (a) = ira_available_class_regs[cover_class]; - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (a); + data = ALLOCNO_COLOR_DATA (a); + data->available_regs_num = 0; + if (aclass == NO_REGS) return; - CLEAR_HARD_REG_SET (temp_set); - ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a); - hard_regs_num = ira_class_hard_regs_num[cover_class]; - all_conflicting_hard_regs (a, &temp_set); - + hard_regs_num = ira_class_hard_regs_num[aclass]; mode = ALLOCNO_MODE (a); + nwords = ALLOCNO_NUM_OBJECTS (a); for (n = 0, i = hard_regs_num - 1; i >= 0; i--) { - hard_regno = ira_class_hard_regs[cover_class][i]; - if (TEST_HARD_REG_BIT (temp_set, hard_regno) - || TEST_HARD_REG_BIT (prohibited_class_mode_regs[cover_class][mode], - hard_regno)) - n++; - } - if (internal_flag_ira_verbose > 2 && n > 0 && ira_dump_file != NULL) - fprintf (ira_dump_file, " Reg %d of %s has %d regs less\n", - ALLOCNO_REGNO (a), reg_class_names[cover_class], n); - ALLOCNO_AVAILABLE_REGS_NUM (a) -= n; -} + hard_regno = ira_class_hard_regs[aclass][i]; + nregs = hard_regno_nregs[hard_regno][mode]; + for (j = 0; j < nregs; j++) + { + int k; + int set_to_test_start = 0, set_to_test_end = nwords; -/* Set up ALLOCNO_LEFT_CONFLICTS_SIZE for allocno A. */ -static void -setup_allocno_left_conflicts_size (ira_allocno_t a) -{ - int i, hard_regs_num, hard_regno, conflict_allocnos_size; - enum reg_class cover_class; - HARD_REG_SET temp_set; + if (nregs == nwords) + { + if (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++) + { + ira_object_t obj = ALLOCNO_OBJECT (a, k); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); - cover_class = ALLOCNO_COVER_CLASS (a); - hard_regs_num = ira_class_hard_regs_num[cover_class]; - CLEAR_HARD_REG_SET (temp_set); - ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a); - all_conflicting_hard_regs (a, &temp_set); - - AND_HARD_REG_SET (temp_set, reg_class_contents[cover_class]); - AND_COMPL_HARD_REG_SET (temp_set, ira_no_alloc_regs); - - conflict_allocnos_size = 0; - if (! hard_reg_set_empty_p (temp_set)) - for (i = 0; i < (int) hard_regs_num; i++) - { - hard_regno = ira_class_hard_regs[cover_class][i]; - if (TEST_HARD_REG_BIT (temp_set, hard_regno)) - { - conflict_allocnos_size++; - CLEAR_HARD_REG_BIT (temp_set, hard_regno); - if (hard_reg_set_empty_p (temp_set)) - break; - } - } - CLEAR_HARD_REG_SET (temp_set); - if (cover_class != NO_REGS) + /* Checking only profitable hard regs. */ + if (TEST_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), + hard_regno + j) + || ! TEST_HARD_REG_BIT (obj_data->profitable_hard_regs, + hard_regno + j)) + break; + } + if (k != set_to_test_end) + break; + } + if (j == nregs) + n++; + } + data->available_regs_num = n; + if (internal_flag_ira_verbose <= 2 || ira_dump_file == NULL) + return; + fprintf + (ira_dump_file, + " Allocno a%dr%d of %s(%d) has %d avail. regs", + ALLOCNO_NUM (a), ALLOCNO_REGNO (a), + reg_class_names[aclass], ira_class_hard_regs_num[aclass], n); + for (i = 0; i < nwords; i++) { - int n = ALLOCNO_NUM_OBJECTS (a); + ira_object_t obj = ALLOCNO_OBJECT (a, i); + object_color_data_t obj_data = OBJECT_COLOR_DATA (obj); - for (i = 0; i < n; i++) + if (nwords != 1) { - ira_object_t obj = ALLOCNO_OBJECT (a, i); - ira_object_t conflict_obj; - ira_object_conflict_iterator oci; - - FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) - { - ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); - - ira_assert (cover_class - == ALLOCNO_COVER_CLASS (conflict_a)); - if (! ALLOCNO_ASSIGNED_P (conflict_a)) - conflict_allocnos_size - += (ira_reg_class_nregs - [cover_class][ALLOCNO_MODE (conflict_a)]); - else if ((hard_regno = ALLOCNO_HARD_REGNO (conflict_a)) - >= 0) - { - int last = (hard_regno - + hard_regno_nregs - [hard_regno][ALLOCNO_MODE (conflict_a)]); - - while (hard_regno < last) - { - if (! TEST_HARD_REG_BIT (temp_set, hard_regno)) - { - conflict_allocnos_size++; - SET_HARD_REG_BIT (temp_set, hard_regno); - } - hard_regno++; - } - } - } - } + if (i != 0) + fprintf (ira_dump_file, ", "); + fprintf (ira_dump_file, " obj %d", i); + } + print_hard_reg_set (ira_dump_file, obj_data->profitable_hard_regs, false); + fprintf (ira_dump_file, " (confl regs = "); + print_hard_reg_set (ira_dump_file, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), + false); + fprintf (ira_dump_file, " ) %snode: ", + hard_reg_set_equal_p (obj_data->profitable_hard_regs, + obj_data->hard_regs_node->hard_regs->set) + ? "" : "^"); + print_hard_reg_set (ira_dump_file, + obj_data->hard_regs_node->hard_regs->set, false); + } - ALLOCNO_LEFT_CONFLICTS_SIZE (a) = conflict_allocnos_size; + fprintf (ira_dump_file, "\n"); } /* Put ALLOCNO in a bucket corresponding to its number and size of its @@ -1419,15 +2275,9 @@ setup_allocno_left_conflicts_size (ira_a static void put_allocno_into_bucket (ira_allocno_t allocno) { - enum reg_class cover_class; - - cover_class = ALLOCNO_COVER_CLASS (allocno); - ALLOCNO_IN_GRAPH_P (allocno) = true; - setup_allocno_left_conflicts_size (allocno); + ALLOCNO_COLOR_DATA (allocno)->in_graph_p = true; setup_allocno_available_regs_num (allocno); - if (ALLOCNO_LEFT_CONFLICTS_SIZE (allocno) - + ira_reg_class_nregs[cover_class][ALLOCNO_MODE (allocno)] - <= ALLOCNO_AVAILABLE_REGS_NUM (allocno)) + if (setup_left_conflict_sizes_p (allocno)) add_allocno_to_bucket (allocno, &colorable_allocno_bucket); else add_allocno_to_bucket (allocno, &uncolorable_allocno_bucket); @@ -1455,8 +2305,8 @@ setup_allocno_priorities (ira_allocno_t allocno_priorities[ALLOCNO_NUM (a)] = priority = (mult - * (ALLOCNO_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a)) - * ira_reg_class_nregs[ALLOCNO_COVER_CLASS (a)][ALLOCNO_MODE (a)]); + * (ALLOCNO_MEMORY_COST (a) - ALLOCNO_CLASS_COST (a)) + * ira_reg_class_max_nregs[ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]); if (priority < 0) priority = -priority; if (max_priority < priority) @@ -1476,6 +2326,242 @@ setup_allocno_priorities (ira_allocno_t } } +/* Sort allocnos according to the profit of usage of a hard register + instead of memory for them. */ +static int +allocno_cost_compare_func (const void *v1p, const void *v2p) +{ + ira_allocno_t p1 = *(const ira_allocno_t *) v1p; + ira_allocno_t p2 = *(const ira_allocno_t *) v2p; + int c1, c2; + + c1 = ALLOCNO_UPDATED_MEMORY_COST (p1) - ALLOCNO_UPDATED_CLASS_COST (p1); + c2 = ALLOCNO_UPDATED_MEMORY_COST (p2) - ALLOCNO_UPDATED_CLASS_COST (p2); + if (c1 - c2) + return c1 - c2; + + /* If regs are equally good, sort by allocno numbers, so that the + results of qsort leave nothing to chance. */ + return ALLOCNO_NUM (p1) - ALLOCNO_NUM (p2); +} + +/* 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. */ +static void +improve_allocation (void) +{ + unsigned int i; + int j, k, n, hregno, conflict_hregno, base_cost, class_size, word, nwords; + int check, spill_cost, min_cost, nregs, conflict_nregs, r, best; + bool try_p; + enum reg_class aclass; + enum machine_mode mode; + int *allocno_costs; + int costs[FIRST_PSEUDO_REGISTER]; + HARD_REG_SET conflicting_regs[2], profitable_hard_regs[2]; + ira_allocno_t a; + bitmap_iterator bi; + + /* Clear counts used to process conflicting allocnos only once for + each allocno. */ + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + ALLOCNO_COLOR_DATA (ira_allocnos[i])->temp = 0; + check = n = 0; + /* Process each allocno and try to assign a hard register to it by + spilling some its conflicting allocnos. */ + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + ALLOCNO_COLOR_DATA (a)->temp = 0; + if (empty_profitable_hard_regs (a)) + continue; + check++; + aclass = ALLOCNO_CLASS (a); + allocno_costs = ALLOCNO_UPDATED_HARD_REG_COSTS (a); + if (allocno_costs == NULL) + allocno_costs = ALLOCNO_HARD_REG_COSTS (a); + if ((hregno = ALLOCNO_HARD_REGNO (a)) < 0) + base_cost = ALLOCNO_UPDATED_MEMORY_COST (a); + else if (allocno_costs == NULL) + /* It means that assigning a hard register is not profitable + (we don't waste memory for hard register costs in this + case). */ + continue; + else + base_cost = allocno_costs[ira_class_hard_reg_index[aclass][hregno]]; + try_p = false; + setup_conflict_profitable_regs (a, false, + conflicting_regs, profitable_hard_regs); + class_size = ira_class_hard_regs_num[aclass]; + /* Set up cost improvement for usage of each profitable hard + register for allocno A. */ + 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)) + continue; + ira_assert (ira_class_hard_reg_index[aclass][hregno] == j); + k = allocno_costs == NULL ? 0 : j; + costs[hregno] = (allocno_costs == NULL + ? ALLOCNO_UPDATED_CLASS_COST (a) : allocno_costs[k]); + costs[hregno] -= base_cost; + if (costs[hregno] < 0) + try_p = true; + } + if (! try_p) + /* There is no chance to improve the allocation cost by + assigning hard register to allocno A even without spilling + conflicting allocnos. */ + continue; + mode = ALLOCNO_MODE (a); + nwords = ALLOCNO_NUM_OBJECTS (a); + /* 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. */ + for (word = 0; word < nwords; word++) + { + ira_object_t conflict_obj; + ira_object_t obj = ALLOCNO_OBJECT (a, word); + ira_object_conflict_iterator oci; + + FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) + { + ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); + + if (ALLOCNO_COLOR_DATA (conflict_a)->temp == check) + /* We already processed this conflicting allocno + because we processed earlier another object of the + conflicting allocno. */ + continue; + ALLOCNO_COLOR_DATA (conflict_a)->temp = check; + if ((conflict_hregno = ALLOCNO_HARD_REGNO (conflict_a)) < 0) + continue; + spill_cost = ALLOCNO_UPDATED_MEMORY_COST (conflict_a); + k = (ira_class_hard_reg_index + [ALLOCNO_CLASS (conflict_a)][conflict_hregno]); + ira_assert (k >= 0); + if ((allocno_costs = ALLOCNO_UPDATED_HARD_REG_COSTS (conflict_a)) + != NULL) + spill_cost -= allocno_costs[k]; + else if ((allocno_costs = ALLOCNO_HARD_REG_COSTS (conflict_a)) + != NULL) + spill_cost -= allocno_costs[k]; + else + spill_cost -= ALLOCNO_UPDATED_CLASS_COST (conflict_a); + conflict_nregs + = hard_regno_nregs[conflict_hregno][ALLOCNO_MODE (conflict_a)]; + for (r = conflict_hregno; + r >= 0 && r + hard_regno_nregs[r][mode] > conflict_hregno; + r--) + if (check_hard_reg_p (a, r, + conflicting_regs, profitable_hard_regs)) + costs[r] += spill_cost; + for (r = conflict_hregno + 1; + r < conflict_hregno + conflict_nregs; + r++) + if (check_hard_reg_p (a, r, + conflicting_regs, profitable_hard_regs)) + costs[r] += spill_cost; + } + } + min_cost = INT_MAX; + best = -1; + /* Now we choose hard register for A which results in highest + allocation cost improvement. */ + 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) + && min_cost > costs[hregno]) + { + best = hregno; + min_cost = costs[hregno]; + } + } + if (min_cost >= 0) + /* We are in a situation when assigning any hard register to A + by spilling some conflicting allocnos does not improve the + allocation cost. */ + continue; + nregs = hard_regno_nregs[best][mode]; + /* Now spill conflicting allocnos which contain a hard register + of A when we assign the best chosen hard register to it. */ + for (word = 0; word < nwords; word++) + { + ira_object_t conflict_obj; + ira_object_t obj = ALLOCNO_OBJECT (a, word); + ira_object_conflict_iterator oci; + + FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) + { + ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); + + if ((conflict_hregno = ALLOCNO_HARD_REGNO (conflict_a)) < 0) + continue; + conflict_nregs + = hard_regno_nregs[conflict_hregno][ALLOCNO_MODE (conflict_a)]; + if (best + nregs <= conflict_hregno + || conflict_hregno + conflict_nregs <= best) + /* No intersection. */ + continue; + ALLOCNO_HARD_REGNO (conflict_a) = -1; + sorted_allocnos[n++] = conflict_a; + if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) + fprintf (ira_dump_file, "Spilling a%dr%d for a%dr%d\n", + ALLOCNO_NUM (conflict_a), ALLOCNO_REGNO (conflict_a), + ALLOCNO_NUM (a), ALLOCNO_REGNO (a)); + } + } + /* Assign the best chosen hard register to A. */ + ALLOCNO_HARD_REGNO (a) = best; + if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) + fprintf (ira_dump_file, "Assigning %d to a%dr%d\n", + best, ALLOCNO_NUM (a), ALLOCNO_REGNO (a)); + } + if (n == 0) + return; + /* 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'. */ + qsort (sorted_allocnos, n, sizeof (ira_allocno_t), + allocno_cost_compare_func); + for (j = 0; j < n; j++) + { + a = sorted_allocnos[j]; + ALLOCNO_ASSIGNED_P (a) = false; + if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) + { + fprintf (ira_dump_file, " "); + ira_print_expanded_allocno (a); + fprintf (ira_dump_file, " -- "); + } + if (assign_hard_reg (a, false)) + { + if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) + fprintf (ira_dump_file, "assign hard reg %d\n", + ALLOCNO_HARD_REGNO (a)); + } + else + { + if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) + fprintf (ira_dump_file, "assign memory\n"); + } + } +} + /* Sort allocnos according to their priorities which are calculated analogous to ones in file `global.c'. */ static int @@ -1510,7 +2596,7 @@ color_allocnos (void) EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) { a = ira_allocnos[i]; - if (ALLOCNO_COVER_CLASS (a) == NO_REGS) + if (ALLOCNO_CLASS (a) == NO_REGS) { ALLOCNO_HARD_REGNO (a) = -1; ALLOCNO_ASSIGNED_P (a) = true; @@ -1556,31 +2642,43 @@ color_allocnos (void) } else { - /* Put the allocnos into the corresponding buckets. */ - colorable_allocno_bucket = NULL; - uncolorable_allocno_bucket = NULL; + setup_profitable_hard_regs (); + form_object_hard_regs_nodes_forest (); + if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) + print_hard_regs_forest (ira_dump_file); EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) { a = ira_allocnos[i]; - if (ALLOCNO_COVER_CLASS (a) == NO_REGS) + if (ALLOCNO_CLASS (a) != NO_REGS && ! empty_profitable_hard_regs (a)) + ALLOCNO_COLOR_DATA (a)->in_graph_p = true; + else { ALLOCNO_HARD_REGNO (a) = -1; ALLOCNO_ASSIGNED_P (a) = true; - ira_assert (ALLOCNO_UPDATED_HARD_REG_COSTS (a) == NULL); - ira_assert (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) == NULL); + /* We don't need updated costs anymore. */ + ira_free_allocno_updated_costs (a); if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) { fprintf (ira_dump_file, " Spill"); ira_print_expanded_allocno (a); fprintf (ira_dump_file, "\n"); } - continue; } - put_allocno_into_bucket (a); + } + /* Put the allocnos into the corresponding buckets. */ + colorable_allocno_bucket = NULL; + uncolorable_allocno_bucket = NULL; + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) + { + a = ira_allocnos[i]; + if (ALLOCNO_COLOR_DATA (a)->in_graph_p) + put_allocno_into_bucket (a); } push_allocnos_to_stack (); pop_allocnos_from_stack (); + finish_object_hard_regs_nodes_forest (); } + improve_allocation (); } @@ -1626,15 +2724,15 @@ print_loop_title (ira_loop_tree_node_t l EXECUTE_IF_SET_IN_BITMAP (loop_tree_node->border_allocnos, 0, j, bi) fprintf (ira_dump_file, " %dr%d", j, ALLOCNO_REGNO (ira_allocnos[j])); fprintf (ira_dump_file, "\n Pressure:"); - for (j = 0; (int) j < ira_reg_class_cover_size; j++) + for (j = 0; (int) j < ira_pressure_classes_num; j++) { - enum reg_class cover_class; + enum reg_class pclass; - cover_class = ira_reg_class_cover[j]; - if (loop_tree_node->reg_pressure[cover_class] == 0) + pclass = ira_pressure_classes[j]; + if (loop_tree_node->reg_pressure[pclass] == 0) continue; - fprintf (ira_dump_file, " %s=%d", reg_class_names[cover_class], - loop_tree_node->reg_pressure[cover_class]); + fprintf (ira_dump_file, " %s=%d", reg_class_names[pclass], + loop_tree_node->reg_pressure[pclass]); } fprintf (ira_dump_file, "\n"); } @@ -1646,12 +2744,12 @@ print_loop_title (ira_loop_tree_node_t l static void color_pass (ira_loop_tree_node_t loop_tree_node) { - int regno, hard_regno, index = -1; + int i, regno, hard_regno, index = -1, n, nobj; int cost, exit_freq, enter_freq; unsigned int j; bitmap_iterator bi; enum machine_mode mode; - enum reg_class rclass, cover_class; + enum reg_class rclass, aclass, pclass; ira_allocno_t a, subloop_allocno; ira_loop_tree_node_t subloop_node; @@ -1661,11 +2759,35 @@ color_pass (ira_loop_tree_node_t loop_tr bitmap_copy (coloring_allocno_bitmap, loop_tree_node->all_allocnos); bitmap_copy (consideration_allocno_bitmap, coloring_allocno_bitmap); + n = nobj = 0; + EXECUTE_IF_SET_IN_BITMAP (consideration_allocno_bitmap, 0, j, bi) + { + a = ira_allocnos[j]; + n++; + nobj += ALLOCNO_NUM_OBJECTS (a); + if (! ALLOCNO_ASSIGNED_P (a)) + continue; + bitmap_clear_bit (coloring_allocno_bitmap, ALLOCNO_NUM (a)); + } + allocno_color_data + = (allocno_color_data_t) ira_allocate (sizeof (struct allocno_color_data) + * n); + memset (allocno_color_data, 0, sizeof (struct allocno_color_data) * n); + object_color_data + = (object_color_data_t) ira_allocate (sizeof (struct object_color_data) + * nobj); + memset (object_color_data, 0, sizeof (struct object_color_data) * nobj); + n = nobj = 0; EXECUTE_IF_SET_IN_BITMAP (consideration_allocno_bitmap, 0, j, bi) { a = ira_allocnos[j]; - if (ALLOCNO_ASSIGNED_P (a)) - bitmap_clear_bit (coloring_allocno_bitmap, ALLOCNO_NUM (a)); + ALLOCNO_ADD_DATA (a) = allocno_color_data + n; + n++; + for (i = 0; i < ALLOCNO_NUM_OBJECTS (a); i++) + { + OBJECT_ADD_DATA (ALLOCNO_OBJECT (a, i)) = object_color_data + nobj; + nobj++; + } } /* Color all mentioned allocnos including transparent ones. */ color_allocnos (); @@ -1679,10 +2801,11 @@ color_pass (ira_loop_tree_node_t loop_tr continue; /* Remove from processing in the next loop. */ bitmap_clear_bit (consideration_allocno_bitmap, j); - rclass = ALLOCNO_COVER_CLASS (a); + rclass = ALLOCNO_CLASS (a); + pclass = ira_pressure_class_translate[rclass]; if (flag_ira_region == IRA_REGION_MIXED - && (loop_tree_node->reg_pressure[rclass] - <= ira_available_class_regs[rclass])) + && (loop_tree_node->reg_pressure[pclass] + <= ira_available_class_regs[pclass])) { mode = ALLOCNO_MODE (a); hard_regno = ALLOCNO_HARD_REGNO (a); @@ -1715,7 +2838,8 @@ color_pass (ira_loop_tree_node_t loop_tr a = ira_allocnos[j]; ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL); mode = ALLOCNO_MODE (a); - rclass = ALLOCNO_COVER_CLASS (a); + rclass = ALLOCNO_CLASS (a); + pclass = ira_pressure_class_translate[rclass]; hard_regno = ALLOCNO_HARD_REGNO (a); /* Use hard register class here. ??? */ if (hard_regno >= 0) @@ -1729,12 +2853,12 @@ color_pass (ira_loop_tree_node_t loop_tr if (subloop_allocno == NULL || ALLOCNO_CAP (subloop_allocno) != NULL) continue; - ira_assert (ALLOCNO_COVER_CLASS (subloop_allocno) == rclass); + ira_assert (ALLOCNO_CLASS (subloop_allocno) == rclass); ira_assert (bitmap_bit_p (subloop_node->all_allocnos, ALLOCNO_NUM (subloop_allocno))); if ((flag_ira_region == IRA_REGION_MIXED) - && (loop_tree_node->reg_pressure[rclass] - <= ira_available_class_regs[rclass])) + && (loop_tree_node->reg_pressure[pclass] + <= ira_available_class_regs[pclass])) { if (! ALLOCNO_ASSIGNED_P (subloop_allocno)) { @@ -1771,23 +2895,23 @@ color_pass (ira_loop_tree_node_t loop_tr } else { - cover_class = ALLOCNO_COVER_CLASS (subloop_allocno); - cost = (ira_get_register_move_cost (mode, rclass, rclass) + aclass = ALLOCNO_CLASS (subloop_allocno); + ira_init_register_move_cost_if_necessary (mode); + cost = (ira_register_move_cost[mode][rclass][rclass] * (exit_freq + enter_freq)); ira_allocate_and_set_or_copy_costs - (&ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno), cover_class, - ALLOCNO_UPDATED_COVER_CLASS_COST (subloop_allocno), + (&ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno), aclass, + ALLOCNO_UPDATED_CLASS_COST (subloop_allocno), ALLOCNO_HARD_REG_COSTS (subloop_allocno)); ira_allocate_and_set_or_copy_costs (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (subloop_allocno), - cover_class, 0, - ALLOCNO_CONFLICT_HARD_REG_COSTS (subloop_allocno)); + aclass, 0, ALLOCNO_CONFLICT_HARD_REG_COSTS (subloop_allocno)); ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno)[index] -= cost; ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (subloop_allocno)[index] -= cost; - if (ALLOCNO_UPDATED_COVER_CLASS_COST (subloop_allocno) + if (ALLOCNO_UPDATED_CLASS_COST (subloop_allocno) > ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno)[index]) - ALLOCNO_UPDATED_COVER_CLASS_COST (subloop_allocno) + ALLOCNO_UPDATED_CLASS_COST (subloop_allocno) = ALLOCNO_UPDATED_HARD_REG_COSTS (subloop_allocno)[index]; ALLOCNO_UPDATED_MEMORY_COST (subloop_allocno) += (ira_memory_move_cost[mode][rclass][0] * enter_freq @@ -1795,6 +2919,15 @@ color_pass (ira_loop_tree_node_t loop_tr } } } + ira_free (object_color_data); + ira_free (allocno_color_data); + EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, j, bi) + { + a = ira_allocnos[j]; + ALLOCNO_ADD_DATA (a) = NULL; + for (i = 0; i < ALLOCNO_NUM_OBJECTS (a); i++) + OBJECT_ADD_DATA (a) = NULL; + } } /* Initialize the common data for coloring and calls functions to do @@ -1803,12 +2936,6 @@ static void do_coloring (void) { coloring_allocno_bitmap = ira_allocate_bitmap (); - allocnos_for_spilling - = (ira_allocno_t *) ira_allocate (sizeof (ira_allocno_t) - * ira_allocnos_num); - splay_tree_node_pool = create_alloc_pool ("splay tree nodes", - sizeof (struct splay_tree_node_s), - 100); if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL) fprintf (ira_dump_file, "\n**** Allocnos coloring:\n\n"); @@ -1817,9 +2944,7 @@ do_coloring (void) if (internal_flag_ira_verbose > 1 && ira_dump_file != NULL) ira_print_disposition (ira_dump_file); - free_alloc_pool (splay_tree_node_pool); ira_free_bitmap (coloring_allocno_bitmap); - ira_free (allocnos_for_spilling); } @@ -1863,13 +2988,14 @@ move_spill_restore (void) || !bitmap_bit_p (loop_node->border_allocnos, ALLOCNO_NUM (a))) continue; mode = ALLOCNO_MODE (a); - rclass = ALLOCNO_COVER_CLASS (a); + rclass = ALLOCNO_CLASS (a); index = ira_class_hard_reg_index[rclass][hard_regno]; ira_assert (index >= 0); cost = (ALLOCNO_MEMORY_COST (a) - (ALLOCNO_HARD_REG_COSTS (a) == NULL - ? ALLOCNO_COVER_CLASS_COST (a) + ? ALLOCNO_CLASS_COST (a) : ALLOCNO_HARD_REG_COSTS (a)[index])); + ira_init_register_move_cost_if_necessary (mode); for (subloop_node = loop_node->subloops; subloop_node != NULL; subloop_node = subloop_node->subloop_next) @@ -1878,13 +3004,13 @@ move_spill_restore (void) subloop_allocno = subloop_node->regno_allocno_map[regno]; if (subloop_allocno == NULL) continue; - ira_assert (rclass == ALLOCNO_COVER_CLASS (subloop_allocno)); + ira_assert (rclass == ALLOCNO_CLASS (subloop_allocno)); /* We have accumulated cost. To get the real cost of allocno usage in the loop we should subtract costs of the subloop allocnos. */ cost -= (ALLOCNO_MEMORY_COST (subloop_allocno) - (ALLOCNO_HARD_REG_COSTS (subloop_allocno) == NULL - ? ALLOCNO_COVER_CLASS_COST (subloop_allocno) + ? ALLOCNO_CLASS_COST (subloop_allocno) : ALLOCNO_HARD_REG_COSTS (subloop_allocno)[index])); exit_freq = ira_loop_edge_freq (subloop_node, regno, true); enter_freq = ira_loop_edge_freq (subloop_node, regno, false); @@ -1897,14 +3023,14 @@ move_spill_restore (void) += (ira_memory_move_cost[mode][rclass][0] * exit_freq + ira_memory_move_cost[mode][rclass][1] * enter_freq); if (hard_regno2 != hard_regno) - cost -= (ira_get_register_move_cost (mode, rclass, rclass) + cost -= (ira_register_move_cost[mode][rclass][rclass] * (exit_freq + enter_freq)); } } if ((parent = loop_node->parent) != NULL && (parent_allocno = parent->regno_allocno_map[regno]) != NULL) { - ira_assert (rclass == ALLOCNO_COVER_CLASS (parent_allocno)); + ira_assert (rclass == ALLOCNO_CLASS (parent_allocno)); exit_freq = ira_loop_edge_freq (loop_node, regno, true); enter_freq = ira_loop_edge_freq (loop_node, regno, false); if ((hard_regno2 = ALLOCNO_HARD_REGNO (parent_allocno)) < 0) @@ -1916,7 +3042,7 @@ move_spill_restore (void) += (ira_memory_move_cost[mode][rclass][1] * exit_freq + ira_memory_move_cost[mode][rclass][0] * enter_freq); if (hard_regno2 != hard_regno) - cost -= (ira_get_register_move_cost (mode, rclass, rclass) + cost -= (ira_register_move_cost[mode][rclass][rclass] * (exit_freq + enter_freq)); } } @@ -1949,16 +3075,17 @@ update_curr_costs (ira_allocno_t a) { int i, hard_regno, cost; enum machine_mode mode; - enum reg_class cover_class, rclass; + enum reg_class aclass, rclass; ira_allocno_t another_a; ira_copy_t cp, next_cp; ira_free_allocno_updated_costs (a); ira_assert (! ALLOCNO_ASSIGNED_P (a)); - cover_class = ALLOCNO_COVER_CLASS (a); - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (a); + if (aclass == NO_REGS) return; mode = ALLOCNO_MODE (a); + ira_init_register_move_cost_if_necessary (mode); for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp) { if (cp->first == a) @@ -1973,25 +3100,23 @@ update_curr_costs (ira_allocno_t a) } else gcc_unreachable (); - if (! ira_reg_classes_intersect_p[cover_class][ALLOCNO_COVER_CLASS - (another_a)] + if (! ira_reg_classes_intersect_p[aclass][ALLOCNO_CLASS (another_a)] || ! ALLOCNO_ASSIGNED_P (another_a) || (hard_regno = ALLOCNO_HARD_REGNO (another_a)) < 0) continue; rclass = REGNO_REG_CLASS (hard_regno); - i = ira_class_hard_reg_index[cover_class][hard_regno]; + i = ira_class_hard_reg_index[aclass][hard_regno]; if (i < 0) continue; cost = (cp->first == a - ? ira_get_register_move_cost (mode, rclass, cover_class) - : ira_get_register_move_cost (mode, cover_class, rclass)); + ? ira_register_move_cost[mode][rclass][aclass] + : ira_register_move_cost[mode][aclass][rclass]); ira_allocate_and_set_or_copy_costs - (&ALLOCNO_UPDATED_HARD_REG_COSTS (a), - cover_class, ALLOCNO_COVER_CLASS_COST (a), + (&ALLOCNO_UPDATED_HARD_REG_COSTS (a), aclass, ALLOCNO_CLASS_COST (a), ALLOCNO_HARD_REG_COSTS (a)); ira_allocate_and_set_or_copy_costs (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a), - cover_class, 0, ALLOCNO_CONFLICT_HARD_REG_COSTS (a)); + aclass, 0, ALLOCNO_CONFLICT_HARD_REG_COSTS (a)); ALLOCNO_UPDATED_HARD_REG_COSTS (a)[i] -= cp->freq * cost; ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a)[i] -= cp->freq * cost; } @@ -2008,7 +3133,7 @@ ira_reassign_conflict_allocnos (int star { int i, allocnos_to_color_num; ira_allocno_t a; - enum reg_class cover_class; + enum reg_class aclass; bitmap allocnos_to_color; ira_allocno_iterator ai; @@ -2021,7 +3146,7 @@ ira_reassign_conflict_allocnos (int star if (! ALLOCNO_ASSIGNED_P (a) && ! bitmap_bit_p (allocnos_to_color, ALLOCNO_NUM (a))) { - if (ALLOCNO_COVER_CLASS (a) != NO_REGS) + if (ALLOCNO_CLASS (a) != NO_REGS) sorted_allocnos[allocnos_to_color_num++] = a; else { @@ -2033,18 +3158,20 @@ ira_reassign_conflict_allocnos (int star bitmap_set_bit (allocnos_to_color, ALLOCNO_NUM (a)); } if (ALLOCNO_REGNO (a) < start_regno - || (cover_class = ALLOCNO_COVER_CLASS (a)) == NO_REGS) + || (aclass = ALLOCNO_CLASS (a)) == NO_REGS) continue; for (i = 0; i < n; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); ira_object_t conflict_obj; ira_object_conflict_iterator oci; + FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci) { ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj); + ira_assert (ira_reg_classes_intersect_p - [cover_class][ALLOCNO_COVER_CLASS (conflict_a)]); + [aclass][ALLOCNO_CLASS (conflict_a)]); if (!bitmap_set_bit (allocnos_to_color, ALLOCNO_NUM (conflict_a))) continue; sorted_allocnos[allocnos_to_color_num++] = conflict_a; @@ -2080,6 +3207,68 @@ ira_reassign_conflict_allocnos (int star +/* This page contains functions used to find conflicts using allocno + live ranges. */ + +/* Return TRUE if live ranges of allocnos A1 and A2 intersect. It is + used to find a conflict for new allocnos or allocnos with the + different allocno classes. */ +static bool +allocnos_conflict_by_live_ranges_p (ira_allocno_t a1, ira_allocno_t a2) +{ + rtx reg1, reg2; + int i, j; + int n1 = ALLOCNO_NUM_OBJECTS (a1); + int n2 = ALLOCNO_NUM_OBJECTS (a2); + + if (a1 == a2) + return false; + reg1 = regno_reg_rtx[ALLOCNO_REGNO (a1)]; + reg2 = regno_reg_rtx[ALLOCNO_REGNO (a2)]; + if (reg1 != NULL && reg2 != NULL + && ORIGINAL_REGNO (reg1) == ORIGINAL_REGNO (reg2)) + return false; + + for (i = 0; i < n1; i++) + { + ira_object_t c1 = ALLOCNO_OBJECT (a1, i); + + for (j = 0; j < n2; j++) + { + ira_object_t c2 = ALLOCNO_OBJECT (a2, j); + + if (ira_live_ranges_intersect_p (OBJECT_LIVE_RANGES (c1), + OBJECT_LIVE_RANGES (c2))) + return true; + } + } + return false; +} + +#ifdef ENABLE_IRA_CHECKING + +/* Return TRUE if live ranges of pseudo-registers REGNO1 and REGNO2 + intersect. This should be used when there is only one region. + Currently this is used during reload. */ +static bool +conflict_by_live_ranges_p (int regno1, int regno2) +{ + ira_allocno_t a1, a2; + + ira_assert (regno1 >= FIRST_PSEUDO_REGISTER + && regno2 >= FIRST_PSEUDO_REGISTER); + /* Reg info caclulated by dataflow infrastructure can be different + from one calculated by regclass. */ + if ((a1 = ira_loop_tree_root->regno_allocno_map[regno1]) == NULL + || (a2 = ira_loop_tree_root->regno_allocno_map[regno2]) == NULL) + return false; + return allocnos_conflict_by_live_ranges_p (a1, a2); +} + +#endif + + + /* 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 @@ -2096,6 +3285,27 @@ static bool allocno_coalesced_p; coalescing. */ static bitmap processed_coalesced_allocno_bitmap; +/* See below. */ +typedef struct coalesce_data *coalesce_data_t; + +/* To decrease footprint of ira_allocno structure we store all data + needed only for coalescing in the following structure. */ +struct coalesce_data +{ + /* Coalesced allocnos form a cyclic list. One allocno given by + FIRST represents all coalesced allocnos. The + list is chained by NEXT. */ + ira_allocno_t first; + ira_allocno_t next; + int temp; +}; + +/* Container for storing allocno data concerning coalescing. */ +static coalesce_data_t allocno_coalesce_data; + +/* Macro to access the data concerning coalescing. */ +#define ALLOCNO_COALESCE_DATA(a) ((coalesce_data_t) ALLOCNO_ADD_DATA (a)) + /* The function is used to sort allocnos according to their execution frequencies. */ static int @@ -2122,58 +3332,55 @@ merge_allocnos (ira_allocno_t a1, ira_al { ira_allocno_t a, first, last, next; - first = ALLOCNO_FIRST_COALESCED_ALLOCNO (a1); - if (first == ALLOCNO_FIRST_COALESCED_ALLOCNO (a2)) + first = ALLOCNO_COALESCE_DATA (a1)->first; + a = ALLOCNO_COALESCE_DATA (a2)->first; + if (first == a) return; - for (last = a2, a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a2);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + for (last = a2, a = ALLOCNO_COALESCE_DATA (a2)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { - ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = first; + ALLOCNO_COALESCE_DATA (a)->first = first; if (a == a2) break; last = a; } - next = ALLOCNO_NEXT_COALESCED_ALLOCNO (first); - ALLOCNO_NEXT_COALESCED_ALLOCNO (first) = a2; - ALLOCNO_NEXT_COALESCED_ALLOCNO (last) = next; + next = allocno_coalesce_data[ALLOCNO_NUM (first)].next; + allocno_coalesce_data[ALLOCNO_NUM (first)].next = a2; + allocno_coalesce_data[ALLOCNO_NUM (last)].next = next; } -/* Given two sets of coalesced sets of allocnos, A1 and A2, this - function determines if any conflicts exist between the two sets. - We use live ranges to find conflicts because conflicts are - represented only for allocnos of the same cover class and during - the reload pass we coalesce allocnos for sharing stack memory - slots. */ +/* Return TRUE if there are conflicting allocnos from two sets of + coalesced allocnos given correspondingly by allocnos A1 and A2. We + use live ranges to find conflicts because conflicts are represented + only for allocnos of the same allocno class and during the reload + pass we coalesce allocnos for sharing stack memory slots. */ static bool coalesced_allocno_conflict_p (ira_allocno_t a1, ira_allocno_t a2) { - ira_allocno_t a, conflict_allocno; + ira_allocno_t a, conflict_a; - bitmap_clear (processed_coalesced_allocno_bitmap); if (allocno_coalesced_p) { - for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a1);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + bitmap_clear (processed_coalesced_allocno_bitmap); + for (a = ALLOCNO_COALESCE_DATA (a1)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { - bitmap_set_bit (processed_coalesced_allocno_bitmap, - OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (a, 0))); + bitmap_set_bit (processed_coalesced_allocno_bitmap, ALLOCNO_NUM (a)); if (a == a1) break; } } - for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a2);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + for (a = ALLOCNO_COALESCE_DATA (a2)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { - for (conflict_allocno = ALLOCNO_NEXT_COALESCED_ALLOCNO (a1);; - conflict_allocno - = ALLOCNO_NEXT_COALESCED_ALLOCNO (conflict_allocno)) + for (conflict_a = ALLOCNO_COALESCE_DATA (a1)->next;; + conflict_a = ALLOCNO_COALESCE_DATA (conflict_a)->next) { - if (allocnos_have_intersected_live_ranges_p (a, conflict_allocno)) + if (allocnos_conflict_by_live_ranges_p (a, conflict_a)) return true; - if (conflict_allocno == a1) + if (conflict_a == a1) break; } - if (a == a2) break; } @@ -2212,7 +3419,7 @@ coalesce_allocnos (void) next_cp = cp->next_first_allocno_copy; regno = ALLOCNO_REGNO (cp->second); /* For priority coloring we coalesce allocnos only with - the same cover class not with intersected cover + the same allocno class not with intersected allocno classes as it were possible. It is done for simplicity. */ if ((cp->insn != NULL || cp->constraint_p) @@ -2255,8 +3462,8 @@ coalesce_allocnos (void) for (n = 0; i < cp_num; i++) { cp = sorted_copies[i]; - if (ALLOCNO_FIRST_COALESCED_ALLOCNO (cp->first) - != ALLOCNO_FIRST_COALESCED_ALLOCNO (cp->second)) + if (allocno_coalesce_data[ALLOCNO_NUM (cp->first)].first + != allocno_coalesce_data[ALLOCNO_NUM (cp->second)].first) sorted_copies[n++] = cp; } cp_num = n; @@ -2326,8 +3533,10 @@ coalesced_pseudo_reg_slot_compare (const if ((diff = slot_num1 - slot_num2) != 0) return (frame_pointer_needed || !FRAME_GROWS_DOWNWARD == STACK_GROWS_DOWNWARD ? diff : -diff); - total_size1 = MAX (PSEUDO_REGNO_BYTES (regno1), regno_max_ref_width[regno1]); - total_size2 = MAX (PSEUDO_REGNO_BYTES (regno2), regno_max_ref_width[regno2]); + total_size1 = MAX (PSEUDO_REGNO_BYTES (regno1), + regno_max_ref_width[regno1]); + total_size2 = MAX (PSEUDO_REGNO_BYTES (regno2), + regno_max_ref_width[regno2]); if ((diff = total_size2 - total_size1) != 0) return diff; return regno1 - regno2; @@ -2352,18 +3561,18 @@ setup_coalesced_allocno_costs_and_nums ( regno_coalesced_allocno_num[regno] = ++num; continue; } - if (ALLOCNO_FIRST_COALESCED_ALLOCNO (allocno) != allocno) + if (ALLOCNO_COALESCE_DATA (allocno)->first != allocno) continue; num++; - for (cost = 0, a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + for (cost = 0, a = ALLOCNO_COALESCE_DATA (allocno)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { cost += ALLOCNO_FREQ (a); if (a == allocno) break; } - for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + for (a = ALLOCNO_COALESCE_DATA (allocno)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { regno_coalesced_allocno_num[ALLOCNO_REGNO (a)] = num; regno_coalesced_allocno_cost[ALLOCNO_REGNO (a)] = cost; @@ -2390,7 +3599,7 @@ collect_spilled_coalesced_allocnos (int regno = pseudo_regnos[i]; allocno = ira_regno_allocno_map[regno]; if (allocno == NULL || ALLOCNO_HARD_REGNO (allocno) >= 0 - || ALLOCNO_FIRST_COALESCED_ALLOCNO (allocno) != allocno) + || ALLOCNO_COALESCE_DATA (allocno)->first != allocno) continue; spilled_coalesced_allocnos[num++] = allocno; } @@ -2410,16 +3619,19 @@ slot_coalesced_allocno_live_ranges_inter { ira_allocno_t a; - for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + for (a = ALLOCNO_COALESCE_DATA (allocno)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { int i; int nr = ALLOCNO_NUM_OBJECTS (a); + for (i = 0; i < nr; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); - if (ira_live_ranges_intersect_p (slot_coalesced_allocnos_live_ranges[n], - OBJECT_LIVE_RANGES (obj))) + + if (ira_live_ranges_intersect_p + (slot_coalesced_allocnos_live_ranges[n], + OBJECT_LIVE_RANGES (obj))) return true; } if (a == allocno) @@ -2437,18 +3649,19 @@ setup_slot_coalesced_allocno_live_ranges ira_allocno_t a; live_range_t r; - n = ALLOCNO_TEMP (allocno); - for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + n = ALLOCNO_COALESCE_DATA (allocno)->temp; + for (a = ALLOCNO_COALESCE_DATA (allocno)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { int nr = ALLOCNO_NUM_OBJECTS (a); for (i = 0; i < nr; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); + r = ira_copy_live_range_list (OBJECT_LIVE_RANGES (obj)); slot_coalesced_allocnos_live_ranges[n] = ira_merge_live_ranges - (slot_coalesced_allocnos_live_ranges[n], r); + (slot_coalesced_allocnos_live_ranges[n], r); } if (a == allocno) break; @@ -2478,7 +3691,7 @@ coalesce_spill_slots (ira_allocno_t *spi for (i = 0; i < num; i++) { allocno = spilled_coalesced_allocnos[i]; - if (ALLOCNO_FIRST_COALESCED_ALLOCNO (allocno) != allocno + if (ALLOCNO_COALESCE_DATA (allocno)->first != allocno || bitmap_bit_p (set_jump_crosses, ALLOCNO_REGNO (allocno)) || (ALLOCNO_REGNO (allocno) < ira_reg_equiv_len && (ira_reg_equiv_const[ALLOCNO_REGNO (allocno)] != NULL_RTX @@ -2487,8 +3700,8 @@ coalesce_spill_slots (ira_allocno_t *spi for (j = 0; j < i; j++) { a = spilled_coalesced_allocnos[j]; - n = ALLOCNO_TEMP (a); - if (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a + n = ALLOCNO_COALESCE_DATA (a)->temp; + if (ALLOCNO_COALESCE_DATA (a)->first == a && ! bitmap_bit_p (set_jump_crosses, ALLOCNO_REGNO (a)) && (ALLOCNO_REGNO (a) >= ira_reg_equiv_len || (! ira_reg_equiv_invariant_p[ALLOCNO_REGNO (a)] @@ -2500,7 +3713,7 @@ coalesce_spill_slots (ira_allocno_t *spi { /* No coalescing: set up number for coalesced allocnos represented by ALLOCNO. */ - ALLOCNO_TEMP (allocno) = last_coalesced_allocno_num++; + ALLOCNO_COALESCE_DATA (allocno)->temp = last_coalesced_allocno_num++; setup_slot_coalesced_allocno_live_ranges (allocno); } else @@ -2512,10 +3725,11 @@ coalesce_spill_slots (ira_allocno_t *spi " Coalescing spilled allocnos a%dr%d->a%dr%d\n", ALLOCNO_NUM (allocno), ALLOCNO_REGNO (allocno), ALLOCNO_NUM (a), ALLOCNO_REGNO (a)); - ALLOCNO_TEMP (allocno) = ALLOCNO_TEMP (a); + ALLOCNO_COALESCE_DATA (allocno)->temp + = ALLOCNO_COALESCE_DATA (a)->temp; setup_slot_coalesced_allocno_live_ranges (allocno); merge_allocnos (a, allocno); - ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a); + ira_assert (ALLOCNO_COALESCE_DATA (a)->first == a); } } for (i = 0; i < ira_allocnos_num; i++) @@ -2546,11 +3760,20 @@ ira_sort_regnos_for_alter_reg (int *pseu regno = pseudo_regnos[i]; allocno = ira_regno_allocno_map[regno]; if (allocno != NULL) - bitmap_set_bit (coloring_allocno_bitmap, - ALLOCNO_NUM (allocno)); + bitmap_set_bit (coloring_allocno_bitmap, ALLOCNO_NUM (allocno)); } allocno_coalesced_p = false; processed_coalesced_allocno_bitmap = ira_allocate_bitmap (); + allocno_coalesce_data + = (coalesce_data_t) ira_allocate (sizeof (struct coalesce_data) + * ira_allocnos_num); + /* Initialize coalesce data for allocnos. */ + FOR_EACH_ALLOCNO (a, ai) + { + ALLOCNO_ADD_DATA (a) = allocno_coalesce_data + ALLOCNO_NUM (a); + ALLOCNO_COALESCE_DATA (a)->first = a; + ALLOCNO_COALESCE_DATA (a)->next = a; + } coalesce_allocnos (); ira_free_bitmap (coloring_allocno_bitmap); regno_coalesced_allocno_cost @@ -2588,7 +3811,7 @@ ira_sort_regnos_for_alter_reg (int *pseu for (i = 0; i < num; i++) { allocno = spilled_coalesced_allocnos[i]; - if (ALLOCNO_FIRST_COALESCED_ALLOCNO (allocno) != allocno + if (ALLOCNO_COALESCE_DATA (allocno)->first != allocno || ALLOCNO_HARD_REGNO (allocno) >= 0 || (ALLOCNO_REGNO (allocno) < ira_reg_equiv_len && (ira_reg_equiv_const[ALLOCNO_REGNO (allocno)] != NULL_RTX @@ -2597,8 +3820,8 @@ ira_sort_regnos_for_alter_reg (int *pseu if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) fprintf (ira_dump_file, " Slot %d (freq,size):", slot_num); slot_num++; - for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);; - a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) + for (a = ALLOCNO_COALESCE_DATA (allocno)->next;; + a = ALLOCNO_COALESCE_DATA (a)->next) { ira_assert (ALLOCNO_HARD_REGNO (a) < 0); ALLOCNO_HARD_REGNO (a) = -slot_num; @@ -2619,13 +3842,9 @@ ira_sort_regnos_for_alter_reg (int *pseu /* Sort regnos according the slot numbers. */ regno_max_ref_width = reg_max_ref_width; qsort (pseudo_regnos, n, sizeof (int), coalesced_pseudo_reg_slot_compare); - /* Uncoalesce allocnos which is necessary for (re)assigning during - the reload pass. */ FOR_EACH_ALLOCNO (a, ai) - { - ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = a; - ALLOCNO_NEXT_COALESCED_ALLOCNO (a) = a; - } + ALLOCNO_ADD_DATA (a) = NULL; + ira_free (allocno_coalesce_data); ira_free (regno_coalesced_allocno_num); ira_free (regno_coalesced_allocno_cost); } @@ -2643,7 +3862,7 @@ ira_mark_allocation_change (int regno) { ira_allocno_t a = ira_regno_allocno_map[regno]; int old_hard_regno, hard_regno, cost; - enum reg_class cover_class = ALLOCNO_COVER_CLASS (a); + enum reg_class aclass = ALLOCNO_CLASS (a); ira_assert (a != NULL); hard_regno = reg_renumber[regno]; @@ -2653,11 +3872,11 @@ ira_mark_allocation_change (int regno) cost = -ALLOCNO_MEMORY_COST (a); else { - ira_assert (ira_class_hard_reg_index[cover_class][old_hard_regno] >= 0); + ira_assert (ira_class_hard_reg_index[aclass][old_hard_regno] >= 0); cost = -(ALLOCNO_HARD_REG_COSTS (a) == NULL - ? ALLOCNO_COVER_CLASS_COST (a) + ? ALLOCNO_CLASS_COST (a) : ALLOCNO_HARD_REG_COSTS (a) - [ira_class_hard_reg_index[cover_class][old_hard_regno]]); + [ira_class_hard_reg_index[aclass][old_hard_regno]]); update_copy_costs (a, false); } ira_overall_cost -= cost; @@ -2667,12 +3886,12 @@ ira_mark_allocation_change (int regno) ALLOCNO_HARD_REGNO (a) = -1; cost += ALLOCNO_MEMORY_COST (a); } - else if (ira_class_hard_reg_index[cover_class][hard_regno] >= 0) + else if (ira_class_hard_reg_index[aclass][hard_regno] >= 0) { cost += (ALLOCNO_HARD_REG_COSTS (a) == NULL - ? ALLOCNO_COVER_CLASS_COST (a) + ? ALLOCNO_CLASS_COST (a) : ALLOCNO_HARD_REG_COSTS (a) - [ira_class_hard_reg_index[cover_class][hard_regno]]); + [ira_class_hard_reg_index[aclass][hard_regno]]); update_copy_costs (a, true); } else @@ -2704,7 +3923,7 @@ static bool allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs) { int hard_regno; - enum reg_class cover_class; + enum reg_class aclass; int regno = ALLOCNO_REGNO (a); HARD_REG_SET saved[2]; int i, n; @@ -2720,7 +3939,7 @@ allocno_reload_assign (ira_allocno_t a, call_used_reg_set); } ALLOCNO_ASSIGNED_P (a) = false; - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); update_curr_costs (a); assign_hard_reg (a, true); hard_regno = ALLOCNO_HARD_REGNO (a); @@ -2729,13 +3948,13 @@ allocno_reload_assign (ira_allocno_t a, ALLOCNO_HARD_REGNO (a) = -1; else { - ira_assert (ira_class_hard_reg_index[cover_class][hard_regno] >= 0); - ira_overall_cost -= (ALLOCNO_MEMORY_COST (a) - - (ALLOCNO_HARD_REG_COSTS (a) == NULL - ? ALLOCNO_COVER_CLASS_COST (a) - : ALLOCNO_HARD_REG_COSTS (a) - [ira_class_hard_reg_index - [cover_class][hard_regno]])); + ira_assert (ira_class_hard_reg_index[aclass][hard_regno] >= 0); + ira_overall_cost + -= (ALLOCNO_MEMORY_COST (a) + - (ALLOCNO_HARD_REG_COSTS (a) == NULL + ? ALLOCNO_CLASS_COST (a) + : ALLOCNO_HARD_REG_COSTS (a)[ira_class_hard_reg_index + [aclass][hard_regno]])); if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0 && ! ira_hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a), call_used_reg_set)) @@ -2856,7 +4075,7 @@ ira_reassign_pseudos (int *spilled_pseud fprintf (ira_dump_file, " Try Assign %d(a%d), cost=%d", regno, ALLOCNO_NUM (a), ALLOCNO_MEMORY_COST (a) - - ALLOCNO_COVER_CLASS_COST (a)); + - ALLOCNO_CLASS_COST (a)); allocno_reload_assign (a, forbidden_regs); if (reg_renumber[regno] >= 0) { @@ -2917,8 +4136,8 @@ ira_reuse_stack_slot (int regno, unsigne FIRST_PSEUDO_REGISTER, i, bi) { another_allocno = ira_regno_allocno_map[i]; - if (allocnos_have_intersected_live_ranges_p (allocno, - another_allocno)) + if (allocnos_conflict_by_live_ranges_p (allocno, + another_allocno)) goto cont; } for (cost = 0, cp = ALLOCNO_COPIES (allocno); @@ -2967,7 +4186,7 @@ ira_reuse_stack_slot (int regno, unsigne EXECUTE_IF_SET_IN_BITMAP (&slot->spilled_regs, FIRST_PSEUDO_REGISTER, i, bi) { - ira_assert (! pseudos_have_intersected_live_ranges_p (regno, i)); + ira_assert (! conflict_by_live_ranges_p (regno, i)); } #endif SET_REGNO_REG_SET (&slot->spilled_regs, regno); @@ -3046,7 +4265,7 @@ calculate_spill_cost (int *regnos, rtx i ira_assert (hard_regno >= 0); a = ira_regno_allocno_map[regno]; length += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) / ALLOCNO_NUM_OBJECTS (a); - cost += ALLOCNO_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a); + cost += ALLOCNO_MEMORY_COST (a) - ALLOCNO_CLASS_COST (a); nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (a)]; for (j = 0; j < nregs; j++) if (! TEST_HARD_REG_BIT (call_used_reg_set, hard_regno + j)) @@ -3061,11 +4280,11 @@ calculate_spill_cost (int *regnos, rtx i saved_cost = 0; if (in_p) saved_cost += ira_memory_move_cost - [ALLOCNO_MODE (a)][ALLOCNO_COVER_CLASS (a)][1]; + [ALLOCNO_MODE (a)][ALLOCNO_CLASS (a)][1]; if (out_p) saved_cost += ira_memory_move_cost - [ALLOCNO_MODE (a)][ALLOCNO_COVER_CLASS (a)][0]; + [ALLOCNO_MODE (a)][ALLOCNO_CLASS (a)][0]; cost -= REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn)) * saved_cost; } } @@ -3151,13 +4370,10 @@ static void color (void) { allocno_stack_vec = VEC_alloc (ira_allocno_t, heap, ira_allocnos_num); - removed_splay_allocno_vec - = VEC_alloc (ira_allocno_t, heap, ira_allocnos_num); memset (allocated_hardreg_p, 0, sizeof (allocated_hardreg_p)); ira_initiate_assign (); do_coloring (); ira_finish_assign (); - VEC_free (ira_allocno_t, heap, removed_splay_allocno_vec); VEC_free (ira_allocno_t, heap, allocno_stack_vec); move_spill_restore (); } @@ -3177,7 +4393,7 @@ fast_allocation (void) #ifdef STACK_REGS bool no_stack_reg_p; #endif - enum reg_class cover_class; + enum reg_class aclass; enum machine_mode mode; ira_allocno_t a; ira_allocno_iterator ai; @@ -3213,20 +4429,20 @@ fast_allocation (void) for (j = r->start; j <= r->finish; j++) IOR_HARD_REG_SET (conflict_hard_regs, used_hard_regs[j]); } - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); ALLOCNO_ASSIGNED_P (a) = true; ALLOCNO_HARD_REGNO (a) = -1; - if (hard_reg_set_subset_p (reg_class_contents[cover_class], + if (hard_reg_set_subset_p (reg_class_contents[aclass], conflict_hard_regs)) continue; mode = ALLOCNO_MODE (a); #ifdef STACK_REGS no_stack_reg_p = ALLOCNO_NO_STACK_REG_P (a); #endif - class_size = ira_class_hard_regs_num[cover_class]; + class_size = ira_class_hard_regs_num[aclass]; for (j = 0; j < class_size; j++) { - hard_regno = ira_class_hard_regs[cover_class][j]; + hard_regno = ira_class_hard_regs[aclass][j]; #ifdef STACK_REGS if (no_stack_reg_p && FIRST_STACK_REG <= hard_regno && hard_regno <= LAST_STACK_REG) @@ -3234,7 +4450,7 @@ fast_allocation (void) #endif if (!ira_hard_reg_not_in_set_p (hard_regno, mode, conflict_hard_regs) || (TEST_HARD_REG_BIT - (prohibited_class_mode_regs[cover_class][mode], hard_regno))) + (ira_prohibited_class_mode_regs[aclass][mode], hard_regno))) continue; ALLOCNO_HARD_REGNO (a) = hard_regno; for (l = 0; l < nr; l++) @@ -3268,7 +4484,7 @@ ira_color (void) FOR_EACH_ALLOCNO (a, ai) { ALLOCNO_UPDATED_MEMORY_COST (a) = ALLOCNO_MEMORY_COST (a); - ALLOCNO_UPDATED_COVER_CLASS_COST (a) = ALLOCNO_COVER_CLASS_COST (a); + ALLOCNO_UPDATED_CLASS_COST (a) = ALLOCNO_CLASS_COST (a); } if (ira_conflicts_p) color (); Index: gcc-4.7-r171648/gcc/opts.c =================================================================== --- gcc-4.7-r171648/gcc/opts.c (revision 171648) +++ gcc-4.7-r171648/gcc/opts.c (revision 171649) @@ -289,11 +289,6 @@ init_options_struct (struct gcc_options opts_set->x_param_values = XCNEWVEC (int, num_params); init_param_values (opts->x_param_values); - /* Use priority coloring if cover classes is not defined for the - target. */ - if (targetm.ira_cover_classes == NULL) - opts->x_flag_ira_algorithm = IRA_ALGORITHM_PRIORITY; - /* Initialize whether `char' is signed. */ opts->x_flag_signed_char = DEFAULT_SIGNED_CHAR; /* Set this to a special "uninitialized" value. The actual default @@ -758,14 +753,6 @@ finish_options (struct gcc_options *opts if (!opts->x_flag_sel_sched_pipelining) opts->x_flag_sel_sched_pipelining_outer_loops = 0; - if (!targetm.ira_cover_classes - && opts->x_flag_ira_algorithm == IRA_ALGORITHM_CB) - { - inform (loc, - "-fira-algorithm=CB does not work on this architecture"); - opts->x_flag_ira_algorithm = IRA_ALGORITHM_PRIORITY; - } - if (opts->x_flag_conserve_stack) { maybe_set_param_value (PARAM_LARGE_STACK_FRAME, 100, Index: gcc-4.7-r171648/gcc/ira-lives.c =================================================================== --- gcc-4.7-r171648/gcc/ira-lives.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira-lives.c (revision 171649) @@ -64,8 +64,8 @@ static int curr_point; register pressure excess. Excess pressure for a register class at some point means that there are more allocnos of given register class living at the point than number of hard-registers of the - class available for the allocation. It is defined only for cover - classes. */ + class available for the allocation. It is defined only for + pressure classes. */ static int high_pressure_start_point[N_REG_CLASSES]; /* Objects live at current point in the scan. */ @@ -97,6 +97,7 @@ make_hard_regno_born (int regno) EXECUTE_IF_SET_IN_SPARSESET (objects_live, i) { ira_object_t obj = ira_object_id_map[i]; + SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno); SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno); } @@ -134,14 +135,17 @@ update_allocno_pressure_excess_length (i { ira_allocno_t a = OBJECT_ALLOCNO (obj); int start, i; - enum reg_class cover_class, cl; + enum reg_class aclass, pclass, cl; live_range_t p; - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); + pclass = ira_pressure_class_translate[aclass]; for (i = 0; - (cl = ira_reg_class_super_classes[cover_class][i]) != LIM_REG_CLASSES; + (cl = ira_reg_class_super_classes[pclass][i]) != LIM_REG_CLASSES; i++) { + if (! ira_reg_pressure_class_p[cl]) + continue; if (high_pressure_start_point[cl] < 0) continue; p = OBJECT_LIVE_RANGES (obj); @@ -166,24 +170,26 @@ make_object_dead (ira_object_t obj) update_allocno_pressure_excess_length (obj); } -/* The current register pressures for each cover class for the current +/* The current register pressures for each pressure class for the current basic block. */ static int curr_reg_pressure[N_REG_CLASSES]; -/* Record that register pressure for COVER_CLASS increased by N - registers. Update the current register pressure, maximal register - pressure for the current BB and the start point of the register - pressure excess. */ +/* Record that register pressure for PCLASS increased by N registers. + Update the current register pressure, maximal register pressure for + the current BB and the start point of the register pressure + excess. */ static void -inc_register_pressure (enum reg_class cover_class, int n) +inc_register_pressure (enum reg_class pclass, int n) { int i; enum reg_class cl; for (i = 0; - (cl = ira_reg_class_super_classes[cover_class][i]) != LIM_REG_CLASSES; + (cl = ira_reg_class_super_classes[pclass][i]) != LIM_REG_CLASSES; i++) { + if (! ira_reg_pressure_class_p[cl]) + continue; curr_reg_pressure[cl] += n; if (high_pressure_start_point[cl] < 0 && (curr_reg_pressure[cl] > ira_available_class_regs[cl])) @@ -193,13 +199,13 @@ inc_register_pressure (enum reg_class co } } -/* Record that register pressure for COVER_CLASS has decreased by - NREGS registers; update current register pressure, start point of - the register pressure excess, and register pressure excess length - for living allocnos. */ +/* Record that register pressure for PCLASS has decreased by NREGS + registers; update current register pressure, start point of the + register pressure excess, and register pressure excess length for + living allocnos. */ static void -dec_register_pressure (enum reg_class cover_class, int nregs) +dec_register_pressure (enum reg_class pclass, int nregs) { int i; unsigned int j; @@ -207,9 +213,11 @@ dec_register_pressure (enum reg_class co bool set_p = false; for (i = 0; - (cl = ira_reg_class_super_classes[cover_class][i]) != LIM_REG_CLASSES; + (cl = ira_reg_class_super_classes[pclass][i]) != LIM_REG_CLASSES; i++) { + if (! ira_reg_pressure_class_p[cl]) + continue; curr_reg_pressure[cl] -= nregs; ira_assert (curr_reg_pressure[cl] >= 0); if (high_pressure_start_point[cl] >= 0 @@ -221,12 +229,15 @@ dec_register_pressure (enum reg_class co EXECUTE_IF_SET_IN_SPARSESET (objects_live, j) update_allocno_pressure_excess_length (ira_object_id_map[j]); for (i = 0; - (cl = ira_reg_class_super_classes[cover_class][i]) - != LIM_REG_CLASSES; + (cl = ira_reg_class_super_classes[pclass][i]) != LIM_REG_CLASSES; i++) - if (high_pressure_start_point[cl] >= 0 - && curr_reg_pressure[cl] <= ira_available_class_regs[cl]) - high_pressure_start_point[cl] = -1; + { + if (! ira_reg_pressure_class_p[cl]) + continue; + if (high_pressure_start_point[cl] >= 0 + && curr_reg_pressure[cl] <= ira_available_class_regs[cl]) + high_pressure_start_point[cl] = -1; + } } } @@ -236,8 +247,8 @@ static void mark_pseudo_regno_live (int regno) { ira_allocno_t a = ira_curr_regno_allocno_map[regno]; + enum reg_class pclass; int i, n, nregs; - enum reg_class cl; if (a == NULL) return; @@ -246,8 +257,8 @@ mark_pseudo_regno_live (int regno) allocno_saved_at_call[ALLOCNO_NUM (a)] = 0; n = ALLOCNO_NUM_OBJECTS (a); - cl = ALLOCNO_COVER_CLASS (a); - nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)]; + pclass = 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. */ @@ -258,10 +269,11 @@ mark_pseudo_regno_live (int regno) for (i = 0; i < n; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); + if (sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj))) continue; - inc_register_pressure (cl, nregs); + inc_register_pressure (pclass, nregs); make_object_born (obj); } } @@ -274,7 +286,7 @@ mark_pseudo_regno_subword_live (int regn { ira_allocno_t a = ira_curr_regno_allocno_map[regno]; int n, nregs; - enum reg_class cl; + enum reg_class pclass; ira_object_t obj; if (a == NULL) @@ -290,15 +302,15 @@ mark_pseudo_regno_subword_live (int regn return; } - cl = ALLOCNO_COVER_CLASS (a); - nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)]; + pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)]; + nregs = ira_reg_class_max_nregs[pclass][ALLOCNO_MODE (a)]; gcc_assert (nregs == n); obj = ALLOCNO_OBJECT (a, subword); if (sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj))) return; - inc_register_pressure (cl, nregs); + inc_register_pressure (pclass, nregs); make_object_born (obj); } @@ -313,14 +325,16 @@ mark_hard_reg_live (rtx reg) if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)) { int last = regno + hard_regno_nregs[regno][GET_MODE (reg)]; + enum reg_class aclass, pclass; while (regno < last) { if (! TEST_HARD_REG_BIT (hard_regs_live, regno) && ! TEST_HARD_REG_BIT (eliminable_regset, regno)) { - enum reg_class cover_class = ira_hard_regno_cover_class[regno]; - inc_register_pressure (cover_class, 1); + aclass = ira_hard_regno_allocno_class[regno]; + pclass = ira_pressure_class_translate[aclass]; + inc_register_pressure (pclass, 1); make_hard_regno_born (regno); } regno++; @@ -375,8 +389,8 @@ mark_pseudo_regno_dead (int regno) allocno_saved_at_call[ALLOCNO_NUM (a)] = 0; n = ALLOCNO_NUM_OBJECTS (a); - cl = ALLOCNO_COVER_CLASS (a); - nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (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. */ @@ -415,8 +429,8 @@ mark_pseudo_regno_subword_dead (int regn /* The allocno as a whole doesn't die in this case. */ return; - cl = ALLOCNO_COVER_CLASS (a); - nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)]; + cl = ira_pressure_class_translate[ALLOCNO_CLASS (a)]; + nregs = ira_reg_class_max_nregs[cl][ALLOCNO_MODE (a)]; gcc_assert (nregs == n); obj = ALLOCNO_OBJECT (a, subword); @@ -437,13 +451,15 @@ mark_hard_reg_dead (rtx reg) if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)) { int last = regno + hard_regno_nregs[regno][GET_MODE (reg)]; + enum reg_class aclass, pclass; while (regno < last) { if (TEST_HARD_REG_BIT (hard_regs_live, regno)) { - enum reg_class cover_class = ira_hard_regno_cover_class[regno]; - dec_register_pressure (cover_class, 1); + aclass = ira_hard_regno_allocno_class[regno]; + pclass = ira_pressure_class_translate[aclass]; + dec_register_pressure (pclass, 1); make_hard_regno_dead (regno); } regno++; @@ -512,7 +528,7 @@ make_pseudo_conflict (rtx reg, enum reg_ return advance_p; a = ira_curr_regno_allocno_map[REGNO (reg)]; - if (! reg_classes_intersect_p (cl, ALLOCNO_COVER_CLASS (a))) + if (! reg_classes_intersect_p (cl, ALLOCNO_CLASS (a))) return advance_p; if (advance_p) @@ -585,7 +601,7 @@ check_and_make_def_conflict (int alt, in return; a = ira_curr_regno_allocno_map[REGNO (dreg)]; - acl = ALLOCNO_COVER_CLASS (a); + acl = ALLOCNO_CLASS (a); if (! reg_classes_intersect_p (acl, def_cl)) return; @@ -815,7 +831,7 @@ single_reg_class (const char *constraint : REG_CLASS_FROM_CONSTRAINT (c, constraints)); if ((cl != NO_REGS && next_cl != cl) || (ira_available_class_regs[next_cl] - > ira_reg_class_nregs[next_cl][GET_MODE (op)])) + > ira_reg_class_max_nregs[next_cl][GET_MODE (op)])) return NO_REGS; cl = next_cl; break; @@ -828,7 +844,7 @@ single_reg_class (const char *constraint if ((cl != NO_REGS && next_cl != cl) || next_cl == NO_REGS || (ira_available_class_regs[next_cl] - > ira_reg_class_nregs[next_cl][GET_MODE (op)])) + > ira_reg_class_max_nregs[next_cl][GET_MODE (op)])) return NO_REGS; cl = next_cl; break; @@ -903,7 +919,7 @@ ira_implicitly_set_insn_hard_regs (HARD_ regs in this class are fixed. */ && ira_available_class_regs[cl] != 0 && (ira_available_class_regs[cl] - <= ira_reg_class_nregs[cl][mode])) + <= ira_reg_class_max_nregs[cl][mode])) IOR_HARD_REG_SET (*set, reg_class_contents[cl]); break; } @@ -944,11 +960,11 @@ process_single_reg_class_operands (bool if (REG_P (operand) && (regno = REGNO (operand)) >= FIRST_PSEUDO_REGISTER) { - enum reg_class cover_class; + enum reg_class aclass; operand_a = ira_curr_regno_allocno_map[regno]; - cover_class = ALLOCNO_COVER_CLASS (operand_a); - if (ira_class_subset_p[cl][cover_class] + aclass = ALLOCNO_CLASS (operand_a); + if (ira_class_subset_p[cl][aclass] && ira_class_hard_regs_num[cl] != 0) { /* View the desired allocation of OPERAND as: @@ -968,21 +984,19 @@ process_single_reg_class_operands (bool offset = subreg_lowpart_offset (ymode, xmode); yregno = simplify_subreg_regno (xregno, xmode, offset, ymode); if (yregno >= 0 - && ira_class_hard_reg_index[cover_class][yregno] >= 0) + && ira_class_hard_reg_index[aclass][yregno] >= 0) { int cost; ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a), - cover_class, 0); - cost - = (freq - * (in_p - ? ira_get_register_move_cost (xmode, cover_class, cl) - : ira_get_register_move_cost (xmode, cl, - cover_class))); + aclass, 0); + ira_init_register_move_cost_if_necessary (xmode); + cost = freq * (in_p + ? ira_register_move_cost[xmode][aclass][cl] + : ira_register_move_cost[xmode][cl][aclass]); ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a) - [ira_class_hard_reg_index[cover_class][yregno]] -= cost; + [ira_class_hard_reg_index[aclass][yregno]] -= cost; } } } @@ -1040,10 +1054,10 @@ process_bb_node_lives (ira_loop_tree_nod bb = loop_tree_node->bb; if (bb != NULL) { - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - curr_reg_pressure[ira_reg_class_cover[i]] = 0; - high_pressure_start_point[ira_reg_class_cover[i]] = -1; + curr_reg_pressure[ira_pressure_classes[i]] = 0; + high_pressure_start_point[ira_pressure_classes[i]] = -1; } curr_bb_node = loop_tree_node; reg_live_out = DF_LR_OUT (bb); @@ -1054,14 +1068,17 @@ process_bb_node_lives (ira_loop_tree_nod for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (hard_regs_live, i)) { - enum reg_class cover_class, cl; + enum reg_class aclass, pclass, cl; - cover_class = ira_class_translate[REGNO_REG_CLASS (i)]; + aclass = ira_allocno_class_translate[REGNO_REG_CLASS (i)]; + pclass = ira_pressure_class_translate[aclass]; for (j = 0; - (cl = ira_reg_class_super_classes[cover_class][j]) + (cl = ira_reg_class_super_classes[pclass][j]) != LIM_REG_CLASSES; j++) { + if (! ira_reg_pressure_class_p[cl]) + continue; curr_reg_pressure[cl]++; if (curr_bb_node->reg_pressure[cl] < curr_reg_pressure[cl]) curr_bb_node->reg_pressure[cl] = curr_reg_pressure[cl]; @@ -1261,6 +1278,7 @@ process_bb_node_lives (ira_loop_tree_nod EXECUTE_IF_SET_IN_SPARSESET (objects_live, px) { ira_allocno_t a = OBJECT_ALLOCNO (ira_object_id_map[px]); + ALLOCNO_NO_STACK_REG_P (a) = true; ALLOCNO_TOTAL_NO_STACK_REG_P (a) = true; } @@ -1284,15 +1302,15 @@ process_bb_node_lives (ira_loop_tree_nod } /* Propagate register pressure to upper loop tree nodes: */ if (loop_tree_node != ira_loop_tree_root) - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - enum reg_class cover_class; + enum reg_class pclass; - cover_class = ira_reg_class_cover[i]; - if (loop_tree_node->reg_pressure[cover_class] - > loop_tree_node->parent->reg_pressure[cover_class]) - loop_tree_node->parent->reg_pressure[cover_class] - = loop_tree_node->reg_pressure[cover_class]; + pclass = ira_pressure_classes[i]; + if (loop_tree_node->reg_pressure[pclass] + > loop_tree_node->parent->reg_pressure[pclass]) + loop_tree_node->parent->reg_pressure[pclass] + = loop_tree_node->reg_pressure[pclass]; } } @@ -1424,6 +1442,7 @@ print_allocno_live_ranges (FILE *f, ira_ { int n = ALLOCNO_NUM_OBJECTS (a); int i; + for (i = 0; i < n; i++) { fprintf (f, " a%d(r%d", ALLOCNO_NUM (a), ALLOCNO_REGNO (a)); Index: gcc-4.7-r171648/gcc/regmove.c =================================================================== --- gcc-4.7-r171648/gcc/regmove.c (revision 171648) +++ gcc-4.7-r171648/gcc/regmove.c (revision 171649) @@ -1236,12 +1236,12 @@ regmove_optimize (void) df_note_add_problem (); df_analyze (); - if (flag_ira_loop_pressure) - ira_set_pseudo_classes (dump_file); - regstat_init_n_sets_and_refs (); regstat_compute_ri (); + if (flag_ira_loop_pressure) + ira_set_pseudo_classes (dump_file); + regno_src_regno = XNEWVEC (int, nregs); for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1; Index: gcc-4.7-r171648/gcc/ira-emit.c =================================================================== --- gcc-4.7-r171648/gcc/ira-emit.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira-emit.c (revision 171649) @@ -1,5 +1,5 @@ /* Integrated Register Allocator. Changing code and generating moves. - Copyright (C) 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Vladimir Makarov . @@ -19,6 +19,52 @@ You should have received a copy of the G along with GCC; see the file COPYING3. If not see . */ +/* When we have more one region, we need to change the original RTL + code after coloring. Let us consider two allocnos representing the + same pseudo-register outside and inside a region respectively. + They can get different hard-registers. The reload pass works on + pseudo registers basis and there is no way to say the reload that + pseudo could be in different registers and it is even more + difficult to say in what places of the code the pseudo should have + particular hard-registers. So in this case IRA has to create and + use a new pseudo-register inside the region and adds code to move + allocno values on the region's borders. This is done by the code + in this file. + + The code makes top-down traversal of the regions and generate new + pseudos and the move code on the region borders. In some + complicated cases IRA can create a new pseudo used temporarily to + move allocno values when a swap of values stored in two + hard-registers is needed (e.g. two allocnos representing different + pseudos outside region got respectively hard registers 1 and 2 and + the corresponding allocnos inside the region got respectively hard + registers 2 and 1). At this stage, the new pseudo is marked as + spilled. + + IRA still creates the pseudo-register and the moves on the region + borders even when the both corresponding allocnos were assigned to + the same hard-register. It is done because, if the reload pass for + some reason spills a pseudo-register representing the original + pseudo outside or inside the region, the effect will be smaller + because another pseudo will still be in the hard-register. In most + cases, this is better then spilling the original pseudo in its + whole live-range. If reload does not change the allocation for the + two pseudo-registers, the trivial move will be removed by + post-reload optimizations. + + IRA does not generate a new pseudo and moves for the allocno values + if the both allocnos representing an original pseudo inside and + outside region assigned to the same hard register when the register + pressure in the region for the corresponding pressure class is less + than number of available hard registers for given pressure class. + + IRA also does some optimizations to remove redundant moves which is + transformed into stores by the reload pass on CFG edges + representing exits from the region. + + IRA tries to reduce duplication of code generated on CFG edges + which are enters and exits to/from regions by moving some code to + the edge sources or destinations when it is possible. */ #include "config.h" #include "system.h" @@ -44,6 +90,73 @@ along with GCC; see the file COPYING3. #include "ira-int.h" +/* Data used to emit live range split insns and to flattening IR. */ +ira_emit_data_t ira_allocno_emit_data; + +/* Definitions for vectors of pointers. */ +typedef void *void_p; +DEF_VEC_P (void_p); +DEF_VEC_ALLOC_P (void_p,heap); + +/* Pointers to data allocated for allocnos being created during + emitting. Usually there are quite few such allocnos because they + are created only for resolving loop in register shuffling. */ +static VEC(void_p, heap) *new_allocno_emit_data_vec; + +/* Allocate and initiate the emit data. */ +void +ira_initiate_emit_data (void) +{ + ira_allocno_t a; + ira_allocno_iterator ai; + + ira_allocno_emit_data + = (ira_emit_data_t) ira_allocate (ira_allocnos_num + * sizeof (struct ira_emit_data)); + memset (ira_allocno_emit_data, 0, + ira_allocnos_num * sizeof (struct ira_emit_data)); + FOR_EACH_ALLOCNO (a, ai) + ALLOCNO_ADD_DATA (a) = ira_allocno_emit_data + ALLOCNO_NUM (a); + new_allocno_emit_data_vec = VEC_alloc (void_p, heap, 50); + +} + +/* Free the emit data. */ +void +ira_finish_emit_data (void) +{ + void_p p; + ira_allocno_t a; + ira_allocno_iterator ai; + + ira_free (ira_allocno_emit_data); + FOR_EACH_ALLOCNO (a, ai) + ALLOCNO_ADD_DATA (a) = NULL; + for (;VEC_length (void_p, new_allocno_emit_data_vec) != 0;) + { + p = VEC_pop (void_p, new_allocno_emit_data_vec); + ira_free (p); + } + VEC_free (void_p, heap, new_allocno_emit_data_vec); +} + +/* Create and return a new allocno with given REGNO and + LOOP_TREE_NODE. Allocate emit data for it. */ +static ira_allocno_t +create_new_allocno (int regno, ira_loop_tree_node_t loop_tree_node) +{ + ira_allocno_t a; + + a = ira_create_allocno (regno, false, loop_tree_node); + ALLOCNO_ADD_DATA (a) = ira_allocate (sizeof (struct ira_emit_data)); + memset (ALLOCNO_ADD_DATA (a), 0, sizeof (struct ira_emit_data)); + VEC_safe_push (void_p, heap, new_allocno_emit_data_vec, ALLOCNO_ADD_DATA (a)); + return a; +} + + + +/* See comments below. */ typedef struct move *move_t; /* The structure represents an allocno move. Both allocnos have the @@ -171,7 +284,7 @@ change_regs (rtx *loc) return false; if (ira_curr_regno_allocno_map[regno] == NULL) return false; - reg = ALLOCNO_REG (ira_curr_regno_allocno_map[regno]); + reg = allocno_emit_reg (ira_curr_regno_allocno_map[regno]); if (reg == *loc) return false; *loc = reg; @@ -258,9 +371,9 @@ set_allocno_reg (ira_allocno_t allocno, a != NULL; a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) if (subloop_tree_node_p (ALLOCNO_LOOP_TREE_NODE (a), node)) - ALLOCNO_REG (a) = reg; + ALLOCNO_EMIT_DATA (a)->reg = reg; for (a = ALLOCNO_CAP (allocno); a != NULL; a = ALLOCNO_CAP (a)) - ALLOCNO_REG (a) = reg; + ALLOCNO_EMIT_DATA (a)->reg = reg; regno = ALLOCNO_REGNO (allocno); for (a = allocno;;) { @@ -273,9 +386,9 @@ set_allocno_reg (ira_allocno_t allocno, } if (a == NULL) continue; - if (ALLOCNO_CHILD_RENAMED_P (a)) + if (ALLOCNO_EMIT_DATA (a)->child_renamed_p) break; - ALLOCNO_CHILD_RENAMED_P (a) = true; + ALLOCNO_EMIT_DATA (a)->child_renamed_p = true; } } @@ -289,7 +402,9 @@ entered_from_non_parent_p (ira_loop_tree edge e; edge_iterator ei; - for (bb_node = loop_node->children; bb_node != NULL; bb_node = bb_node->next) + for (bb_node = loop_node->children; + bb_node != NULL; + bb_node = bb_node->next) if (bb_node->bb != NULL) { FOR_EACH_EDGE (e, ei, bb_node->bb->preds) @@ -344,14 +459,14 @@ store_can_be_removed_p (ira_allocno_t sr ira_assert (ALLOCNO_CAP_MEMBER (src_allocno) == NULL && ALLOCNO_CAP_MEMBER (dest_allocno) == NULL); orig_regno = ALLOCNO_REGNO (src_allocno); - regno = REGNO (ALLOCNO_REG (dest_allocno)); + regno = REGNO (allocno_emit_reg (dest_allocno)); for (node = ALLOCNO_LOOP_TREE_NODE (src_allocno); node != NULL; node = node->parent) { a = node->regno_allocno_map[orig_regno]; ira_assert (a != NULL); - if (REGNO (ALLOCNO_REG (a)) == (unsigned) regno) + if (REGNO (allocno_emit_reg (a)) == (unsigned) regno) /* We achieved the destination and everything is ok. */ return true; else if (bitmap_bit_p (node->modified_regnos, orig_regno)) @@ -396,8 +511,8 @@ generate_edge_moves (edge e) { src_allocno = src_map[regno]; dest_allocno = dest_map[regno]; - if (REGNO (ALLOCNO_REG (src_allocno)) - == REGNO (ALLOCNO_REG (dest_allocno))) + if (REGNO (allocno_emit_reg (src_allocno)) + == REGNO (allocno_emit_reg (dest_allocno))) continue; /* Remove unnecessary stores at the region exit. We should do this for readonly memory for sure and this is guaranteed by @@ -408,8 +523,8 @@ generate_edge_moves (edge e) && ALLOCNO_HARD_REGNO (src_allocno) >= 0 && store_can_be_removed_p (src_allocno, dest_allocno)) { - ALLOCNO_MEM_OPTIMIZED_DEST (src_allocno) = dest_allocno; - ALLOCNO_MEM_OPTIMIZED_DEST_P (dest_allocno) = true; + ALLOCNO_EMIT_DATA (src_allocno)->mem_optimized_dest = dest_allocno; + ALLOCNO_EMIT_DATA (dest_allocno)->mem_optimized_dest_p = true; if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) fprintf (ira_dump_file, " Remove r%d:a%d->a%d(mem)\n", regno, ALLOCNO_NUM (src_allocno), @@ -445,7 +560,7 @@ change_loop (ira_loop_tree_node_t node) bool used_p; ira_allocno_t allocno, parent_allocno, *map; rtx insn, original_reg; - enum reg_class cover_class; + enum reg_class aclass, pclass; ira_loop_tree_node_t parent; if (node != ira_loop_tree_root) @@ -474,7 +589,8 @@ change_loop (ira_loop_tree_node_t node) { allocno = ira_allocnos[i]; regno = ALLOCNO_REGNO (allocno); - cover_class = ALLOCNO_COVER_CLASS (allocno); + aclass = ALLOCNO_CLASS (allocno); + pclass = ira_pressure_class_translate[aclass]; parent_allocno = map[regno]; ira_assert (regno < ira_reg_equiv_len); /* We generate the same hard register move because the @@ -487,8 +603,8 @@ change_loop (ira_loop_tree_node_t node) && (ALLOCNO_HARD_REGNO (allocno) == ALLOCNO_HARD_REGNO (parent_allocno)) && (ALLOCNO_HARD_REGNO (allocno) < 0 - || (parent->reg_pressure[cover_class] + 1 - <= ira_available_class_regs[cover_class]) + || (parent->reg_pressure[pclass] + 1 + <= ira_available_class_regs[pclass]) || TEST_HARD_REG_BIT (ira_prohibited_mode_move_regs [ALLOCNO_MODE (allocno)], ALLOCNO_HARD_REGNO (allocno)) @@ -498,9 +614,10 @@ change_loop (ira_loop_tree_node_t node) || ira_reg_equiv_invariant_p[regno] || ira_reg_equiv_const[regno] != NULL_RTX)) continue; - original_reg = ALLOCNO_REG (allocno); + original_reg = allocno_emit_reg (allocno); if (parent_allocno == NULL - || REGNO (ALLOCNO_REG (parent_allocno)) == REGNO (original_reg)) + || (REGNO (allocno_emit_reg (parent_allocno)) + == REGNO (original_reg))) { if (internal_flag_ira_verbose > 3 && ira_dump_file) fprintf (ira_dump_file, " %i vs parent %i:", @@ -523,11 +640,11 @@ change_loop (ira_loop_tree_node_t node) if (ALLOCNO_CAP_MEMBER (allocno) != NULL) continue; used_p = !bitmap_set_bit (used_regno_bitmap, regno); - ALLOCNO_SOMEWHERE_RENAMED_P (allocno) = true; + ALLOCNO_EMIT_DATA (allocno)->somewhere_renamed_p = true; if (! used_p) continue; bitmap_set_bit (renamed_regno_bitmap, regno); - set_allocno_reg (allocno, create_new_reg (ALLOCNO_REG (allocno))); + set_allocno_reg (allocno, create_new_reg (allocno_emit_reg (allocno))); } } @@ -543,8 +660,8 @@ set_allocno_somewhere_renamed_p (void) { regno = ALLOCNO_REGNO (allocno); if (bitmap_bit_p (renamed_regno_bitmap, regno) - && REGNO (ALLOCNO_REG (allocno)) == regno) - ALLOCNO_SOMEWHERE_RENAMED_P (allocno) = true; + && REGNO (allocno_emit_reg (allocno)) == regno) + ALLOCNO_EMIT_DATA (allocno)->somewhere_renamed_p = true; } } @@ -724,16 +841,16 @@ modify_move_list (move_t list) subsequent IRA internal representation flattening. */ new_allocno - = ira_create_allocno (ALLOCNO_REGNO (set_move->to), false, + = create_new_allocno (ALLOCNO_REGNO (set_move->to), ALLOCNO_LOOP_TREE_NODE (set_move->to)); ALLOCNO_MODE (new_allocno) = ALLOCNO_MODE (set_move->to); - ira_set_allocno_cover_class - (new_allocno, ALLOCNO_COVER_CLASS (set_move->to)); + ira_set_allocno_class (new_allocno, + ALLOCNO_CLASS (set_move->to)); ira_create_allocno_objects (new_allocno); ALLOCNO_ASSIGNED_P (new_allocno) = true; ALLOCNO_HARD_REGNO (new_allocno) = -1; - ALLOCNO_REG (new_allocno) - = create_new_reg (ALLOCNO_REG (set_move->to)); + ALLOCNO_EMIT_DATA (new_allocno)->reg + = create_new_reg (allocno_emit_reg (set_move->to)); /* Make it possibly conflicting with all earlier created allocnos. Cases where temporary allocnos @@ -756,7 +873,7 @@ modify_move_list (move_t list) fprintf (ira_dump_file, " Creating temporary allocno a%dr%d\n", ALLOCNO_NUM (new_allocno), - REGNO (ALLOCNO_REG (new_allocno))); + REGNO (allocno_emit_reg (new_allocno))); } } if ((hard_regno = ALLOCNO_HARD_REGNO (to)) < 0) @@ -786,13 +903,14 @@ emit_move_list (move_t list, int freq) int cost; rtx result, insn; enum machine_mode mode; - enum reg_class cover_class; + enum reg_class aclass; start_sequence (); for (; list != NULL; list = list->next) { start_sequence (); - emit_move_insn (ALLOCNO_REG (list->to), ALLOCNO_REG (list->from)); + emit_move_insn (allocno_emit_reg (list->to), + allocno_emit_reg (list->from)); list->insn = get_insns (); end_sequence (); /* The reload needs to have set up insn codes. If the reload @@ -803,13 +921,13 @@ emit_move_list (move_t list, int freq) recog_memoized (insn); emit_insn (list->insn); mode = ALLOCNO_MODE (list->to); - cover_class = ALLOCNO_COVER_CLASS (list->to); + aclass = ALLOCNO_CLASS (list->to); cost = 0; if (ALLOCNO_HARD_REGNO (list->to) < 0) { if (ALLOCNO_HARD_REGNO (list->from) >= 0) { - cost = ira_memory_move_cost[mode][cover_class][0] * freq; + cost = ira_memory_move_cost[mode][aclass][0] * freq; ira_store_cost += cost; } } @@ -817,14 +935,14 @@ emit_move_list (move_t list, int freq) { if (ALLOCNO_HARD_REGNO (list->to) >= 0) { - cost = ira_memory_move_cost[mode][cover_class][0] * freq; + cost = ira_memory_move_cost[mode][aclass][0] * freq; ira_load_cost += cost; } } else { - cost = (ira_get_register_move_cost (mode, cover_class, cover_class) - * freq); + ira_init_register_move_cost_if_necessary (mode); + cost = ira_register_move_cost[mode][aclass][aclass] * freq; ira_shuffle_cost += cost; } ira_overall_cost += cost; @@ -902,7 +1020,7 @@ update_costs (ira_allocno_t a, bool read ALLOCNO_NREFS (a)++; ALLOCNO_FREQ (a) += freq; ALLOCNO_MEMORY_COST (a) - += (ira_memory_move_cost[ALLOCNO_MODE (a)][ALLOCNO_COVER_CLASS (a)] + += (ira_memory_move_cost[ALLOCNO_MODE (a)][ALLOCNO_CLASS (a)] [read_p ? 1 : 0] * freq); if (ALLOCNO_CAP (a) != NULL) a = ALLOCNO_CAP (a); @@ -956,7 +1074,7 @@ add_range_and_copies_from_move_list (mov { if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) fprintf (ira_dump_file, " Allocate conflicts for a%dr%d\n", - ALLOCNO_NUM (to), REGNO (ALLOCNO_REG (to))); + ALLOCNO_NUM (to), REGNO (allocno_emit_reg (to))); ira_allocate_object_conflicts (to_obj, n); } } @@ -969,8 +1087,9 @@ add_range_and_copies_from_move_list (mov if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) fprintf (ira_dump_file, " Adding cp%d:a%dr%d-a%dr%d\n", cp->num, ALLOCNO_NUM (cp->first), - REGNO (ALLOCNO_REG (cp->first)), ALLOCNO_NUM (cp->second), - REGNO (ALLOCNO_REG (cp->second))); + REGNO (allocno_emit_reg (cp->first)), + ALLOCNO_NUM (cp->second), + REGNO (allocno_emit_reg (cp->second))); nr = ALLOCNO_NUM_OBJECTS (from); for (i = 0; i < nr; i++) @@ -984,7 +1103,7 @@ add_range_and_copies_from_move_list (mov fprintf (ira_dump_file, " Adding range [%d..%d] to allocno a%dr%d\n", start, ira_max_point, ALLOCNO_NUM (from), - REGNO (ALLOCNO_REG (from))); + REGNO (allocno_emit_reg (from))); } else { @@ -993,7 +1112,7 @@ add_range_and_copies_from_move_list (mov fprintf (ira_dump_file, " Adding range [%d..%d] to allocno a%dr%d\n", r->start, ira_max_point, ALLOCNO_NUM (from), - REGNO (ALLOCNO_REG (from))); + REGNO (allocno_emit_reg (from))); } } ira_max_point++; @@ -1020,7 +1139,7 @@ add_range_and_copies_from_move_list (mov fprintf (ira_dump_file, " Adding range [%d..%d] to allocno a%dr%d\n", r->start, r->finish, ALLOCNO_NUM (move->to), - REGNO (ALLOCNO_REG (move->to))); + REGNO (allocno_emit_reg (move->to))); } } } @@ -1030,7 +1149,7 @@ add_range_and_copies_from_move_list (mov int nr, i; a = node->regno_allocno_map[regno]; - if ((to = ALLOCNO_MEM_OPTIMIZED_DEST (a)) != NULL) + if ((to = ALLOCNO_EMIT_DATA (a)->mem_optimized_dest) != NULL) a = to; nr = ALLOCNO_NUM_OBJECTS (a); for (i = 0; i < nr; i++) @@ -1044,7 +1163,7 @@ add_range_and_copies_from_move_list (mov " Adding range [%d..%d] to live through %s allocno a%dr%d\n", start, ira_max_point - 1, to != NULL ? "upper level" : "", - ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a))); + ALLOCNO_NUM (a), REGNO (allocno_emit_reg (a))); } } @@ -1097,7 +1216,7 @@ ira_emit (bool loops_p) ira_allocno_iterator ai; FOR_EACH_ALLOCNO (a, ai) - ALLOCNO_REG (a) = regno_reg_rtx[ALLOCNO_REGNO (a)]; + ALLOCNO_EMIT_DATA (a)->reg = regno_reg_rtx[ALLOCNO_REGNO (a)]; if (! loops_p) return; at_bb_start = (move_t *) ira_allocate (sizeof (move_t) * last_basic_block); Index: gcc-4.7-r171648/gcc/ira-build.c =================================================================== --- gcc-4.7-r171648/gcc/ira-build.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira-build.c (revision 171649) @@ -415,7 +415,8 @@ initiate_allocnos (void) = VEC_alloc (ira_object_t, heap, max_reg_num () * 2); ira_object_id_map = NULL; ira_regno_allocno_map - = (ira_allocno_t *) ira_allocate (max_reg_num () * sizeof (ira_allocno_t)); + = (ira_allocno_t *) ira_allocate (max_reg_num () + * sizeof (ira_allocno_t)); memset (ira_regno_allocno_map, 0, max_reg_num () * sizeof (ira_allocno_t)); } @@ -423,7 +424,7 @@ initiate_allocnos (void) static ira_object_t ira_create_object (ira_allocno_t a, int subword) { - enum reg_class cover_class = ALLOCNO_COVER_CLASS (a); + enum reg_class aclass = ALLOCNO_CLASS (a); ira_object_t obj = (ira_object_t) pool_alloc (object_pool); OBJECT_ALLOCNO (obj) = a; @@ -435,12 +436,13 @@ ira_create_object (ira_allocno_t a, int COPY_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), ira_no_alloc_regs); COPY_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), ira_no_alloc_regs); IOR_COMPL_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), - reg_class_contents[cover_class]); + reg_class_contents[aclass]); IOR_COMPL_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), - reg_class_contents[cover_class]); + reg_class_contents[aclass]); OBJECT_MIN (obj) = INT_MAX; OBJECT_MAX (obj) = -1; OBJECT_LIVE_RANGES (obj) = NULL; + OBJECT_ADD_DATA (obj) = NULL; VEC_safe_push (ira_object_t, heap, ira_object_id_map_vec, obj); ira_object_id_map @@ -454,7 +456,8 @@ ira_create_object (ira_allocno_t a, int LOOP_TREE_NODE. Add the allocno to the list of allocnos with the same regno if CAP_P is FALSE. */ ira_allocno_t -ira_create_allocno (int regno, bool cap_p, ira_loop_tree_node_t loop_tree_node) +ira_create_allocno (int regno, bool cap_p, + ira_loop_tree_node_t loop_tree_node) { ira_allocno_t a; @@ -484,35 +487,24 @@ ira_create_allocno (int regno, bool cap_ ALLOCNO_NO_STACK_REG_P (a) = false; ALLOCNO_TOTAL_NO_STACK_REG_P (a) = false; #endif - ALLOCNO_MEM_OPTIMIZED_DEST (a) = NULL; - ALLOCNO_MEM_OPTIMIZED_DEST_P (a) = false; - ALLOCNO_SOMEWHERE_RENAMED_P (a) = false; - ALLOCNO_CHILD_RENAMED_P (a) = false; ALLOCNO_DONT_REASSIGN_P (a) = false; ALLOCNO_BAD_SPILL_P (a) = false; - ALLOCNO_IN_GRAPH_P (a) = false; ALLOCNO_ASSIGNED_P (a) = false; - ALLOCNO_MAY_BE_SPILLED_P (a) = false; - ALLOCNO_SPLAY_REMOVED_P (a) = false; ALLOCNO_MODE (a) = (regno < 0 ? VOIDmode : PSEUDO_REGNO_MODE (regno)); ALLOCNO_COPIES (a) = NULL; ALLOCNO_HARD_REG_COSTS (a) = NULL; ALLOCNO_CONFLICT_HARD_REG_COSTS (a) = NULL; ALLOCNO_UPDATED_HARD_REG_COSTS (a) = NULL; ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) = NULL; - ALLOCNO_LEFT_CONFLICTS_SIZE (a) = -1; - ALLOCNO_COVER_CLASS (a) = NO_REGS; - ALLOCNO_UPDATED_COVER_CLASS_COST (a) = 0; - ALLOCNO_COVER_CLASS_COST (a) = 0; + ALLOCNO_CLASS (a) = NO_REGS; + ALLOCNO_UPDATED_CLASS_COST (a) = 0; + ALLOCNO_CLASS_COST (a) = 0; ALLOCNO_MEMORY_COST (a) = 0; ALLOCNO_UPDATED_MEMORY_COST (a) = 0; ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) = 0; - ALLOCNO_NEXT_BUCKET_ALLOCNO (a) = NULL; - ALLOCNO_PREV_BUCKET_ALLOCNO (a) = NULL; - ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = a; - ALLOCNO_NEXT_COALESCED_ALLOCNO (a) = a; ALLOCNO_NUM_OBJECTS (a) = 0; + ALLOCNO_ADD_DATA (a) = NULL; VEC_safe_push (ira_allocno_t, heap, allocno_vec, a); ira_allocnos = VEC_address (ira_allocno_t, allocno_vec); ira_allocnos_num = VEC_length (ira_allocno_t, allocno_vec); @@ -520,11 +512,22 @@ ira_create_allocno (int regno, bool cap_ return a; } -/* Set up cover class for A and update its conflict hard registers. */ +/* Set up register class for A and update its conflict hard + registers. */ void -ira_set_allocno_cover_class (ira_allocno_t a, enum reg_class cover_class) +ira_set_allocno_class (ira_allocno_t a, enum reg_class aclass) { - ALLOCNO_COVER_CLASS (a) = cover_class; + ira_allocno_object_iterator oi; + ira_object_t obj; + + ALLOCNO_CLASS (a) = aclass; + FOR_EACH_ALLOCNO_OBJECT (a, obj, oi) + { + IOR_COMPL_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), + reg_class_contents[aclass]); + IOR_COMPL_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), + reg_class_contents[aclass]); + } } /* Determine the number of objects we should associate with allocno A @@ -533,8 +536,8 @@ void ira_create_allocno_objects (ira_allocno_t a) { enum machine_mode mode = ALLOCNO_MODE (a); - enum reg_class cover_class = ALLOCNO_COVER_CLASS (a); - int n = ira_reg_class_nregs[cover_class][mode]; + enum reg_class aclass = ALLOCNO_CLASS (a); + int n = ira_reg_class_max_nregs[aclass][mode]; int i; if (GET_MODE_SIZE (mode) != 2 * UNITS_PER_WORD || n != 2) @@ -546,7 +549,7 @@ ira_create_allocno_objects (ira_allocno_ } /* For each allocno, set ALLOCNO_NUM_OBJECTS and create the - ALLOCNO_OBJECT structures. This must be called after the cover + ALLOCNO_OBJECT structures. This must be called after the allocno classes are known. */ static void create_allocno_objects (void) @@ -571,6 +574,7 @@ merge_hard_reg_conflicts (ira_allocno_t { ira_object_t from_obj = ALLOCNO_OBJECT (from, i); ira_object_t to_obj = ALLOCNO_OBJECT (to, i); + if (!total_only) IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (to_obj), OBJECT_CONFLICT_HARD_REGS (from_obj)); @@ -592,6 +596,7 @@ ior_hard_reg_conflicts (ira_allocno_t a, { ira_allocno_object_iterator i; ira_object_t obj; + FOR_EACH_ALLOCNO_OBJECT (a, obj, i) { IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), *set); @@ -849,25 +854,22 @@ create_cap_allocno (ira_allocno_t a) { ira_allocno_t cap; ira_loop_tree_node_t parent; - enum reg_class cover_class; + enum reg_class aclass; - ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a - && ALLOCNO_NEXT_COALESCED_ALLOCNO (a) == a); parent = ALLOCNO_LOOP_TREE_NODE (a)->parent; cap = ira_create_allocno (ALLOCNO_REGNO (a), true, parent); ALLOCNO_MODE (cap) = ALLOCNO_MODE (a); - cover_class = ALLOCNO_COVER_CLASS (a); - ira_set_allocno_cover_class (cap, cover_class); + aclass = ALLOCNO_CLASS (a); + ira_set_allocno_class (cap, aclass); ira_create_allocno_objects (cap); - ALLOCNO_AVAILABLE_REGS_NUM (cap) = ALLOCNO_AVAILABLE_REGS_NUM (a); ALLOCNO_CAP_MEMBER (cap) = a; ALLOCNO_CAP (a) = cap; - ALLOCNO_COVER_CLASS_COST (cap) = ALLOCNO_COVER_CLASS_COST (a); + ALLOCNO_CLASS_COST (cap) = ALLOCNO_CLASS_COST (a); ALLOCNO_MEMORY_COST (cap) = ALLOCNO_MEMORY_COST (a); ira_allocate_and_copy_costs - (&ALLOCNO_HARD_REG_COSTS (cap), cover_class, ALLOCNO_HARD_REG_COSTS (a)); + (&ALLOCNO_HARD_REG_COSTS (cap), aclass, ALLOCNO_HARD_REG_COSTS (a)); ira_allocate_and_copy_costs - (&ALLOCNO_CONFLICT_HARD_REG_COSTS (cap), cover_class, + (&ALLOCNO_CONFLICT_HARD_REG_COSTS (cap), aclass, ALLOCNO_CONFLICT_HARD_REG_COSTS (a)); ALLOCNO_BAD_SPILL_P (cap) = ALLOCNO_BAD_SPILL_P (a); ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a); @@ -1063,23 +1065,24 @@ ira_finish_live_range_list (live_range_t void ira_free_allocno_updated_costs (ira_allocno_t a) { - enum reg_class cover_class; + enum reg_class aclass; - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); if (ALLOCNO_UPDATED_HARD_REG_COSTS (a) != NULL) - ira_free_cost_vector (ALLOCNO_UPDATED_HARD_REG_COSTS (a), cover_class); + ira_free_cost_vector (ALLOCNO_UPDATED_HARD_REG_COSTS (a), aclass); ALLOCNO_UPDATED_HARD_REG_COSTS (a) = NULL; if (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) != NULL) ira_free_cost_vector (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a), - cover_class); + aclass); ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) = NULL; } -/* Free the memory allocated for allocno A. */ +/* Free and nullify all cost vectors allocated earlier for allocno + A. */ static void -finish_allocno (ira_allocno_t a) +ira_free_allocno_costs (ira_allocno_t a) { - enum reg_class cover_class = ALLOCNO_COVER_CLASS (a); + enum reg_class aclass = ALLOCNO_CLASS (a); ira_object_t obj; ira_allocno_object_iterator oi; @@ -1094,14 +1097,25 @@ finish_allocno (ira_allocno_t a) ira_allocnos[ALLOCNO_NUM (a)] = NULL; if (ALLOCNO_HARD_REG_COSTS (a) != NULL) - ira_free_cost_vector (ALLOCNO_HARD_REG_COSTS (a), cover_class); + ira_free_cost_vector (ALLOCNO_HARD_REG_COSTS (a), aclass); if (ALLOCNO_CONFLICT_HARD_REG_COSTS (a) != NULL) - ira_free_cost_vector (ALLOCNO_CONFLICT_HARD_REG_COSTS (a), cover_class); + ira_free_cost_vector (ALLOCNO_CONFLICT_HARD_REG_COSTS (a), aclass); if (ALLOCNO_UPDATED_HARD_REG_COSTS (a) != NULL) - ira_free_cost_vector (ALLOCNO_UPDATED_HARD_REG_COSTS (a), cover_class); + ira_free_cost_vector (ALLOCNO_UPDATED_HARD_REG_COSTS (a), aclass); if (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) != NULL) ira_free_cost_vector (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a), - cover_class); + aclass); + ALLOCNO_HARD_REG_COSTS (a) = NULL; + ALLOCNO_CONFLICT_HARD_REG_COSTS (a) = NULL; + ALLOCNO_UPDATED_HARD_REG_COSTS (a) = NULL; + ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) = NULL; +} + +/* Free the memory allocated for allocno A. */ +static void +finish_allocno (ira_allocno_t a) +{ + ira_free_allocno_costs (a); pool_free (allocno_pool, a); } @@ -1365,55 +1379,54 @@ finish_copies (void) -/* Pools for cost vectors. It is defined only for cover classes. */ +/* Pools for cost vectors. It is defined only for allocno classes. */ static alloc_pool cost_vector_pool[N_REG_CLASSES]; /* The function initiates work with hard register cost vectors. It - creates allocation pool for each cover class. */ + creates allocation pool for each allocno class. */ static void initiate_cost_vectors (void) { int i; - enum reg_class cover_class; + enum reg_class aclass; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_allocno_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - cost_vector_pool[cover_class] + aclass = ira_allocno_classes[i]; + cost_vector_pool[aclass] = create_alloc_pool ("cost vectors", - sizeof (int) - * ira_class_hard_regs_num[cover_class], + sizeof (int) * ira_class_hard_regs_num[aclass], 100); } } -/* Allocate and return a cost vector VEC for COVER_CLASS. */ +/* Allocate and return a cost vector VEC for ACLASS. */ int * -ira_allocate_cost_vector (enum reg_class cover_class) +ira_allocate_cost_vector (enum reg_class aclass) { - return (int *) pool_alloc (cost_vector_pool[cover_class]); + return (int *) pool_alloc (cost_vector_pool[aclass]); } -/* Free a cost vector VEC for COVER_CLASS. */ +/* Free a cost vector VEC for ACLASS. */ void -ira_free_cost_vector (int *vec, enum reg_class cover_class) +ira_free_cost_vector (int *vec, enum reg_class aclass) { ira_assert (vec != NULL); - pool_free (cost_vector_pool[cover_class], vec); + pool_free (cost_vector_pool[aclass], vec); } /* Finish work with hard register cost vectors. Release allocation - pool for each cover class. */ + pool for each allocno class. */ static void finish_cost_vectors (void) { int i; - enum reg_class cover_class; + enum reg_class aclass; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_allocno_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - free_alloc_pool (cost_vector_pool[cover_class]); + aclass = ira_allocno_classes[i]; + free_alloc_pool (cost_vector_pool[aclass]); } } @@ -1644,7 +1657,7 @@ propagate_allocno_info (void) int i; ira_allocno_t a, parent_a; ira_loop_tree_node_t parent; - enum reg_class cover_class; + enum reg_class aclass; if (flag_ira_region != IRA_REGION_ALL && flag_ira_region != IRA_REGION_MIXED) @@ -1670,17 +1683,17 @@ propagate_allocno_info (void) += ALLOCNO_CALLS_CROSSED_NUM (a); ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a) += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a); - cover_class = ALLOCNO_COVER_CLASS (a); - ira_assert (cover_class == ALLOCNO_COVER_CLASS (parent_a)); + aclass = ALLOCNO_CLASS (a); + ira_assert (aclass == ALLOCNO_CLASS (parent_a)); ira_allocate_and_accumulate_costs - (&ALLOCNO_HARD_REG_COSTS (parent_a), cover_class, + (&ALLOCNO_HARD_REG_COSTS (parent_a), aclass, ALLOCNO_HARD_REG_COSTS (a)); ira_allocate_and_accumulate_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (parent_a), - cover_class, + aclass, ALLOCNO_CONFLICT_HARD_REG_COSTS (a)); - ALLOCNO_COVER_CLASS_COST (parent_a) - += ALLOCNO_COVER_CLASS_COST (a); + ALLOCNO_CLASS_COST (parent_a) + += ALLOCNO_CLASS_COST (a); ALLOCNO_MEMORY_COST (parent_a) += ALLOCNO_MEMORY_COST (a); } } @@ -1778,16 +1791,16 @@ static bool low_pressure_loop_node_p (ira_loop_tree_node_t node) { int i; - enum reg_class cover_class; + enum reg_class pclass; if (node->bb != NULL) return false; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - if (node->reg_pressure[cover_class] - > ira_available_class_regs[cover_class]) + pclass = ira_pressure_classes[i]; + if (node->reg_pressure[pclass] > ira_available_class_regs[pclass] + && ira_available_class_regs[pclass] > 1) return false; } return true; @@ -2003,7 +2016,7 @@ ira_rebuild_regno_allocno_list (int regn static void propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a) { - enum reg_class cover_class; + enum reg_class aclass; merge_hard_reg_conflicts (from_a, a, false); ALLOCNO_NREFS (a) += ALLOCNO_NREFS (from_a); @@ -2014,14 +2027,14 @@ propagate_some_info_from_allocno (ira_al += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from_a); if (! ALLOCNO_BAD_SPILL_P (from_a)) ALLOCNO_BAD_SPILL_P (a) = false; - cover_class = ALLOCNO_COVER_CLASS (from_a); - ira_assert (cover_class == ALLOCNO_COVER_CLASS (a)); - ira_allocate_and_accumulate_costs (&ALLOCNO_HARD_REG_COSTS (a), cover_class, + aclass = ALLOCNO_CLASS (from_a); + ira_assert (aclass == ALLOCNO_CLASS (a)); + ira_allocate_and_accumulate_costs (&ALLOCNO_HARD_REG_COSTS (a), aclass, ALLOCNO_HARD_REG_COSTS (from_a)); ira_allocate_and_accumulate_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), - cover_class, + aclass, ALLOCNO_CONFLICT_HARD_REG_COSTS (from_a)); - ALLOCNO_COVER_CLASS_COST (a) += ALLOCNO_COVER_CLASS_COST (from_a); + ALLOCNO_CLASS_COST (a) += ALLOCNO_CLASS_COST (from_a); ALLOCNO_MEMORY_COST (a) += ALLOCNO_MEMORY_COST (from_a); } @@ -2173,8 +2186,8 @@ remove_low_level_allocnos (void) /* Remove loops from consideration. We remove all loops except for root if ALL_P or loops for which a separate allocation will not improve the result. We have to do this after allocno creation and - their costs and cover class evaluation because only after that the - register pressure can be known and is calculated. */ + their costs and allocno class evaluation because only after that + the register pressure can be known and is calculated. */ static void remove_unnecessary_regions (bool all_p) { @@ -2223,27 +2236,27 @@ update_bad_spill_attribute (void) ira_allocno_object_iterator aoi; ira_object_t obj; live_range_t r; - enum reg_class cover_class; + enum reg_class aclass; bitmap_head dead_points[N_REG_CLASSES]; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_allocno_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - bitmap_initialize (&dead_points[cover_class], ®_obstack); + aclass = ira_allocno_classes[i]; + bitmap_initialize (&dead_points[aclass], ®_obstack); } FOR_EACH_ALLOCNO (a, ai) { - cover_class = ALLOCNO_COVER_CLASS (a); - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (a); + if (aclass == NO_REGS) continue; FOR_EACH_ALLOCNO_OBJECT (a, obj, aoi) for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next) - bitmap_set_bit (&dead_points[cover_class], r->finish); + bitmap_set_bit (&dead_points[aclass], r->finish); } FOR_EACH_ALLOCNO (a, ai) { - cover_class = ALLOCNO_COVER_CLASS (a); - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (a); + if (aclass == NO_REGS) continue; if (! ALLOCNO_BAD_SPILL_P (a)) continue; @@ -2252,7 +2265,7 @@ update_bad_spill_attribute (void) for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next) { for (i = r->start + 1; i < r->finish; i++) - if (bitmap_bit_p (&dead_points[cover_class], i)) + if (bitmap_bit_p (&dead_points[aclass], i)) break; if (i < r->finish) break; @@ -2264,10 +2277,10 @@ update_bad_spill_attribute (void) } } } - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_allocno_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - bitmap_clear (&dead_points[cover_class]); + aclass = ira_allocno_classes[i]; + bitmap_clear (&dead_points[aclass]); } } @@ -2290,6 +2303,7 @@ setup_min_max_allocno_live_range_point ( FOR_EACH_ALLOCNO (a, ai) { int n = ALLOCNO_NUM_OBJECTS (a); + for (i = 0; i < n; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); @@ -2309,6 +2323,7 @@ setup_min_max_allocno_live_range_point ( { int j; int n = ALLOCNO_NUM_OBJECTS (a); + for (j = 0; j < n; j++) { ira_object_t obj = ALLOCNO_OBJECT (a, j); @@ -2352,10 +2367,10 @@ setup_min_max_allocno_live_range_point ( } /* Sort allocnos according to their live ranges. Allocnos with - smaller cover class are put first unless we use priority coloring. - Allocnos with the same cover class are ordered according their start - (min). Allocnos with the same start are ordered according their - finish (max). */ + smaller allocno class are put first unless we use priority + coloring. Allocnos with the same class are ordered according + their start (min). Allocnos with the same start are ordered + according their finish (max). */ static int object_range_compare_func (const void *v1p, const void *v2p) { @@ -2365,9 +2380,6 @@ object_range_compare_func (const void *v ira_allocno_t a1 = OBJECT_ALLOCNO (obj1); ira_allocno_t a2 = OBJECT_ALLOCNO (obj2); - if (flag_ira_algorithm != IRA_ALGORITHM_PRIORITY - && (diff = ALLOCNO_COVER_CLASS (a1) - ALLOCNO_COVER_CLASS (a2)) != 0) - return diff; if ((diff = OBJECT_MIN (obj1) - OBJECT_MIN (obj2)) != 0) return diff; if ((diff = OBJECT_MAX (obj1) - OBJECT_MAX (obj2)) != 0) @@ -2397,6 +2409,7 @@ sort_conflict_id_map (void) for (i = 0; i < num; i++) { ira_object_t obj = ira_object_id_map[i]; + gcc_assert (obj != NULL); OBJECT_CONFLICT_ID (obj) = i; } @@ -2409,7 +2422,7 @@ sort_conflict_id_map (void) static void setup_min_max_conflict_allocno_ids (void) { - int cover_class; + int aclass; int i, j, min, max, start, finish, first_not_finished, filled_area_start; int *live_range_min, *last_lived; int word0_min, word0_max; @@ -2417,21 +2430,20 @@ setup_min_max_conflict_allocno_ids (void ira_allocno_iterator ai; live_range_min = (int *) ira_allocate (sizeof (int) * ira_objects_num); - cover_class = -1; + aclass = -1; first_not_finished = -1; for (i = 0; i < ira_objects_num; i++) { ira_object_t obj = ira_object_id_map[i]; + if (obj == NULL) continue; a = OBJECT_ALLOCNO (obj); - if (cover_class < 0 - || (flag_ira_algorithm != IRA_ALGORITHM_PRIORITY - && cover_class != (int) ALLOCNO_COVER_CLASS (a))) + if (aclass < 0) { - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); min = i; first_not_finished = i; } @@ -2456,20 +2468,19 @@ setup_min_max_conflict_allocno_ids (void OBJECT_MIN (obj) = min; } last_lived = (int *) ira_allocate (sizeof (int) * ira_max_point); - cover_class = -1; + aclass = -1; filled_area_start = -1; for (i = ira_objects_num - 1; i >= 0; i--) { ira_object_t obj = ira_object_id_map[i]; + if (obj == NULL) continue; a = OBJECT_ALLOCNO (obj); - if (cover_class < 0 - || (flag_ira_algorithm != IRA_ALGORITHM_PRIORITY - && cover_class != (int) ALLOCNO_COVER_CLASS (a))) + if (aclass < 0) { - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); for (j = 0; j < ira_max_point; j++) last_lived[j] = -1; filled_area_start = ira_max_point; @@ -2507,6 +2518,7 @@ setup_min_max_conflict_allocno_ids (void { int n = ALLOCNO_NUM_OBJECTS (a); ira_object_t obj0; + if (n < 2) continue; obj0 = ALLOCNO_OBJECT (a, 0); @@ -2519,6 +2531,7 @@ setup_min_max_conflict_allocno_ids (void { int n = ALLOCNO_NUM_OBJECTS (a); ira_object_t obj0; + if (n < 2) continue; obj0 = ALLOCNO_OBJECT (a, 0); @@ -2611,7 +2624,7 @@ copy_info_to_removed_store_destinations a != NULL; a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) { - if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))]) + if (a != regno_top_level_allocno_map[REGNO (allocno_emit_reg (a))]) /* This allocno will be removed. */ continue; @@ -2621,9 +2634,10 @@ copy_info_to_removed_store_destinations parent != NULL; parent = parent->parent) if ((parent_a = parent->regno_allocno_map[regno]) == NULL - || (parent_a == regno_top_level_allocno_map[REGNO (ALLOCNO_REG - (parent_a))] - && ALLOCNO_MEM_OPTIMIZED_DEST_P (parent_a))) + || (parent_a + == regno_top_level_allocno_map[REGNO + (allocno_emit_reg (parent_a))] + && ALLOCNO_EMIT_DATA (parent_a)->mem_optimized_dest_p)) break; if (parent == NULL || parent_a == NULL) continue; @@ -2655,7 +2669,7 @@ ira_flattening (int max_regno_before_emi int hard_regs_num; bool new_pseudos_p, merged_p, mem_dest_p; unsigned int n; - enum reg_class cover_class; + enum reg_class aclass; ira_allocno_t a, parent_a, first, second, node_first, node_second; ira_copy_t cp; ira_loop_tree_node_t node; @@ -2664,7 +2678,8 @@ ira_flattening (int max_regno_before_emi ira_copy_iterator ci; regno_top_level_allocno_map - = (ira_allocno_t *) ira_allocate (max_reg_num () * sizeof (ira_allocno_t)); + = (ira_allocno_t *) ira_allocate (max_reg_num () + * sizeof (ira_allocno_t)); memset (regno_top_level_allocno_map, 0, max_reg_num () * sizeof (ira_allocno_t)); new_pseudos_p = merged_p = false; @@ -2672,6 +2687,7 @@ ira_flattening (int max_regno_before_emi { ira_allocno_object_iterator oi; ira_object_t obj; + if (ALLOCNO_CAP_MEMBER (a) != NULL) /* Caps are not in the regno allocno maps and they are never will be transformed into allocnos existing after IR @@ -2692,28 +2708,31 @@ ira_flattening (int max_regno_before_emi a != NULL; a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) { + ira_emit_data_t parent_data, data = ALLOCNO_EMIT_DATA (a); + ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL); - if (ALLOCNO_SOMEWHERE_RENAMED_P (a)) + if (data->somewhere_renamed_p) new_pseudos_p = true; parent_a = ira_parent_allocno (a); if (parent_a == NULL) { ALLOCNO_COPIES (a) = NULL; - regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))] = a; + regno_top_level_allocno_map[REGNO (data->reg)] = a; continue; } ira_assert (ALLOCNO_CAP_MEMBER (parent_a) == NULL); - if (ALLOCNO_MEM_OPTIMIZED_DEST (a) != NULL) + if (data->mem_optimized_dest != NULL) mem_dest_p = true; - if (REGNO (ALLOCNO_REG (a)) == REGNO (ALLOCNO_REG (parent_a))) + parent_data = ALLOCNO_EMIT_DATA (parent_a); + if (REGNO (data->reg) == REGNO (parent_data->reg)) { merge_hard_reg_conflicts (a, parent_a, true); move_allocno_live_ranges (a, parent_a); merged_p = true; - ALLOCNO_MEM_OPTIMIZED_DEST_P (parent_a) - = (ALLOCNO_MEM_OPTIMIZED_DEST_P (parent_a) - || ALLOCNO_MEM_OPTIMIZED_DEST_P (a)); + parent_data->mem_optimized_dest_p + = (parent_data->mem_optimized_dest_p + || data->mem_optimized_dest_p); continue; } new_pseudos_p = true; @@ -2729,8 +2748,8 @@ ira_flattening (int max_regno_before_emi ira_assert (ALLOCNO_CALLS_CROSSED_NUM (parent_a) >= 0 && ALLOCNO_NREFS (parent_a) >= 0 && ALLOCNO_FREQ (parent_a) >= 0); - cover_class = ALLOCNO_COVER_CLASS (parent_a); - hard_regs_num = ira_class_hard_regs_num[cover_class]; + aclass = ALLOCNO_CLASS (parent_a); + hard_regs_num = ira_class_hard_regs_num[aclass]; if (ALLOCNO_HARD_REG_COSTS (a) != NULL && ALLOCNO_HARD_REG_COSTS (parent_a) != NULL) for (j = 0; j < hard_regs_num; j++) @@ -2741,15 +2760,15 @@ ira_flattening (int max_regno_before_emi for (j = 0; j < hard_regs_num; j++) ALLOCNO_CONFLICT_HARD_REG_COSTS (parent_a)[j] -= ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[j]; - ALLOCNO_COVER_CLASS_COST (parent_a) - -= ALLOCNO_COVER_CLASS_COST (a); + ALLOCNO_CLASS_COST (parent_a) + -= ALLOCNO_CLASS_COST (a); ALLOCNO_MEMORY_COST (parent_a) -= ALLOCNO_MEMORY_COST (a); parent_a = ira_parent_allocno (parent_a); if (parent_a == NULL) break; } ALLOCNO_COPIES (a) = NULL; - regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))] = a; + regno_top_level_allocno_map[REGNO (data->reg)] = a; } if (mem_dest_p && copy_info_to_removed_store_destinations (i)) merged_p = true; @@ -2766,7 +2785,8 @@ ira_flattening (int max_regno_before_emi { ira_allocno_object_iterator oi; ira_object_t obj; - if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))] + + if (a != regno_top_level_allocno_map[REGNO (allocno_emit_reg (a))] || ALLOCNO_CAP_MEMBER (a) != NULL) continue; FOR_EACH_ALLOCNO_OBJECT (a, obj, oi) @@ -2782,19 +2802,21 @@ ira_flattening (int max_regno_before_emi for (r = ira_start_point_ranges[i]; r != NULL; r = r->start_next) { ira_object_t obj = r->object; + a = OBJECT_ALLOCNO (obj); - if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))] + if (a != regno_top_level_allocno_map[REGNO (allocno_emit_reg (a))] || ALLOCNO_CAP_MEMBER (a) != NULL) continue; - cover_class = ALLOCNO_COVER_CLASS (a); + aclass = ALLOCNO_CLASS (a); sparseset_set_bit (objects_live, OBJECT_CONFLICT_ID (obj)); EXECUTE_IF_SET_IN_SPARSESET (objects_live, n) { ira_object_t live_obj = ira_object_id_map[n]; ira_allocno_t live_a = OBJECT_ALLOCNO (live_obj); - enum reg_class live_cover = ALLOCNO_COVER_CLASS (live_a); - if (ira_reg_classes_intersect_p[cover_class][live_cover] + enum reg_class live_aclass = ALLOCNO_CLASS (live_a); + + if (ira_reg_classes_intersect_p[aclass][live_aclass] /* Don't set up conflict for the allocno with itself. */ && live_a != a) ira_add_conflict (obj, live_obj); @@ -2818,14 +2840,18 @@ ira_flattening (int max_regno_before_emi fprintf (ira_dump_file, " Remove cp%d:%c%dr%d-%c%dr%d\n", cp->num, ALLOCNO_CAP_MEMBER (cp->first) != NULL ? 'c' : 'a', - ALLOCNO_NUM (cp->first), REGNO (ALLOCNO_REG (cp->first)), + ALLOCNO_NUM (cp->first), + REGNO (allocno_emit_reg (cp->first)), ALLOCNO_CAP_MEMBER (cp->second) != NULL ? 'c' : 'a', - ALLOCNO_NUM (cp->second), REGNO (ALLOCNO_REG (cp->second))); + ALLOCNO_NUM (cp->second), + REGNO (allocno_emit_reg (cp->second))); cp->loop_tree_node = NULL; continue; } - first = regno_top_level_allocno_map[REGNO (ALLOCNO_REG (cp->first))]; - second = regno_top_level_allocno_map[REGNO (ALLOCNO_REG (cp->second))]; + first + = regno_top_level_allocno_map[REGNO (allocno_emit_reg (cp->first))]; + second + = regno_top_level_allocno_map[REGNO (allocno_emit_reg (cp->second))]; node = cp->loop_tree_node; if (node == NULL) keep_p = true; /* It copy generated in ira-emit.c. */ @@ -2835,10 +2861,10 @@ ira_flattening (int max_regno_before_emi which we will have different pseudos. */ node_first = node->regno_allocno_map[ALLOCNO_REGNO (cp->first)]; node_second = node->regno_allocno_map[ALLOCNO_REGNO (cp->second)]; - keep_p = ((REGNO (ALLOCNO_REG (first)) - == REGNO (ALLOCNO_REG (node_first))) - && (REGNO (ALLOCNO_REG (second)) - == REGNO (ALLOCNO_REG (node_second)))); + keep_p = ((REGNO (allocno_emit_reg (first)) + == REGNO (allocno_emit_reg (node_first))) + && (REGNO (allocno_emit_reg (second)) + == REGNO (allocno_emit_reg (node_second)))); } if (keep_p) { @@ -2852,28 +2878,29 @@ ira_flattening (int max_regno_before_emi if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL) fprintf (ira_dump_file, " Remove cp%d:a%dr%d-a%dr%d\n", cp->num, ALLOCNO_NUM (cp->first), - REGNO (ALLOCNO_REG (cp->first)), ALLOCNO_NUM (cp->second), - REGNO (ALLOCNO_REG (cp->second))); + REGNO (allocno_emit_reg (cp->first)), + ALLOCNO_NUM (cp->second), + REGNO (allocno_emit_reg (cp->second))); } } /* Remove unnecessary allocnos on lower levels of the loop tree. */ FOR_EACH_ALLOCNO (a, ai) { - if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))] + if (a != regno_top_level_allocno_map[REGNO (allocno_emit_reg (a))] || ALLOCNO_CAP_MEMBER (a) != NULL) { if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL) fprintf (ira_dump_file, " Remove a%dr%d\n", - ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a))); + ALLOCNO_NUM (a), REGNO (allocno_emit_reg (a))); finish_allocno (a); continue; } ALLOCNO_LOOP_TREE_NODE (a) = ira_loop_tree_root; - ALLOCNO_REGNO (a) = REGNO (ALLOCNO_REG (a)); + ALLOCNO_REGNO (a) = REGNO (allocno_emit_reg (a)); ALLOCNO_CAP (a) = NULL; /* Restore updated costs for assignments from reload. */ ALLOCNO_UPDATED_MEMORY_COST (a) = ALLOCNO_MEMORY_COST (a); - ALLOCNO_UPDATED_COVER_CLASS_COST (a) = ALLOCNO_COVER_CLASS_COST (a); + ALLOCNO_UPDATED_CLASS_COST (a) = ALLOCNO_CLASS_COST (a); if (! ALLOCNO_ASSIGNED_P (a)) ira_free_allocno_updated_costs (a); ira_assert (ALLOCNO_UPDATED_HARD_REG_COSTS (a) == NULL); @@ -2942,29 +2969,28 @@ update_conflict_hard_reg_costs (void) FOR_EACH_ALLOCNO (a, ai) { - enum reg_class cover_class = ALLOCNO_COVER_CLASS (a); + enum reg_class aclass = ALLOCNO_CLASS (a); enum reg_class pref = reg_preferred_class (ALLOCNO_REGNO (a)); if (reg_class_size[pref] != 1) continue; - index = (ira_class_hard_reg_index[cover_class] - [ira_class_hard_regs[pref][0]]); + index = ira_class_hard_reg_index[aclass][ira_class_hard_regs[pref][0]]; if (index < 0) continue; if (ALLOCNO_CONFLICT_HARD_REG_COSTS (a) == NULL || ALLOCNO_HARD_REG_COSTS (a) == NULL) continue; min = INT_MAX; - for (i = ira_class_hard_regs_num[cover_class] - 1; i >= 0; i--) - if (ALLOCNO_HARD_REG_COSTS (a)[i] > ALLOCNO_COVER_CLASS_COST (a) + for (i = ira_class_hard_regs_num[aclass] - 1; i >= 0; i--) + if (ALLOCNO_HARD_REG_COSTS (a)[i] > ALLOCNO_CLASS_COST (a) && min > ALLOCNO_HARD_REG_COSTS (a)[i]) min = ALLOCNO_HARD_REG_COSTS (a)[i]; if (min == INT_MAX) continue; ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), - cover_class, 0); + aclass, 0); ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[index] - -= min - ALLOCNO_COVER_CLASS_COST (a); + -= min - ALLOCNO_CLASS_COST (a); } } @@ -3000,7 +3026,7 @@ ira_build (bool loops_p) propagate_allocno_info (); create_caps (); } - ira_tune_allocno_costs_and_cover_classes (); + ira_tune_allocno_costs (); #ifdef ENABLE_IRA_CHECKING check_allocno_creation (); #endif @@ -3042,6 +3068,7 @@ ira_build (bool loops_p) FOR_EACH_ALLOCNO (a, ai) { int j, nobj = ALLOCNO_NUM_OBJECTS (a); + if (nobj > 1) nr_big++; for (j = 0; j < nobj; j++) Index: gcc-4.7-r171648/gcc/loop-invariant.c =================================================================== --- gcc-4.7-r171648/gcc/loop-invariant.c (revision 171648) +++ gcc-4.7-r171648/gcc/loop-invariant.c (revision 171649) @@ -64,7 +64,7 @@ struct loop_data struct loop *outermost_exit; /* The outermost exit of the loop. */ bool has_call; /* True if the loop contains a call. */ /* Maximal register pressure inside loop for given register class - (defined only for the cover classes). */ + (defined only for the pressure classes). */ int max_reg_pressure[N_REG_CLASSES]; /* Loop regs referenced and live pseudo-registers. */ bitmap_head regs_ref; @@ -1012,13 +1012,13 @@ free_use_list (struct use *use) } } -/* Return cover class and number of hard registers (through *NREGS) +/* Return pressure class and number of hard registers (through *NREGS) for destination of INSN. */ static enum reg_class -get_cover_class_and_nregs (rtx insn, int *nregs) +get_pressure_class_and_nregs (rtx insn, int *nregs) { rtx reg; - enum reg_class cover_class; + enum reg_class pressure_class; rtx set = single_set (insn); /* Considered invariant insns have only one set. */ @@ -1029,19 +1029,23 @@ get_cover_class_and_nregs (rtx insn, int if (MEM_P (reg)) { *nregs = 0; - cover_class = NO_REGS; + pressure_class = NO_REGS; } else { if (! REG_P (reg)) reg = NULL_RTX; if (reg == NULL_RTX) - cover_class = GENERAL_REGS; + pressure_class = GENERAL_REGS; else - cover_class = reg_cover_class (REGNO (reg)); - *nregs = ira_reg_class_nregs[cover_class][GET_MODE (SET_SRC (set))]; + { + pressure_class = reg_allocno_class (REGNO (reg)); + pressure_class = ira_pressure_class_translate[pressure_class]; + } + *nregs + = ira_reg_class_max_nregs[pressure_class][GET_MODE (SET_SRC (set))]; } - return cover_class; + return pressure_class; } /* Calculates cost and number of registers needed for moving invariant INV @@ -1064,8 +1068,8 @@ get_inv_cost (struct invariant *inv, int regs_needed[0] = 0; else { - for (i = 0; i < ira_reg_class_cover_size; i++) - regs_needed[ira_reg_class_cover[i]] = 0; + for (i = 0; i < ira_pressure_classes_num; i++) + regs_needed[ira_pressure_classes[i]] = 0; } if (inv->move @@ -1078,10 +1082,10 @@ get_inv_cost (struct invariant *inv, int else { int nregs; - enum reg_class cover_class; + enum reg_class pressure_class; - cover_class = get_cover_class_and_nregs (inv->insn, &nregs); - regs_needed[cover_class] += nregs; + pressure_class = get_pressure_class_and_nregs (inv->insn, &nregs); + regs_needed[pressure_class] += nregs; } if (!inv->cheap_address @@ -1112,7 +1116,7 @@ get_inv_cost (struct invariant *inv, int && constant_pool_constant_p (SET_SRC (set))) { if (flag_ira_loop_pressure) - regs_needed[STACK_REG_COVER_CLASS] += 2; + regs_needed[ira_stack_reg_pressure_class] += 2; else regs_needed[0] += 2; } @@ -1131,10 +1135,10 @@ get_inv_cost (struct invariant *inv, int check_p = aregs_needed[0] != 0; else { - for (i = 0; i < ira_reg_class_cover_size; i++) - if (aregs_needed[ira_reg_class_cover[i]] != 0) + for (i = 0; i < ira_pressure_classes_num; i++) + if (aregs_needed[ira_pressure_classes[i]] != 0) break; - check_p = i < ira_reg_class_cover_size; + check_p = i < ira_pressure_classes_num; } if (check_p /* We need to check always_executed, since if the original value of @@ -1151,10 +1155,10 @@ get_inv_cost (struct invariant *inv, int else { int nregs; - enum reg_class cover_class; + enum reg_class pressure_class; - cover_class = get_cover_class_and_nregs (inv->insn, &nregs); - aregs_needed[cover_class] -= nregs; + pressure_class = get_pressure_class_and_nregs (inv->insn, &nregs); + aregs_needed[pressure_class] -= nregs; } } @@ -1162,9 +1166,9 @@ get_inv_cost (struct invariant *inv, int regs_needed[0] += aregs_needed[0]; else { - for (i = 0; i < ira_reg_class_cover_size; i++) - regs_needed[ira_reg_class_cover[i]] - += aregs_needed[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + regs_needed[ira_pressure_classes[i]] + += aregs_needed[ira_pressure_classes[i]]; } (*comp_cost) += acomp_cost; } @@ -1197,19 +1201,19 @@ gain_for_invariant (struct invariant *in else { int i; - enum reg_class cover_class; + enum reg_class pressure_class; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - if ((int) new_regs[cover_class] - + (int) regs_needed[cover_class] - + LOOP_DATA (curr_loop)->max_reg_pressure[cover_class] + pressure_class = ira_pressure_classes[i]; + if ((int) new_regs[pressure_class] + + (int) regs_needed[pressure_class] + + LOOP_DATA (curr_loop)->max_reg_pressure[pressure_class] + IRA_LOOP_RESERVED_REGS - > ira_available_class_regs[cover_class]) + > ira_available_class_regs[pressure_class]) break; } - if (i < ira_reg_class_cover_size) + if (i < ira_pressure_classes_num) /* There will be register pressure excess and we want not to make this loop invariant motion. All loop invariants with non-positive gains will be rejected in function @@ -1273,9 +1277,9 @@ best_gain_for_invariant (struct invarian regs_needed[0] = aregs_needed[0]; else { - for (i = 0; i < ira_reg_class_cover_size; i++) - regs_needed[ira_reg_class_cover[i]] - = aregs_needed[ira_reg_class_cover[i]]; + for (i = 0; i < ira_pressure_classes_num; i++) + regs_needed[ira_pressure_classes[i]] + = aregs_needed[ira_pressure_classes[i]]; } } } @@ -1352,8 +1356,8 @@ find_invariants_to_move (bool speed, boo new_regs[0] = regs_needed[0] = 0; else { - for (i = 0; (int) i < ira_reg_class_cover_size; i++) - new_regs[ira_reg_class_cover[i]] = 0; + for (i = 0; (int) i < ira_pressure_classes_num; i++) + new_regs[ira_pressure_classes[i]] = 0; } while ((gain = best_gain_for_invariant (&inv, regs_needed, new_regs, regs_used, @@ -1364,9 +1368,9 @@ find_invariants_to_move (bool speed, boo new_regs[0] += regs_needed[0]; else { - for (i = 0; (int) i < ira_reg_class_cover_size; i++) - new_regs[ira_reg_class_cover[i]] - += regs_needed[ira_reg_class_cover[i]]; + for (i = 0; (int) i < ira_pressure_classes_num; i++) + new_regs[ira_pressure_classes[i]] + += regs_needed[ira_pressure_classes[i]]; } } } @@ -1519,7 +1523,7 @@ move_invariants (struct loop *loop) setup_reg_classes (REGNO (inv->reg), reg_preferred_class (inv->orig_regno), reg_alternate_class (inv->orig_regno), - reg_cover_class (inv->orig_regno)); + reg_allocno_class (inv->orig_regno)); else setup_reg_classes (REGNO (inv->reg), GENERAL_REGS, NO_REGS, GENERAL_REGS); @@ -1604,7 +1608,7 @@ free_loop_data (struct loop *loop) /* Registers currently living. */ static bitmap_head curr_regs_live; -/* Current reg pressure for each cover class. */ +/* Current reg pressure for each pressure class. */ static int curr_reg_pressure[N_REG_CLASSES]; /* Record all regs that are set in any one insn. Communication from @@ -1615,23 +1619,26 @@ static rtx regs_set[(FIRST_PSEUDO_REGIST /* Number of regs stored in the previous array. */ static int n_regs_set; -/* Return cover class and number of needed hard registers (through +/* Return pressure class and number of needed hard registers (through *NREGS) of register REGNO. */ static enum reg_class -get_regno_cover_class (int regno, int *nregs) +get_regno_pressure_class (int regno, int *nregs) { if (regno >= FIRST_PSEUDO_REGISTER) { - enum reg_class cover_class = reg_cover_class (regno); + enum reg_class pressure_class; - *nregs = ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; - return cover_class; + pressure_class = reg_allocno_class (regno); + pressure_class = ira_pressure_class_translate[pressure_class]; + *nregs + = ira_reg_class_max_nregs[pressure_class][PSEUDO_REGNO_MODE (regno)]; + return pressure_class; } else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno) && ! TEST_HARD_REG_BIT (eliminable_regset, regno)) { *nregs = 1; - return ira_class_translate[REGNO_REG_CLASS (regno)]; + return ira_pressure_class_translate[REGNO_REG_CLASS (regno)]; } else { @@ -1646,18 +1653,18 @@ static void change_pressure (int regno, bool incr_p) { int nregs; - enum reg_class cover_class; + enum reg_class pressure_class; - cover_class = get_regno_cover_class (regno, &nregs); + pressure_class = get_regno_pressure_class (regno, &nregs); if (! incr_p) - curr_reg_pressure[cover_class] -= nregs; + curr_reg_pressure[pressure_class] -= nregs; else { - curr_reg_pressure[cover_class] += nregs; - if (LOOP_DATA (curr_loop)->max_reg_pressure[cover_class] - < curr_reg_pressure[cover_class]) - LOOP_DATA (curr_loop)->max_reg_pressure[cover_class] - = curr_reg_pressure[cover_class]; + curr_reg_pressure[pressure_class] += nregs; + if (LOOP_DATA (curr_loop)->max_reg_pressure[pressure_class] + < curr_reg_pressure[pressure_class]) + LOOP_DATA (curr_loop)->max_reg_pressure[pressure_class] + = curr_reg_pressure[pressure_class]; } } @@ -1813,8 +1820,8 @@ calculate_loop_reg_pressure (void) bitmap_ior_into (&LOOP_DATA (loop)->regs_live, DF_LR_IN (bb)); bitmap_copy (&curr_regs_live, DF_LR_IN (bb)); - for (i = 0; i < ira_reg_class_cover_size; i++) - curr_reg_pressure[ira_reg_class_cover[i]] = 0; + for (i = 0; i < ira_pressure_classes_num; i++) + curr_reg_pressure[ira_pressure_classes[i]] = 0; EXECUTE_IF_SET_IN_BITMAP (&curr_regs_live, 0, j, bi) change_pressure (j, true); @@ -1864,11 +1871,11 @@ calculate_loop_reg_pressure (void) EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi) if (! bitmap_bit_p (&LOOP_DATA (loop)->regs_ref, j)) { - enum reg_class cover_class; + enum reg_class pressure_class; int nregs; - cover_class = get_regno_cover_class (j, &nregs); - LOOP_DATA (loop)->max_reg_pressure[cover_class] -= nregs; + pressure_class = get_regno_pressure_class (j, &nregs); + LOOP_DATA (loop)->max_reg_pressure[pressure_class] -= nregs; } } if (dump_file == NULL) @@ -1886,15 +1893,15 @@ calculate_loop_reg_pressure (void) EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi) fprintf (dump_file, " %d", j); fprintf (dump_file, "\n Pressure:"); - for (i = 0; (int) i < ira_reg_class_cover_size; i++) + for (i = 0; (int) i < ira_pressure_classes_num; i++) { - enum reg_class cover_class; + enum reg_class pressure_class; - cover_class = ira_reg_class_cover[i]; - if (LOOP_DATA (loop)->max_reg_pressure[cover_class] == 0) + pressure_class = ira_pressure_classes[i]; + if (LOOP_DATA (loop)->max_reg_pressure[pressure_class] == 0) continue; - fprintf (dump_file, " %s=%d", reg_class_names[cover_class], - LOOP_DATA (loop)->max_reg_pressure[cover_class]); + fprintf (dump_file, " %s=%d", reg_class_names[pressure_class], + LOOP_DATA (loop)->max_reg_pressure[pressure_class]); } fprintf (dump_file, "\n"); } @@ -1913,8 +1920,10 @@ move_loop_invariants (void) if (flag_ira_loop_pressure) { df_analyze (); + regstat_init_n_sets_and_refs (); ira_set_pseudo_classes (dump_file); calculate_loop_reg_pressure (); + regstat_free_n_sets_and_refs (); } df_set_flags (DF_EQ_NOTES + DF_DEFER_INSN_RESCAN); /* Process the loops, innermost first. */ Index: gcc-4.7-r171648/gcc/ira.c =================================================================== --- gcc-4.7-r171648/gcc/ira.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira.c (revision 171649) @@ -38,40 +38,51 @@ along with GCC; see the file COPYING3. the other regions. Therefore data structure representing a region is called loop_tree_node. - o *Cover class* is a register class belonging to a set of - non-intersecting register classes containing all of the - hard-registers available for register allocation. The set of - all cover classes for a target is defined in the corresponding - machine-description file according some criteria. Such notion - is needed because Chaitin-Briggs algorithm works on - non-intersected register classes. + o *Allocno class* is a register class used for allocation of + given allocno. It means that only hard register of given + register class can be assigned to given allocno. In reality, + even smaller subset of (*profitable*) hard registers can be + assigned. In rare cases, the subset can be even smaller + because our modification of Chaitin-Briggs algorithm requires + that sets of hard registers can be assigned to allocnos forms a + forest, i.e. the sets can be ordered in a way where any + previous set is not intersected with given set or is a superset + of given set. + + o *Pressure class* is a register class belonging to a set of + register classes containing all of the hard-registers available + for register allocation. The set of all pressure classes for a + target is defined in the corresponding machine-description file + according some criteria. Register pressure is calculated only + for pressure classes and it affects some IRA decisions as + forming allocation regions. o *Allocno* represents the live range of a pseudo-register in a region. Besides the obvious attributes like the corresponding - pseudo-register number, cover class, conflicting allocnos and + pseudo-register number, allocno class, conflicting allocnos and conflicting hard-registers, there are a few allocno attributes which are important for understanding the allocation algorithm: - - *Live ranges*. This is a list of ranges of *program - points* where the allocno lives. Program points represent - places where a pseudo can be born or become dead (there are + - *Live ranges*. This is a list of ranges of *program points* + where the allocno lives. Program points represent places + where a pseudo can be born or become dead (there are approximately two times more program points than the insns) and they are represented by integers starting with 0. The - live ranges are used to find conflicts between allocnos of - different cover classes. They also play very important role - for the transformation of the IRA internal representation of - several regions into a one region representation. The later is - used during the reload pass work because each allocno - represents all of the corresponding pseudo-registers. + live ranges are used to find conflicts between allocnos. + They also play very important role for the transformation of + the IRA internal representation of several regions into a one + region representation. The later is used during the reload + pass work because each allocno represents all of the + corresponding pseudo-registers. - *Hard-register costs*. This is a vector of size equal to the - number of available hard-registers of the allocno's cover - class. The cost of a callee-clobbered hard-register for an - allocno is increased by the cost of save/restore code around - the calls through the given allocno's life. If the allocno - is a move instruction operand and another operand is a - hard-register of the allocno's cover class, the cost of the - hard-register is decreased by the move cost. + number of available hard-registers of the allocno class. The + cost of a callee-clobbered hard-register for an allocno is + increased by the cost of save/restore code around the calls + through the given allocno's life. If the allocno is a move + instruction operand and another operand is a hard-register of + the allocno class, the cost of the hard-register is decreased + by the move cost. When an allocno is assigned, the hard-register with minimal full cost is used. Initially, a hard-register's full cost is @@ -139,12 +150,12 @@ along with GCC; see the file COPYING3. * First, IRA builds regions and creates allocnos (file ira-build.c) and initializes most of their attributes. - * Then IRA finds a cover class for each allocno and calculates - its initial (non-accumulated) cost of memory and each - hard-register of its cover class (file ira-cost.c). + * Then IRA finds an allocno class for each allocno and + calculates its initial (non-accumulated) cost of memory and + each hard-register of its allocno class (file ira-cost.c). * IRA creates live ranges of each allocno, calulates register - pressure for each cover class in each region, sets up + pressure for each pressure class in each region, sets up conflict hard registers for each allocno and info about calls the allocno lives through (file ira-lives.c). @@ -157,23 +168,63 @@ along with GCC; see the file COPYING3. * IRA creates all caps (file ira-build.c). - * Having live-ranges of allocnos and their cover classes, IRA - creates conflicting allocnos of the same cover class for each - allocno. Conflicting allocnos are stored as a bit vector or - array of pointers to the conflicting allocnos whatever is - more profitable (file ira-conflicts.c). At this point IRA - creates allocno copies. + * Having live-ranges of allocnos and their classes, IRA creates + conflicting allocnos for each allocno. Conflicting allocnos + are stored as a bit vector or array of pointers to the + conflicting allocnos whatever is more profitable (file + ira-conflicts.c). At this point IRA creates allocno copies. o Coloring. Now IRA has all necessary info to start graph coloring process. It is done in each region on top-down traverse of the region tree (file ira-color.c). There are following subpasses: + * Finding profitable hard registers of corresponding allocno + class for each allocno. For example, only callee-saved hard + registers are frequently profitable for allocnos living + through colors. If the profitable hard register set of + allocno does not form a tree based on subset relation, we use + some approximation to form the tree. This approximation is + used to figure out trivial colorability of allocnos. The + approximation is a pretty rare case. + * Putting allocnos onto the coloring stack. IRA uses Briggs optimistic coloring which is a major improvement over Chaitin's coloring. Therefore IRA does not spill allocnos at this point. There is some freedom in the order of putting allocnos on the stack which can affect the final result of - the allocation. IRA uses some heuristics to improve the order. + the allocation. IRA uses some heuristics to improve the + order. + + We also use a modification of Chaitin-Briggs algorithm which + works for intersected register classes of allocnos. To + figure out trivial colorability of allocnos, the mentioned + above tree of hard register sets is used. To get an idea how + the algorithm works in i386 example, let us consider an + allocno to which any general hard register can be assigned. + If the allocno conflicts with eight allocnos to which only + EAX register can be assigned, given allocno is still + trivially colorable because all conflicting allocnos might be + assigned only to EAX and all other general hard registers are + still free. + + To get an idea of the used trivial colorability criterion, it + is also useful to read article "Graph-Coloring Register + Allocation for Irregular Architectures" by Michael D. Smith + and Glen Holloway. Major difference between the article + approach and approach used in IRA is that Smith's approach + takes register classes only from machine description and IRA + calculate register classes from intermediate code too + (e.g. an explicit usage of hard registers in RTL code for + parameter passing can result in creation of additional + register classes which contain or exclude the hard + registers). That makes IRA approach useful for improving + coloring even for architectures with regular register files + and in fact some benchmarking shows the improvement for + regular class architectures is even bigger than for irregular + ones. Another difference is that Smith's approach chooses + intersection of classes of all insn operands in which a given + pseudo occurs. IRA can use bigger classes if it is still + more profitable than memory usage. * Popping the allocnos from the stack and assigning them hard registers. If IRA can not assign a hard register to an @@ -187,6 +238,13 @@ along with GCC; see the file COPYING3. hard-register for the allocno and cost of usage of the hard-register for allocnos conflicting with given allocno. + * Chaitin-Briggs coloring assigns as many pseudos as possible + to hard registers. After coloringh we try to improve + allocation with cost point of view. We improve the + allocation by spilling some allocnos and assigning the freed + hard registers to other allocnos if it decreases the overall + allocation cost. + * After allono assigning in the region, IRA modifies the hard register and memory costs for the corresponding allocnos in the subregions to reflect the cost of possible loads, stores, @@ -194,8 +252,8 @@ along with GCC; see the file COPYING3. When default regional allocation algorithm is used (-fira-algorithm=mixed), IRA just propagates the assignment for allocnos if the register pressure in the region for the - corresponding cover class is less than number of available - hard registers for given cover class. + corresponding pressure class is less than number of available + hard registers for given pressure class. o Spill/restore code moving. When IRA performs an allocation by traversing regions in top-down order, it does not know what @@ -210,28 +268,29 @@ along with GCC; see the file COPYING3. practice, so there is no real need for a better time complexity algorithm. - o Code change. After coloring, two allocnos representing the same - pseudo-register outside and inside a region respectively may be - assigned to different locations (hard-registers or memory). In - this case IRA creates and uses a new pseudo-register inside the - region and adds code to move allocno values on the region's - borders. This is done during top-down traversal of the regions - (file ira-emit.c). In some complicated cases IRA can create a - new allocno to move allocno values (e.g. when a swap of values - stored in two hard-registers is needed). At this stage, the - new allocno is marked as spilled. IRA still creates the - pseudo-register and the moves on the region borders even when - both allocnos were assigned to the same hard-register. If the - reload pass spills a pseudo-register for some reason, the - effect will be smaller because another allocno will still be in - the hard-register. In most cases, this is better then spilling - both allocnos. If reload does not change the allocation - for the two pseudo-registers, the trivial move will be removed - by post-reload optimizations. IRA does not generate moves for + o Code change. After coloring, two allocnos representing the + same pseudo-register outside and inside a region respectively + may be assigned to different locations (hard-registers or + memory). In this case IRA creates and uses a new + pseudo-register inside the region and adds code to move allocno + values on the region's borders. This is done during top-down + traversal of the regions (file ira-emit.c). In some + complicated cases IRA can create a new allocno to move allocno + values (e.g. when a swap of values stored in two hard-registers + is needed). At this stage, the new allocno is marked as + spilled. IRA still creates the pseudo-register and the moves + on the region borders even when both allocnos were assigned to + the same hard-register. If the reload pass spills a + pseudo-register for some reason, the effect will be smaller + because another allocno will still be in the hard-register. In + most cases, this is better then spilling both allocnos. If + reload does not change the allocation for the two + pseudo-registers, the trivial move will be removed by + post-reload optimizations. IRA does not generate moves for allocnos assigned to the same hard register when the default regional allocation algorithm is used and the register pressure - in the region for the corresponding allocno cover class is less - than number of available hard registers for given cover class. + in the region for the corresponding pressure class is less than + number of available hard registers for given pressure class. IRA also does some optimizations to remove redundant stores and to reduce code duplication on the region borders. @@ -287,6 +346,9 @@ along with GCC; see the file COPYING3. o Guei-Yuan Lueh, Thomas Gross, and Ali-Reza Adl-Tabatabai. Global Register Allocation Based on Graph Fusion. + o Michael D. Smith and Glenn Holloway. Graph-Coloring Register + Allocation for Irregular Architectures + o Vladimir Makarov. The Integrated Register Allocator for GCC. o Vladimir Makarov. The top-down register allocator for irregular @@ -461,11 +523,53 @@ setup_alloc_regs (bool use_hard_frame_p) -/* Set up IRA_MEMORY_MOVE_COST, IRA_REGISTER_MOVE_COST. */ +#define alloc_reg_class_subclasses \ + (this_target_ira_int->x_alloc_reg_class_subclasses) + +/* Initialize the table of subclasses of each reg class. */ +static void +setup_reg_subclasses (void) +{ + int i, j; + HARD_REG_SET temp_hard_regset2; + + for (i = 0; i < N_REG_CLASSES; i++) + for (j = 0; j < N_REG_CLASSES; j++) + alloc_reg_class_subclasses[i][j] = LIM_REG_CLASSES; + + for (i = 0; i < N_REG_CLASSES; i++) + { + if (i == (int) NO_REGS) + continue; + + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[i]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + if (hard_reg_set_empty_p (temp_hard_regset)) + continue; + for (j = 0; j < N_REG_CLASSES; j++) + if (i != j) + { + enum reg_class *p; + + COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[j]); + AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); + if (! hard_reg_set_subset_p (temp_hard_regset, + temp_hard_regset2)) + continue; + p = &alloc_reg_class_subclasses[j][0]; + while (*p != LIM_REG_CLASSES) p++; + *p = (enum reg_class) i; + } + } +} + + + +/* Set up IRA_MEMORY_MOVE_COST and IRA_MAX_MEMORY_MOVE_COST. */ static void setup_class_subset_and_memory_move_costs (void) { - int cl, cl2, mode; + int cl, cl2, mode, cost; HARD_REG_SET temp_hard_regset2; for (mode = 0; mode < MAX_MACHINE_MODE; mode++) @@ -476,34 +580,60 @@ setup_class_subset_and_memory_move_costs if (cl != (int) NO_REGS) for (mode = 0; mode < MAX_MACHINE_MODE; mode++) { - ira_memory_move_cost[mode][cl][0] = - memory_move_cost ((enum machine_mode) mode, - (enum reg_class) cl, false); - ira_memory_move_cost[mode][cl][1] = - memory_move_cost ((enum machine_mode) mode, - (enum reg_class) cl, true); + ira_max_memory_move_cost[mode][cl][0] + = ira_memory_move_cost[mode][cl][0] + = memory_move_cost ((enum machine_mode) mode, + (enum reg_class) cl, false); + ira_max_memory_move_cost[mode][cl][1] + = ira_memory_move_cost[mode][cl][1] + = memory_move_cost ((enum machine_mode) mode, + (enum reg_class) cl, true); /* Costs for NO_REGS are used in cost calculation on the 1st pass when the preferred register classes are not known yet. In this case we take the best scenario. */ if (ira_memory_move_cost[mode][NO_REGS][0] > ira_memory_move_cost[mode][cl][0]) - ira_memory_move_cost[mode][NO_REGS][0] + ira_max_memory_move_cost[mode][NO_REGS][0] + = ira_memory_move_cost[mode][NO_REGS][0] = ira_memory_move_cost[mode][cl][0]; if (ira_memory_move_cost[mode][NO_REGS][1] > ira_memory_move_cost[mode][cl][1]) - ira_memory_move_cost[mode][NO_REGS][1] + ira_max_memory_move_cost[mode][NO_REGS][1] + = ira_memory_move_cost[mode][NO_REGS][1] = ira_memory_move_cost[mode][cl][1]; } - for (cl2 = (int) N_REG_CLASSES - 1; cl2 >= 0; cl2--) - { - COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); - AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); - COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]); - AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); - ira_class_subset_p[cl][cl2] - = hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2); - } } + for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--) + for (cl2 = (int) N_REG_CLASSES - 1; cl2 >= 0; cl2--) + { + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]); + AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); + ira_class_subset_p[cl][cl2] + = hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2); + if (! hard_reg_set_empty_p (temp_hard_regset2) + && hard_reg_set_subset_p (reg_class_contents[cl2], + reg_class_contents[cl])) + for (mode = 0; mode < MAX_MACHINE_MODE; mode++) + { + cost = ira_memory_move_cost[mode][cl2][0]; + if (cost > ira_max_memory_move_cost[mode][cl][0]) + ira_max_memory_move_cost[mode][cl][0] = cost; + cost = ira_memory_move_cost[mode][cl2][1]; + if (cost > ira_max_memory_move_cost[mode][cl][1]) + ira_max_memory_move_cost[mode][cl][1] = cost; + } + } + for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--) + for (mode = 0; mode < MAX_MACHINE_MODE; mode++) + { + ira_memory_move_cost[mode][cl][0] + = ira_max_memory_move_cost[mode][cl][0]; + ira_memory_move_cost[mode][cl][1] + = ira_max_memory_move_cost[mode][cl][1]; + } + setup_reg_subclasses (); } @@ -535,20 +665,6 @@ ira_allocate (size_t len) return res; } -/* Reallocate memory PTR of size LEN for IRA data. */ -void * -ira_reallocate (void *ptr, size_t len) -{ - void *res; - -#ifndef IRA_NO_OBSTACK - res = obstack_alloc (&ira_obstack, len); -#else - res = xrealloc (ptr, len); -#endif - return res; -} - /* Free memory ADDR allocated for IRA data. */ void ira_free (void *addr ATTRIBUTE_UNUSED) @@ -618,120 +734,235 @@ ira_debug_disposition (void) } -#define alloc_reg_class_subclasses \ - (this_target_ira_int->x_alloc_reg_class_subclasses) -/* Initialize the table of subclasses of each reg class. */ -static void -setup_reg_subclasses (void) -{ - int i, j; - HARD_REG_SET temp_hard_regset2; +/* Set up ira_stack_reg_pressure_class which is the biggest pressure + register class containing stack registers or NO_REGS if there are + no stack registers. To find this class, we iterate through all + register pressure classes and choose the first register pressure + class containing all the stack registers and having the biggest + size. */ +static void +setup_stack_reg_pressure_class (void) +{ + ira_stack_reg_pressure_class = NO_REGS; +#ifdef STACK_REGS + { + int i, best, size; + enum reg_class cl; + HARD_REG_SET temp_hard_regset2; + + CLEAR_HARD_REG_SET (temp_hard_regset); + for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) + SET_HARD_REG_BIT (temp_hard_regset, i); + best = 0; + for (i = 0; i < ira_pressure_classes_num; i++) + { + cl = ira_pressure_classes[i]; + COPY_HARD_REG_SET (temp_hard_regset2, temp_hard_regset); + AND_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl]); + size = hard_reg_set_size (temp_hard_regset2); + if (best < size) + { + best = size; + ira_stack_reg_pressure_class = cl; + } + } + } +#endif +} - for (i = 0; i < N_REG_CLASSES; i++) - for (j = 0; j < N_REG_CLASSES; j++) - alloc_reg_class_subclasses[i][j] = LIM_REG_CLASSES; +/* Find pressure classes which are register classes for which we + calculate register pressure in IRA, register pressure sensitive + insn scheduling, and register pressure sensitive loop invariant + motion. + + To make register pressure calculation easy, we always use + non-intersected register pressure classes. A move of hard + registers from one register pressure class is not more expensive + than load and store of the hard registers. Most likely an allocno + class will be a subset of a register pressure class and in many + cases a register pressure class. That makes usage of register + pressure classes a good approximation to find a high register + pressure. */ +static void +setup_pressure_classes (void) +{ + int cost, i, n, curr; + int cl, cl2; + enum reg_class pressure_classes[N_REG_CLASSES]; + int m; + HARD_REG_SET temp_hard_regset2; + bool insert_p; - for (i = 0; i < N_REG_CLASSES; i++) + n = 0; + for (cl = 0; cl < N_REG_CLASSES; cl++) { - if (i == (int) NO_REGS) + if (ira_available_class_regs[cl] == 0) continue; - - COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[i]); - AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); - if (hard_reg_set_empty_p (temp_hard_regset)) + /* Check that the moves between any hard registers of the + current class are not more expensive for a legal mode than + load/store of the hard registers of the current class. Such + class is a potential candidate to be a register pressure + class. */ + for (m = 0; m < NUM_MACHINE_MODES; m++) + { + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + AND_COMPL_HARD_REG_SET (temp_hard_regset, + ira_prohibited_class_mode_regs[cl][m]); + if (hard_reg_set_empty_p (temp_hard_regset)) + continue; + ira_init_register_move_cost_if_necessary ((enum machine_mode) m); + cost = ira_register_move_cost[m][cl][cl]; + if (cost <= ira_max_memory_move_cost[m][cl][1] + || cost <= ira_max_memory_move_cost[m][cl][0]) + break; + } + if (m >= NUM_MACHINE_MODES) continue; - for (j = 0; j < N_REG_CLASSES; j++) - if (i != j) - { - enum reg_class *p; - - COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[j]); - AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); - if (! hard_reg_set_subset_p (temp_hard_regset, - temp_hard_regset2)) + curr = 0; + insert_p = true; + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + /* Remove so far added pressure classes which are subset of the + current candidate class. Prefer GENERAL_REGS as a pressure + register class to another class containing the same + allocatable hard registers. We do this because machine + dependent cost hooks might give wrong costs for the latter + class but always give the right cost for the former class + (GENERAL_REGS). */ + for (i = 0; i < n; i++) + { + cl2 = pressure_classes[i]; + COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]); + AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); + if (hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2) + && (! hard_reg_set_equal_p (temp_hard_regset, temp_hard_regset2) + || cl2 == (int) GENERAL_REGS)) + { + pressure_classes[curr++] = (enum reg_class) cl2; + insert_p = false; continue; - p = &alloc_reg_class_subclasses[j][0]; - while (*p != LIM_REG_CLASSES) p++; - *p = (enum reg_class) i; - } + } + if (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset) + && (! hard_reg_set_equal_p (temp_hard_regset2, temp_hard_regset) + || cl == (int) GENERAL_REGS)) + continue; + pressure_classes[curr++] = (enum reg_class) cl2; + } + /* If the current candidate is a subset of a so far added + pressure class, don't add it to the list of the pressure + classes. */ + if (insert_p) + pressure_classes[curr++] = (enum reg_class) cl; + n = curr; } -} - - - -/* Set the four global variables defined above. */ +#ifdef ENABLE_IRA_CHECKING + /* Check pressure classes correctness: here we check that hard + registers from all register pressure classes contains all hard + registers available for the allocation. */ + CLEAR_HARD_REG_SET (temp_hard_regset); + CLEAR_HARD_REG_SET (temp_hard_regset2); + for (cl = 0; cl <= LIM_REG_CLASSES; cl++) + { + for (i = 0; i < n; i++) + if ((int) pressure_classes[i] == cl) + break; + IOR_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl]); + if (i >= n) + IOR_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); + } + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); + ira_assert (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset)); +#endif + ira_pressure_classes_num = 0; + for (i = 0; i < n; i++) + { + cl = (int) pressure_classes[i]; + ira_reg_pressure_class_p[cl] = true; + ira_pressure_classes[ira_pressure_classes_num++] = (enum reg_class) cl; + } + setup_stack_reg_pressure_class (); +} + +/* Set up IRA_ALLOCNO_CLASSES, IRA_ALLOCNO_CLASSES_NUM, + IRA_IMPORTANT_CLASSES, and IRA_IMPORTANT_CLASSES_NUM. + + Target may have many subtargets and not all target hard regiters can + be used for allocation, e.g. x86 port in 32-bit mode can not use + hard registers introduced in x86-64 like r8-r15). Some classes + might have the same allocatable hard registers, e.g. INDEX_REGS + and GENERAL_REGS in x86 port in 32-bit mode. To decrease different + calculations efforts we introduce allocno classes which contain + unique non-empty sets of allocatable hard-registers. + + Pseudo class cost calculation in ira-costs.c is very expensive. + Therefore we are trying to decrease number of classes involved in + such calculation. Register classes used in the cost calculation + are called important classes. They are allocno classes and other + non-empty classes whose allocatable hard register sets are inside + of an allocno class hard register set. From the first sight, it + looks like that they are just allocno classes. It is not true. In + example of x86-port in 32-bit mode, allocno classes will contain + GENERAL_REGS but not LEGACY_REGS (because allocatable hard + registers are the same for the both classes). The important + classes will contain GENERAL_REGS and LEGACY_REGS. It is done + because a machine description insn constraint may refers for + LEGACY_REGS and code in ira-costs.c is mostly base on investigation + of the insn constraints. */ static void -setup_cover_and_important_classes (void) +setup_allocno_and_important_classes (void) { int i, j, n, cl; bool set_p; - const reg_class_t *cover_classes; HARD_REG_SET temp_hard_regset2; static enum reg_class classes[LIM_REG_CLASSES + 1]; - if (targetm.ira_cover_classes == NULL) - cover_classes = NULL; - else - cover_classes = targetm.ira_cover_classes (); - if (cover_classes == NULL) - ira_assert (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY); - else - { - for (i = 0; (cl = cover_classes[i]) != LIM_REG_CLASSES; i++) - classes[i] = (enum reg_class) cl; - classes[i] = LIM_REG_CLASSES; - } - - if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY) + n = 0; + /* Collect classes which contain unique sets of allocatable hard + registers. Prefer GENERAL_REGS to other classes containing the + same set of hard registers. */ + for (i = 0; i <= LIM_REG_CLASSES; i++) { - n = 0; - for (i = 0; i <= LIM_REG_CLASSES; i++) + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[i]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + for (j = 0; j < n; j++) { - if (i == NO_REGS) - continue; -#ifdef CONSTRAINT_NUM_DEFINED_P - for (j = 0; j < CONSTRAINT__LIMIT; j++) - if ((int) REG_CLASS_FOR_CONSTRAINT ((enum constraint_num) j) == i) - break; - if (j < CONSTRAINT__LIMIT) - { - classes[n++] = (enum reg_class) i; - continue; - } -#endif - COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[i]); - AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); - for (j = 0; j < LIM_REG_CLASSES; j++) - { - if (i == j) - continue; - COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[j]); - AND_COMPL_HARD_REG_SET (temp_hard_regset2, - no_unit_alloc_regs); - if (hard_reg_set_equal_p (temp_hard_regset, - temp_hard_regset2)) - break; - } - if (j >= i) - classes[n++] = (enum reg_class) i; + cl = classes[j]; + COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl]); + AND_COMPL_HARD_REG_SET (temp_hard_regset2, + no_unit_alloc_regs); + if (hard_reg_set_equal_p (temp_hard_regset, + temp_hard_regset2)) + break; } - classes[n] = LIM_REG_CLASSES; - } - - ira_reg_class_cover_size = 0; + if (j >= n) + classes[n++] = (enum reg_class) i; + else if (i == GENERAL_REGS) + /* Prefer general regs. For i386 example, it means that + we prefer GENERAL_REGS over INDEX_REGS or LEGACY_REGS + (all of them consists of the same available hard + registers). */ + classes[j] = (enum reg_class) i; + } + classes[n] = LIM_REG_CLASSES; + + /* Set up classes which can be used for allocnos as classes + conatining non-empty unique sets of allocatable hard + registers. */ + ira_allocno_classes_num = 0; for (i = 0; (cl = classes[i]) != LIM_REG_CLASSES; i++) { - for (j = 0; j < i; j++) - if (flag_ira_algorithm != IRA_ALGORITHM_PRIORITY - && reg_classes_intersect_p ((enum reg_class) cl, classes[j])) - gcc_unreachable (); COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); - if (! hard_reg_set_empty_p (temp_hard_regset)) - ira_reg_class_cover[ira_reg_class_cover_size++] = (enum reg_class) cl; + if (hard_reg_set_empty_p (temp_hard_regset)) + continue; + ira_allocno_classes[ira_allocno_classes_num++] = (enum reg_class) cl; } ira_important_classes_num = 0; + /* Add non-allocno classes containing to non-empty set of + allocatable hard regs. */ for (cl = 0; cl < N_REG_CLASSES; cl++) { COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); @@ -739,95 +970,86 @@ setup_cover_and_important_classes (void) if (! hard_reg_set_empty_p (temp_hard_regset)) { set_p = false; - for (j = 0; j < ira_reg_class_cover_size; j++) + for (j = 0; j < ira_allocno_classes_num; j++) { - COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); - AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); COPY_HARD_REG_SET (temp_hard_regset2, - reg_class_contents[ira_reg_class_cover[j]]); + reg_class_contents[ira_allocno_classes[j]]); AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); - if ((enum reg_class) cl == ira_reg_class_cover[j] - || hard_reg_set_equal_p (temp_hard_regset, - temp_hard_regset2)) + if ((enum reg_class) cl == ira_allocno_classes[j]) break; else if (hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2)) set_p = true; } - if (set_p && j >= ira_reg_class_cover_size) + if (set_p && j >= ira_allocno_classes_num) ira_important_classes[ira_important_classes_num++] = (enum reg_class) cl; } } - for (j = 0; j < ira_reg_class_cover_size; j++) + /* Now add allocno classes to the important classes. */ + for (j = 0; j < ira_allocno_classes_num; j++) ira_important_classes[ira_important_classes_num++] - = ira_reg_class_cover[j]; -} - -/* Set up array IRA_CLASS_TRANSLATE. */ + = ira_allocno_classes[j]; + for (cl = 0; cl < N_REG_CLASSES; cl++) + { + ira_reg_allocno_class_p[cl] = false; + ira_reg_pressure_class_p[cl] = false; + } + for (j = 0; j < ira_allocno_classes_num; j++) + ira_reg_allocno_class_p[ira_allocno_classes[j]] = true; + setup_pressure_classes (); +} + +/* Setup translation in CLASS_TRANSLATE of all classes into a class + given by array CLASSES of length CLASSES_NUM. The function is used + make translation any reg class to an allocno class or to an + pressure class. This translation is necessary for some + calculations when we can use only allocno or pressure classes and + such translation represents an approximate representation of all + classes. + + The translation in case when allocatable hard register set of a + given class is subset of allocatable hard register set of a class + in CLASSES is pretty simple. We use smallest classes from CLASSES + containing a given class. If allocatable hard register set of a + given class is not a subset of any corresponding set of a class + from CLASSES, we use the cheapest (with load/store point of view) + class from CLASSES whose set intersects with given class set */ static void -setup_class_translate (void) +setup_class_translate_array (enum reg_class *class_translate, + int classes_num, enum reg_class *classes) { int cl, mode; - enum reg_class cover_class, best_class, *cl_ptr; + enum reg_class aclass, best_class, *cl_ptr; int i, cost, min_cost, best_cost; for (cl = 0; cl < N_REG_CLASSES; cl++) - ira_class_translate[cl] = NO_REGS; - - if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY) - for (cl = 0; cl < LIM_REG_CLASSES; cl++) - { - COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); - AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); - for (i = 0; i < ira_reg_class_cover_size; i++) - { - HARD_REG_SET temp_hard_regset2; + class_translate[cl] = NO_REGS; - cover_class = ira_reg_class_cover[i]; - COPY_HARD_REG_SET (temp_hard_regset2, - reg_class_contents[cover_class]); - AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs); - if (hard_reg_set_equal_p (temp_hard_regset, temp_hard_regset2)) - ira_class_translate[cl] = cover_class; - } - } - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - if (flag_ira_algorithm != IRA_ALGORITHM_PRIORITY) - for (cl_ptr = &alloc_reg_class_subclasses[cover_class][0]; - (cl = *cl_ptr) != LIM_REG_CLASSES; - cl_ptr++) - { - if (ira_class_translate[cl] == NO_REGS) - ira_class_translate[cl] = cover_class; -#ifdef ENABLE_IRA_CHECKING - else - { - COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); - AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); - if (! hard_reg_set_empty_p (temp_hard_regset)) - gcc_unreachable (); - } -#endif - } - ira_class_translate[cover_class] = cover_class; - } - /* For classes which are not fully covered by a cover class (in - other words covered by more one cover class), use the cheapest - cover class. */ + aclass = classes[i]; + for (cl_ptr = &alloc_reg_class_subclasses[aclass][0]; + (cl = *cl_ptr) != LIM_REG_CLASSES; + cl_ptr++) + if (class_translate[cl] == NO_REGS) + class_translate[cl] = aclass; + class_translate[aclass] = aclass; + } + /* For classes which are not fully covered by one of given classes + (in other words covered by more one given class), use the + cheapest class. */ for (cl = 0; cl < N_REG_CLASSES; cl++) { - if (cl == NO_REGS || ira_class_translate[cl] != NO_REGS) + if (cl == NO_REGS || class_translate[cl] != NO_REGS) continue; best_class = NO_REGS; best_cost = INT_MAX; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < classes_num; i++) { - cover_class = ira_reg_class_cover[i]; + aclass = classes[i]; COPY_HARD_REG_SET (temp_hard_regset, - reg_class_contents[cover_class]); + reg_class_contents[aclass]); AND_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]); AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); if (! hard_reg_set_empty_p (temp_hard_regset)) @@ -842,19 +1064,29 @@ setup_class_translate (void) } if (best_class == NO_REGS || best_cost > min_cost) { - best_class = cover_class; + best_class = aclass; best_cost = min_cost; } } } - ira_class_translate[cl] = best_class; + class_translate[cl] = best_class; } } -/* Order numbers of cover classes in original target cover class - array, -1 for non-cover classes. This is only live during - reorder_important_classes. */ -static int cover_class_order[N_REG_CLASSES]; +/* Set up array IRA_ALLOCNO_CLASS_TRANSLATE and + IRA_PRESSURE_CLASS_TRANSLATE. */ +static void +setup_class_translate (void) +{ + setup_class_translate_array (ira_allocno_class_translate, + ira_allocno_classes_num, ira_allocno_classes); + setup_class_translate_array (ira_pressure_class_translate, + ira_pressure_classes_num, ira_pressure_classes); +} + +/* Order numbers of allocno classes in original target allocno class + array, -1 for non-allocno classes. */ +static int allocno_class_order[N_REG_CLASSES]; /* The function used to sort the important classes. */ static int @@ -862,32 +1094,47 @@ comp_reg_classes_func (const void *v1p, { enum reg_class cl1 = *(const enum reg_class *) v1p; enum reg_class cl2 = *(const enum reg_class *) v2p; + enum reg_class tcl1, tcl2; int diff; - cl1 = ira_class_translate[cl1]; - cl2 = ira_class_translate[cl2]; - if (cl1 != NO_REGS && cl2 != NO_REGS - && (diff = cover_class_order[cl1] - cover_class_order[cl2]) != 0) + tcl1 = ira_allocno_class_translate[cl1]; + tcl2 = ira_allocno_class_translate[cl2]; + if (tcl1 != NO_REGS && tcl2 != NO_REGS + && (diff = allocno_class_order[tcl1] - allocno_class_order[tcl2]) != 0) return diff; return (int) cl1 - (int) cl2; } -/* Reorder important classes according to the order of their cover - classes. */ +/* For correct work of function setup_reg_class_relation we need to + reorder important classes according to the order of their allocno + classes. It places important classes containing the same + allocatable hard register set adjacent to each other and allocno + class with the allocatable hard register set right after the other + important classes with the same set. + + In example from comments of function + setup_allocno_and_important_classes, it places LEGACY_REGS and + GENERAL_REGS close to each other and GENERAL_REGS is after + LEGACY_REGS. */ static void reorder_important_classes (void) { int i; for (i = 0; i < N_REG_CLASSES; i++) - cover_class_order[i] = -1; - for (i = 0; i < ira_reg_class_cover_size; i++) - cover_class_order[ira_reg_class_cover[i]] = i; + allocno_class_order[i] = -1; + for (i = 0; i < ira_allocno_classes_num; i++) + allocno_class_order[ira_allocno_classes[i]] = i; qsort (ira_important_classes, ira_important_classes_num, sizeof (enum reg_class), comp_reg_classes_func); + for (i = 0; i < ira_important_classes_num; i++) + ira_important_class_nums[ira_important_classes[i]] = i; } -/* Set up the above reg class relations. */ +/* Set up IRA_REG_CLASS_SUBUNION, IRA_REG_CLASS_SUPERUNION, + IRA_REG_CLASS_SUPER_CLASSES, IRA_REG_CLASSES_INTERSECT, and + IRA_REG_CLASSES_INTERSECT_P. For the meaning of the relations, + please see corresponding comments in ira-int.h. */ static void setup_reg_class_relations (void) { @@ -912,6 +1159,9 @@ setup_reg_class_relations (void) if (hard_reg_set_empty_p (temp_hard_regset) && hard_reg_set_empty_p (temp_set2)) { + /* The both classes have no allocatable hard registers + -- take all class hard registers into account and use + reg_class_subunion and reg_class_superunion. */ for (i = 0;; i++) { cl3 = reg_class_subclasses[cl1][i]; @@ -921,7 +1171,8 @@ setup_reg_class_relations (void) (enum reg_class) cl3)) ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3; } - ira_reg_class_union[cl1][cl2] = reg_class_subunion[cl1][cl2]; + ira_reg_class_subunion[cl1][cl2] = reg_class_subunion[cl1][cl2]; + ira_reg_class_superunion[cl1][cl2] = reg_class_superunion[cl1][cl2]; continue; } ira_reg_classes_intersect_p[cl1][cl2] @@ -929,6 +1180,9 @@ setup_reg_class_relations (void) if (important_class_p[cl1] && important_class_p[cl2] && hard_reg_set_subset_p (temp_hard_regset, temp_set2)) { + /* CL1 and CL2 are important classes and CL1 allocatable + hard register set is inside of CL2 allocatable hard + registers -- make CL1 a superset of CL2. */ enum reg_class *p; p = &ira_reg_class_super_classes[cl1][0]; @@ -937,7 +1191,8 @@ setup_reg_class_relations (void) *p++ = (enum reg_class) cl2; *p = LIM_REG_CLASSES; } - ira_reg_class_union[cl1][cl2] = NO_REGS; + ira_reg_class_subunion[cl1][cl2] = NO_REGS; + ira_reg_class_superunion[cl1][cl2] = NO_REGS; COPY_HARD_REG_SET (intersection_set, reg_class_contents[cl1]); AND_HARD_REG_SET (intersection_set, reg_class_contents[cl2]); AND_COMPL_HARD_REG_SET (intersection_set, no_unit_alloc_regs); @@ -951,77 +1206,121 @@ setup_reg_class_relations (void) AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); if (hard_reg_set_subset_p (temp_hard_regset, intersection_set)) { + /* CL3 allocatable hard register set is inside of + intersection of allocatable hard register sets + of CL1 and CL2. */ COPY_HARD_REG_SET (temp_set2, reg_class_contents[(int) ira_reg_class_intersect[cl1][cl2]]); AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs); if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2) - /* Ignore unavailable hard registers and prefer - smallest class for debugging purposes. */ + /* If the allocatable hard register sets are the + same, prefer GENERAL_REGS or the smallest + class for debugging purposes. */ || (hard_reg_set_equal_p (temp_hard_regset, temp_set2) - && hard_reg_set_subset_p - (reg_class_contents[cl3], - reg_class_contents - [(int) ira_reg_class_intersect[cl1][cl2]]))) + && (cl3 == GENERAL_REGS + || (ira_reg_class_intersect[cl1][cl2] != GENERAL_REGS + && hard_reg_set_subset_p + (reg_class_contents[cl3], + reg_class_contents + [(int) ira_reg_class_intersect[cl1][cl2]]))))) ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3; } if (hard_reg_set_subset_p (temp_hard_regset, union_set)) { + /* CL3 allocatbale hard register set is inside of + union of allocatable hard register sets of CL1 + and CL2. */ COPY_HARD_REG_SET (temp_set2, - reg_class_contents[(int) ira_reg_class_union[cl1][cl2]]); + reg_class_contents[(int) ira_reg_class_subunion[cl1][cl2]]); AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs); - if (ira_reg_class_union[cl1][cl2] == NO_REGS + if (ira_reg_class_subunion[cl1][cl2] == NO_REGS || (hard_reg_set_subset_p (temp_set2, temp_hard_regset) + + && (! hard_reg_set_equal_p (temp_set2, + temp_hard_regset) + || cl3 == GENERAL_REGS + /* If the allocatable hard register sets are the + same, prefer GENERAL_REGS or the smallest + class for debugging purposes. */ + || (ira_reg_class_subunion[cl1][cl2] != GENERAL_REGS + && hard_reg_set_subset_p + (reg_class_contents[cl3], + reg_class_contents + [(int) ira_reg_class_subunion[cl1][cl2]]))))) + ira_reg_class_subunion[cl1][cl2] = (enum reg_class) cl3; + } + if (hard_reg_set_subset_p (union_set, temp_hard_regset)) + { + /* CL3 allocatable hard register set contains union + of allocatable hard register sets of CL1 and + CL2. */ + COPY_HARD_REG_SET + (temp_set2, + reg_class_contents[(int) ira_reg_class_superunion[cl1][cl2]]); + AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs); + if (ira_reg_class_superunion[cl1][cl2] == NO_REGS + || (hard_reg_set_subset_p (temp_hard_regset, temp_set2) && (! hard_reg_set_equal_p (temp_set2, temp_hard_regset) - /* Ignore unavailable hard registers and - prefer smallest class for debugging - purposes. */ - || hard_reg_set_subset_p - (reg_class_contents[cl3], - reg_class_contents - [(int) ira_reg_class_union[cl1][cl2]])))) - ira_reg_class_union[cl1][cl2] = (enum reg_class) cl3; + || cl3 == GENERAL_REGS + /* If the allocatable hard register sets are the + same, prefer GENERAL_REGS or the smallest + class for debugging purposes. */ + || (ira_reg_class_superunion[cl1][cl2] != GENERAL_REGS + && hard_reg_set_subset_p + (reg_class_contents[cl3], + reg_class_contents + [(int) ira_reg_class_superunion[cl1][cl2]]))))) + ira_reg_class_superunion[cl1][cl2] = (enum reg_class) cl3; } } } } } -/* Output all cover classes and the translation map into file F. */ +/* Output all possible allocno classes and the translation map into + file F. */ static void -print_class_cover (FILE *f) +print_classes (FILE *f, bool pressure_p) { + int classes_num = (pressure_p + ? ira_pressure_classes_num : ira_allocno_classes_num); + enum reg_class *classes = (pressure_p + ? ira_pressure_classes : ira_allocno_classes); + enum reg_class *class_translate = (pressure_p + ? ira_pressure_class_translate + : ira_allocno_class_translate); static const char *const reg_class_names[] = REG_CLASS_NAMES; int i; - fprintf (f, "Class cover:\n"); - for (i = 0; i < ira_reg_class_cover_size; i++) - fprintf (f, " %s", reg_class_names[ira_reg_class_cover[i]]); + fprintf (f, "%s classes:\n", pressure_p ? "Pressure" : "Allocno"); + for (i = 0; i < classes_num; i++) + fprintf (f, " %s", reg_class_names[classes[i]]); fprintf (f, "\nClass translation:\n"); for (i = 0; i < N_REG_CLASSES; i++) fprintf (f, " %s -> %s\n", reg_class_names[i], - reg_class_names[ira_class_translate[i]]); + reg_class_names[class_translate[i]]); } -/* Output all cover classes and the translation map into - stderr. */ +/* Output all possible allocno and translation classes and the + translation maps into stderr. */ void -ira_debug_class_cover (void) +ira_debug_allocno_classes (void) { - print_class_cover (stderr); + print_classes (stderr, false); + print_classes (stderr, true); } -/* Set up different arrays concerning class subsets, cover and +/* Set up different arrays concerning class subsets, allocno and important classes. */ static void -find_reg_class_closure (void) +find_reg_classes (void) { - setup_reg_subclasses (); - setup_cover_and_important_classes (); + setup_allocno_and_important_classes (); setup_class_translate (); reorder_important_classes (); setup_reg_class_relations (); @@ -1031,77 +1330,158 @@ find_reg_class_closure (void) /* Set up the array above. */ static void -setup_hard_regno_cover_class (void) +setup_hard_regno_aclass (void) { int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { - ira_hard_regno_cover_class[i] +#if 1 + ira_hard_regno_allocno_class[i] = (TEST_HARD_REG_BIT (no_unit_alloc_regs, i) ? NO_REGS - : ira_class_translate[REGNO_REG_CLASS (i)]); + : ira_allocno_class_translate[REGNO_REG_CLASS (i)]); +#else + int j; + enum reg_class cl; + ira_hard_regno_allocno_class[i] = NO_REGS; + for (j = 0; j < ira_allocno_classes_num; j++) + { + cl = ira_allocno_classes[j]; + if (ira_class_hard_reg_index[cl][i] >= 0) + { + ira_hard_regno_allocno_class[i] = cl; + break; + } + } +#endif } } -/* Form IRA_REG_CLASS_NREGS map. */ +/* Form IRA_REG_CLASS_MAX_NREGS and IRA_REG_CLASS_MIN_NREGS maps. */ static void setup_reg_class_nregs (void) { - int cl, m; + int i, cl, cl2, m; - for (cl = 0; cl < N_REG_CLASSES; cl++) - for (m = 0; m < MAX_MACHINE_MODE; m++) - ira_reg_class_nregs[cl][m] = CLASS_MAX_NREGS ((enum reg_class) cl, - (enum machine_mode) m); + for (m = 0; m < MAX_MACHINE_MODE; m++) + { + for (cl = 0; cl < N_REG_CLASSES; cl++) + ira_reg_class_max_nregs[cl][m] + = ira_reg_class_min_nregs[cl][m] + = CLASS_MAX_NREGS ((enum reg_class) cl, (enum machine_mode) m); + for (cl = 0; cl < N_REG_CLASSES; cl++) + for (i = 0; + (cl2 = alloc_reg_class_subclasses[cl][i]) != LIM_REG_CLASSES; + i++) + if (ira_reg_class_min_nregs[cl2][m] + < ira_reg_class_min_nregs[cl][m]) + ira_reg_class_min_nregs[cl][m] = ira_reg_class_min_nregs[cl2][m]; + } } -/* Set up PROHIBITED_CLASS_MODE_REGS. */ +/* Set up IRA_PROHIBITED_CLASS_MODE_REGS. */ static void setup_prohibited_class_mode_regs (void) { - int i, j, k, hard_regno; - enum reg_class cl; + int j, k, hard_regno, cl; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--) { - cl = ira_reg_class_cover[i]; for (j = 0; j < NUM_MACHINE_MODES; j++) { - CLEAR_HARD_REG_SET (prohibited_class_mode_regs[cl][j]); + CLEAR_HARD_REG_SET (ira_prohibited_class_mode_regs[cl][j]); for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--) { hard_regno = ira_class_hard_regs[cl][k]; if (! HARD_REGNO_MODE_OK (hard_regno, (enum machine_mode) j)) - SET_HARD_REG_BIT (prohibited_class_mode_regs[cl][j], + SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j], hard_regno); } } } } +/* Clarify IRA_PROHIBITED_CLASS_MODE_REGS by excluding hard registers + spanning from one register pressure class to another one. It is + called after defining the pressure classes. */ +static void +clarify_prohibited_class_mode_regs (void) +{ + int j, k, hard_regno, cl, pclass, nregs; + + for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--) + for (j = 0; j < NUM_MACHINE_MODES; j++) + for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--) + { + hard_regno = ira_class_hard_regs[cl][k]; + if (TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j], hard_regno)) + continue; + nregs = hard_regno_nregs[hard_regno][j]; + pclass = ira_pressure_class_translate[REGNO_REG_CLASS (hard_regno)]; + for (nregs-- ;nregs >= 0; nregs--) + if (((enum reg_class) pclass + != ira_pressure_class_translate[REGNO_REG_CLASS + (hard_regno + nregs)])) + { + SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j], + hard_regno); + break; + } + } +} + /* Allocate and initialize IRA_REGISTER_MOVE_COST, - IRA_MAY_MOVE_IN_COST, and IRA_MAY_MOVE_OUT_COST for MODE if it is - not done yet. */ + IRA_MAX_REGISTER_MOVE_COST, IRA_MAY_MOVE_IN_COST, + IRA_MAY_MOVE_OUT_COST, IRA_MAX_MAY_MOVE_IN_COST, and + IRA_MAX_MAY_MOVE_OUT_COST for MODE if it is not done yet. */ void ira_init_register_move_cost (enum machine_mode mode) { - int cl1, cl2; + int cl1, cl2, cl3; ira_assert (ira_register_move_cost[mode] == NULL + && ira_max_register_move_cost[mode] == NULL && ira_may_move_in_cost[mode] == NULL - && ira_may_move_out_cost[mode] == NULL); + && ira_may_move_out_cost[mode] == NULL + && ira_max_may_move_in_cost[mode] == NULL + && ira_max_may_move_out_cost[mode] == NULL); if (move_cost[mode] == NULL) init_move_cost (mode); ira_register_move_cost[mode] = move_cost[mode]; /* Don't use ira_allocate because the tables exist out of scope of a IRA call. */ + ira_max_register_move_cost[mode] + = (move_table *) xmalloc (sizeof (move_table) * N_REG_CLASSES); + memcpy (ira_max_register_move_cost[mode], ira_register_move_cost[mode], + sizeof (move_table) * N_REG_CLASSES); + for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++) + { + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl1]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + if (hard_reg_set_empty_p (temp_hard_regset)) + continue; + for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++) + if (hard_reg_set_subset_p (reg_class_contents[cl1], + reg_class_contents[cl2])) + for (cl3 = 0; cl3 < N_REG_CLASSES; cl3++) + { + if (ira_max_register_move_cost[mode][cl2][cl3] + < ira_register_move_cost[mode][cl1][cl3]) + ira_max_register_move_cost[mode][cl2][cl3] + = ira_register_move_cost[mode][cl1][cl3]; + if (ira_max_register_move_cost[mode][cl3][cl2] + < ira_register_move_cost[mode][cl3][cl1]) + ira_max_register_move_cost[mode][cl3][cl2] + = ira_register_move_cost[mode][cl3][cl1]; + } + } ira_may_move_in_cost[mode] = (move_table *) xmalloc (sizeof (move_table) * N_REG_CLASSES); memcpy (ira_may_move_in_cost[mode], may_move_in_cost[mode], @@ -1110,14 +1490,36 @@ ira_init_register_move_cost (enum machin = (move_table *) xmalloc (sizeof (move_table) * N_REG_CLASSES); memcpy (ira_may_move_out_cost[mode], may_move_out_cost[mode], sizeof (move_table) * N_REG_CLASSES); + ira_max_may_move_in_cost[mode] + = (move_table *) xmalloc (sizeof (move_table) * N_REG_CLASSES); + memcpy (ira_max_may_move_in_cost[mode], ira_max_register_move_cost[mode], + sizeof (move_table) * N_REG_CLASSES); + ira_max_may_move_out_cost[mode] + = (move_table *) xmalloc (sizeof (move_table) * N_REG_CLASSES); + memcpy (ira_max_may_move_out_cost[mode], ira_max_register_move_cost[mode], + sizeof (move_table) * N_REG_CLASSES); for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++) { for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++) { + COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl2]); + AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); + if (hard_reg_set_empty_p (temp_hard_regset)) + continue; if (ira_class_subset_p[cl1][cl2]) ira_may_move_in_cost[mode][cl1][cl2] = 0; if (ira_class_subset_p[cl2][cl1]) ira_may_move_out_cost[mode][cl1][cl2] = 0; + if (ira_class_subset_p[cl1][cl2]) + ira_max_may_move_in_cost[mode][cl1][cl2] = 0; + if (ira_class_subset_p[cl2][cl1]) + ira_max_may_move_out_cost[mode][cl1][cl2] = 0; + ira_register_move_cost[mode][cl1][cl2] + = ira_max_register_move_cost[mode][cl1][cl2]; + ira_may_move_in_cost[mode][cl1][cl2] + = ira_max_may_move_in_cost[mode][cl1][cl2]; + ira_may_move_out_cost[mode][cl1][cl2] + = ira_max_may_move_out_cost[mode][cl1][cl2]; } } } @@ -1135,14 +1537,18 @@ ira_init_once (void) for (mode = 0; mode < MAX_MACHINE_MODE; mode++) { ira_register_move_cost[mode] = NULL; + ira_max_register_move_cost[mode] = NULL; ira_may_move_in_cost[mode] = NULL; ira_may_move_out_cost[mode] = NULL; + ira_max_may_move_in_cost[mode] = NULL; + ira_max_may_move_out_cost[mode] = NULL; } ira_init_costs_once (); } -/* Free ira_register_move_cost, ira_may_move_in_cost, and - ira_may_move_out_cost for each mode. */ +/* Free ira_max_register_move_cost, ira_may_move_in_cost, + ira_may_move_out_cost, ira_max_may_move_in_cost, and + ira_max_may_move_out_cost for each mode. */ static void free_register_move_costs (void) { @@ -1150,13 +1556,22 @@ free_register_move_costs (void) for (mode = 0; mode < MAX_MACHINE_MODE; mode++) { + if (ira_max_register_move_cost[mode] != NULL) + free (ira_max_register_move_cost[mode]); if (ira_may_move_in_cost[mode] != NULL) free (ira_may_move_in_cost[mode]); if (ira_may_move_out_cost[mode] != NULL) free (ira_may_move_out_cost[mode]); + if (ira_max_may_move_in_cost[mode] != NULL) + free (ira_max_may_move_in_cost[mode]); + if (ira_max_may_move_out_cost[mode] != NULL) + free (ira_max_may_move_out_cost[mode]); ira_register_move_cost[mode] = NULL; + ira_max_register_move_cost[mode] = NULL; ira_may_move_in_cost[mode] = NULL; ira_may_move_out_cost[mode] = NULL; + ira_max_may_move_in_cost[mode] = NULL; + ira_max_may_move_out_cost[mode] = NULL; } } @@ -1169,10 +1584,11 @@ ira_init (void) setup_reg_mode_hard_regset (); setup_alloc_regs (flag_omit_frame_pointer != 0); setup_class_subset_and_memory_move_costs (); - find_reg_class_closure (); - setup_hard_regno_cover_class (); setup_reg_class_nregs (); setup_prohibited_class_mode_regs (); + find_reg_classes (); + clarify_prohibited_class_mode_regs (); + setup_hard_regno_aclass (); ira_init_costs (); } @@ -1271,10 +1687,6 @@ ira_bad_reload_regno (int regno, rtx in, || ira_bad_reload_regno_1 (regno, out)); } -/* Function specific hard registers that can not be used for the - register allocation. */ -HARD_REG_SET ira_no_alloc_regs; - /* Return TRUE if *LOC contains an asm. */ static int insn_contains_asm_1 (rtx *loc, void *data ATTRIBUTE_UNUSED) @@ -1497,17 +1909,32 @@ setup_reg_renumber (void) ALLOCNO_ASSIGNED_P (a) = true; ira_free_allocno_updated_costs (a); hard_regno = ALLOCNO_HARD_REGNO (a); - regno = (int) REGNO (ALLOCNO_REG (a)); + regno = ALLOCNO_REGNO (a); reg_renumber[regno] = (hard_regno < 0 ? -1 : hard_regno); - if (hard_regno >= 0 && ALLOCNO_CALLS_CROSSED_NUM (a) != 0 - && ! ira_hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a), - call_used_reg_set)) - { - ira_assert (!optimize || flag_caller_saves - || regno >= ira_reg_equiv_len - || ira_reg_equiv_const[regno] - || ira_reg_equiv_invariant_p[regno]); - caller_save_needed = 1; + if (hard_regno >= 0) + { + int i, nwords; + enum reg_class pclass; + ira_object_t obj; + + pclass = ira_pressure_class_translate[REGNO_REG_CLASS (hard_regno)]; + nwords = ALLOCNO_NUM_OBJECTS (a); + for (i = 0; i < nwords; i++) + { + obj = ALLOCNO_OBJECT (a, i); + IOR_COMPL_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), + reg_class_contents[pclass]); + } + if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0 + && ! ira_hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a), + call_used_reg_set)) + { + ira_assert (!optimize || flag_caller_saves + || regno >= ira_reg_equiv_len + || ira_reg_equiv_const[regno] + || ira_reg_equiv_invariant_p[regno]); + caller_save_needed = 1; + } } } } @@ -1535,13 +1962,13 @@ setup_allocno_assignment_flags (void) allocnos because the cost info and info about intersected calls are incorrect for them. */ ALLOCNO_ASSIGNED_P (a) = (hard_regno >= 0 - || ALLOCNO_MEM_OPTIMIZED_DEST_P (a) + || ALLOCNO_EMIT_DATA (a)->mem_optimized_dest_p || (ALLOCNO_MEMORY_COST (a) - - ALLOCNO_COVER_CLASS_COST (a)) < 0); + - ALLOCNO_CLASS_COST (a)) < 0); ira_assert (hard_regno < 0 || ! ira_hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a), reg_class_contents - [ALLOCNO_COVER_CLASS (a)])); + [ALLOCNO_CLASS (a)])); } } @@ -1561,7 +1988,7 @@ calculate_allocation_cost (void) ira_assert (hard_regno < 0 || ! ira_hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a), - reg_class_contents[ALLOCNO_COVER_CLASS (a)])); + reg_class_contents[ALLOCNO_CLASS (a)])); if (hard_regno < 0) { cost = ALLOCNO_MEMORY_COST (a); @@ -1571,12 +1998,12 @@ calculate_allocation_cost (void) { cost = (ALLOCNO_HARD_REG_COSTS (a) [ira_class_hard_reg_index - [ALLOCNO_COVER_CLASS (a)][hard_regno]]); + [ALLOCNO_CLASS (a)][hard_regno]]); ira_reg_cost += cost; } else { - cost = ALLOCNO_COVER_CLASS_COST (a); + cost = ALLOCNO_CLASS_COST (a); ira_reg_cost += cost; } ira_overall_cost += cost; @@ -1768,7 +2195,7 @@ setup_preferred_alternate_classes_for_ne ira_assert (i != old_regno); setup_reg_classes (i, reg_preferred_class (old_regno), reg_alternate_class (old_regno), - reg_cover_class (old_regno)); + reg_allocno_class (old_regno)); if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) fprintf (ira_dump_file, " New r%d: setting preferred %s, alternative %s\n", @@ -1798,12 +2225,12 @@ static bool too_high_register_pressure_p (void) { int i; - enum reg_class cover_class; + enum reg_class pclass; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cover_class = ira_reg_class_cover[i]; - if (ira_loop_tree_root->reg_pressure[cover_class] > 10000) + pclass = ira_pressure_classes[i]; + if (ira_loop_tree_root->reg_pressure[pclass] > 10000) return true; } return false; @@ -2015,9 +2442,10 @@ equiv_init_movable_p (rtx x, int regno) return 0; case REG: - return (reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth - && reg_equiv[REGNO (x)].replace) - || (REG_BASIC_BLOCK (REGNO (x)) < NUM_FIXED_BLOCKS && ! rtx_varies_p (x, 0)); + return ((reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth + && reg_equiv[REGNO (x)].replace) + || (REG_BASIC_BLOCK (REGNO (x)) < NUM_FIXED_BLOCKS + && ! rtx_varies_p (x, 0))); case UNSPEC_VOLATILE: return 0; @@ -2050,7 +2478,8 @@ equiv_init_movable_p (rtx x, int regno) return 1; } -/* TRUE if X uses any registers for which reg_equiv[REGNO].replace is true. */ +/* TRUE if X uses any registers for which reg_equiv[REGNO].replace is + true. */ static int contains_replace_regs (rtx x) { @@ -2198,7 +2627,8 @@ memref_used_between_p (rtx memref, rtx s assignment - a SET, CLOBBER or REG_INC note. It is currently not used, but needs to be there because this function is called from note_stores. */ static void -no_equiv (rtx reg, const_rtx store ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) +no_equiv (rtx reg, const_rtx store ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) { int regno; rtx list; @@ -2243,12 +2673,13 @@ adjust_cleared_regs (rtx loc, const_rtx static int recorded_label_ref; /* Find registers that are equivalent to a single value throughout the - compilation (either because they can be referenced in memory or are set once - from a single constant). Lower their priority for a register. - - If such a register is only referenced once, try substituting its value - into the using insn. If it succeeds, we can eliminate the register - completely. + compilation (either because they can be referenced in memory or are + set once from a single constant). Lower their priority for a + register. + + If such a register is only referenced once, try substituting its + value into the using insn. If it succeeds, we can eliminate the + register completely. Initialize the REG_EQUIV_INIT array of initializing insns. @@ -3191,6 +3622,8 @@ ira (FILE *f) ira_max_point_before_emit = ira_max_point; + ira_initiate_emit_data (); + ira_emit (loops_p); if (ira_conflicts_p) @@ -3223,6 +3656,8 @@ ira (FILE *f) } } + ira_finish_emit_data (); + setup_reg_renumber (); calculate_allocation_cost (); Index: gcc-4.7-r171648/gcc/sched-deps.c =================================================================== --- gcc-4.7-r171648/gcc/sched-deps.c (revision 171648) +++ gcc-4.7-r171648/gcc/sched-deps.c (revision 171649) @@ -1821,10 +1821,10 @@ mark_insn_pseudo_birth (rtx insn, int re enum reg_class cl; gcc_assert (regno >= FIRST_PSEUDO_REGISTER); - cl = sched_regno_cover_class[regno]; + cl = sched_regno_pressure_class[regno]; if (cl != NO_REGS) { - incr = ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (regno)]; + incr = ira_reg_class_max_nregs[cl][PSEUDO_REGNO_MODE (regno)]; if (clobber_p) { new_incr = reg_pressure_info[cl].clobber_increase + incr; @@ -1861,7 +1861,7 @@ mark_insn_hard_regno_birth (rtx insn, in gcc_assert (regno < FIRST_PSEUDO_REGISTER); if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)) { - cl = sched_regno_cover_class[regno]; + cl = sched_regno_pressure_class[regno]; if (cl != NO_REGS) { if (clobber_p) @@ -1922,10 +1922,10 @@ mark_pseudo_death (int regno) enum reg_class cl; gcc_assert (regno >= FIRST_PSEUDO_REGISTER); - cl = sched_regno_cover_class[regno]; + cl = sched_regno_pressure_class[regno]; if (cl != NO_REGS) { - incr = ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (regno)]; + incr = ira_reg_class_max_nregs[cl][PSEUDO_REGNO_MODE (regno)]; reg_pressure_info[cl].change -= incr; } } @@ -1943,7 +1943,7 @@ mark_hard_regno_death (int regno, int nr gcc_assert (regno < FIRST_PSEUDO_REGISTER); if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)) { - cl = sched_regno_cover_class[regno]; + cl = sched_regno_pressure_class[regno]; if (cl != NO_REGS) reg_pressure_info[cl].change -= 1; } @@ -2004,9 +2004,9 @@ setup_insn_reg_pressure_info (rtx insn) if (! INSN_P (insn)) return; - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cl = ira_reg_class_cover[i]; + cl = ira_pressure_classes[i]; reg_pressure_info[cl].clobber_increase = 0; reg_pressure_info[cl].set_increase = 0; reg_pressure_info[cl].unused_set_increase = 0; @@ -2027,14 +2027,14 @@ setup_insn_reg_pressure_info (rtx insn) if (REG_NOTE_KIND (link) == REG_DEAD) mark_reg_death (XEXP (link, 0)); - len = sizeof (struct reg_pressure_data) * ira_reg_class_cover_size; + len = sizeof (struct reg_pressure_data) * ira_pressure_classes_num; pressure_info = INSN_REG_PRESSURE (insn) = (struct reg_pressure_data *) xmalloc (len); - INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_reg_class_cover_size + INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_pressure_classes_num * sizeof (int), 1); - for (i = 0; i < ira_reg_class_cover_size; i++) + for (i = 0; i < ira_pressure_classes_num; i++) { - cl = ira_reg_class_cover[i]; + cl = ira_pressure_classes[i]; pressure_info[i].clobber_increase = reg_pressure_info[cl].clobber_increase; pressure_info[i].set_increase = reg_pressure_info[cl].set_increase; Index: gcc-4.7-r171648/gcc/ira.h =================================================================== --- gcc-4.7-r171648/gcc/ira.h (revision 171648) +++ gcc-4.7-r171648/gcc/ira.h (revision 171649) @@ -20,10 +20,6 @@ You should have received a copy of the G along with GCC; see the file COPYING3. If not see . */ -/* Function specific hard registers can not be used for the register - allocation. */ -extern HARD_REG_SET ira_no_alloc_regs; - /* True if we have allocno conflicts. It is false for non-optimized mode or when the conflict table is too big. */ extern bool ira_conflicts_p; @@ -33,31 +29,47 @@ struct target_ira { allocation for given classes. */ int x_ira_available_class_regs[N_REG_CLASSES]; - /* Map: hard register number -> cover class it belongs to. If the + /* Map: hard register number -> allocno class it belongs to. If the corresponding class is NO_REGS, the hard register is not available for allocation. */ - enum reg_class x_ira_hard_regno_cover_class[FIRST_PSEUDO_REGISTER]; + enum reg_class x_ira_hard_regno_allocno_class[FIRST_PSEUDO_REGISTER]; - /* Number of cover classes. Cover classes is non-intersected register - classes containing all hard-registers available for the - allocation. */ - int x_ira_reg_class_cover_size; + /* Number of allocno classes. Allocno classes are register classes + which can be used for allocations of allocnos. */ + int x_ira_allocno_classes_num; + + /* The array containing allocno classes. Only first + IRA_ALLOCNO_CLASSES_NUM elements are used for this. */ + enum reg_class x_ira_allocno_classes[N_REG_CLASSES]; + + /* Map of all register classes to corresponding allocno classes + containing the given class. If given class is not a subset of an + allocno class, we translate it into the cheapest allocno class. */ + enum reg_class x_ira_allocno_class_translate[N_REG_CLASSES]; + + /* Number of pressure classes. Pressure classes are register + classes for which we calculate register pressure. */ + int x_ira_pressure_classes_num; + + /* The array containing pressure classes. Only first + IRA_PRESSURE_CLASSES_NUM elements are used for this. */ + enum reg_class x_ira_pressure_classes[N_REG_CLASSES]; + + /* Map of all register classes to corresponding pressure classes + containing the given class. If given class is not a subset of an + pressure class, we translate it into the cheapest pressure + class. */ + enum reg_class x_ira_pressure_class_translate[N_REG_CLASSES]; - /* The array containing cover classes (see also comments for macro - IRA_COVER_CLASSES;. Only first IRA_REG_CLASS_COVER_SIZE elements are - used for this. */ - enum reg_class x_ira_reg_class_cover[N_REG_CLASSES]; - - /* Map of all register classes to corresponding cover class containing - the given class. If given class is not a subset of a cover class, - we translate it into the cheapest cover class. */ - enum reg_class x_ira_class_translate[N_REG_CLASSES]; - - /* Map: register class x machine mode -> number of hard registers of - given class needed to store value of given mode. If the number for - some hard-registers of the register class is different, the size - will be negative. */ - int x_ira_reg_class_nregs[N_REG_CLASSES][MAX_MACHINE_MODE]; + /* Bigest pressure register class containing stack registers. + NO_REGS if there are no stack registers. */ + enum reg_class x_ira_stack_reg_pressure_class; + + /* Maps: register class x machine mode -> maximal/minimal number of + hard registers of given class needed to store value of given + mode. */ + int x_ira_reg_class_max_nregs[N_REG_CLASSES][MAX_MACHINE_MODE]; + int x_ira_reg_class_min_nregs[N_REG_CLASSES][MAX_MACHINE_MODE]; /* Array analogous to target hook TARGET_MEMORY_MOVE_COST. */ short x_ira_memory_move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][2]; @@ -70,6 +82,10 @@ struct target_ira { /* The number of elements of the above array for given register class. */ int x_ira_class_hard_regs_num[N_REG_CLASSES]; + + /* Function specific hard registers can not be used for the register + allocation. */ + HARD_REG_SET x_ira_no_alloc_regs; }; extern struct target_ira default_target_ira; @@ -81,22 +97,34 @@ extern struct target_ira *this_target_ir #define ira_available_class_regs \ (this_target_ira->x_ira_available_class_regs) -#define ira_hard_regno_cover_class \ - (this_target_ira->x_ira_hard_regno_cover_class) -#define ira_reg_class_cover_size \ - (this_target_ira->x_ira_reg_class_cover_size) -#define ira_reg_class_cover \ - (this_target_ira->x_ira_reg_class_cover) -#define ira_class_translate \ - (this_target_ira->x_ira_class_translate) -#define ira_reg_class_nregs \ - (this_target_ira->x_ira_reg_class_nregs) +#define ira_hard_regno_allocno_class \ + (this_target_ira->x_ira_hard_regno_allocno_class) +#define ira_allocno_classes_num \ + (this_target_ira->x_ira_allocno_classes_num) +#define ira_allocno_classes \ + (this_target_ira->x_ira_allocno_classes) +#define ira_allocno_class_translate \ + (this_target_ira->x_ira_allocno_class_translate) +#define ira_pressure_classes_num \ + (this_target_ira->x_ira_pressure_classes_num) +#define ira_pressure_classes \ + (this_target_ira->x_ira_pressure_classes) +#define ira_pressure_class_translate \ + (this_target_ira->x_ira_pressure_class_translate) +#define ira_stack_reg_pressure_class \ + (this_target_ira->x_ira_stack_reg_pressure_class) +#define ira_reg_class_max_nregs \ + (this_target_ira->x_ira_reg_class_max_nregs) +#define ira_reg_class_min_nregs \ + (this_target_ira->x_ira_reg_class_min_nregs) #define ira_memory_move_cost \ (this_target_ira->x_ira_memory_move_cost) #define ira_class_hard_regs \ (this_target_ira->x_ira_class_hard_regs) #define ira_class_hard_regs_num \ (this_target_ira->x_ira_class_hard_regs_num) +#define ira_no_alloc_regs \ + (this_target_ira->x_ira_no_alloc_regs) extern void ira_init_once (void); extern void ira_init (void); Index: gcc-4.7-r171648/gcc/target-def.h =================================================================== --- gcc-4.7-r171648/gcc/target-def.h (revision 171648) +++ gcc-4.7-r171648/gcc/target-def.h (revision 171649) @@ -104,10 +104,6 @@ TARGET_ASM_UNALIGNED_DI_OP, \ TARGET_ASM_UNALIGNED_TI_OP} -#ifndef IRA_COVER_CLASSES -#define TARGET_IRA_COVER_CLASSES 0 -#endif - #if !defined (TARGET_FUNCTION_INCOMING_ARG) #define TARGET_FUNCTION_INCOMING_ARG TARGET_FUNCTION_ARG #endif Index: gcc-4.7-r171648/gcc/ira-costs.c =================================================================== --- gcc-4.7-r171648/gcc/ira-costs.c (revision 171648) +++ gcc-4.7-r171648/gcc/ira-costs.c (revision 171649) @@ -62,8 +62,7 @@ struct costs { int mem_cost; /* Costs for register classes start here. We process only some - register classes (cover classes on the 1st cost calculation - iteration and important classes on the 2nd iteration). */ + allocno classes. */ int cost[1]; }; @@ -77,8 +76,6 @@ struct costs (this_target_ira_int->x_op_costs) #define this_op_costs \ (this_target_ira_int->x_this_op_costs) -#define cost_classes \ - (this_target_ira_int->x_cost_classes) /* Costs of each class for each allocno or pseudo. */ static struct costs *costs; @@ -86,13 +83,6 @@ static struct costs *costs; /* Accumulated costs of each class for each allocno. */ static struct costs *total_allocno_costs; -/* The size of the previous array. */ -static int cost_classes_num; - -/* Map: cost class -> order number (they start with 0) of the cost - class. The order number is negative for non-cost classes. */ -static int cost_class_nums[N_REG_CLASSES]; - /* It is the current size of struct costs. */ static int struct_costs_size; @@ -102,8 +92,8 @@ static int struct_costs_size; ((struct costs *) ((char *) (arr) + (num) * struct_costs_size)) /* Return index in COSTS when processing reg with REGNO. */ -#define COST_INDEX(regno) (allocno_p \ - ? ALLOCNO_NUM (ira_curr_regno_allocno_map[regno]) \ +#define COST_INDEX(regno) (allocno_p \ + ? ALLOCNO_NUM (ira_curr_regno_allocno_map[regno]) \ : (int) regno) /* Record register class preferences of each allocno or pseudo. Null @@ -114,8 +104,8 @@ static enum reg_class *pref; /* Allocated buffers for pref. */ static enum reg_class *pref_buffer; -/* Record cover register class of each allocno with the same regno. */ -static enum reg_class *regno_cover_class; +/* Record allocno class of each allocno with the same regno. */ +static enum reg_class *regno_aclass; /* Record cost gains for not allocating a register with an invariant equivalence. */ @@ -126,6 +116,204 @@ static int frequency; +/* Info about reg classes whose costs are calculated for a pseudo. */ +struct cost_classes +{ + /* Number of the cost classes in the subsequent array. */ + int num; + /* Container of the cost classes. */ + enum reg_class classes[N_REG_CLASSES]; + /* Map reg class -> index of the reg class in the previous array. + -1 if it is not a cost classe. */ + int index[N_REG_CLASSES]; + /* Map hard regno index of first class in array CLASSES containing + the hard regno, -1 otherwise. */ + int hard_regno_index[FIRST_PSEUDO_REGISTER]; +}; + +/* Types of pointers to the structure above. */ +typedef struct cost_classes *cost_classes_t; +typedef const struct cost_classes *const_cost_classes_t; + +/* Info about cost classes for each pseudo. */ +static cost_classes_t *regno_cost_classes; + +/* Returns hash value for cost classes info V. */ +static hashval_t +cost_classes_hash (const void *v) +{ + const_cost_classes_t hv = (const_cost_classes_t) v; + + return iterative_hash (&hv->classes, sizeof (enum reg_class) * hv->num, 0); +} + +/* Compares cost classes info V1 and V2. */ +static int +cost_classes_eq (const void *v1, const void *v2) +{ + const_cost_classes_t hv1 = (const_cost_classes_t) v1; + const_cost_classes_t hv2 = (const_cost_classes_t) v2; + + return hv1->num == hv2->num && memcmp (hv1->classes, hv2->classes, + sizeof (enum reg_class) * hv1->num); +} + +/* Delete cost classes info V from the hash table. */ +static void +cost_classes_del (void *v) +{ + ira_free (v); +} + +/* Hash table of unique cost classes. */ +static htab_t cost_classes_htab; + +/* Map allocno class -> cost classes for pseudo of given allocno + class. */ +static cost_classes_t cost_classes_aclass_cache[N_REG_CLASSES]; + +/* Map mode -> cost classes for pseudo of give mode. */ +static cost_classes_t cost_classes_mode_cache[MAX_MACHINE_MODE]; + +/* Initialize info about the cost classes for each pseudo. */ +static void +initiate_regno_cost_classes (void) +{ + int size = sizeof (cost_classes_t) * max_reg_num (); + + regno_cost_classes = (cost_classes_t *) ira_allocate (size); + memset (regno_cost_classes, 0, size); + memset (cost_classes_aclass_cache, 0, + sizeof (cost_classes_t) * N_REG_CLASSES); + memset (cost_classes_mode_cache, 0, + sizeof (cost_classes_t) * MAX_MACHINE_MODE); + cost_classes_htab + = htab_create (200, cost_classes_hash, cost_classes_eq, cost_classes_del); +} + +/* Create new cost classes from cost classes FROM and set up members + index and hard_regno_index. Return the new classes. The function + implements some common code of two functions + setup_regno_cost_classes_by_aclass and + setup_regno_cost_classes_by_mode. */ +static cost_classes_t +setup_cost_classes (cost_classes_t from) +{ + cost_classes_t classes_ptr; + enum reg_class cl; + int i, j, hard_regno; + + classes_ptr = (cost_classes_t) ira_allocate (sizeof (struct cost_classes)); + classes_ptr->num = from->num; + for (i = 0; i < N_REG_CLASSES; i++) + classes_ptr->index[i] = -1; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + classes_ptr->hard_regno_index[i] = -1; + for (i = 0; i < from->num; i++) + { + cl = classes_ptr->classes[i] = from->classes[i]; + classes_ptr->index[cl] = i; + for (j = ira_class_hard_regs_num[cl] - 1; j >= 0; j--) + { + hard_regno = ira_class_hard_regs[cl][j]; + if (classes_ptr->hard_regno_index[hard_regno] < 0) + classes_ptr->hard_regno_index[hard_regno] = i; + } + } + return classes_ptr; +} + +/* Setup cost classes for pseudo REGNO whose allocno class is ACLASS. + This function is used when we know an initial approximation of + allocno class of the pseudo already, e.g. on the second iteration + of class cost calculation or after class cost calculation in + register-pressure sensitive insn scheduling or register-pressure + sensitive loop-invariant motion. */ +static void +setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass) +{ + static struct cost_classes classes; + cost_classes_t classes_ptr; + enum reg_class cl; + int i; + PTR *slot; + HARD_REG_SET temp, temp2; + + if ((classes_ptr = cost_classes_aclass_cache[aclass]) == NULL) + { + COPY_HARD_REG_SET (temp, reg_class_contents[aclass]); + AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs); + classes.num = 0; + for (i = 0; i < ira_important_classes_num; i++) + { + cl = ira_important_classes[i]; + COPY_HARD_REG_SET (temp2, reg_class_contents[cl]); + AND_COMPL_HARD_REG_SET (temp2, ira_no_alloc_regs); + if (! ira_reg_pressure_class_p[cl] + && hard_reg_set_subset_p (temp2, temp) && cl != aclass) + continue; + classes.classes[classes.num++] = cl; + } + slot = htab_find_slot (cost_classes_htab, &classes, INSERT); + if (*slot == NULL) + { + classes_ptr = setup_cost_classes (&classes); + *slot = classes_ptr; + } + classes_ptr = cost_classes_aclass_cache[aclass] = (cost_classes_t) *slot; + } + regno_cost_classes[regno] = classes_ptr; +} + +/* Setup cost classes for pseudo REGNO with MODE. Usage of MODE can + decrease number of cost classes for the pseudo, if hard registers + of some important classes can not hold a value of MODE. So the + pseudo can not get hard register of some important classes and cost + calculation for such important classes is only waisting CPU + time. */ +static void +setup_regno_cost_classes_by_mode (int regno, enum machine_mode mode) +{ + static struct cost_classes classes; + cost_classes_t classes_ptr; + enum reg_class cl; + int i; + PTR *slot; + HARD_REG_SET temp; + + if ((classes_ptr = cost_classes_mode_cache[mode]) == NULL) + { + classes.num = 0; + for (i = 0; i < ira_important_classes_num; i++) + { + cl = ira_important_classes[i]; + COPY_HARD_REG_SET (temp, ira_prohibited_class_mode_regs[cl][mode]); + IOR_HARD_REG_SET (temp, ira_no_alloc_regs); + if (hard_reg_set_subset_p (reg_class_contents[cl], temp)) + continue; + classes.classes[classes.num++] = cl; + } + slot = htab_find_slot (cost_classes_htab, &classes, INSERT); + if (*slot == NULL) + { + classes_ptr = setup_cost_classes (&classes); + *slot = classes_ptr; + } + cost_classes_mode_cache[mode] = (cost_classes_t) *slot; + } + regno_cost_classes[regno] = classes_ptr; +} + +/* Finilize info about the cost classes for each pseudo. */ +static void +finish_regno_cost_classes (void) +{ + ira_free (regno_cost_classes); + htab_delete (cost_classes_htab); +} + + + /* Compute the cost of loading X into (if TO_P is TRUE) or from (if TO_P is FALSE) a register of class RCLASS in mode MODE. X must not be a pseudo register. */ @@ -313,53 +501,78 @@ record_reg_classes (int n_alts, int n_op Moreover, if we cannot tie them, this alternative needs to do a copy, which is one insn. */ struct costs *pp = this_op_costs[i]; + int *pp_costs = pp->cost; + cost_classes_t cost_classes_ptr + = regno_cost_classes[REGNO (op)]; + enum reg_class *cost_classes = cost_classes_ptr->classes; + bool in_p = recog_data.operand_type[i] != OP_OUT; + bool out_p = recog_data.operand_type[i] != OP_IN; + enum reg_class op_class = classes[i]; + move_table *move_in_cost, *move_out_cost; - for (k = 0; k < cost_classes_num; k++) + ira_init_register_move_cost_if_necessary (mode); + if (! in_p) { - rclass = cost_classes[k]; - pp->cost[k] - = (((recog_data.operand_type[i] != OP_OUT - ? ira_get_may_move_cost (mode, rclass, - classes[i], true) : 0) - + (recog_data.operand_type[i] != OP_IN - ? ira_get_may_move_cost (mode, classes[i], - rclass, false) : 0)) - * frequency); + ira_assert (out_p); + move_out_cost = ira_may_move_out_cost[mode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + pp_costs[k] + = move_out_cost[op_class][rclass] * frequency; + } + } + else if (! out_p) + { + ira_assert (in_p); + move_in_cost = ira_may_move_in_cost[mode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + pp_costs[k] + = move_in_cost[rclass][op_class] * frequency; + } + } + else + { + move_in_cost = ira_may_move_in_cost[mode]; + move_out_cost = ira_may_move_out_cost[mode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + pp_costs[k] = ((move_in_cost[rclass][op_class] + + move_out_cost[op_class][rclass]) + * frequency); + } } /* If the alternative actually allows memory, make things a bit cheaper since we won't need an extra insn to load it. */ pp->mem_cost - = ((recog_data.operand_type[i] != OP_IN - ? ira_memory_move_cost[mode][classes[i]][0] : 0) - + (recog_data.operand_type[i] != OP_OUT - ? ira_memory_move_cost[mode][classes[i]][1] : 0) + = ((out_p ? ira_memory_move_cost[mode][op_class][0] : 0) + + (in_p ? ira_memory_move_cost[mode][op_class][1] : 0) - allows_mem[i]) * frequency; - /* If we have assigned a class to this allocno in our - first pass, add a cost to this alternative - corresponding to what we would add if this allocno - were not in the appropriate class. We could use - cover class here but it is less accurate - approximation. */ + /* If we have assigned a class to this allocno in + our first pass, add a cost to this alternative + corresponding to what we would add if this + allocno were not in the appropriate class. */ if (pref) { enum reg_class pref_class = pref[COST_INDEX (REGNO (op))]; if (pref_class == NO_REGS) alt_cost - += ((recog_data.operand_type[i] != OP_IN - ? ira_memory_move_cost[mode][classes[i]][0] - : 0) - + (recog_data.operand_type[i] != OP_OUT - ? ira_memory_move_cost[mode][classes[i]][1] + += ((out_p + ? ira_memory_move_cost[mode][op_class][0] : 0) + + (in_p + ? ira_memory_move_cost[mode][op_class][1] : 0)); else if (ira_reg_class_intersect - [pref_class][classes[i]] == NO_REGS) - alt_cost += ira_get_register_move_cost (mode, - pref_class, - classes[i]); + [pref_class][op_class] == NO_REGS) + alt_cost + += ira_register_move_cost[mode][pref_class][op_class]; } if (REGNO (ops[i]) != REGNO (ops[j]) && ! find_reg_note (insn, REG_DEAD, op)) @@ -405,7 +618,7 @@ record_reg_classes (int n_alts, int n_op to be allocated to a register that can be the base of an address, i.e. BASE_REG_CLASS. */ classes[i] - = ira_reg_class_union[classes[i]] + = ira_reg_class_subunion[classes[i]] [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; break; @@ -491,12 +704,12 @@ record_reg_classes (int n_alts, int n_op win = 1; insn_allows_mem[i] = allows_mem[i] = 1; case 'r': - classes[i] = ira_reg_class_union[classes[i]][GENERAL_REGS]; + classes[i] = ira_reg_class_subunion[classes[i]][GENERAL_REGS]; break; default: if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS) - classes[i] = ira_reg_class_union[classes[i]] + classes[i] = ira_reg_class_subunion[classes[i]] [REG_CLASS_FROM_CONSTRAINT (c, p)]; #ifdef EXTRA_CONSTRAINT_STR else if (EXTRA_CONSTRAINT_STR (op, c, p)) @@ -520,7 +733,7 @@ record_reg_classes (int n_alts, int n_op that can be the base of an address, i.e. BASE_REG_CLASS. */ classes[i] - = ira_reg_class_union[classes[i]] + = ira_reg_class_subunion[classes[i]] [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; } #endif @@ -554,53 +767,77 @@ record_reg_classes (int n_alts, int n_op } else { + unsigned int regno = REGNO (op); struct costs *pp = this_op_costs[i]; + int *pp_costs = pp->cost; + cost_classes_t cost_classes_ptr = regno_cost_classes[regno]; + enum reg_class *cost_classes = cost_classes_ptr->classes; + bool in_p = recog_data.operand_type[i] != OP_OUT; + bool out_p = recog_data.operand_type[i] != OP_IN; + enum reg_class op_class = classes[i]; + move_table *move_in_cost, *move_out_cost; - for (k = 0; k < cost_classes_num; k++) + ira_init_register_move_cost_if_necessary (mode); + if (! in_p) { - rclass = cost_classes[k]; - pp->cost[k] - = (((recog_data.operand_type[i] != OP_OUT - ? ira_get_may_move_cost (mode, rclass, - classes[i], true) : 0) - + (recog_data.operand_type[i] != OP_IN - ? ira_get_may_move_cost (mode, classes[i], - rclass, false) : 0)) - * frequency); + ira_assert (out_p); + move_out_cost = ira_may_move_out_cost[mode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + pp_costs[k] + = move_out_cost[op_class][rclass] * frequency; + } + } + else if (! out_p) + { + ira_assert (in_p); + move_in_cost = ira_may_move_in_cost[mode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + pp_costs[k] + = move_in_cost[rclass][op_class] * frequency; + } + } + else + { + move_in_cost = ira_may_move_in_cost[mode]; + move_out_cost = ira_may_move_out_cost[mode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + pp_costs[k] = ((move_in_cost[rclass][op_class] + + move_out_cost[op_class][rclass]) + * frequency); + } } /* If the alternative actually allows memory, make things a bit cheaper since we won't need an extra insn to load it. */ pp->mem_cost - = ((recog_data.operand_type[i] != OP_IN - ? ira_memory_move_cost[mode][classes[i]][0] : 0) - + (recog_data.operand_type[i] != OP_OUT - ? ira_memory_move_cost[mode][classes[i]][1] : 0) + = ((out_p ? ira_memory_move_cost[mode][op_class][0] : 0) + + (in_p ? ira_memory_move_cost[mode][op_class][1] : 0) - allows_mem[i]) * frequency; - /* If we have assigned a class to this allocno in our - first pass, add a cost to this alternative - corresponding to what we would add if this allocno - were not in the appropriate class. We could use - cover class here but it is less accurate - approximation. */ + /* If we have assigned a class to this allocno in + our first pass, add a cost to this alternative + corresponding to what we would add if this + allocno were not in the appropriate class. */ if (pref) { enum reg_class pref_class = pref[COST_INDEX (REGNO (op))]; if (pref_class == NO_REGS) alt_cost - += ((recog_data.operand_type[i] != OP_IN - ? ira_memory_move_cost[mode][classes[i]][0] - : 0) - + (recog_data.operand_type[i] != OP_OUT - ? ira_memory_move_cost[mode][classes[i]][1] + += ((out_p + ? ira_memory_move_cost[mode][op_class][0] : 0) + + (in_p + ? ira_memory_move_cost[mode][op_class][1] : 0)); - else if (ira_reg_class_intersect[pref_class][classes[i]] + else if (ira_reg_class_intersect[pref_class][op_class] == NO_REGS) - alt_cost += ira_get_register_move_cost (mode, - pref_class, - classes[i]); + alt_cost += ira_register_move_cost[mode][pref_class][op_class]; } } } @@ -643,14 +880,17 @@ record_reg_classes (int n_alts, int n_op if (REG_P (ops[i]) && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) { struct costs *pp = op_costs[i], *qq = this_op_costs[i]; + int *pp_costs = pp->cost, *qq_costs = qq->cost; int scale = 1 + (recog_data.operand_type[i] == OP_INOUT); + cost_classes_t cost_classes_ptr + = regno_cost_classes[REGNO (ops[i])]; pp->mem_cost = MIN (pp->mem_cost, (qq->mem_cost + op_cost_add) * scale); - for (k = 0; k < cost_classes_num; k++) - pp->cost[k] - = MIN (pp->cost[k], (qq->cost[k] + op_cost_add) * scale); + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + pp_costs[k] + = MIN (pp_costs[k], (qq_costs[k] + op_cost_add) * scale); } } @@ -686,37 +926,40 @@ record_reg_classes (int n_alts, int n_op && REG_P (ops[0]) && REG_P (ops[1]) && find_regno_note (insn, REG_DEAD, REGNO (ops[1]))) for (i = 0; i <= 1; i++) - if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) + if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER + && REGNO (ops[!i]) < FIRST_PSEUDO_REGISTER) { - unsigned int regno = REGNO (ops[!i]); + unsigned int regno = REGNO (ops[i]); + unsigned int other_regno = REGNO (ops[!i]); enum machine_mode mode = GET_MODE (ops[!i]); + cost_classes_t cost_classes_ptr = regno_cost_classes[regno]; + enum reg_class *cost_classes = cost_classes_ptr->classes; enum reg_class rclass; - unsigned int nr; + int nr; - if (regno < FIRST_PSEUDO_REGISTER) - for (k = 0; k < cost_classes_num; k++) - { - rclass = cost_classes[k]; - if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno) - && (reg_class_size[rclass] - == (unsigned) CLASS_MAX_NREGS (rclass, mode))) - { - if (reg_class_size[rclass] == 1) - op_costs[i]->cost[k] = -frequency; - else - { - for (nr = 0; - nr < (unsigned) hard_regno_nregs[regno][mode]; - nr++) - if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], - regno + nr)) - break; - - if (nr == (unsigned) hard_regno_nregs[regno][mode]) - op_costs[i]->cost[k] = -frequency; - } - } - } + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + rclass = cost_classes[k]; + if (TEST_HARD_REG_BIT (reg_class_contents[rclass], other_regno) + && (reg_class_size[rclass] + == (unsigned) CLASS_MAX_NREGS (rclass, mode))) + { + if (reg_class_size[rclass] == 1) + op_costs[i]->cost[k] = -frequency; + else + { + for (nr = 0; + nr < hard_regno_nregs[other_regno][mode]; + nr++) + if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], + other_regno + nr)) + break; + + if (nr == hard_regno_nregs[other_regno][mode]) + op_costs[i]->cost[k] = -frequency; + } + } + } } } @@ -903,21 +1146,38 @@ record_address_regs (enum machine_mode m case REG: { struct costs *pp; + int *pp_costs; enum reg_class i; - int k; + int k, regno, add_cost; + cost_classes_t cost_classes_ptr; + enum reg_class *cost_classes; + move_table *move_in_cost; if (REGNO (x) < FIRST_PSEUDO_REGISTER) break; + regno = REGNO (x); if (allocno_p) - ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true; - pp = COSTS (costs, COST_INDEX (REGNO (x))); - pp->mem_cost += (ira_memory_move_cost[Pmode][rclass][1] * scale) / 2; - for (k = 0; k < cost_classes_num; k++) + ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[regno]) = true; + pp = COSTS (costs, COST_INDEX (regno)); + add_cost = (ira_memory_move_cost[Pmode][rclass][1] * scale) / 2; + if (INT_MAX - add_cost < pp->mem_cost) + pp->mem_cost = INT_MAX; + else + pp->mem_cost += add_cost; + cost_classes_ptr = regno_cost_classes[regno]; + cost_classes = cost_classes_ptr->classes; + pp_costs = pp->cost; + ira_init_register_move_cost_if_necessary (Pmode); + move_in_cost = ira_may_move_in_cost[Pmode]; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) { i = cost_classes[k]; - pp->cost[k] - += (ira_get_may_move_cost (Pmode, i, rclass, true) * scale) / 2; + add_cost = (move_in_cost[i][rclass] * scale) / 2; + if (INT_MAX - add_cost < pp_costs[k]) + pp_costs[k] = INT_MAX; + else + pp_costs[k] += add_cost; } } break; @@ -972,7 +1232,7 @@ record_operand_costs (rtx insn, enum reg record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS, SCRATCH, frequency * 2); } - + /* Check for commutative in a separate loop so everything will have been initialized. We must do this even if one operand is a constant--see addsi3 in m68k.md. */ @@ -1041,8 +1301,6 @@ scan_one_insn (rtx insn) rtx reg = SET_DEST (set); int num = COST_INDEX (REGNO (reg)); - if (pref) - cl = pref[num]; COSTS (costs, num)->mem_cost -= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency; record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0), @@ -1061,13 +1319,28 @@ scan_one_insn (rtx insn) int regno = REGNO (recog_data.operand[i]); struct costs *p = COSTS (costs, COST_INDEX (regno)); struct costs *q = op_costs[i]; + int *p_costs = p->cost, *q_costs = q->cost; + cost_classes_t cost_classes_ptr = regno_cost_classes[regno]; + int add_cost; /* If the already accounted for the memory "cost" above, don't do so again. */ if (!counted_mem) - p->mem_cost += q->mem_cost; - for (k = 0; k < cost_classes_num; k++) - p->cost[k] += q->cost[k]; + { + add_cost = q->mem_cost; + if (add_cost > 0 && INT_MAX - add_cost < p->mem_cost) + p->mem_cost = INT_MAX; + else + p->mem_cost += add_cost; + } + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + add_cost = q_costs[k]; + if (add_cost > 0 && INT_MAX - add_cost < p_costs[k]) + p_costs[k] = INT_MAX; + else + p_costs[k] += add_cost; + } } return insn; @@ -1090,6 +1363,8 @@ print_allocno_costs (FILE *f) int i, rclass; basic_block bb; int regno = ALLOCNO_REGNO (a); + cost_classes_t cost_classes_ptr = regno_cost_classes[regno]; + enum reg_class *cost_classes = cost_classes_ptr->classes; i = ALLOCNO_NUM (a); fprintf (f, " a%d(r%d,", i, regno); @@ -1098,7 +1373,7 @@ print_allocno_costs (FILE *f) else fprintf (f, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num); fprintf (f, ") costs:"); - for (k = 0; k < cost_classes_num; k++) + for (k = 0; k < cost_classes_ptr->num; k++) { rclass = cost_classes[k]; if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] @@ -1117,7 +1392,11 @@ print_allocno_costs (FILE *f) fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]); } } - fprintf (f, " MEM:%i\n", COSTS (costs, i)->mem_cost); + fprintf (f, " MEM:%i", COSTS (costs, i)->mem_cost); + if (flag_ira_region == IRA_REGION_ALL + || flag_ira_region == IRA_REGION_MIXED) + fprintf (f, ",%d", COSTS (total_allocno_costs, i)->mem_cost); + fprintf (f, "\n"); } } @@ -1127,15 +1406,19 @@ print_pseudo_costs (FILE *f) { int regno, k; int rclass; + cost_classes_t cost_classes_ptr; + enum reg_class *cost_classes; ira_assert (! allocno_p); fprintf (f, "\n"); for (regno = max_reg_num () - 1; regno >= FIRST_PSEUDO_REGISTER; regno--) { - if (regno_reg_rtx[regno] == NULL_RTX) + if (REG_N_REFS (regno) <= 0) continue; + cost_classes_ptr = regno_cost_classes[regno]; + cost_classes = cost_classes_ptr->classes; fprintf (f, " r%d costs:", regno); - for (k = 0; k < cost_classes_num; k++) + for (k = 0; k < cost_classes_ptr->num; k++) { rclass = cost_classes[k]; if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] @@ -1180,31 +1463,54 @@ process_bb_node_for_costs (ira_loop_tree } /* Find costs of register classes and memory for allocnos or pseudos - and their best costs. Set up preferred, alternative and cover + and their best costs. Set up preferred, alternative and allocno classes for pseudos. */ static void find_costs_and_classes (FILE *dump_file) { - int i, k, start; + int i, k, start, max_cost_classes_num; int pass; basic_block bb; + enum reg_class *regno_best_class; init_recog (); #ifdef FORBIDDEN_INC_DEC_CLASSES in_inc_dec = ira_allocate (sizeof (bool) * cost_elements_num); #endif /* FORBIDDEN_INC_DEC_CLASSES */ - pref = NULL; - start = 0; - if (!resize_reg_info () && allocno_p && pseudo_classes_defined_p) + regno_best_class + = (enum reg_class *) ira_allocate (max_reg_num () + * sizeof (enum reg_class)); + for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--) + regno_best_class[i] = NO_REGS; + if (!resize_reg_info () && allocno_p + && pseudo_classes_defined_p && flag_expensive_optimizations) { ira_allocno_t a; ira_allocno_iterator ai; pref = pref_buffer; + max_cost_classes_num = 1; FOR_EACH_ALLOCNO (a, ai) - pref[ALLOCNO_NUM (a)] = reg_preferred_class (ALLOCNO_REGNO (a)); - if (flag_expensive_optimizations) - start = 1; + { + pref[ALLOCNO_NUM (a)] = reg_preferred_class (ALLOCNO_REGNO (a)); + setup_regno_cost_classes_by_aclass + (ALLOCNO_REGNO (a), pref[ALLOCNO_NUM (a)]); + max_cost_classes_num + = MAX (max_cost_classes_num, + regno_cost_classes[ALLOCNO_REGNO (a)]->num); + } + start = 1; + } + else + { + pref = NULL; + max_cost_classes_num = ira_important_classes_num; + for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--) + if (regno_reg_rtx[i] != NULL_RTX) + setup_regno_cost_classes_by_mode (i, PSEUDO_REGNO_MODE (i)); + else + setup_regno_cost_classes_by_aclass (i, ALL_REGS); + start = 0; } if (allocno_p) /* Clear the flag for the next compiled function. */ @@ -1218,22 +1524,20 @@ find_costs_and_classes (FILE *dump_file) if ((!allocno_p || internal_flag_ira_verbose > 0) && dump_file) fprintf (dump_file, "\nPass %i for finding pseudo/allocno costs\n\n", pass); - /* We could use only cover classes. Unfortunately it does not - work well for some targets where some subclass of cover class - is costly and wrong cover class is chosen. */ - for (i = 0; i < N_REG_CLASSES; i++) - cost_class_nums[i] = -1; - for (cost_classes_num = 0; - cost_classes_num < ira_important_classes_num; - cost_classes_num++) + + if (pass != start) { - cost_classes[cost_classes_num] - = ira_important_classes[cost_classes_num]; - cost_class_nums[cost_classes[cost_classes_num]] - = cost_classes_num; + max_cost_classes_num = 1; + for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--) + { + setup_regno_cost_classes_by_aclass (i, regno_best_class[i]); + max_cost_classes_num + = MAX (max_cost_classes_num, regno_cost_classes[i]->num); + } } + struct_costs_size - = sizeof (struct costs) + sizeof (int) * (cost_classes_num - 1); + = sizeof (struct costs) + sizeof (int) * (max_cost_classes_num - 1); /* Zero out our accumulation of the cost of each class for each allocno. */ memset (costs, 0, cost_elements_num * struct_costs_size); @@ -1267,13 +1571,17 @@ find_costs_and_classes (FILE *dump_file) for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--) { ira_allocno_t a, parent_a; - int rclass, a_num, parent_a_num; + int rclass, a_num, parent_a_num, add_cost; ira_loop_tree_node_t parent; int best_cost, allocno_cost; enum reg_class best, alt_class; #ifdef FORBIDDEN_INC_DEC_CLASSES int inc_dec_p = false; #endif + cost_classes_t cost_classes_ptr = regno_cost_classes[i]; + enum reg_class *cost_classes = cost_classes_ptr->classes; + int *i_costs = temp_costs->cost; + int i_mem_cost; int equiv_savings = regno_equiv_gains[i]; if (! allocno_p) @@ -1284,17 +1592,21 @@ find_costs_and_classes (FILE *dump_file) inc_dec_p = in_inc_dec[i]; #endif memcpy (temp_costs, COSTS (costs, i), struct_costs_size); + i_mem_cost = temp_costs->mem_cost; } else { if (ira_regno_allocno_map[i] == NULL) continue; memset (temp_costs, 0, struct_costs_size); + i_mem_cost = 0; /* Find cost of all allocnos with the same regno. */ for (a = ira_regno_allocno_map[i]; a != NULL; a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) { + int *a_costs, *p_costs; + a_num = ALLOCNO_NUM (a); if ((flag_ira_region == IRA_REGION_ALL || flag_ira_region == IRA_REGION_MIXED) @@ -1308,15 +1620,42 @@ find_costs_and_classes (FILE *dump_file) /* Propagate costs to upper levels in the region tree. */ parent_a_num = ALLOCNO_NUM (parent_a); - for (k = 0; k < cost_classes_num; k++) - COSTS (total_allocno_costs, parent_a_num)->cost[k] - += COSTS (total_allocno_costs, a_num)->cost[k]; - COSTS (total_allocno_costs, parent_a_num)->mem_cost - += COSTS (total_allocno_costs, a_num)->mem_cost; + a_costs = COSTS (total_allocno_costs, a_num)->cost; + p_costs = COSTS (total_allocno_costs, parent_a_num)->cost; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + add_cost = a_costs[k]; + if (add_cost > 0 && INT_MAX - add_cost < p_costs[k]) + p_costs[k] = INT_MAX; + else + p_costs[k] += add_cost; + } + add_cost = COSTS (total_allocno_costs, a_num)->mem_cost; + if (add_cost > 0 + && (INT_MAX - add_cost + < COSTS (total_allocno_costs, + parent_a_num)->mem_cost)) + COSTS (total_allocno_costs, parent_a_num)->mem_cost + = INT_MAX; + else + COSTS (total_allocno_costs, parent_a_num)->mem_cost + += add_cost; + } - for (k = 0; k < cost_classes_num; k++) - temp_costs->cost[k] += COSTS (costs, a_num)->cost[k]; - temp_costs->mem_cost += COSTS (costs, a_num)->mem_cost; + a_costs = COSTS (costs, a_num)->cost; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + { + add_cost = a_costs[k]; + if (add_cost > 0 && INT_MAX - add_cost < i_costs[k]) + i_costs[k] = INT_MAX; + else + i_costs[k] += add_cost; + } + add_cost = COSTS (costs, a_num)->mem_cost; + if (add_cost && INT_MAX - add_cost < i_mem_cost) + i_mem_cost = INT_MAX; + else + i_mem_cost += add_cost; #ifdef FORBIDDEN_INC_DEC_CLASSES if (in_inc_dec[a_num]) inc_dec_p = true; @@ -1328,8 +1667,8 @@ find_costs_and_classes (FILE *dump_file) else if (equiv_savings > 0) { temp_costs->mem_cost = 0; - for (k = 0; k < cost_classes_num; k++) - temp_costs->cost[k] += equiv_savings; + for (k = cost_classes_ptr->num - 1; k >= 0; k--) + i_costs[k] += equiv_savings; } best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1; @@ -1337,7 +1676,7 @@ find_costs_and_classes (FILE *dump_file) alt_class = NO_REGS; /* Find best common class for all allocnos with the same regno. */ - for (k = 0; k < cost_classes_num; k++) + for (k = 0; k < cost_classes_ptr->num; k++) { rclass = cost_classes[k]; /* Ignore classes that are too small for this operand or @@ -1351,48 +1690,49 @@ find_costs_and_classes (FILE *dump_file) #endif ) continue; - if (temp_costs->cost[k] < best_cost) + if (i_costs[k] < best_cost) { - best_cost = temp_costs->cost[k]; + best_cost = i_costs[k]; best = (enum reg_class) rclass; } - else if (temp_costs->cost[k] == best_cost) - best = ira_reg_class_union[best][rclass]; + else if (i_costs[k] == best_cost) + best = ira_reg_class_subunion[best][rclass]; if (pass == flag_expensive_optimizations - && temp_costs->cost[k] < temp_costs->mem_cost + && i_costs[k] < i_mem_cost && (reg_class_size[reg_class_subunion[alt_class][rclass]] > reg_class_size[alt_class])) alt_class = reg_class_subunion[alt_class][rclass]; } - alt_class = ira_class_translate[alt_class]; - if (best_cost > temp_costs->mem_cost) - regno_cover_class[i] = NO_REGS; - else if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY) - /* Make the common class the biggest class of best and - alt_class. */ - regno_cover_class[i] = alt_class == NO_REGS ? best : alt_class; + alt_class = ira_allocno_class_translate[alt_class]; + if (best_cost > i_mem_cost) + regno_aclass[i] = NO_REGS; else - /* Make the common class a cover class. Remember all - allocnos with the same regno should have the same cover - class. */ - regno_cover_class[i] = ira_class_translate[best]; + { + /* Make the common class the biggest class of best and + alt_class. */ + regno_aclass[i] + = ira_reg_class_superunion[best][alt_class]; + ira_assert (regno_aclass[i] != NO_REGS + && ira_reg_allocno_class_p[regno_aclass[i]]); + } if (pass == flag_expensive_optimizations) { - if (best_cost > temp_costs->mem_cost) + if (best_cost > i_mem_cost) best = alt_class = NO_REGS; else if (best == alt_class) alt_class = NO_REGS; - setup_reg_classes (i, best, alt_class, regno_cover_class[i]); + setup_reg_classes (i, best, alt_class, regno_aclass[i]); if ((!allocno_p || internal_flag_ira_verbose > 2) && dump_file != NULL) fprintf (dump_file, - " r%d: preferred %s, alternative %s, cover %s\n", + " r%d: preferred %s, alternative %s, allocno %s\n", i, reg_class_names[best], reg_class_names[alt_class], - reg_class_names[regno_cover_class[i]]); + reg_class_names[regno_aclass[i]]); } + regno_best_class[i] = best; if (! allocno_p) { - pref[i] = best_cost > temp_costs->mem_cost ? NO_REGS : best; + pref[i] = best_cost > i_mem_cost ? NO_REGS : best; continue; } for (a = ira_regno_allocno_map[i]; @@ -1400,19 +1740,22 @@ find_costs_and_classes (FILE *dump_file) a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) { a_num = ALLOCNO_NUM (a); - if (regno_cover_class[i] == NO_REGS) + if (regno_aclass[i] == NO_REGS) best = NO_REGS; else { + int *total_a_costs = COSTS (total_allocno_costs, a_num)->cost; + int *a_costs = COSTS (costs, a_num)->cost; + /* Finding best class which is subset of the common class. */ best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1; allocno_cost = best_cost; best = ALL_REGS; - for (k = 0; k < cost_classes_num; k++) + for (k = 0; k < cost_classes_ptr->num; k++) { rclass = cost_classes[k]; - if (! ira_class_subset_p[rclass][regno_cover_class[i]]) + if (! ira_class_subset_p[rclass][regno_aclass[i]]) continue; /* Ignore classes that are too small for this operand or invalid for an operand that was @@ -1426,26 +1769,20 @@ find_costs_and_classes (FILE *dump_file) #endif ) ; - else if (COSTS (total_allocno_costs, a_num)->cost[k] - < best_cost) + else if (total_a_costs[k] < best_cost) { - best_cost - = COSTS (total_allocno_costs, a_num)->cost[k]; - allocno_cost = COSTS (costs, a_num)->cost[k]; + best_cost = total_a_costs[k]; + allocno_cost = a_costs[k]; best = (enum reg_class) rclass; } - else if (COSTS (total_allocno_costs, a_num)->cost[k] - == best_cost) + else if (total_a_costs[k] == best_cost) { - best = ira_reg_class_union[best][rclass]; - allocno_cost - = MAX (allocno_cost, COSTS (costs, a_num)->cost[k]); + best = ira_reg_class_subunion[best][rclass]; + allocno_cost = MAX (allocno_cost, a_costs[k]); } } - ALLOCNO_COVER_CLASS_COST (a) = allocno_cost; + ALLOCNO_CLASS_COST (a) = allocno_cost; } - ira_assert (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY - || ira_class_translate[best] == regno_cover_class[i]); if (internal_flag_ira_verbose > 2 && dump_file != NULL && (pass == 0 || pref[a_num] != best)) { @@ -1455,14 +1792,14 @@ find_costs_and_classes (FILE *dump_file) else fprintf (dump_file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num); - fprintf (dump_file, ") best %s, cover %s\n", + fprintf (dump_file, ") best %s, allocno %s\n", reg_class_names[best], - reg_class_names[regno_cover_class[i]]); + reg_class_names[regno_aclass[i]]); } pref[a_num] = best; } } - + if (internal_flag_ira_verbose > 4 && dump_file) { if (allocno_p) @@ -1472,6 +1809,7 @@ find_costs_and_classes (FILE *dump_file) fprintf (dump_file,"\n"); } } + ira_free (regno_best_class); #ifdef FORBIDDEN_INC_DEC_CLASSES ira_free (in_inc_dec); #endif @@ -1480,8 +1818,8 @@ find_costs_and_classes (FILE *dump_file) /* Process moves involving hard regs to modify allocno hard register - costs. We can do this only after determining allocno cover class. - If a hard register forms a register class, than moves with the hard + costs. We can do this only after determining allocno class. If a + hard register forms a register class, than moves with the hard register are already taken into account in class costs for the allocno. */ static void @@ -1530,7 +1868,7 @@ process_bb_node_for_hard_reg_moves (ira_ } else continue; - rclass = ALLOCNO_COVER_CLASS (a); + rclass = ALLOCNO_CLASS (a); if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], hard_regno)) continue; i = ira_class_hard_reg_index[rclass][hard_regno]; @@ -1538,65 +1876,64 @@ process_bb_node_for_hard_reg_moves (ira_ continue; mode = ALLOCNO_MODE (a); hard_reg_class = REGNO_REG_CLASS (hard_regno); + ira_init_register_move_cost_if_necessary (mode); cost - = (to_p ? ira_get_register_move_cost (mode, hard_reg_class, rclass) - : ira_get_register_move_cost (mode, rclass, hard_reg_class)) * freq; + = (to_p ? ira_register_move_cost[mode][hard_reg_class][rclass] + : ira_register_move_cost[mode][rclass][hard_reg_class]) * freq; ira_allocate_and_set_costs (&ALLOCNO_HARD_REG_COSTS (a), rclass, - ALLOCNO_COVER_CLASS_COST (a)); + ALLOCNO_CLASS_COST (a)); ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), rclass, 0); ALLOCNO_HARD_REG_COSTS (a)[i] -= cost; ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[i] -= cost; - ALLOCNO_COVER_CLASS_COST (a) = MIN (ALLOCNO_COVER_CLASS_COST (a), + ALLOCNO_CLASS_COST (a) = MIN (ALLOCNO_CLASS_COST (a), ALLOCNO_HARD_REG_COSTS (a)[i]); } } /* After we find hard register and memory costs for allocnos, define - its cover class and modify hard register cost because insns moving + its class and modify hard register cost because insns moving allocno to/from hard registers. */ static void -setup_allocno_cover_class_and_costs (void) +setup_allocno_class_and_costs (void) { - int i, j, n, regno, num; + int i, j, n, regno, hard_regno, num; int *reg_costs; - enum reg_class cover_class, rclass; + enum reg_class aclass, rclass; ira_allocno_t a; ira_allocno_iterator ai; + cost_classes_t cost_classes_ptr; ira_assert (allocno_p); FOR_EACH_ALLOCNO (a, ai) { i = ALLOCNO_NUM (a); - cover_class = regno_cover_class[ALLOCNO_REGNO (a)]; - ira_assert (pref[i] == NO_REGS || cover_class != NO_REGS); + regno = ALLOCNO_REGNO (a); + aclass = regno_aclass[regno]; + cost_classes_ptr = regno_cost_classes[regno]; + ira_assert (pref[i] == NO_REGS || aclass != NO_REGS); ALLOCNO_MEMORY_COST (a) = COSTS (costs, i)->mem_cost; - ira_set_allocno_cover_class (a, cover_class); - if (cover_class == NO_REGS) + ira_set_allocno_class (a, aclass); + if (aclass == NO_REGS) continue; - ALLOCNO_AVAILABLE_REGS_NUM (a) = ira_available_class_regs[cover_class]; - if (optimize && ALLOCNO_COVER_CLASS (a) != pref[i]) + if (optimize && ALLOCNO_CLASS (a) != pref[i]) { - n = ira_class_hard_regs_num[cover_class]; + n = ira_class_hard_regs_num[aclass]; ALLOCNO_HARD_REG_COSTS (a) - = reg_costs = ira_allocate_cost_vector (cover_class); + = reg_costs = ira_allocate_cost_vector (aclass); for (j = n - 1; j >= 0; j--) { - regno = ira_class_hard_regs[cover_class][j]; - if (TEST_HARD_REG_BIT (reg_class_contents[pref[i]], regno)) - reg_costs[j] = ALLOCNO_COVER_CLASS_COST (a); + hard_regno = ira_class_hard_regs[aclass][j]; + if (TEST_HARD_REG_BIT (reg_class_contents[pref[i]], hard_regno)) + reg_costs[j] = ALLOCNO_CLASS_COST (a); else { - rclass = REGNO_REG_CLASS (regno); - num = cost_class_nums[rclass]; + rclass = REGNO_REG_CLASS (hard_regno); + num = cost_classes_ptr->index[rclass]; if (num < 0) { - /* The hard register class is not a cover class or a - class not fully inside in a cover class -- use - the allocno cover class. */ - ira_assert (ira_hard_regno_cover_class[regno] - == cover_class); - num = cost_class_nums[cover_class]; + num = cost_classes_ptr->hard_regno_index[hard_regno]; + ira_assert (num >= 0); } reg_costs[j] = COSTS (costs, i)->cost[num]; } @@ -1623,7 +1960,6 @@ ira_init_costs_once (void) this_op_costs[i] = NULL; } temp_costs = NULL; - cost_classes = NULL; } /* Free allocated temporary cost vectors. */ @@ -1646,9 +1982,6 @@ free_ira_costs (void) if (temp_costs != NULL) free (temp_costs); temp_costs = NULL; - if (cost_classes != NULL) - free (cost_classes); - cost_classes = NULL; } /* This is called each time register related information is @@ -1661,7 +1994,8 @@ ira_init_costs (void) free_ira_costs (); max_struct_costs_size = sizeof (struct costs) + sizeof (int) * (ira_important_classes_num - 1); - /* Don't use ira_allocate because vectors live through several IRA calls. */ + /* Don't use ira_allocate because vectors live through several IRA + calls. */ init_cost = (struct costs *) xmalloc (max_struct_costs_size); init_cost->mem_cost = 1000000; for (i = 0; i < ira_important_classes_num; i++) @@ -1672,8 +2006,6 @@ ira_init_costs (void) this_op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size); } temp_costs = (struct costs *) xmalloc (max_struct_costs_size); - cost_classes = (enum reg_class *) xmalloc (sizeof (enum reg_class) - * ira_important_classes_num); } /* Function called once at the end of compiler work. */ @@ -1693,12 +2025,10 @@ init_costs (void) init_subregs_of_mode (); costs = (struct costs *) ira_allocate (max_struct_costs_size * cost_elements_num); - pref_buffer - = (enum reg_class *) ira_allocate (sizeof (enum reg_class) - * cost_elements_num); - regno_cover_class - = (enum reg_class *) ira_allocate (sizeof (enum reg_class) - * max_reg_num ()); + pref_buffer = (enum reg_class *) ira_allocate (sizeof (enum reg_class) + * cost_elements_num); + regno_aclass = (enum reg_class *) ira_allocate (sizeof (enum reg_class) + * max_reg_num ()); regno_equiv_gains = (int *) ira_allocate (sizeof (int) * max_reg_num ()); memset (regno_equiv_gains, 0, sizeof (int) * max_reg_num ()); } @@ -1710,13 +2040,13 @@ finish_costs (void) { finish_subregs_of_mode (); ira_free (regno_equiv_gains); - ira_free (regno_cover_class); + ira_free (regno_aclass); ira_free (pref_buffer); ira_free (costs); } -/* Entry function which defines cover class, memory and hard register - costs for each allocno. */ +/* Entry function which defines register class, memory and hard + register costs for each allocno. */ void ira_costs (void) { @@ -1725,9 +2055,11 @@ ira_costs (void) init_costs (); total_allocno_costs = (struct costs *) ira_allocate (max_struct_costs_size * ira_allocnos_num); + initiate_regno_cost_classes (); calculate_elim_costs_all_insns (); find_costs_and_classes (ira_dump_file); - setup_allocno_cover_class_and_costs (); + setup_allocno_class_and_costs (); + finish_regno_cost_classes (); finish_costs (); ira_free (total_allocno_costs); } @@ -1740,7 +2072,9 @@ ira_set_pseudo_classes (FILE *dump_file) internal_flag_ira_verbose = flag_ira_verbose; cost_elements_num = max_reg_num (); init_costs (); + initiate_regno_cost_classes (); find_costs_and_classes (dump_file); + finish_regno_cost_classes (); pseudo_classes_defined_p = true; finish_costs (); } @@ -1751,32 +2085,48 @@ ira_set_pseudo_classes (FILE *dump_file) function calls. This is called only when we found all intersected calls during building allocno live ranges. */ void -ira_tune_allocno_costs_and_cover_classes (void) +ira_tune_allocno_costs (void) { int j, n, regno; int cost, min_cost, *reg_costs; - enum reg_class cover_class, rclass; + enum reg_class aclass, rclass; enum machine_mode mode; ira_allocno_t a; ira_allocno_iterator ai; + ira_allocno_object_iterator oi; + ira_object_t obj; + bool skip_p; FOR_EACH_ALLOCNO (a, ai) { - cover_class = ALLOCNO_COVER_CLASS (a); - if (cover_class == NO_REGS) + aclass = ALLOCNO_CLASS (a); + if (aclass == NO_REGS) continue; mode = ALLOCNO_MODE (a); - n = ira_class_hard_regs_num[cover_class]; + n = ira_class_hard_regs_num[aclass]; min_cost = INT_MAX; if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) { ira_allocate_and_set_costs - (&ALLOCNO_HARD_REG_COSTS (a), cover_class, - ALLOCNO_COVER_CLASS_COST (a)); + (&ALLOCNO_HARD_REG_COSTS (a), aclass, + ALLOCNO_CLASS_COST (a)); reg_costs = ALLOCNO_HARD_REG_COSTS (a); for (j = n - 1; j >= 0; j--) { - regno = ira_class_hard_regs[cover_class][j]; + regno = ira_class_hard_regs[aclass][j]; + skip_p = false; + FOR_EACH_ALLOCNO_OBJECT (a, obj, oi) + { + if (! ira_hard_reg_not_in_set_p (regno, mode, + OBJECT_CONFLICT_HARD_REGS + (obj))) + { + skip_p = true; + break; + } + } + if (skip_p) + continue; rclass = REGNO_REG_CLASS (regno); cost = 0; if (! ira_hard_reg_not_in_set_p (regno, mode, call_used_reg_set) @@ -1790,33 +2140,35 @@ ira_tune_allocno_costs_and_cover_classes * ALLOCNO_FREQ (a) * IRA_HARD_REGNO_ADD_COST_MULTIPLIER (regno) / 2); #endif - reg_costs[j] += cost; + if (INT_MAX - cost < reg_costs[j]) + reg_costs[j] = INT_MAX; + else + reg_costs[j] += cost; if (min_cost > reg_costs[j]) min_cost = reg_costs[j]; } } if (min_cost != INT_MAX) - ALLOCNO_COVER_CLASS_COST (a) = min_cost; + ALLOCNO_CLASS_COST (a) = min_cost; /* Some targets allow pseudos to be allocated to unaligned sequences of hard registers. However, selecting an unaligned sequence can unnecessarily restrict later allocations. So increase the cost of unaligned hard regs to encourage the use of aligned hard regs. */ { - const int nregs = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)]; + const int nregs = ira_reg_class_max_nregs[aclass][ALLOCNO_MODE (a)]; if (nregs > 1) { ira_allocate_and_set_costs - (&ALLOCNO_HARD_REG_COSTS (a), cover_class, - ALLOCNO_COVER_CLASS_COST (a)); + (&ALLOCNO_HARD_REG_COSTS (a), aclass, ALLOCNO_CLASS_COST (a)); reg_costs = ALLOCNO_HARD_REG_COSTS (a); for (j = n - 1; j >= 0; j--) { - regno = ira_non_ordered_class_hard_regs[cover_class][j]; + regno = ira_non_ordered_class_hard_regs[aclass][j]; if ((regno % nregs) != 0) { - int index = ira_class_hard_reg_index[cover_class][regno]; + int index = ira_class_hard_reg_index[aclass][regno]; ira_assert (index != -1); reg_costs[index] += ALLOCNO_FREQ (a); } Index: gcc-4.7-r171648/gcc/rtl.h =================================================================== --- gcc-4.7-r171648/gcc/rtl.h (revision 171648) +++ gcc-4.7-r171648/gcc/rtl.h (revision 171649) @@ -1992,7 +1992,7 @@ extern const char *decode_asm_operands ( extern enum reg_class reg_preferred_class (int); extern enum reg_class reg_alternate_class (int); -extern enum reg_class reg_cover_class (int); +extern enum reg_class reg_allocno_class (int); extern void setup_reg_classes (int, enum reg_class, enum reg_class, enum reg_class); Index: gcc-4.7-r171648/gcc/sched-int.h =================================================================== --- gcc-4.7-r171648/gcc/sched-int.h (revision 171648) +++ gcc-4.7-r171648/gcc/sched-int.h (revision 171649) @@ -653,9 +653,9 @@ extern struct haifa_sched_info *current_ up. */ extern bool sched_pressure_p; -/* Map regno -> its cover class. The map defined only when +/* Map regno -> its pressure class. The map defined only when SCHED_PRESSURE_P is true. */ -extern enum reg_class *sched_regno_cover_class; +extern enum reg_class *sched_regno_pressure_class; /* Indexed by INSN_UID, the collection of all data associated with a single instruction. */ @@ -707,7 +707,7 @@ struct _haifa_deps_insn_data #define INCREASE_BITS 8 /* The structure describes how the corresponding insn increases the - register pressure for each cover class. */ + register pressure for each pressure class. */ struct reg_pressure_data { /* Pressure increase for given class because of clobber. */ @@ -736,7 +736,7 @@ struct reg_use_data }; /* The following structure describes used sets of registers by insns. - Registers are pseudos whose cover class is not NO_REGS or hard + Registers are pseudos whose pressure class is not NO_REGS or hard registers available for allocations. */ struct reg_set_data { @@ -804,7 +804,7 @@ struct _haifa_insn_data struct reg_pressure_data *reg_pressure; /* The following array contains maximal reg pressure between last scheduled insn and given insn. There is an element for each - cover class of pseudos referenced in insns. This info updated + pressure class of pseudos referenced in insns. This info updated after scheduling each insn for each insn between the two mentioned insns. */ int *max_reg_pressure; Index: gcc-4.7-r171648/gcc/system.h =================================================================== --- gcc-4.7-r171648/gcc/system.h (revision 171648) +++ gcc-4.7-r171648/gcc/system.h (revision 171649) @@ -829,7 +829,7 @@ extern void fancy_abort (const char *, i HANDLE_SYSV_PRAGMA HANDLE_PRAGMA_WEAK CONDITIONAL_REGISTER_USAGE \ FUNCTION_ARG_BOUNDARY MUST_USE_SJLJ_EXCEPTIONS US_SOFTWARE_GOFAST \ USING_SVR4_H SVR4_ASM_SPEC FUNCTION_ARG FUNCTION_ARG_ADVANCE \ - FUNCTION_INCOMING_ARG + FUNCTION_INCOMING_ARG IRA_COVER_CLASSES /* Hooks that are no longer used. */ #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE \ @@ -840,7 +840,8 @@ extern void fancy_abort (const char *, i LANG_HOOKS_POPLEVEL LANG_HOOKS_TRUTHVALUE_CONVERSION \ TARGET_PROMOTE_FUNCTION_ARGS TARGET_PROMOTE_FUNCTION_RETURN \ LANG_HOOKS_MISSING_ARGUMENT LANG_HOOKS_HASH_TYPES \ - TARGET_HANDLE_OFAST TARGET_OPTION_OPTIMIZATION + TARGET_HANDLE_OFAST TARGET_OPTION_OPTIMIZATION \ + TARGET_IRA_COVER_CLASSES /* Hooks into libgcc2. */ #pragma GCC poison LIBGCC2_DOUBLE_TYPE_SIZE LIBGCC2_WORDS_BIG_ENDIAN \ Index: gcc-4.7-r171648/gcc/reginfo.c =================================================================== --- gcc-4.7-r171648/gcc/reginfo.c (revision 171648) +++ gcc-4.7-r171648/gcc/reginfo.c (revision 171649) @@ -890,9 +890,9 @@ struct reg_pref union of most major pair of classes, that generality is not required. */ char altclass; - /* coverclass is a register class that IRA uses for allocating + /* allocnoclass is a register class that IRA uses for allocating the pseudo. */ - char coverclass; + char allocnoclass; }; /* Record preferences of each pseudo. This is available after RA is @@ -925,12 +925,12 @@ reg_alternate_class (int regno) /* Return the reg_class which is used by IRA for its allocation. */ enum reg_class -reg_cover_class (int regno) +reg_allocno_class (int regno) { if (reg_pref == 0) return NO_REGS; - return (enum reg_class) reg_pref[regno].coverclass; + return (enum reg_class) reg_pref[regno].allocnoclass; } @@ -1027,18 +1027,18 @@ struct rtl_opt_pass pass_reginfo_init = /* Set up preferred, alternate, and cover classes for REGNO as - PREFCLASS, ALTCLASS, and COVERCLASS. */ + PREFCLASS, ALTCLASS, and ALLOCNOCLASS. */ void setup_reg_classes (int regno, enum reg_class prefclass, enum reg_class altclass, - enum reg_class coverclass) + enum reg_class allocnoclass) { if (reg_pref == NULL) return; gcc_assert (reg_info_size == max_reg_num ()); reg_pref[regno].prefclass = prefclass; reg_pref[regno].altclass = altclass; - reg_pref[regno].coverclass = coverclass; + reg_pref[regno].allocnoclass = allocnoclass; } Index: gcc-4.7-r171648/gcc/Makefile.in =================================================================== --- gcc-4.7-r171648/gcc/Makefile.in (revision 171648) +++ gcc-4.7-r171648/gcc/Makefile.in (revision 171649) @@ -3318,7 +3318,7 @@ ira-conflicts.o: ira-conflicts.c $(CONFI ira-color.o: ira-color.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \ $(EXPR_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_CORE_H) $(TM_P_H) reload.h $(PARAMS_H) \ - $(DF_H) $(SPLAY_TREE_H) $(IRA_INT_H) + $(DF_H) $(IRA_INT_H) ira-emit.o: ira-emit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(REGS_H) $(RTL_H) $(TM_P_H) $(TARGET_H) $(FLAGS_H) hard-reg-set.h \ $(BASIC_BLOCK_H) $(EXPR_H) $(RECOG_H) $(PARAMS_H) $(TIMEVAR_H) \ Index: gcc-4.7-r171648/gcc/config/alpha/alpha.h =================================================================== --- gcc-4.7-r171648/gcc/config/alpha/alpha.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/alpha/alpha.h (revision 171649) @@ -511,19 +511,6 @@ enum reg_class { {0x00000000, 0x7fffffff}, /* FLOAT_REGS */ \ {0xffffffff, 0xffffffff} } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FLOAT_REGS, LIM_REG_CLASSES \ -} - /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression Index: gcc-4.7-r171648/gcc/config/frv/frv.h =================================================================== --- gcc-4.7-r171648/gcc/config/frv/frv.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/frv/frv.h (revision 171649) @@ -970,21 +970,6 @@ enum reg_class { 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0x1fff}, /* ALL_REGS */\ } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GPR_REGS, FPR_REGS, ACC_REGS, ICR_REGS, FCR_REGS, ICC_REGS, FCC_REGS, \ - ACCG_REGS, SPR_REGS, \ - LIM_REG_CLASSES \ -} - /* A C expression whose value is a register class containing hard register REGNO. In general there is more than one such class; choose a class which is "minimal", meaning that no smaller class also contains the register. */ Index: gcc-4.7-r171648/gcc/config/s390/s390.h =================================================================== --- gcc-4.7-r171648/gcc/config/s390/s390.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/s390/s390.h (revision 171649) @@ -468,19 +468,6 @@ enum reg_class { 0xffffffff, 0x0000003f }, /* ALL_REGS */ \ } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FP_REGS, CC_REGS, ACCESS_REGS, LIM_REG_CLASSES \ -} - /* In some case register allocation order is not enough for IRA to generate a good code. The following macro (if defined) increases cost of REGNO for a pseudo approximately by pseudo usage frequency Index: gcc-4.7-r171648/gcc/config/spu/spu.h =================================================================== --- gcc-4.7-r171648/gcc/config/spu/spu.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/spu/spu.h (revision 171649) @@ -196,9 +196,6 @@ enum reg_class { LIM_REG_CLASSES }; -/* SPU is simple, it really only has one class of registers. */ -#define IRA_COVER_CLASSES { GENERAL_REGS, LIM_REG_CLASSES } - #define N_REG_CLASSES (int) LIM_REG_CLASSES #define REG_CLASS_NAMES \ Index: gcc-4.7-r171648/gcc/config/sparc/sparc.h =================================================================== --- gcc-4.7-r171648/gcc/config/sparc/sparc.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/sparc/sparc.h (revision 171649) @@ -972,19 +972,6 @@ extern enum reg_class sparc_regno_reg_cl #define REGNO_REG_CLASS(REGNO) sparc_regno_reg_class[(REGNO)] -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, EXTRA_FP_REGS, FPCC_REGS, LIM_REG_CLASSES \ -} - /* Defines invalid mode changes. Borrowed from pa64-regs.h. SImode loads to floating-point registers are not zero-extended. Index: gcc-4.7-r171648/gcc/config/mep/mep.h =================================================================== --- gcc-4.7-r171648/gcc/config/mep/mep.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/mep/mep.h (revision 171649) @@ -407,8 +407,6 @@ enum reg_class #define REGNO_REG_CLASS(REGNO) (enum reg_class) mep_regno_reg_class (REGNO) -#define IRA_COVER_CLASSES { GENERAL_REGS, CONTROL_REGS, CR_REGS, CCR_REGS, LIM_REG_CLASSES } - #define BASE_REG_CLASS GENERAL_REGS #define INDEX_REG_CLASS GENERAL_REGS Index: gcc-4.7-r171648/gcc/config/m32r/m32r.h =================================================================== --- gcc-4.7-r171648/gcc/config/m32r/m32r.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/m32r/m32r.h (revision 171649) @@ -459,11 +459,6 @@ enum reg_class NO_REGS, CARRY_REG, ACCUM_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES }; -#define IRA_COVER_CLASSES \ -{ \ - ACCUM_REGS, GENERAL_REGS, LIM_REG_CLASSES \ -} - #define N_REG_CLASSES ((int) LIM_REG_CLASSES) /* Give names of register classes as strings for dump file. */ Index: gcc-4.7-r171648/gcc/config/rx/rx.h =================================================================== --- gcc-4.7-r171648/gcc/config/rx/rx.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/rx/rx.h (revision 171649) @@ -187,11 +187,6 @@ enum reg_class { 0x0000ffff } /* All registers. */ \ } -#define IRA_COVER_CLASSES \ - { \ - GR_REGS, LIM_REG_CLASSES \ - } - #define SMALL_REGISTER_CLASSES 0 #define N_REG_CLASSES (int) LIM_REG_CLASSES #define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \ Index: gcc-4.7-r171648/gcc/config/i386/i386.h =================================================================== --- gcc-4.7-r171648/gcc/config/i386/i386.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/i386/i386.h (revision 171649) @@ -870,9 +870,6 @@ enum target_cpu_default || ((MODE) == DFmode && !(TARGET_SSE2 && TARGET_SSE_MATH)) \ || (MODE) == XFmode) -/* Cover class containing the stack registers. */ -#define STACK_REG_COVER_CLASS FLOAT_REGS - /* Number of actual hardware registers. The hardware registers are assigned numbers for the compiler from 0 to just below FIRST_PSEUDO_REGISTER. Index: gcc-4.7-r171648/gcc/config/i386/i386.c =================================================================== --- gcc-4.7-r171648/gcc/config/i386/i386.c (revision 171648) +++ gcc-4.7-r171648/gcc/config/i386/i386.c (revision 171649) @@ -28434,22 +28434,6 @@ ix86_free_from_memory (enum machine_mode } } -/* Implement TARGET_IRA_COVER_CLASSES. If -mfpmath=sse, we prefer - SSE_REGS to FLOAT_REGS if their costs for a pseudo are the - same. */ -static const reg_class_t * -i386_ira_cover_classes (void) -{ - static const reg_class_t sse_fpmath_classes[] = { - GENERAL_REGS, SSE_REGS, MMX_REGS, FLOAT_REGS, LIM_REG_CLASSES - }; - static const reg_class_t no_sse_fpmath_classes[] = { - GENERAL_REGS, FLOAT_REGS, MMX_REGS, SSE_REGS, LIM_REG_CLASSES - }; - - return TARGET_SSE_MATH ? sse_fpmath_classes : no_sse_fpmath_classes; -} - /* Implement TARGET_PREFERRED_RELOAD_CLASS. Put float CONST_DOUBLE in the constant pool instead of fp regs. @@ -35349,9 +35333,6 @@ ix86_autovectorize_vector_sizes (void) #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P ix86_legitimate_address_p -#undef TARGET_IRA_COVER_CLASSES -#define TARGET_IRA_COVER_CLASSES i386_ira_cover_classes - #undef TARGET_FRAME_POINTER_REQUIRED #define TARGET_FRAME_POINTER_REQUIRED ix86_frame_pointer_required Index: gcc-4.7-r171648/gcc/config/sh/sh.h =================================================================== --- gcc-4.7-r171648/gcc/config/sh/sh.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/sh/sh.h (revision 171649) @@ -1133,20 +1133,6 @@ enum reg_class extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER]; #define REGNO_REG_CLASS(REGNO) regno_reg_class[(REGNO)] -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FP_REGS, PR_REGS, T_REGS, MAC_REGS, TARGET_REGS, \ - FPUL_REGS, LIM_REG_CLASSES \ -} - /* When this hook returns true for MODE, the compiler allows registers explicitly used in the rtl to be used as spill registers but prevents the compiler from extending the lifetime of these Index: gcc-4.7-r171648/gcc/config/avr/avr.h =================================================================== --- gcc-4.7-r171648/gcc/config/avr/avr.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/avr/avr.h (revision 171649) @@ -296,19 +296,6 @@ enum reg_class { #define REGNO_REG_CLASS(R) avr_regno_reg_class(R) -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, LIM_REG_CLASSES \ -} - #define BASE_REG_CLASS (reload_completed ? BASE_POINTER_REGS : POINTER_REGS) #define INDEX_REG_CLASS NO_REGS Index: gcc-4.7-r171648/gcc/config/xtensa/xtensa.h =================================================================== --- gcc-4.7-r171648/gcc/config/xtensa/xtensa.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/xtensa/xtensa.h (revision 171649) @@ -432,11 +432,6 @@ enum reg_class { 0xffffffff, 0x0000000f } /* all registers */ \ } -#define IRA_COVER_CLASSES \ -{ \ - BR_REGS, FP_REGS, ACC_REG, AR_REGS, LIM_REG_CLASSES \ -} - /* A C expression whose value is a register class containing hard register REGNO. In general there is more that one such class; choose a class which is "minimal", meaning that no smaller class Index: gcc-4.7-r171648/gcc/config/stormy16/stormy16.h =================================================================== --- gcc-4.7-r171648/gcc/config/stormy16/stormy16.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/stormy16/stormy16.h (revision 171649) @@ -179,11 +179,6 @@ enum reg_class #define N_REG_CLASSES ((int) LIM_REG_CLASSES) -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, LIM_REG_CLASSES \ -} - #define REG_CLASS_NAMES \ { \ "NO_REGS", \ Index: gcc-4.7-r171648/gcc/config/fr30/fr30.h =================================================================== --- gcc-4.7-r171648/gcc/config/fr30/fr30.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/fr30/fr30.h (revision 171649) @@ -290,11 +290,6 @@ enum reg_class #define GENERAL_REGS REAL_REGS #define N_REG_CLASSES ((int) LIM_REG_CLASSES) -#define IRA_COVER_CLASSES \ -{ \ - REAL_REGS, MULTIPLY_64_REG, LIM_REG_CLASSES \ -} - /* An initializer containing the names of the register classes as C string constants. These names are used in writing some of the debugging dumps. */ #define REG_CLASS_NAMES \ Index: gcc-4.7-r171648/gcc/config/moxie/moxie.h =================================================================== --- gcc-4.7-r171648/gcc/config/moxie/moxie.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/moxie/moxie.h (revision 171649) @@ -135,15 +135,6 @@ enum reg_class }; -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ -#define IRA_COVER_CLASSES { GENERAL_REGS, LIM_REG_CLASSES } - #define REG_CLASS_CONTENTS \ { { 0x00000000 }, /* Empty */ \ { 0x0003FFFF }, /* $fp, $sp, $r0 to $r13, ?fp */ \ Index: gcc-4.7-r171648/gcc/config/cris/cris.h =================================================================== --- gcc-4.7-r171648/gcc/config/cris/cris.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/cris/cris.h (revision 171649) @@ -550,8 +550,6 @@ enum reg_class #define INDEX_REG_CLASS GENERAL_REGS -#define IRA_COVER_CLASSES { GENERAL_REGS, SPECIAL_REGS, LIM_REG_CLASSES } - #define REG_CLASS_FROM_LETTER(C) \ ( \ (C) == 'a' ? ACR_REGS : \ Index: gcc-4.7-r171648/gcc/config/iq2000/iq2000.h =================================================================== --- gcc-4.7-r171648/gcc/config/iq2000/iq2000.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/iq2000/iq2000.h (revision 171649) @@ -209,11 +209,6 @@ enum reg_class #define N_REG_CLASSES (int) LIM_REG_CLASSES -#define IRA_COVER_CLASSES \ -{ \ - GR_REGS, LIM_REG_CLASSES \ -} - #define REG_CLASS_NAMES \ { \ "NO_REGS", \ Index: gcc-4.7-r171648/gcc/config/mn10300/mn10300.h =================================================================== --- gcc-4.7-r171648/gcc/config/mn10300/mn10300.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/mn10300/mn10300.h (revision 171649) @@ -309,19 +309,6 @@ enum reg_class { 0xffffffff, 0xfffff } /* ALL_REGS */ \ } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FP_REGS, MDR_REGS, LIM_REG_CLASSES \ -} - /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression Index: gcc-4.7-r171648/gcc/config/ia64/ia64.h =================================================================== --- gcc-4.7-r171648/gcc/config/ia64/ia64.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/ia64/ia64.h (revision 171649) @@ -774,19 +774,6 @@ enum reg_class 0xFFFFFFFF, 0xFFFFFFFF, 0x3FFF }, \ } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - PR_REGS, BR_REGS, AR_M_REGS, AR_I_REGS, GR_REGS, FR_REGS, LIM_REG_CLASSES \ -} - /* A C expression whose value is a register class containing hard register REGNO. In general there is more than one such class; choose a class which is "minimal", meaning that no smaller class also contains the register. */ Index: gcc-4.7-r171648/gcc/config/m68k/m68k.h =================================================================== --- gcc-4.7-r171648/gcc/config/m68k/m68k.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/m68k/m68k.h (revision 171649) @@ -496,10 +496,6 @@ extern enum reg_class regno_reg_class[]; #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ ((((CLASS1) == FP_REGS) != ((CLASS2) == FP_REGS)) ? 4 : 2) -#define IRA_COVER_CLASSES \ -{ \ - ALL_REGS, LIM_REG_CLASSES \ -} /* Stack layout; function entry, exit and calling. */ Index: gcc-4.7-r171648/gcc/config/rs6000/rs6000.c =================================================================== --- gcc-4.7-r171648/gcc/config/rs6000/rs6000.c (revision 171648) +++ gcc-4.7-r171648/gcc/config/rs6000/rs6000.c (revision 171649) @@ -1208,8 +1208,6 @@ static reg_class_t rs6000_secondary_relo enum machine_mode, struct secondary_reload_info *); -static const reg_class_t *rs6000_ira_cover_classes (void); - const int INSN_NOT_AVAILABLE = -1; static enum machine_mode rs6000_eh_return_filter_mode (void); static bool rs6000_can_eliminate (const int, const int); @@ -1636,9 +1634,6 @@ static const struct default_options rs60 #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD rs6000_secondary_reload -#undef TARGET_IRA_COVER_CLASSES -#define TARGET_IRA_COVER_CLASSES rs6000_ira_cover_classes - #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P rs6000_legitimate_address_p @@ -15288,26 +15283,6 @@ rs6000_secondary_reload_ppc64 (rtx reg, return; } -/* Target hook to return the cover classes for Integrated Register Allocator. - Cover classes is a set of non-intersected register classes covering all hard - registers used for register allocation purpose. Any move between two - registers of a cover class should be cheaper than load or store of the - registers. The value is array of register classes with LIM_REG_CLASSES used - as the end marker. - - We need two IRA_COVER_CLASSES, one for pre-VSX, and the other for VSX to - account for the Altivec and Floating registers being subsets of the VSX - register set under VSX, but distinct register sets on pre-VSX machines. */ - -static const reg_class_t * -rs6000_ira_cover_classes (void) -{ - static const reg_class_t cover_pre_vsx[] = IRA_COVER_CLASSES_PRE_VSX; - static const reg_class_t cover_vsx[] = IRA_COVER_CLASSES_VSX; - - return (TARGET_VSX) ? cover_vsx : cover_pre_vsx; -} - /* Allocate a 64-bit stack slot to be used for copying SDmode values through if this function has any SDmode references. */ Index: gcc-4.7-r171648/gcc/config/rs6000/rs6000.h =================================================================== --- gcc-4.7-r171648/gcc/config/rs6000/rs6000.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/rs6000/rs6000.h (revision 171649) @@ -1252,34 +1252,6 @@ enum reg_class { 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff } /* ALL_REGS */ \ } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. - - We need two IRA_COVER_CLASSES, one for pre-VSX, and the other for VSX to - account for the Altivec and Floating registers being subsets of the VSX - register set. */ - -#define IRA_COVER_CLASSES_PRE_VSX \ -{ \ - GENERAL_REGS, SPECIAL_REGS, FLOAT_REGS, ALTIVEC_REGS, /* VSX_REGS, */ \ - /* VRSAVE_REGS,*/ VSCR_REGS, SPE_ACC_REGS, SPEFSCR_REGS, \ - /* MQ_REGS, LINK_REGS, CTR_REGS, */ \ - CR_REGS, CA_REGS, LIM_REG_CLASSES \ -} - -#define IRA_COVER_CLASSES_VSX \ -{ \ - GENERAL_REGS, SPECIAL_REGS, /* FLOAT_REGS, ALTIVEC_REGS, */ VSX_REGS, \ - /* VRSAVE_REGS,*/ VSCR_REGS, SPE_ACC_REGS, SPEFSCR_REGS, \ - /* MQ_REGS, LINK_REGS, CTR_REGS, */ \ - CR_REGS, CA_REGS, LIM_REG_CLASSES \ -} - /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression Index: gcc-4.7-r171648/gcc/config/picochip/picochip.h =================================================================== --- gcc-4.7-r171648/gcc/config/picochip/picochip.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/picochip/picochip.h (revision 171649) @@ -292,19 +292,6 @@ enum reg_class #define N_REG_CLASSES (int) LIM_REG_CLASSES -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GR_REGS, LIM_REG_CLASSES \ -} - /* The names of the register classes */ #define REG_CLASS_NAMES \ Index: gcc-4.7-r171648/gcc/config/mcore/mcore.h =================================================================== --- gcc-4.7-r171648/gcc/config/mcore/mcore.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/mcore/mcore.h (revision 171649) @@ -324,11 +324,6 @@ enum reg_class #define N_REG_CLASSES (int) LIM_REG_CLASSES -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, C_REGS, LIM_REG_CLASSES \ -} - /* Give names of register classes as strings for dump file. */ #define REG_CLASS_NAMES \ Index: gcc-4.7-r171648/gcc/config/score/score.h =================================================================== --- gcc-4.7-r171648/gcc/config/score/score.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/score/score.h (revision 171649) @@ -390,18 +390,6 @@ enum reg_class also contains the register. */ #define REGNO_REG_CLASS(REGNO) (enum reg_class) score_reg_class (REGNO) -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ -#define IRA_COVER_CLASSES \ -{ \ - G32_REGS, CE_REGS, SP_REGS, LIM_REG_CLASSES \ -} - /* A macro whose definition is the name of the class to which a valid base register must belong. A base register is one used in an address which is the register value plus a displacement. */ Index: gcc-4.7-r171648/gcc/config/arm/arm.h =================================================================== --- gcc-4.7-r171648/gcc/config/arm/arm.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/arm/arm.h (revision 171649) @@ -1152,20 +1152,6 @@ enum reg_class or could index an array. */ #define REGNO_REG_CLASS(REGNO) arm_regno_class (REGNO) -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FPA_REGS, CIRRUS_REGS, VFP_REGS, IWMMXT_GR_REGS, IWMMXT_REGS,\ - LIM_REG_CLASSES \ -} - /* FPA registers can't do subreg as all values are reformatted to internal precision. In VFPv1, VFP registers could only be accessed in the mode they were set, so subregs would be invalid there too. However, we don't Index: gcc-4.7-r171648/gcc/config/pa/pa32-regs.h =================================================================== --- gcc-4.7-r171648/gcc/config/pa/pa32-regs.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/pa/pa32-regs.h (revision 171649) @@ -294,19 +294,6 @@ enum reg_class { NO_REGS, R1_REGS, GENER {0x00000000, 0x00000000, 0x01000000}, /* SHIFT_REGS */ \ {0xfffffffe, 0xffffffff, 0x03ffffff}} /* ALL_REGS */ -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FP_REGS, SHIFT_REGS, LIM_REG_CLASSES \ -} - /* Defines invalid mode changes. */ #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ Index: gcc-4.7-r171648/gcc/config/pa/pa64-regs.h =================================================================== --- gcc-4.7-r171648/gcc/config/pa/pa64-regs.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/pa/pa64-regs.h (revision 171649) @@ -230,19 +230,6 @@ enum reg_class { NO_REGS, R1_REGS, GENER {0x00000000, 0x10000000}, /* SHIFT_REGS */ \ {0xfffffffe, 0x3fffffff}} /* ALL_REGS */ -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, FP_REGS, SHIFT_REGS, LIM_REG_CLASSES \ -} - /* Defines invalid mode changes. */ #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ Index: gcc-4.7-r171648/gcc/config/mips/mips.c =================================================================== --- gcc-4.7-r171648/gcc/config/mips/mips.c (revision 171648) +++ gcc-4.7-r171648/gcc/config/mips/mips.c (revision 171649) @@ -11017,29 +11017,6 @@ mips_memory_move_cost (enum machine_mode + memory_move_secondary_cost (mode, rclass, in)); } -/* Implement TARGET_IRA_COVER_CLASSES. */ - -static const reg_class_t * -mips_ira_cover_classes (void) -{ - static const reg_class_t acc_classes[] = { - GR_AND_ACC_REGS, FP_REGS, COP0_REGS, COP2_REGS, COP3_REGS, - ST_REGS, LIM_REG_CLASSES - }; - static const reg_class_t no_acc_classes[] = { - GR_REGS, FP_REGS, COP0_REGS, COP2_REGS, COP3_REGS, - ST_REGS, LIM_REG_CLASSES - }; - - /* Don't allow the register allocators to use LO and HI in MIPS16 mode, - which has no MTLO or MTHI instructions. Also, using GR_AND_ACC_REGS - as a cover class only works well when we keep per-register costs. - Using it when not optimizing can cause us to think accumulators - have the same cost as GPRs in cases where GPRs are actually much - cheaper. */ - return TARGET_MIPS16 || !optimize ? no_acc_classes : acc_classes; -} - /* Return the register class required for a secondary register when copying between one of the registers in RCLASS and value X, which has mode MODE. X is the source of the move if IN_P, otherwise it @@ -16618,9 +16595,6 @@ mips_shift_truncation_mask (enum machine #undef TARGET_DWARF_REGISTER_SPAN #define TARGET_DWARF_REGISTER_SPAN mips_dwarf_register_span -#undef TARGET_IRA_COVER_CLASSES -#define TARGET_IRA_COVER_CLASSES mips_ira_cover_classes - #undef TARGET_ASM_FINAL_POSTSCAN_INSN #define TARGET_ASM_FINAL_POSTSCAN_INSN mips_final_postscan_insn Index: gcc-4.7-r171648/gcc/config/vax/vax.h =================================================================== --- gcc-4.7-r171648/gcc/config/vax/vax.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/vax/vax.h (revision 171649) @@ -226,15 +226,6 @@ enum reg_class { NO_REGS, ALL_REGS, LIM_ #define REG_CLASS_NAMES \ { "NO_REGS", "ALL_REGS" } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ -#define IRA_COVER_CLASSES { ALL_REGS, LIM_REG_CLASSES } - /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. */ #define CLASS_MAX_NREGS(CLASS, MODE) \ Index: gcc-4.7-r171648/gcc/config/h8300/h8300.h =================================================================== --- gcc-4.7-r171648/gcc/config/h8300/h8300.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/h8300/h8300.h (revision 171649) @@ -330,19 +330,6 @@ enum reg_class { { "NO_REGS", "COUNTER_REGS", "SOURCE_REGS", "DESTINATION_REGS", \ "GENERAL_REGS", "MAC_REGS", "ALL_REGS", "LIM_REGS" } -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, MAC_REGS, LIM_REG_CLASSES \ -} - /* Define which registers fit in which classes. This is an initializer for a vector of HARD_REG_SET of length N_REG_CLASSES. */ Index: gcc-4.7-r171648/gcc/config/v850/v850.h =================================================================== --- gcc-4.7-r171648/gcc/config/v850/v850.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/v850/v850.h (revision 171649) @@ -304,11 +304,6 @@ enum reg_class #define N_REG_CLASSES (int) LIM_REG_CLASSES -#define IRA_COVER_CLASSES \ -{ \ - GENERAL_REGS, LIM_REG_CLASSES \ -} - /* Give names of register classes as strings for dump file. */ #define REG_CLASS_NAMES \ Index: gcc-4.7-r171648/gcc/config/bfin/bfin.h =================================================================== --- gcc-4.7-r171648/gcc/config/bfin/bfin.h (revision 171648) +++ gcc-4.7-r171648/gcc/config/bfin/bfin.h (revision 171649) @@ -664,19 +664,6 @@ enum reg_class : (REGNO) >= REG_RETS ? PROLOGUE_REGS \ : NO_REGS) -/* The following macro defines cover classes for Integrated Register - Allocator. Cover classes is a set of non-intersected register - classes covering all hard registers used for register allocation - purpose. Any move between two registers of a cover class should be - cheaper than load or store of the registers. The macro value is - array of register classes with LIM_REG_CLASSES used as the end - marker. */ - -#define IRA_COVER_CLASSES \ -{ \ - MOST_REGS, AREGS, CCREGS, LIM_REG_CLASSES \ -} - /* When this hook returns true for MODE, the compiler allows registers explicitly used in the rtl to be used as spill registers but prevents the compiler from extending the lifetime of these