summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2019-09-09 16:52:12 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2019-09-09 16:52:12 +0000
commitf78f73cbd284abe4f1718fd7803f5f98800de225 (patch)
tree1364617a9bf22e5a87b95265c441ea3ef6428ccb /gcc
parenta6edd18cb32993213508aaa4879af7485c1bbaac (diff)
Remove bt-load.c
bt-load.c has AFAIK been dead code since the removal of the SH5 port in 2016. I have a patch series that would need to update the liveness tracking in a nontrivial way, so it seemed better to remove the pass rather than install an untested and probably bogus change. 2019-09-09 Richard Sandiford <richard.sandiford@arm.com> gcc/ * Makefile.in (OBJS): Remove bt-load.o. * doc/invoke.texi (fbranch-target-load-optimize): Delete. (fbranch-target-load-optimize2, fbtr-bb-exclusive): Likewise. * common.opt (fbranch-target-load-optimize): Mark as Ignore and document that the option no longer does anything. (fbranch-target-load-optimize2, fbtr-bb-exclusive): Likewise. * target.def (branch_target_register_class): Delete. (branch_target_register_callee_saved): Likewise. * doc/tm.texi.in (TARGET_BRANCH_TARGET_REGISTER_CLASS): Likewise. (TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED): Likewise. * doc/tm.texi: Regenerate. * tree-pass.h (make_pass_branch_target_load_optimize1): Delete. (make_pass_branch_target_load_optimize2): Likewise. * passes.def (pass_branch_target_load_optimize1): Likewise. (pass_branch_target_load_optimize2): Likewise. * targhooks.h (default_branch_target_register_class): Likewise. * targhooks.c (default_branch_target_register_class): Likewise. * opt-suggestions.c (test_completion_valid_options): Remove -fbtr-bb-exclusive from the list of test options. * bt-load.c: Remove. From-SVN: r275521
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/bt-load.c1577
-rw-r--r--gcc/common.opt12
-rw-r--r--gcc/doc/invoke.texi21
-rw-r--r--gcc/doc/tm.texi22
-rw-r--r--gcc/doc/tm.texi.in4
-rw-r--r--gcc/opt-suggestions.c1
-rw-r--r--gcc/passes.def2
-rw-r--r--gcc/target.def32
-rw-r--r--gcc/targhooks.c6
-rw-r--r--gcc/targhooks.h1
-rw-r--r--gcc/tree-pass.h4
13 files changed, 30 insertions, 1676 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b58b92ad114..f640d89ac3e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,26 @@
+2019-09-09 Richard Sandiford <richard.sandiford@arm.com>
+
+ * Makefile.in (OBJS): Remove bt-load.o.
+ * doc/invoke.texi (fbranch-target-load-optimize): Delete.
+ (fbranch-target-load-optimize2, fbtr-bb-exclusive): Likewise.
+ * common.opt (fbranch-target-load-optimize): Mark as Ignore and
+ document that the option no longer does anything.
+ (fbranch-target-load-optimize2, fbtr-bb-exclusive): Likewise.
+ * target.def (branch_target_register_class): Delete.
+ (branch_target_register_callee_saved): Likewise.
+ * doc/tm.texi.in (TARGET_BRANCH_TARGET_REGISTER_CLASS): Likewise.
+ (TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED): Likewise.
+ * doc/tm.texi: Regenerate.
+ * tree-pass.h (make_pass_branch_target_load_optimize1): Delete.
+ (make_pass_branch_target_load_optimize2): Likewise.
+ * passes.def (pass_branch_target_load_optimize1): Likewise.
+ (pass_branch_target_load_optimize2): Likewise.
+ * targhooks.h (default_branch_target_register_class): Likewise.
+ * targhooks.c (default_branch_target_register_class): Likewise.
+ * opt-suggestions.c (test_completion_valid_options): Remove
+ -fbtr-bb-exclusive from the list of test options.
+ * bt-load.c: Remove.
+
2019-09-09 Barnaby Wilks <barnaby.wilks@arm.com>
* match.pd: Add flag_unsafe_math_optimizations check
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 99d88a46f1d..0fe02fb27a1 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1241,7 +1241,6 @@ OBJS = \
auto-profile.o \
bb-reorder.o \
bitmap.o \
- bt-load.o \
builtins.o \
caller-save.o \
calls.o \
diff --git a/gcc/bt-load.c b/gcc/bt-load.c
deleted file mode 100644
index f68879ca49a..00000000000
--- a/gcc/bt-load.c
+++ /dev/null
@@ -1,1577 +0,0 @@
-/* Perform branch target register load optimizations.
- Copyright (C) 2001-2019 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "target.h"
-#include "rtl.h"
-#include "tree.h"
-#include "df.h"
-#include "insn-config.h"
-#include "regs.h"
-#include "memmodel.h"
-#include "emit-rtl.h"
-#include "recog.h"
-#include "diagnostic-core.h"
-#include "expr.h"
-#include "insn-attr.h"
-#include "tree-pass.h"
-#include "cfgrtl.h"
-#include "cfganal.h"
-#include "cfgcleanup.h"
-#include "cfgloop.h"
-#include "rtl-iter.h"
-#include "fibonacci_heap.h"
-
-struct btr_def;
-
-/* Target register optimizations - these are performed after reload. */
-
-struct btr_def_group
-{
- btr_def_group *next;
- rtx src;
- btr_def *members;
-};
-
-struct btr_user
-{
- btr_user *next;
- basic_block bb;
- int luid;
- rtx_insn *insn;
- /* If INSN has a single use of a single branch register, then
- USE points to it within INSN. If there is more than
- one branch register use, or the use is in some way ambiguous,
- then USE is NULL. */
- rtx use;
- int n_reaching_defs;
- int first_reaching_def;
- char other_use_this_block;
-};
-
-/* btr_def structs appear on three lists:
- 1. A list of all btr_def structures (head is
- ALL_BTR_DEFS, linked by the NEXT field).
- 2. A list of branch reg definitions per basic block (head is
- BB_BTR_DEFS[i], linked by the NEXT_THIS_BB field).
- 3. A list of all branch reg definitions belonging to the same
- group (head is in a BTR_DEF_GROUP struct, linked by
- NEXT_THIS_GROUP field). */
-
-struct btr_def
-{
- btr_def *next_this_bb;
- btr_def *next_this_group;
- basic_block bb;
- int luid;
- rtx_insn *insn;
- int btr;
- int cost;
- /* For a branch register setting insn that has a constant
- source (i.e. a label), group links together all the
- insns with the same source. For other branch register
- setting insns, group is NULL. */
- btr_def_group *group;
- btr_user *uses;
- /* If this def has a reaching use which is not a simple use
- in a branch instruction, then has_ambiguous_use will be true,
- and we will not attempt to migrate this definition. */
- char has_ambiguous_use;
- /* live_range is an approximation to the true live range for this
- def/use web, because it records the set of blocks that contain
- the live range. There could be other live ranges for the same
- branch register in that set of blocks, either in the block
- containing the def (before the def), or in a block containing
- a use (after the use). If there are such other live ranges, then
- other_btr_uses_before_def or other_btr_uses_after_use must be set true
- as appropriate. */
- char other_btr_uses_before_def;
- char other_btr_uses_after_use;
- /* We set own_end when we have moved a definition into a dominator.
- Thus, when a later combination removes this definition again, we know
- to clear out trs_live_at_end again. */
- char own_end;
- bitmap live_range;
-};
-
-typedef fibonacci_heap <long, btr_def> btr_heap_t;
-typedef fibonacci_node <long, btr_def> btr_heap_node_t;
-
-static int issue_rate;
-
-static int basic_block_freq (const_basic_block);
-static int insn_sets_btr_p (const rtx_insn *, int, int *);
-static void find_btr_def_group (btr_def_group **, btr_def *);
-static btr_def *add_btr_def (btr_heap_t *, basic_block, int, rtx_insn *,
- unsigned int, int, btr_def_group **);
-static btr_user *new_btr_user (basic_block, int, rtx_insn *);
-static void dump_hard_reg_set (HARD_REG_SET);
-static void dump_btrs_live (int);
-static void note_other_use_this_block (unsigned int, btr_user *);
-static void compute_defs_uses_and_gen (btr_heap_t *, btr_def **, btr_user **,
- sbitmap *, sbitmap *, HARD_REG_SET *);
-static void compute_kill (sbitmap *, sbitmap *, HARD_REG_SET *);
-static void compute_out (sbitmap *bb_out, sbitmap *, sbitmap *, int);
-static void link_btr_uses (btr_def **, btr_user **, sbitmap *, sbitmap *, int);
-static void build_btr_def_use_webs (btr_heap_t *);
-static int block_at_edge_of_live_range_p (int, btr_def *);
-static void clear_btr_from_live_range (btr_def *def);
-static void add_btr_to_live_range (btr_def *, int);
-static void augment_live_range (bitmap, HARD_REG_SET *, basic_block,
- basic_block, int);
-static int choose_btr (HARD_REG_SET);
-static void combine_btr_defs (btr_def *, HARD_REG_SET *);
-static void btr_def_live_range (btr_def *, HARD_REG_SET *);
-static void move_btr_def (basic_block, int, btr_def *, bitmap, HARD_REG_SET *);
-static int migrate_btr_def (btr_def *, int);
-static void migrate_btr_defs (enum reg_class, int);
-static int can_move_up (const_basic_block, const rtx_insn *, int);
-static void note_btr_set (rtx, const_rtx, void *);
-
-/* The following code performs code motion of target load instructions
- (instructions that set branch target registers), to move them
- forward away from the branch instructions and out of loops (or,
- more generally, from a more frequently executed place to a less
- frequently executed place).
- Moving target load instructions further in front of the branch
- instruction that uses the target register value means that the hardware
- has a better chance of preloading the instructions at the branch
- target by the time the branch is reached. This avoids bubbles
- when a taken branch needs to flush out the pipeline.
- Moving target load instructions out of loops means they are executed
- less frequently. */
-
-/* An obstack to hold the def-use web data structures built up for
- migrating branch target load instructions. */
-static struct obstack migrate_btrl_obstack;
-
-/* Array indexed by basic block number, giving the set of registers
- live in that block. */
-static HARD_REG_SET *btrs_live;
-
-/* Array indexed by basic block number, giving the set of registers live at
- the end of that block, including any uses by a final jump insn, if any. */
-static HARD_REG_SET *btrs_live_at_end;
-
-/* Set of all target registers that we are willing to allocate. */
-static HARD_REG_SET all_btrs;
-
-/* Provide lower and upper bounds for target register numbers, so that
- we don't need to search through all the hard registers all the time. */
-static int first_btr, last_btr;
-
-
-
-/* Return an estimate of the frequency of execution of block bb. */
-static int
-basic_block_freq (const_basic_block bb)
-{
- return bb->count.to_frequency (cfun);
-}
-
-/* If the rtx at *XP references (sets or reads) any branch target
- register, return one such register. If EXCLUDEP is set, disregard
- any references within that location. */
-static rtx *
-find_btr_use (rtx *xp, rtx *excludep = 0)
-{
- subrtx_ptr_iterator::array_type array;
- FOR_EACH_SUBRTX_PTR (iter, array, xp, NONCONST)
- {
- rtx *loc = *iter;
- if (loc == excludep)
- iter.skip_subrtxes ();
- else
- {
- const_rtx x = *loc;
- if (REG_P (x)
- && overlaps_hard_reg_set_p (all_btrs, GET_MODE (x), REGNO (x)))
- return loc;
- }
- }
- return 0;
-}
-
-/* Return true if insn is an instruction that sets a target register.
- if CHECK_CONST is true, only return true if the source is constant.
- If such a set is found and REGNO is nonzero, assign the register number
- of the destination register to *REGNO. */
-static int
-insn_sets_btr_p (const rtx_insn *insn, int check_const, int *regno)
-{
- rtx set;
-
- if (NONJUMP_INSN_P (insn)
- && (set = single_set (insn)))
- {
- rtx dest = SET_DEST (set);
- rtx src = SET_SRC (set);
-
- if (GET_CODE (dest) == SUBREG)
- dest = XEXP (dest, 0);
-
- if (REG_P (dest)
- && TEST_HARD_REG_BIT (all_btrs, REGNO (dest)))
- {
- gcc_assert (!find_btr_use (&src));
-
- if (!check_const || CONSTANT_P (src))
- {
- if (regno)
- *regno = REGNO (dest);
- return 1;
- }
- }
- }
- return 0;
-}
-
-/* Find the group that the target register definition DEF belongs
- to in the list starting with *ALL_BTR_DEF_GROUPS. If no such
- group exists, create one. Add def to the group. */
-static void
-find_btr_def_group (btr_def_group **all_btr_def_groups, btr_def *def)
-{
- if (insn_sets_btr_p (def->insn, 1, NULL))
- {
- btr_def_group *this_group;
- rtx def_src = SET_SRC (single_set (def->insn));
-
- /* ?? This linear search is an efficiency concern, particularly
- as the search will almost always fail to find a match. */
- for (this_group = *all_btr_def_groups;
- this_group != NULL;
- this_group = this_group->next)
- if (rtx_equal_p (def_src, this_group->src))
- break;
-
- if (!this_group)
- {
- this_group = XOBNEW (&migrate_btrl_obstack, btr_def_group);
- this_group->src = def_src;
- this_group->members = NULL;
- this_group->next = *all_btr_def_groups;
- *all_btr_def_groups = this_group;
- }
- def->group = this_group;
- def->next_this_group = this_group->members;
- this_group->members = def;
- }
- else
- def->group = NULL;
-}
-
-/* Create a new target register definition structure, for a definition in
- block BB, instruction INSN, and insert it into ALL_BTR_DEFS. Return
- the new definition. */
-static btr_def *
-add_btr_def (btr_heap_t *all_btr_defs, basic_block bb, int insn_luid,
- rtx_insn *insn,
- unsigned int dest_reg, int other_btr_uses_before_def,
- btr_def_group **all_btr_def_groups)
-{
- btr_def *this_def = XOBNEW (&migrate_btrl_obstack, btr_def);
- this_def->bb = bb;
- this_def->luid = insn_luid;
- this_def->insn = insn;
- this_def->btr = dest_reg;
- this_def->cost = basic_block_freq (bb);
- this_def->has_ambiguous_use = 0;
- this_def->other_btr_uses_before_def = other_btr_uses_before_def;
- this_def->other_btr_uses_after_use = 0;
- this_def->next_this_bb = NULL;
- this_def->next_this_group = NULL;
- this_def->uses = NULL;
- this_def->live_range = NULL;
- find_btr_def_group (all_btr_def_groups, this_def);
-
- all_btr_defs->insert (-this_def->cost, this_def);
-
- if (dump_file)
- fprintf (dump_file,
- "Found target reg definition: sets %u { bb %d, insn %d }%s priority %d\n",
- dest_reg, bb->index, INSN_UID (insn),
- (this_def->group ? "" : ":not const"), this_def->cost);
-
- return this_def;
-}
-
-/* Create a new target register user structure, for a use in block BB,
- instruction INSN. Return the new user. */
-static btr_user *
-new_btr_user (basic_block bb, int insn_luid, rtx_insn *insn)
-{
- /* This instruction reads target registers. We need
- to decide whether we can replace all target register
- uses easily.
- */
- rtx *usep = find_btr_use (&PATTERN (insn));
- rtx use;
- btr_user *user = NULL;
-
- if (usep)
- {
- int unambiguous_single_use;
-
- /* We want to ensure that USE is the only use of a target
- register in INSN, so that we know that to rewrite INSN to use
- a different target register, all we have to do is replace USE. */
- unambiguous_single_use = !find_btr_use (&PATTERN (insn), usep);
- if (!unambiguous_single_use)
- usep = NULL;
- }
- use = usep ? *usep : NULL_RTX;
- user = XOBNEW (&migrate_btrl_obstack, btr_user);
- user->bb = bb;
- user->luid = insn_luid;
- user->insn = insn;
- user->use = use;
- user->other_use_this_block = 0;
- user->next = NULL;
- user->n_reaching_defs = 0;
- user->first_reaching_def = -1;
-
- if (dump_file)
- {
- fprintf (dump_file, "Uses target reg: { bb %d, insn %d }",
- bb->index, INSN_UID (insn));
-
- if (user->use)
- fprintf (dump_file, ": unambiguous use of reg %d\n",
- REGNO (user->use));
- }
-
- return user;
-}
-
-/* Write the contents of S to the dump file. */
-static void
-dump_hard_reg_set (HARD_REG_SET s)
-{
- int reg;
- for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
- if (TEST_HARD_REG_BIT (s, reg))
- fprintf (dump_file, " %d", reg);
-}
-
-/* Write the set of target regs live in block BB to the dump file. */
-static void
-dump_btrs_live (int bb)
-{
- fprintf (dump_file, "BB%d live:", bb);
- dump_hard_reg_set (btrs_live[bb]);
- fprintf (dump_file, "\n");
-}
-
-/* REGNO is the number of a branch target register that is being used or
- set. USERS_THIS_BB is a list of preceding branch target register users;
- If any of them use the same register, set their other_use_this_block
- flag. */
-static void
-note_other_use_this_block (unsigned int regno, btr_user *users_this_bb)
-{
- btr_user *user;
-
- for (user = users_this_bb; user != NULL; user = user->next)
- if (user->use && REGNO (user->use) == regno)
- user->other_use_this_block = 1;
-}
-
-struct defs_uses_info {
- btr_user *users_this_bb;
- HARD_REG_SET btrs_written_in_block;
- HARD_REG_SET btrs_live_in_block;
- sbitmap bb_gen;
- sbitmap *btr_defset;
-};
-
-/* Called via note_stores or directly to register stores into /
- clobbers of a branch target register DEST that are not recognized as
- straightforward definitions. DATA points to information about the
- current basic block that needs updating. */
-static void
-note_btr_set (rtx dest, const_rtx set ATTRIBUTE_UNUSED, void *data)
-{
- defs_uses_info *info = (defs_uses_info *) data;
- int regno, end_regno;
-
- if (!REG_P (dest))
- return;
- regno = REGNO (dest);
- end_regno = END_REGNO (dest);
- for (; regno < end_regno; regno++)
- if (TEST_HARD_REG_BIT (all_btrs, regno))
- {
- note_other_use_this_block (regno, info->users_this_bb);
- SET_HARD_REG_BIT (info->btrs_written_in_block, regno);
- SET_HARD_REG_BIT (info->btrs_live_in_block, regno);
- bitmap_and_compl (info->bb_gen, info->bb_gen,
- info->btr_defset[regno - first_btr]);
- }
-}
-
-static void
-compute_defs_uses_and_gen (btr_heap_t *all_btr_defs, btr_def **def_array,
- btr_user **use_array, sbitmap *btr_defset,
- sbitmap *bb_gen, HARD_REG_SET *btrs_written)
-{
- /* Scan the code building up the set of all defs and all uses.
- For each target register, build the set of defs of that register.
- For each block, calculate the set of target registers
- written in that block.
- Also calculate the set of btrs ever live in that block.
- */
- int i;
- int insn_luid = 0;
- btr_def_group *all_btr_def_groups = NULL;
- defs_uses_info info;
-
- bitmap_vector_clear (bb_gen, last_basic_block_for_fn (cfun));
- for (i = NUM_FIXED_BLOCKS; i < last_basic_block_for_fn (cfun); i++)
- {
- basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
- int reg;
- btr_def *defs_this_bb = NULL;
- rtx_insn *insn;
- rtx_insn *last;
- int can_throw = 0;
-
- info.users_this_bb = NULL;
- info.bb_gen = bb_gen[i];
- info.btr_defset = btr_defset;
-
- CLEAR_HARD_REG_SET (info.btrs_live_in_block);
- CLEAR_HARD_REG_SET (info.btrs_written_in_block);
- for (reg = first_btr; reg <= last_btr; reg++)
- if (TEST_HARD_REG_BIT (all_btrs, reg)
- && REGNO_REG_SET_P (df_get_live_in (bb), reg))
- SET_HARD_REG_BIT (info.btrs_live_in_block, reg);
-
- for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb));
- insn != last;
- insn = NEXT_INSN (insn), insn_luid++)
- {
- if (INSN_P (insn))
- {
- int regno;
- int insn_uid = INSN_UID (insn);
-
- if (insn_sets_btr_p (insn, 0, &regno))
- {
- btr_def *def = add_btr_def (
- all_btr_defs, bb, insn_luid, insn, regno,
- TEST_HARD_REG_BIT (info.btrs_live_in_block, regno),
- &all_btr_def_groups);
-
- def_array[insn_uid] = def;
- SET_HARD_REG_BIT (info.btrs_written_in_block, regno);
- SET_HARD_REG_BIT (info.btrs_live_in_block, regno);
- bitmap_and_compl (bb_gen[i], bb_gen[i],
- btr_defset[regno - first_btr]);
- bitmap_set_bit (bb_gen[i], insn_uid);
- def->next_this_bb = defs_this_bb;
- defs_this_bb = def;
- bitmap_set_bit (btr_defset[regno - first_btr], insn_uid);
- note_other_use_this_block (regno, info.users_this_bb);
- }
- /* Check for the blockage emitted by expand_nl_goto_receiver. */
- else if (cfun->has_nonlocal_label
- && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE)
- {
- btr_user *user;
-
- /* Do the equivalent of calling note_other_use_this_block
- for every target register. */
- for (user = info.users_this_bb; user != NULL;
- user = user->next)
- if (user->use)
- user->other_use_this_block = 1;
- IOR_HARD_REG_SET (info.btrs_written_in_block, all_btrs);
- IOR_HARD_REG_SET (info.btrs_live_in_block, all_btrs);
- bitmap_clear (info.bb_gen);
- }
- else
- {
- if (find_btr_use (&PATTERN (insn)))
- {
- btr_user *user = new_btr_user (bb, insn_luid, insn);
-
- use_array[insn_uid] = user;
- if (user->use)
- SET_HARD_REG_BIT (info.btrs_live_in_block,
- REGNO (user->use));
- else
- {
- int reg;
- for (reg = first_btr; reg <= last_btr; reg++)
- if (TEST_HARD_REG_BIT (all_btrs, reg)
- && refers_to_regno_p (reg, user->insn))
- {
- note_other_use_this_block (reg,
- info.users_this_bb);
- SET_HARD_REG_BIT (info.btrs_live_in_block, reg);
- }
- note_stores (PATTERN (insn), note_btr_set, &info);
- }
- user->next = info.users_this_bb;
- info.users_this_bb = user;
- }
- if (CALL_P (insn))
- {
- HARD_REG_SET *clobbered = &call_used_reg_set;
- HARD_REG_SET call_saved;
- rtx pat = PATTERN (insn);
- int i;
-
- /* Check for sibcall. */
- if (GET_CODE (pat) == PARALLEL)
- for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
- if (ANY_RETURN_P (XVECEXP (pat, 0, i)))
- {
- COMPL_HARD_REG_SET (call_saved,
- call_used_reg_set);
- clobbered = &call_saved;
- }
-
- for (regno = first_btr; regno <= last_btr; regno++)
- if (TEST_HARD_REG_BIT (*clobbered, regno))
- note_btr_set (regno_reg_rtx[regno], NULL_RTX, &info);
- }
- }
- }
- }
-
- COPY_HARD_REG_SET (btrs_live[i], info.btrs_live_in_block);
- COPY_HARD_REG_SET (btrs_written[i], info.btrs_written_in_block);
-
- REG_SET_TO_HARD_REG_SET (btrs_live_at_end[i], df_get_live_out (bb));
- /* If this block ends in a jump insn, add any uses or even clobbers
- of branch target registers that it might have. */
- for (insn = BB_END (bb); insn != BB_HEAD (bb) && ! INSN_P (insn); )
- insn = PREV_INSN (insn);
- /* ??? for the fall-through edge, it would make sense to insert the
- btr set on the edge, but that would require to split the block
- early on so that we can distinguish between dominance from the fall
- through edge - which can use the call-clobbered registers - from
- dominance by the throw edge. */
- if (can_throw_internal (insn))
- {
- HARD_REG_SET tmp;
-
- COPY_HARD_REG_SET (tmp, call_used_reg_set);
- AND_HARD_REG_SET (tmp, all_btrs);
- IOR_HARD_REG_SET (btrs_live_at_end[i], tmp);
- can_throw = 1;
- }
- if (can_throw || JUMP_P (insn))
- {
- int regno;
-
- for (regno = first_btr; regno <= last_btr; regno++)
- if (refers_to_regno_p (regno, insn))
- SET_HARD_REG_BIT (btrs_live_at_end[i], regno);
- }
-
- if (dump_file)
- dump_btrs_live (i);
- }
-}
-
-static void
-compute_kill (sbitmap *bb_kill, sbitmap *btr_defset,
- HARD_REG_SET *btrs_written)
-{
- int i;
- int regno;
-
- /* For each basic block, form the set BB_KILL - the set
- of definitions that the block kills. */
- bitmap_vector_clear (bb_kill, last_basic_block_for_fn (cfun));
- for (i = NUM_FIXED_BLOCKS; i < last_basic_block_for_fn (cfun); i++)
- {
- for (regno = first_btr; regno <= last_btr; regno++)
- if (TEST_HARD_REG_BIT (all_btrs, regno)
- && TEST_HARD_REG_BIT (btrs_written[i], regno))
- bitmap_ior (bb_kill[i], bb_kill[i],
- btr_defset[regno - first_btr]);
- }
-}
-
-static void
-compute_out (sbitmap *bb_out, sbitmap *bb_gen, sbitmap *bb_kill, int max_uid)
-{
- /* Perform iterative dataflow:
- Initially, for all blocks, BB_OUT = BB_GEN.
- For each block,
- BB_IN = union over predecessors of BB_OUT(pred)
- BB_OUT = (BB_IN - BB_KILL) + BB_GEN
- Iterate until the bb_out sets stop growing. */
- int i;
- int changed;
- auto_sbitmap bb_in (max_uid);
-
- for (i = NUM_FIXED_BLOCKS; i < last_basic_block_for_fn (cfun); i++)
- bitmap_copy (bb_out[i], bb_gen[i]);
-
- changed = 1;
- while (changed)
- {
- changed = 0;
- for (i = NUM_FIXED_BLOCKS; i < last_basic_block_for_fn (cfun); i++)
- {
- bitmap_union_of_preds (bb_in, bb_out, BASIC_BLOCK_FOR_FN (cfun, i));
- changed |= bitmap_ior_and_compl (bb_out[i], bb_gen[i],
- bb_in, bb_kill[i]);
- }
- }
-}
-
-static void
-link_btr_uses (btr_def **def_array, btr_user **use_array, sbitmap *bb_out,
- sbitmap *btr_defset, int max_uid)
-{
- int i;
- auto_sbitmap reaching_defs (max_uid);
-
- /* Link uses to the uses lists of all of their reaching defs.
- Count up the number of reaching defs of each use. */
- for (i = NUM_FIXED_BLOCKS; i < last_basic_block_for_fn (cfun); i++)
- {
- basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
- rtx_insn *insn;
- rtx_insn *last;
-
- bitmap_union_of_preds (reaching_defs, bb_out, BASIC_BLOCK_FOR_FN (cfun, i));
- for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb));
- insn != last;
- insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- {
- int insn_uid = INSN_UID (insn);
-
- btr_def *def = def_array[insn_uid];
- btr_user *user = use_array[insn_uid];
- if (def != NULL)
- {
- /* Remove all reaching defs of regno except
- for this one. */
- bitmap_and_compl (reaching_defs, reaching_defs,
- btr_defset[def->btr - first_btr]);
- bitmap_set_bit (reaching_defs, insn_uid);
- }
-
- if (user != NULL)
- {
- /* Find all the reaching defs for this use. */
- auto_sbitmap reaching_defs_of_reg (max_uid);
- unsigned int uid = 0;
- sbitmap_iterator sbi;
-
- if (user->use)
- bitmap_and (
- reaching_defs_of_reg,
- reaching_defs,
- btr_defset[REGNO (user->use) - first_btr]);
- else
- {
- int reg;
-
- bitmap_clear (reaching_defs_of_reg);
- for (reg = first_btr; reg <= last_btr; reg++)
- if (TEST_HARD_REG_BIT (all_btrs, reg)
- && refers_to_regno_p (reg, user->insn))
- bitmap_or_and (reaching_defs_of_reg,
- reaching_defs_of_reg,
- reaching_defs,
- btr_defset[reg - first_btr]);
- }
- EXECUTE_IF_SET_IN_BITMAP (reaching_defs_of_reg, 0, uid, sbi)
- {
- btr_def *def = def_array[uid];
-
- /* We now know that def reaches user. */
-
- if (dump_file)
- fprintf (dump_file,
- "Def in insn %d reaches use in insn %d\n",
- uid, insn_uid);
-
- user->n_reaching_defs++;
- if (!user->use)
- def->has_ambiguous_use = 1;
- if (user->first_reaching_def != -1)
- { /* There is more than one reaching def. This is
- a rare case, so just give up on this def/use
- web when it occurs. */
- def->has_ambiguous_use = 1;
- def_array[user->first_reaching_def]
- ->has_ambiguous_use = 1;
- if (dump_file)
- fprintf (dump_file,
- "(use %d has multiple reaching defs)\n",
- insn_uid);
- }
- else
- user->first_reaching_def = uid;
- if (user->other_use_this_block)
- def->other_btr_uses_after_use = 1;
- user->next = def->uses;
- def->uses = user;
- }
- }
-
- if (CALL_P (insn))
- {
- int regno;
-
- for (regno = first_btr; regno <= last_btr; regno++)
- if (TEST_HARD_REG_BIT (all_btrs, regno)
- && TEST_HARD_REG_BIT (call_used_reg_set, regno))
- bitmap_and_compl (reaching_defs, reaching_defs,
- btr_defset[regno - first_btr]);
- }
- }
- }
- }
-}
-
-static void
-build_btr_def_use_webs (btr_heap_t *all_btr_defs)
-{
- const int max_uid = get_max_uid ();
- btr_def **def_array = XCNEWVEC (btr_def *, max_uid);
- btr_user **use_array = XCNEWVEC (btr_user *, max_uid);
- sbitmap *btr_defset = sbitmap_vector_alloc (
- (last_btr - first_btr) + 1, max_uid);
- sbitmap *bb_gen = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
- max_uid);
- HARD_REG_SET *btrs_written = XCNEWVEC (HARD_REG_SET,
- last_basic_block_for_fn (cfun));
- sbitmap *bb_kill;
- sbitmap *bb_out;
-
- bitmap_vector_clear (btr_defset, (last_btr - first_btr) + 1);
-
- compute_defs_uses_and_gen (all_btr_defs, def_array, use_array, btr_defset,
- bb_gen, btrs_written);
-
- bb_kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), max_uid);
- compute_kill (bb_kill, btr_defset, btrs_written);
- free (btrs_written);
-
- bb_out = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), max_uid);
- compute_out (bb_out, bb_gen, bb_kill, max_uid);
-
- sbitmap_vector_free (bb_gen);
- sbitmap_vector_free (bb_kill);
-
- link_btr_uses (def_array, use_array, bb_out, btr_defset, max_uid);
-
- sbitmap_vector_free (bb_out);
- sbitmap_vector_free (btr_defset);
- free (use_array);
- free (def_array);
-}
-
-/* Return true if basic block BB contains the start or end of the
- live range of the definition DEF, AND there are other live
- ranges of the same target register that include BB. */
-static int
-block_at_edge_of_live_range_p (int bb, btr_def *def)
-{
- if (def->other_btr_uses_before_def
- && BASIC_BLOCK_FOR_FN (cfun, bb) == def->bb)
- return 1;
- else if (def->other_btr_uses_after_use)
- {
- btr_user *user;
- for (user = def->uses; user != NULL; user = user->next)
- if (BASIC_BLOCK_FOR_FN (cfun, bb) == user->bb)
- return 1;
- }
- return 0;
-}
-
-/* We are removing the def/use web DEF. The target register
- used in this web is therefore no longer live in the live range
- of this web, so remove it from the live set of all basic blocks
- in the live range of the web.
- Blocks at the boundary of the live range may contain other live
- ranges for the same target register, so we have to be careful
- to remove the target register from the live set of these blocks
- only if they do not contain other live ranges for the same register. */
-static void
-clear_btr_from_live_range (btr_def *def)
-{
- unsigned bb;
- bitmap_iterator bi;
-
- EXECUTE_IF_SET_IN_BITMAP (def->live_range, 0, bb, bi)
- {
- if ((!def->other_btr_uses_before_def
- && !def->other_btr_uses_after_use)
- || !block_at_edge_of_live_range_p (bb, def))
- {
- CLEAR_HARD_REG_BIT (btrs_live[bb], def->btr);
- CLEAR_HARD_REG_BIT (btrs_live_at_end[bb], def->btr);
- if (dump_file)
- dump_btrs_live (bb);
- }
- }
- if (def->own_end)
- CLEAR_HARD_REG_BIT (btrs_live_at_end[def->bb->index], def->btr);
-}
-
-
-/* We are adding the def/use web DEF. Add the target register used
- in this web to the live set of all of the basic blocks that contain
- the live range of the web.
- If OWN_END is set, also show that the register is live from our
- definitions at the end of the basic block where it is defined. */
-static void
-add_btr_to_live_range (btr_def *def, int own_end)
-{
- unsigned bb;
- bitmap_iterator bi;
-
- EXECUTE_IF_SET_IN_BITMAP (def->live_range, 0, bb, bi)
- {
- SET_HARD_REG_BIT (btrs_live[bb], def->btr);
- SET_HARD_REG_BIT (btrs_live_at_end[bb], def->btr);
- if (dump_file)
- dump_btrs_live (bb);
- }
- if (own_end)
- {
- SET_HARD_REG_BIT (btrs_live_at_end[def->bb->index], def->btr);
- def->own_end = 1;
- }
-}
-
-/* Update a live range to contain the basic block NEW_BLOCK, and all
- blocks on paths between the existing live range and NEW_BLOCK.
- HEAD is a block contained in the existing live range that dominates
- all other blocks in the existing live range.
- Also add to the set BTRS_LIVE_IN_RANGE all target registers that
- are live in the blocks that we add to the live range.
- If FULL_RANGE is set, include the full live range of NEW_BB;
- otherwise, if NEW_BB dominates HEAD_BB, only add registers that
- are life at the end of NEW_BB for NEW_BB itself.
- It is a precondition that either NEW_BLOCK dominates HEAD,or
- HEAD dom NEW_BLOCK. This is used to speed up the
- implementation of this function. */
-static void
-augment_live_range (bitmap live_range, HARD_REG_SET *btrs_live_in_range,
- basic_block head_bb, basic_block new_bb, int full_range)
-{
- basic_block *worklist, *tos;
-
- tos = worklist = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun) + 1);
-
- if (dominated_by_p (CDI_DOMINATORS, new_bb, head_bb))
- {
- if (new_bb == head_bb)
- {
- if (full_range)
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[new_bb->index]);
- free (tos);
- return;
- }
- *tos++ = new_bb;
- }
- else
- {
- edge e;
- edge_iterator ei;
- int new_block = new_bb->index;
-
- gcc_assert (dominated_by_p (CDI_DOMINATORS, head_bb, new_bb));
-
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[head_bb->index]);
- bitmap_set_bit (live_range, new_block);
- /* A previous btr migration could have caused a register to be
- live just at the end of new_block which we need in full, so
- use trs_live_at_end even if full_range is set. */
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live_at_end[new_block]);
- if (full_range)
- IOR_HARD_REG_SET (*btrs_live_in_range, btrs_live[new_block]);
- if (dump_file)
- {
- fprintf (dump_file,
- "Adding end of block %d and rest of %d to live range\n",
- new_block, head_bb->index);
- fprintf (dump_file,"Now live btrs are ");
- dump_hard_reg_set (*btrs_live_in_range);
- fprintf (dump_file, "\n");
- }
- FOR_EACH_EDGE (e, ei, head_bb->preds)
- *tos++ = e->src;
- }
-
- while (tos != worklist)
- {
- basic_block bb = *--tos;
- if (!bitmap_bit_p (live_range, bb->index))
- {
- edge e;
- edge_iterator ei;
-
- bitmap_set_bit (live_range, bb->index);
- IOR_HARD_REG_SET (*btrs_live_in_range,
- btrs_live[bb->index]);
- /* A previous btr migration could have caused a register to be
- live just at the end of a block which we need in full. */
- IOR_HARD_REG_SET (*btrs_live_in_range,
- btrs_live_at_end[bb->index]);
- if (dump_file)
- {
- fprintf (dump_file,
- "Adding block %d to live range\n", bb->index);
- fprintf (dump_file,"Now live btrs are ");
- dump_hard_reg_set (*btrs_live_in_range);
- fprintf (dump_file, "\n");
- }
-
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- basic_block pred = e->src;
- if (!bitmap_bit_p (live_range, pred->index))
- *tos++ = pred;
- }
- }
- }
-
- free (worklist);
-}
-
-/* Return the most desirable target register that is not in
- the set USED_BTRS. */
-static int
-choose_btr (HARD_REG_SET used_btrs)
-{
- int i;
-
- if (!hard_reg_set_subset_p (all_btrs, used_btrs))
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
-#ifdef REG_ALLOC_ORDER
- int regno = reg_alloc_order[i];
-#else
- int regno = i;
-#endif
- if (TEST_HARD_REG_BIT (all_btrs, regno)
- && !TEST_HARD_REG_BIT (used_btrs, regno))
- return regno;
- }
- return -1;
-}
-
-/* Calculate the set of basic blocks that contain the live range of
- the def/use web DEF.
- Also calculate the set of target registers that are live at time
- in this live range, but ignore the live range represented by DEF
- when calculating this set. */
-static void
-btr_def_live_range (btr_def *def, HARD_REG_SET *btrs_live_in_range)
-{
- if (!def->live_range)
- {
- btr_user *user;
-
- def->live_range = BITMAP_ALLOC (NULL);
-
- bitmap_set_bit (def->live_range, def->bb->index);
- COPY_HARD_REG_SET (*btrs_live_in_range,
- (flag_btr_bb_exclusive
- ? btrs_live : btrs_live_at_end)[def->bb->index]);
-
- for (user = def->uses; user != NULL; user = user->next)
- augment_live_range (def->live_range, btrs_live_in_range,
- def->bb, user->bb,
- (flag_btr_bb_exclusive
- || user->insn != BB_END (def->bb)
- || !JUMP_P (user->insn)));
- }
- else
- {
- /* def->live_range is accurate, but we need to recompute
- the set of target registers live over it, because migration
- of other PT instructions may have affected it.
- */
- unsigned bb;
- unsigned def_bb = flag_btr_bb_exclusive ? -1 : def->bb->index;
- bitmap_iterator bi;
-
- CLEAR_HARD_REG_SET (*btrs_live_in_range);
- EXECUTE_IF_SET_IN_BITMAP (def->live_range, 0, bb, bi)
- {
- IOR_HARD_REG_SET (*btrs_live_in_range,
- (def_bb == bb
- ? btrs_live_at_end : btrs_live) [bb]);
- }
- }
- if (!def->other_btr_uses_before_def &&
- !def->other_btr_uses_after_use)
- CLEAR_HARD_REG_BIT (*btrs_live_in_range, def->btr);
-}
-
-/* Merge into the def/use web DEF any other def/use webs in the same
- group that are dominated by DEF, provided that there is a target
- register available to allocate to the merged web. */
-static void
-combine_btr_defs (btr_def *def, HARD_REG_SET *btrs_live_in_range)
-{
- btr_def *other_def;
-
- for (other_def = def->group->members;
- other_def != NULL;
- other_def = other_def->next_this_group)
- {
- if (other_def != def
- && other_def->uses != NULL
- && ! other_def->has_ambiguous_use
- && dominated_by_p (CDI_DOMINATORS, other_def->bb, def->bb))
- {
- /* def->bb dominates the other def, so def and other_def could
- be combined. */
- /* Merge their live ranges, and get the set of
- target registers live over the merged range. */
- int btr;
- HARD_REG_SET combined_btrs_live;
- auto_bitmap combined_live_range;
- btr_user *user;
-
- if (other_def->live_range == NULL)
- {
- HARD_REG_SET dummy_btrs_live_in_range;
- btr_def_live_range (other_def, &dummy_btrs_live_in_range);
- }
- COPY_HARD_REG_SET (combined_btrs_live, *btrs_live_in_range);
- bitmap_copy (combined_live_range, def->live_range);
-
- for (user = other_def->uses; user != NULL; user = user->next)
- augment_live_range (combined_live_range, &combined_btrs_live,
- def->bb, user->bb,
- (flag_btr_bb_exclusive
- || user->insn != BB_END (def->bb)
- || !JUMP_P (user->insn)));
-
- btr = choose_btr (combined_btrs_live);
- if (btr != -1)
- {
- /* We can combine them. */
- if (dump_file)
- fprintf (dump_file,
- "Combining def in insn %d with def in insn %d\n",
- INSN_UID (other_def->insn), INSN_UID (def->insn));
-
- def->btr = btr;
- user = other_def->uses;
- while (user != NULL)
- {
- btr_user *next = user->next;
-
- user->next = def->uses;
- def->uses = user;
- user = next;
- }
- /* Combining def/use webs can make target registers live
- after uses where they previously were not. This means
- some REG_DEAD notes may no longer be correct. We could
- be more precise about this if we looked at the combined
- live range, but here I just delete any REG_DEAD notes
- in case they are no longer correct. */
- for (user = def->uses; user != NULL; user = user->next)
- remove_note (user->insn,
- find_regno_note (user->insn, REG_DEAD,
- REGNO (user->use)));
- clear_btr_from_live_range (other_def);
- other_def->uses = NULL;
- bitmap_copy (def->live_range, combined_live_range);
- if (other_def->btr == btr && other_def->other_btr_uses_after_use)
- def->other_btr_uses_after_use = 1;
- COPY_HARD_REG_SET (*btrs_live_in_range, combined_btrs_live);
-
- /* Delete the old target register initialization. */
- delete_insn (other_def->insn);
-
- }
- }
- }
-}
-
-/* Move the definition DEF from its current position to basic
- block NEW_DEF_BB, and modify it to use branch target register BTR.
- Delete the old defining insn, and insert a new one in NEW_DEF_BB.
- Update all reaching uses of DEF in the RTL to use BTR.
- If this new position means that other defs in the
- same group can be combined with DEF then combine them. */
-static void
-move_btr_def (basic_block new_def_bb, int btr, btr_def *def, bitmap live_range,
- HARD_REG_SET *btrs_live_in_range)
-{
- /* We can move the instruction.
- Set a target register in block NEW_DEF_BB to the value
- needed for this target register definition.
- Replace all uses of the old target register definition by
- uses of the new definition. Delete the old definition. */
- basic_block b = new_def_bb;
- rtx_insn *insp = BB_HEAD (b);
- rtx_insn *old_insn = def->insn;
- rtx src;
- rtx btr_rtx;
- rtx_insn *new_insn;
- machine_mode btr_mode;
- btr_user *user;
- rtx set;
-
- if (dump_file)
- fprintf(dump_file, "migrating to basic block %d, using reg %d\n",
- new_def_bb->index, btr);
-
- clear_btr_from_live_range (def);
- def->btr = btr;
- def->bb = new_def_bb;
- def->luid = 0;
- def->cost = basic_block_freq (new_def_bb);
- bitmap_copy (def->live_range, live_range);
- combine_btr_defs (def, btrs_live_in_range);
- btr = def->btr;
- def->other_btr_uses_before_def
- = TEST_HARD_REG_BIT (btrs_live[b->index], btr) ? 1 : 0;
- add_btr_to_live_range (def, 1);
- if (LABEL_P (insp))
- insp = NEXT_INSN (insp);
- /* N.B.: insp is expected to be NOTE_INSN_BASIC_BLOCK now. Some
- optimizations can result in insp being both first and last insn of
- its basic block. */
- /* ?? some assertions to check that insp is sensible? */
-
- if (def->other_btr_uses_before_def)
- {
- for (insp = BB_END (b); ! INSN_P (insp); insp = PREV_INSN (insp))
- gcc_assert (insp != BB_HEAD (b));
-
- if (JUMP_P (insp) || can_throw_internal (insp))
- insp = PREV_INSN (insp);
- }
-
- set = single_set (old_insn);
- src = SET_SRC (set);
- btr_mode = GET_MODE (SET_DEST (set));
- btr_rtx = gen_rtx_REG (btr_mode, btr);
-
- new_insn = gen_move_insn (btr_rtx, src);
-
- /* Insert target register initialization at head of basic block. */
- def->insn = emit_insn_after (new_insn, insp);
-
- df_set_regs_ever_live (btr, true);
-
- if (dump_file)
- fprintf (dump_file, "New pt is insn %d, inserted after insn %d\n",
- INSN_UID (def->insn), INSN_UID (insp));
-
- /* Delete the old target register initialization. */
- delete_insn (old_insn);
-
- /* Replace each use of the old target register by a use of the new target
- register. */
- for (user = def->uses; user != NULL; user = user->next)
- {
- /* Some extra work here to ensure consistent modes, because
- it seems that a target register REG rtx can be given a different
- mode depending on the context (surely that should not be
- the case?). */
- rtx replacement_rtx;
- if (GET_MODE (user->use) == GET_MODE (btr_rtx)
- || GET_MODE (user->use) == VOIDmode)
- replacement_rtx = btr_rtx;
- else
- replacement_rtx = gen_rtx_REG (GET_MODE (user->use), btr);
- validate_replace_rtx (user->use, replacement_rtx, user->insn);
- user->use = replacement_rtx;
- }
-}
-
-/* We anticipate intra-block scheduling to be done. See if INSN could move
- up within BB by N_INSNS. */
-static int
-can_move_up (const_basic_block bb, const rtx_insn *insn, int n_insns)
-{
- while (insn != BB_HEAD (bb) && n_insns > 0)
- {
- insn = PREV_INSN (insn);
- /* ??? What if we have an anti-dependency that actually prevents the
- scheduler from doing the move? We'd like to re-allocate the register,
- but not necessarily put the load into another basic block. */
- if (INSN_P (insn))
- n_insns--;
- }
- return n_insns <= 0;
-}
-
-/* Attempt to migrate the target register definition DEF to an
- earlier point in the flowgraph.
-
- It is a precondition of this function that DEF is migratable:
- i.e. it has a constant source, and all uses are unambiguous.
-
- Only migrations that reduce the cost of DEF will be made.
- MIN_COST is the lower bound on the cost of the DEF after migration.
- If we migrate DEF so that its cost falls below MIN_COST,
- then we do not attempt to migrate further. The idea is that
- we migrate definitions in a priority order based on their cost,
- when the cost of this definition falls below MIN_COST, then
- there is another definition with cost == MIN_COST which now
- has a higher priority than this definition.
-
- Return nonzero if there may be benefit from attempting to
- migrate this DEF further (i.e. we have reduced the cost below
- MIN_COST, but we may be able to reduce it further).
- Return zero if no further migration is possible. */
-static int
-migrate_btr_def (btr_def *def, int min_cost)
-{
- HARD_REG_SET btrs_live_in_range;
- int btr_used_near_def = 0;
- int def_basic_block_freq;
- basic_block attempt;
- int give_up = 0;
- int def_moved = 0;
- btr_user *user;
- int def_latency;
-
- if (dump_file)
- fprintf (dump_file,
- "Attempting to migrate pt from insn %d (cost = %d, min_cost = %d) ... ",
- INSN_UID (def->insn), def->cost, min_cost);
-
- if (!def->group || def->has_ambiguous_use)
- /* These defs are not migratable. */
- {
- if (dump_file)
- fprintf (dump_file, "it's not migratable\n");
- return 0;
- }
-
- if (!def->uses)
- /* We have combined this def with another in the same group, so
- no need to consider it further.
- */
- {
- if (dump_file)
- fprintf (dump_file, "it's already combined with another pt\n");
- return 0;
- }
-
- btr_def_live_range (def, &btrs_live_in_range);
- auto_bitmap live_range;
- bitmap_copy (live_range, def->live_range);
-
-#ifdef INSN_SCHEDULING
- def_latency = insn_default_latency (def->insn) * issue_rate;
-#else
- def_latency = issue_rate;
-#endif
-
- for (user = def->uses; user != NULL; user = user->next)
- {
- if (user->bb == def->bb
- && user->luid > def->luid
- && (def->luid + def_latency) > user->luid
- && ! can_move_up (def->bb, def->insn,
- (def->luid + def_latency) - user->luid))
- {
- btr_used_near_def = 1;
- break;
- }
- }
-
- def_basic_block_freq = basic_block_freq (def->bb);
-
- for (attempt = get_immediate_dominator (CDI_DOMINATORS, def->bb);
- !give_up && attempt && attempt != ENTRY_BLOCK_PTR_FOR_FN (cfun)
- && def->cost >= min_cost;
- attempt = get_immediate_dominator (CDI_DOMINATORS, attempt))
- {
- /* Try to move the instruction that sets the target register into
- basic block ATTEMPT. */
- int try_freq = basic_block_freq (attempt);
- edge_iterator ei;
- edge e;
-
- /* If ATTEMPT has abnormal edges, skip it. */
- FOR_EACH_EDGE (e, ei, attempt->succs)
- if (e->flags & EDGE_COMPLEX)
- break;
- if (e)
- continue;
-
- if (dump_file)
- fprintf (dump_file, "trying block %d ...", attempt->index);
-
- if (try_freq < def_basic_block_freq
- || (try_freq == def_basic_block_freq && btr_used_near_def))
- {
- int btr;
- augment_live_range (live_range, &btrs_live_in_range, def->bb, attempt,
- flag_btr_bb_exclusive);
- if (dump_file)
- {
- fprintf (dump_file, "Now btrs live in range are: ");
- dump_hard_reg_set (btrs_live_in_range);
- fprintf (dump_file, "\n");
- }
- btr = choose_btr (btrs_live_in_range);
- if (btr != -1)
- {
- move_btr_def (attempt, btr, def, live_range, &btrs_live_in_range);
- bitmap_copy (live_range, def->live_range);
- btr_used_near_def = 0;
- def_moved = 1;
- def_basic_block_freq = basic_block_freq (def->bb);
- }
- else
- {
- /* There are no free target registers available to move
- this far forward, so give up */
- give_up = 1;
- if (dump_file)
- fprintf (dump_file,
- "giving up because there are no free target registers\n");
- }
-
- }
- }
- if (!def_moved)
- {
- give_up = 1;
- if (dump_file)
- fprintf (dump_file, "failed to move\n");
- }
-
- return !give_up;
-}
-
-/* Attempt to move instructions that set target registers earlier
- in the flowgraph, away from their corresponding uses. */
-static void
-migrate_btr_defs (enum reg_class btr_class, int allow_callee_save)
-{
- btr_heap_t all_btr_defs (LONG_MIN);
- int reg;
-
- gcc_obstack_init (&migrate_btrl_obstack);
- if (dump_file)
- {
- int i;
-
- for (i = NUM_FIXED_BLOCKS; i < last_basic_block_for_fn (cfun); i++)
- {
- basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
- fprintf (dump_file, "Basic block %d: count = ", i);
- bb->count.dump (dump_file);
- fprintf (dump_file, " loop-depth = %d idom = %d\n",
- bb_loop_depth (bb),
- get_immediate_dominator (CDI_DOMINATORS, bb)->index);
- }
- }
-
- CLEAR_HARD_REG_SET (all_btrs);
- for (first_btr = -1, reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
- if (TEST_HARD_REG_BIT (reg_class_contents[(int) btr_class], reg)
- && (allow_callee_save || call_used_regs[reg]
- || df_regs_ever_live_p (reg)))
- {
- SET_HARD_REG_BIT (all_btrs, reg);
- last_btr = reg;
- if (first_btr < 0)
- first_btr = reg;
- }
-
- btrs_live = XCNEWVEC (HARD_REG_SET, last_basic_block_for_fn (cfun));
- btrs_live_at_end = XCNEWVEC (HARD_REG_SET, last_basic_block_for_fn (cfun));
-
- build_btr_def_use_webs (&all_btr_defs);
-
- while (!all_btr_defs.empty ())
- {
- int min_cost = -all_btr_defs.min_key ();
- btr_def *def = all_btr_defs.extract_min ();
- if (migrate_btr_def (def, min_cost))
- {
- all_btr_defs.insert (-def->cost, def);
- if (dump_file)
- {
- fprintf (dump_file,
- "Putting insn %d back on queue with priority %d\n",
- INSN_UID (def->insn), def->cost);
- }
- }
- else
- BITMAP_FREE (def->live_range);
- }
-
- free (btrs_live);
- free (btrs_live_at_end);
- obstack_free (&migrate_btrl_obstack, NULL);
-}
-
-static void
-branch_target_load_optimize (bool after_prologue_epilogue_gen)
-{
- enum reg_class klass
- = (enum reg_class) targetm.branch_target_register_class ();
- if (klass != NO_REGS)
- {
- /* Initialize issue_rate. */
- if (targetm.sched.issue_rate)
- issue_rate = targetm.sched.issue_rate ();
- else
- issue_rate = 1;
-
- if (!after_prologue_epilogue_gen)
- {
- /* Build the CFG for migrate_btr_defs. */
-#if 1
- /* This may or may not be needed, depending on where we
- run this phase. */
- cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
-#endif
- }
- df_analyze ();
-
-
- /* Dominator info is also needed for migrate_btr_def. */
- calculate_dominance_info (CDI_DOMINATORS);
- migrate_btr_defs (klass,
- (targetm.branch_target_register_callee_saved
- (after_prologue_epilogue_gen)));
-
- free_dominance_info (CDI_DOMINATORS);
- }
-}
-
-namespace {
-
-const pass_data pass_data_branch_target_load_optimize1 =
-{
- RTL_PASS, /* type */
- "btl1", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_branch_target_load_optimize1 : public rtl_opt_pass
-{
-public:
- pass_branch_target_load_optimize1 (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_branch_target_load_optimize1, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *) { return flag_branch_target_load_optimize; }
- virtual unsigned int execute (function *)
- {
- branch_target_load_optimize (epilogue_completed);
- return 0;
- }
-
-}; // class pass_branch_target_load_optimize1
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_branch_target_load_optimize1 (gcc::context *ctxt)
-{
- return new pass_branch_target_load_optimize1 (ctxt);
-}
-
-
-namespace {
-
-const pass_data pass_data_branch_target_load_optimize2 =
-{
- RTL_PASS, /* type */
- "btl2", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_branch_target_load_optimize2 : public rtl_opt_pass
-{
-public:
- pass_branch_target_load_optimize2 (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_branch_target_load_optimize2, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return (optimize > 0 && flag_branch_target_load_optimize2);
- }
-
- virtual unsigned int execute (function *);
-
-}; // class pass_branch_target_load_optimize2
-
-unsigned int
-pass_branch_target_load_optimize2::execute (function *)
-{
- static int warned = 0;
-
- /* Leave this a warning for now so that it is possible to experiment
- with running this pass twice. In 3.6, we should either make this
- an error, or use separate dump files. */
- if (flag_branch_target_load_optimize
- && flag_branch_target_load_optimize2
- && !warned)
- {
- warning (0, "branch target register load optimization is not intended "
- "to be run twice");
-
- warned = 1;
- }
-
- branch_target_load_optimize (epilogue_completed);
- return 0;
-}
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_branch_target_load_optimize2 (gcc::context *ctxt)
-{
- return new pass_branch_target_load_optimize2 (ctxt);
-}
diff --git a/gcc/common.opt b/gcc/common.opt
index f2214ed93ad..0d165f5018a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1076,16 +1076,16 @@ Common Report Var(flag_branch_probabilities) Optimization
Use profiling information for branch probabilities.
fbranch-target-load-optimize
-Common Report Var(flag_branch_target_load_optimize) Optimization
-Perform branch target load optimization before prologue / epilogue threading.
+Common Ignore
+Does nothing. Preserved for backward compatibility.
fbranch-target-load-optimize2
-Common Report Var(flag_branch_target_load_optimize2) Optimization
-Perform branch target load optimization after prologue / epilogue threading.
+Common Ignore
+Does nothing. Preserved for backward compatibility.
fbtr-bb-exclusive
-Common Report Var(flag_btr_bb_exclusive) Optimization
-Restrict target load migration not to re-use registers in any basic block.
+Common Ignore
+Does nothing. Preserved for backward compatibility.
fcall-saved-
Common Joined RejectNegative Var(common_deferred_options) Defer
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7bcdfcbca15..ef23a7d8933 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -406,8 +406,7 @@ Objective-C and Objective-C++ Dialects}.
-falign-loops[=@var{n}[:@var{m}:[@var{n2}[:@var{m2}]]]] @gol
-fassociative-math -fauto-profile -fauto-profile[=@var{path}] @gol
-fauto-inc-dec -fbranch-probabilities @gol
--fbranch-target-load-optimize -fbranch-target-load-optimize2 @gol
--fbtr-bb-exclusive -fcaller-saves @gol
+-fcaller-saves @gol
-fcombine-stack-adjustments -fconserve-stack @gol
-fcompare-elim -fcprop-registers -fcrossjumping @gol
-fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules @gol
@@ -11025,24 +11024,6 @@ locations inside a translation unit since the locations are unknown until
link time. An example of such an optimization is relaxing calls to short call
instructions.
-@item -fbranch-target-load-optimize
-@opindex fbranch-target-load-optimize
-Perform branch target register load optimization before prologue / epilogue
-threading.
-The use of target registers can typically be exposed only during reload,
-thus hoisting loads out of loops and doing inter-block scheduling needs
-a separate optimization pass.
-
-@item -fbranch-target-load-optimize2
-@opindex fbranch-target-load-optimize2
-Perform branch target register load optimization after prologue / epilogue
-threading.
-
-@item -fbtr-bb-exclusive
-@opindex fbtr-bb-exclusive
-When performing branch target register load optimization, don't reuse
-branch target registers within any basic block.
-
@item -fstdarg-opt
@opindex fstdarg-opt
Optimize the prologue of variadic argument functions with respect to usage of
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 0b5a08d490e..7bb8157df6e 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11755,28 +11755,6 @@ cannot_modify_jumps_past_reload_p ()
@end smallexample
@end deftypefn
-@deftypefn {Target Hook} reg_class_t TARGET_BRANCH_TARGET_REGISTER_CLASS (void)
-This target hook returns a register class for which branch target register
-optimizations should be applied. All registers in this class should be
-usable interchangeably. After reload, registers in this class will be
-re-allocated and loads will be hoisted out of loops and be subjected
-to inter-block scheduling.
-@end deftypefn
-
-@deftypefn {Target Hook} bool TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED (bool @var{after_prologue_epilogue_gen})
-Branch target register optimization will by default exclude callee-saved
-registers
-that are not already live during the current function; if this target hook
-returns true, they will be included. The target code must than make sure
-that all target registers in the class returned by
-@samp{TARGET_BRANCH_TARGET_REGISTER_CLASS} that might need saving are
-saved. @var{after_prologue_epilogue_gen} indicates if prologues and
-epilogues have already been generated. Note, even if you only return
-true when @var{after_prologue_epilogue_gen} is false, you still are likely
-to have to make special provisions in @code{INITIAL_ELIMINATION_OFFSET}
-to reserve space for caller-saved target registers.
-@end deftypefn
-
@deftypefn {Target Hook} bool TARGET_HAVE_CONDITIONAL_EXECUTION (void)
This target hook returns true if the target supports conditional execution.
This target hook is required only when the target has several different
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index a9200551ed4..e926c10d197 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8001,10 +8001,6 @@ build_type_attribute_variant (@var{mdecl},
@hook TARGET_CANNOT_MODIFY_JUMPS_P
-@hook TARGET_BRANCH_TARGET_REGISTER_CLASS
-
-@hook TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED
-
@hook TARGET_HAVE_CONDITIONAL_EXECUTION
@hook TARGET_GEN_CCMP_FIRST
diff --git a/gcc/opt-suggestions.c b/gcc/opt-suggestions.c
index a820c78ff56..1ec94203c81 100644
--- a/gcc/opt-suggestions.c
+++ b/gcc/opt-suggestions.c
@@ -307,7 +307,6 @@ test_completion_valid_options (option_proposer &proposer)
"-Wassign-intercept",
"-Wno-format-security",
"-fno-sched-stalled-insns",
- "-fbtr-bb-exclusive",
"-fno-tree-tail-merge",
"-Wlong-long",
"-Wno-unused-but-set-parameter",
diff --git a/gcc/passes.def b/gcc/passes.def
index e50cf62657c..93879223a8b 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -461,7 +461,6 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_split_after_reload);
NEXT_PASS (pass_ree);
NEXT_PASS (pass_compare_elim_after_reload);
- NEXT_PASS (pass_branch_target_load_optimize1);
NEXT_PASS (pass_thread_prologue_and_epilogue);
NEXT_PASS (pass_rtl_dse2);
NEXT_PASS (pass_stack_adjustments);
@@ -474,7 +473,6 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_cprop_hardreg);
NEXT_PASS (pass_fast_rtl_dce);
NEXT_PASS (pass_reorder_blocks);
- NEXT_PASS (pass_branch_target_load_optimize2);
NEXT_PASS (pass_leaf_regs);
NEXT_PASS (pass_split_before_sched2);
NEXT_PASS (pass_sched2);
diff --git a/gcc/target.def b/gcc/target.def
index ca7e7ad96b4..825c1e6d307 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2597,38 +2597,6 @@ DEFHOOK
bool, (const rtx_insn *follower, const rtx_insn *followee),
hook_bool_const_rtx_insn_const_rtx_insn_true)
-/* Return a register class for which branch target register
- optimizations should be applied. */
-DEFHOOK
-(branch_target_register_class,
- "This target hook returns a register class for which branch target register\n\
-optimizations should be applied. All registers in this class should be\n\
-usable interchangeably. After reload, registers in this class will be\n\
-re-allocated and loads will be hoisted out of loops and be subjected\n\
-to inter-block scheduling.",
- reg_class_t, (void),
- default_branch_target_register_class)
-
-/* Return true if branch target register optimizations should include
- callee-saved registers that are not already live during the current
- function. AFTER_PE_GEN is true if prologues and epilogues have
- already been generated. */
-DEFHOOK
-(branch_target_register_callee_saved,
- "Branch target register optimization will by default exclude callee-saved\n\
-registers\n\
-that are not already live during the current function; if this target hook\n\
-returns true, they will be included. The target code must than make sure\n\
-that all target registers in the class returned by\n\
-@samp{TARGET_BRANCH_TARGET_REGISTER_CLASS} that might need saving are\n\
-saved. @var{after_prologue_epilogue_gen} indicates if prologues and\n\
-epilogues have already been generated. Note, even if you only return\n\
-true when @var{after_prologue_epilogue_gen} is false, you still are likely\n\
-to have to make special provisions in @code{INITIAL_ELIMINATION_OFFSET}\n\
-to reserve space for caller-saved target registers.",
- bool, (bool after_prologue_epilogue_gen),
- hook_bool_bool_false)
-
/* Return true if the target supports conditional execution. */
DEFHOOK
(have_conditional_execution,
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 1d12ec54704..ed77afb1da5 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1054,12 +1054,6 @@ default_return_pops_args (tree, tree, poly_int64)
}
reg_class_t
-default_branch_target_register_class (void)
-{
- return NO_REGS;
-}
-
-reg_class_t
default_ira_change_pseudo_allocno_class (int regno ATTRIBUTE_UNUSED,
reg_class_t cl,
reg_class_t best_cl ATTRIBUTE_UNUSED)
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 20a6e79d2d2..5aba67660f8 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -164,7 +164,6 @@ extern rtx default_internal_arg_pointer (void);
extern rtx default_static_chain (const_tree, bool);
extern void default_trampoline_init (rtx, tree, rtx);
extern poly_int64 default_return_pops_args (tree, tree, poly_int64);
-extern reg_class_t default_branch_target_register_class (void);
extern reg_class_t default_ira_change_pseudo_allocno_class (int, reg_class_t,
reg_class_t);
extern bool default_lra_p (void);
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index be7603a4c72..7106eba54af 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -585,8 +585,6 @@ extern rtl_opt_pass *make_pass_postreload_jump (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_postreload_cse (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_gcse2 (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_split_after_reload (gcc::context *ctxt);
-extern rtl_opt_pass *make_pass_branch_target_load_optimize1 (gcc::context
- *ctxt);
extern rtl_opt_pass *make_pass_thread_prologue_and_epilogue (gcc::context
*ctxt);
extern rtl_opt_pass *make_pass_stack_adjustments (gcc::context *ctxt);
@@ -596,8 +594,6 @@ extern rtl_opt_pass *make_pass_if_after_reload (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_regrename (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_cprop_hardreg (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_reorder_blocks (gcc::context *ctxt);
-extern rtl_opt_pass *make_pass_branch_target_load_optimize2 (gcc::context
- *ctxt);
extern rtl_opt_pass *make_pass_leaf_regs (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_split_before_sched2 (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_compare_elim_after_reload (gcc::context *ctxt);