This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[ira] rewriting save/restore palcement optimization
- From: Vladimir Makarov <vmakarov at redhat dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 29 May 2008 13:20:39 -0400
- Subject: [ira] rewriting save/restore palcement optimization
The following patch contains mostly rewritting optimization of
placement of saves/restores around calls. The goal of this
optimization is to remove redundant saves/restores, move them away as
far as possible to less frequently executed points to free hard
registers for the reload registers. As I wrote the previous version
was supposed to be a temporary solution. This version permits to move
saves too (the previous version moved only restores). It also permits
to move saves/restores through loops and permits to use saved hard
registers for the reload registers (the previous version did not
permitted to do it).
The patch was tested and bootstrapped on x86/x86_64, ppc64, an
itanium. I see a bit better results (in performance and code size)
with the patch for SPEC2000 on x86.
2008-05-29 Vladimir Makarov <vmakarov@redhat.com>
* Makefile.in (caller-save.o): Add CFGLOOP_H.
* ira.c (ira): Call flow_loops_find after the allocation before
the reload.
* global.c (print_insn_chain): Print bitmap saved.
* reload.h (insn_chain): Add members saved and saved_pseudo_regno.
* reload1.c (changed_allocation_pseudos): New bitmap.
(init_reload): Initiate the bitmap.
(new_insn_chain): Initiate bitmap saved.
(order_regs_for_reload): Check bitmap saved.
(find_reg): Check bitmap saved to find register.
(delete_caller_save_insns): Print about removing caller-save insn.
Invalidate reload register taken from saved registers.
Recalculate used_spill_regs.
(finish_spills): Check bitmap saved. Set up
changed_allocation_pseudos. Remove sanity check.
* caller-save.c (cfgloop.h): Add the header.
(set_regs): New variable.
(bb_info): Remove members empty_save_in_p, kill, gen. Add members
empty_save_out_p, empty_restore_in_p, save_kill, save_gen,
restore_kill, restore_gen, free_gen, restore_in, restore_out,
free_in, free_out, live_at_end, restore_here, restore_in_mode,
restore_out_mode, save_in_pseudo, save_out_pseudo,
restore_in_pseudo, restore_out_pseudo.
(loop_info): New structure.
(LOOP_INFO): New macro.
(calculate_local_save_info): Add calculation of new bb_info
members for local info.
(restore_trans_fun, restore_con_fun_0, restore_con_fun_n,
calculate_restore_in_out, calculate_restore_here, free_trans_fun,
free_con_fun_0, free_con_fun_n, calculate_free_in_out): New
functions.
(make_global_save_analysis): Add calculation of new bb_info
members for global info.
(print_hard_reg_set_and_mode): Rename to
print_annotated_hard_reg_set. Print pseudo regnos too.
(print_save_data): Add printing new bb_info members.
(set_hard_reg_saved): New parameters from_saved_pseudo,
save_pseudo. Set them up.
(save_call_clobbered_regs): Rewrite.
(mark_referenced_regs): Set up set_regs.
(insert_restore, insert_save): New parameter save_pseudo. Use it
for setting save_pseudo_regno and for debugging output.
* ira-conflicts.c (build_conflict_bit_table): Check min/max.
* ira-build.c (conflict_vector_profitable_p): Ditto.
(clear_allocno_conflicts): Check that conflict allocno array size.
Index: ira-conflicts.c
===================================================================
--- ira-conflicts.c (revision 136136)
+++ ira-conflicts.c (working copy)
@@ -96,6 +96,11 @@ build_conflict_bit_table (void)
FOR_EACH_ALLOCNO (allocno, ai)
{
num = ALLOCNO_NUM (allocno);
+ if (ALLOCNO_MAX (allocno) < ALLOCNO_MIN (allocno))
+ {
+ conflicts[num] = NULL;
+ continue;
+ }
conflict_bit_vec_words_num
= (ALLOCNO_MAX (allocno) - ALLOCNO_MIN (allocno) + INT_BITS) / INT_BITS;
allocated_words_num += conflict_bit_vec_words_num;
@@ -756,8 +761,11 @@ build_allocno_conflicts (void)
{
free_p = FALSE;
ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) = conflicts[ALLOCNO_NUM (a)];
- conflict_bit_vec_words_num
- = (ALLOCNO_MAX (a) - ALLOCNO_MIN (a) + INT_BITS) / INT_BITS;
+ if (ALLOCNO_MAX (a) < ALLOCNO_MIN (a))
+ conflict_bit_vec_words_num = 0;
+ else
+ conflict_bit_vec_words_num
+ = (ALLOCNO_MAX (a) - ALLOCNO_MIN (a) + INT_BITS) / INT_BITS;
ALLOCNO_CONFLICT_ALLOCNO_ARRAY_SIZE (a)
= conflict_bit_vec_words_num * sizeof (INT_TYPE);
}
Index: reload.h
===================================================================
--- reload.h (revision 136136)
+++ reload.h (working copy)
@@ -213,10 +213,15 @@ struct insn_chain
live pseudos that have a hard register. */
regset_head live_throughout;
regset_head dead_or_set;
-
+ /* Register life information: record all all live pseudos that was
+ saved through given insn. */
+ regset_head saved;
/* Copies of the global variables computed by find_reloads. */
struct reload *rld;
int n_reloads;
+ /* It is defined only when IS_CALLER_SAVE_INSN is TRUE. The value
+ is regno of pseudo saved/restored by the insn. */
+ int saved_pseudo_regno;
/* Indicates which registers have already been used for spills. */
HARD_REG_SET used_spill_regs;
Index: caller-save.c
===================================================================
--- caller-save.c (revision 136136)
+++ caller-save.c (working copy)
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.
#include "tm_p.h"
#include "addresses.h"
#include "output.h"
+#include "cfgloop.h"
#include "ira.h"
#include "df.h"
#include "ggc.h"
@@ -96,6 +97,8 @@ static int n_regs_saved;
/* Computed by mark_referenced_regs, all regs referenced in a given
insn. */
static HARD_REG_SET referenced_regs;
+/* Computed by mark_referenced_regs, all regs set in a given insn. */
+static HARD_REG_SET set_regs;
static int reg_save_code (int, enum machine_mode);
@@ -107,27 +110,36 @@ static struct saved_hard_reg *new_saved_
static void finish_saved_hard_regs (void);
static int saved_hard_reg_compare_func (const void *, const void *);
static void calculate_local_save_info (void);
+static bool restore_trans_fun (int);
+static void restore_con_fun_0 (basic_block);
+static void restore_con_fun_n (edge);
+static void calculate_restore_in_out (void);
+static int calculate_restore_here (void);
static bool save_trans_fun (int);
static void save_con_fun_0 (basic_block);
static void save_con_fun_n (edge);
-
static void calculate_save_in_out (void);
static int calculate_save_here (void);
+static bool free_trans_fun (int);
+static void free_con_fun_0 (basic_block);
+static void free_con_fun_n (edge);
+static void calculate_free_in_out (void);
+
static void make_global_save_analysis (void);
-static void print_hard_reg_set_and_mode (FILE *, HARD_REG_SET,
- unsigned char *);
+static void print_annotated_hard_reg_set (FILE *, HARD_REG_SET,
+ unsigned char *, int *);
static void print_hard_reg_set (FILE *, HARD_REG_SET);
static void print_save_data (FILE *);
static void set_hard_reg_saved (HARD_REG_SET, unsigned char *,
- enum machine_mode *);
+ enum machine_mode *, int *, int *);
static void mark_set_regs (rtx, const_rtx, void *);
static void add_stored_regs (rtx, const_rtx, void *);
static void mark_referenced_regs (rtx);
static int insert_save (struct insn_chain *, int, int, HARD_REG_SET *,
- enum machine_mode *);
+ enum machine_mode *, int *);
static int insert_restore (struct insn_chain *, int, int, int,
- enum machine_mode *);
+ enum machine_mode *, int *);
static struct insn_chain *insert_one_insn (struct insn_chain *, int, int,
rtx);
static void add_stored_regs (rtx, const_rtx, void *);
@@ -593,6 +605,7 @@ setup_save_areas (void)
if (r < 0)
continue;
+
bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
for (; r < bound; r++)
if (TEST_HARD_REG_BIT (used_regs, r))
@@ -767,58 +780,100 @@ setup_save_areas (void)
save/restore insn when IRA is used. */
/* The following structure contains basic block data flow information
- used to calculate hard registers to save at BB ends. Data flow
- equation is bidirectional because we don't want to put save/restore
- code on CFG edges. */
+ used to optimize save/restore placement. Data flow equations are
+ bidirectional because we don't want to put save/restore code on CFG
+ edges. */
struct bb_info
{
- /* True if save_in should be empty for this block. */
- int empty_save_in_p;
- /* Hard registers should be saved through calls in the basic block
- and correspondingly mentioned in the BB but not used after the BB
- and set in the BB and used after the BB. */
- HARD_REG_SET kill, gen;
- /* Registers needed to be saved at the start and end of the basic
- block. */
- HARD_REG_SET save_in, save_out;
- /* Hard registers living at the start of the basic block. */
- HARD_REG_SET live_at_start;
+ /* True if save_out/restore_in should be empty for this block. */
+ int empty_save_out_p, empty_restore_in_p;
+ /* Hard registers set/mentioned in the BB. */
+ HARD_REG_SET save_kill;
+ HARD_REG_SET restore_kill;
+ /* Hard registers needed to be saved and this save not killed (see above)
+ by an insn in the BB before that. */
+ HARD_REG_SET save_gen;
+ /* Hard registers needed to be restored and this restore not killed
+ by an insn in the BB after that. */
+ HARD_REG_SET restore_gen;
+ /* Hard registers free and not killed by an insn in the BB before
+ that. */
+ HARD_REG_SET free_gen;
+ /* Registers needed to be saved/restored at the start and end of the
+ basic block. */
+ HARD_REG_SET save_in, save_out, restore_in, restore_out;
+ /* Registers free at the start and end of the basic block. */
+ HARD_REG_SET free_in, free_out;
+ /* Hard registers living at the start/end of the basic block. */
+ HARD_REG_SET live_at_start, live_at_end;
/* We don't want to generate save/restore insns on edges because it
- changes CFG during the reload. To prevent this we use the following
- set. This set defines what hard registers should be saved at the
- end of basic block. */
- HARD_REG_SET save_here;
- /* Saving modes at the start and end of the basic block. */
- unsigned char save_in_mode[FIRST_PSEUDO_REGISTER];
- /* It corresponds to set GEN right after the call of
+ changes CFG during the reload. To prevent this we use the
+ following set. This set defines what hard registers should be
+ saved/restored at the start/end of basic block. */
+ HARD_REG_SET save_here, restore_here;
+ /* It corresponds to set SAVE_GEN right after the call of
calculate_local_save_info. */
+ unsigned char save_in_mode[FIRST_PSEUDO_REGISTER];
+ /* Saving modes at the end of the basic block. */
unsigned char save_out_mode[FIRST_PSEUDO_REGISTER];
+ /* Restoring modes at the start of the basic block. */
+ unsigned char restore_in_mode[FIRST_PSEUDO_REGISTER];
+ /* It corresponds to set RESTORE_GEN right after the call of
+ calculate_local_save_info. */
+ unsigned char restore_out_mode[FIRST_PSEUDO_REGISTER];
+ /* Analogous but the corresponding pseudo-register numbers. */
+ int save_in_pseudo[FIRST_PSEUDO_REGISTER];
+ int save_out_pseudo[FIRST_PSEUDO_REGISTER];
+ int restore_in_pseudo[FIRST_PSEUDO_REGISTER];
+ int restore_out_pseudo[FIRST_PSEUDO_REGISTER];
};
/* Macros for accessing data flow information of basic blocks. */
#define BB_INFO(BB) ((struct bb_info *) (BB)->aux)
#define BB_INFO_BY_INDEX(N) BB_INFO (BASIC_BLOCK(N))
+/* The following structure contains loop info necessary for
+ save/restore placement optimization. */
+struct loop_info
+{
+ /* All hard registers mentioned in the loop. If a pseudo is
+ mentioned in the loop, the hard registers assigned to it are also
+ believed to be mentioned in the loop. */
+ HARD_REG_SET mentioned_regs;
+};
+
+/* Macro for accessing data flow information of LOOP. */
+#define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
+
/* The function calculates sets KILL, GEN, LIVE_AT_START and
- SAVE_OUT_MODES corresponding to GEN for basic blocks. */
+ RESTORE_OUT_MODES corresponding to GEN for basic blocks. */
static void
calculate_local_save_info (void)
{
- int i, empty_save_in_p;
+ int i, empty_save_out_p, empty_restore_in_p;
struct insn_chain *chain, *next;
struct bb_info *bb_info;
/* Computed in mark_set_regs, holds all registers set by the current
instruction. */
- HARD_REG_SET this_insn_sets, gen, kill;
+ HARD_REG_SET save_kill, restore_kill;
+ HARD_REG_SET this_insn_sets, save_gen, restore_gen, free_gen, temp_set;
unsigned regno;
reg_set_iterator rsi;
enum machine_mode save_mode[FIRST_PSEUDO_REGISTER];
+ int save_pseudo[FIRST_PSEUDO_REGISTER];
- CLEAR_HARD_REG_SET (gen);
- CLEAR_HARD_REG_SET (kill);
- empty_save_in_p = FALSE;
+ CLEAR_HARD_REG_SET (save_gen);
+ CLEAR_HARD_REG_SET (restore_gen);
+ CLEAR_HARD_REG_SET (free_gen);
+ CLEAR_HARD_REG_SET (save_kill);
+ CLEAR_HARD_REG_SET (restore_kill);
+ empty_save_out_p = FALSE;
+ empty_restore_in_p = FALSE;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- save_mode[i] = VOIDmode;
+ {
+ save_mode[i] = VOIDmode;
+ save_pseudo[i] = -1;
+ }
for (chain = reload_insn_chain; chain != 0; chain = next)
{
@@ -827,23 +882,21 @@ calculate_local_save_info (void)
next = chain->next;
- gcc_assert (!chain->is_caller_save_insn);
-
bb_info = BB_INFO_BY_INDEX (chain->block);
if (INSN_P (insn))
{
- if (JUMP_P (insn)
- && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
- || GET_CODE (PATTERN (insn)) == ADDR_VEC))
- empty_save_in_p = TRUE;
-
CLEAR_HARD_REG_SET (referenced_regs);
+ CLEAR_HARD_REG_SET (set_regs);
mark_referenced_regs (PATTERN (insn));
- IOR_HARD_REG_SET (kill, referenced_regs);
- AND_COMPL_HARD_REG_SET (gen, referenced_regs);
-
+ AND_COMPL_HARD_REG_SET (restore_gen, referenced_regs);
+ IOR_HARD_REG_SET (restore_kill, referenced_regs);
+ IOR_HARD_REG_SET (save_kill, set_regs);
+
if (code == CALL_INSN && find_reg_note (insn, REG_NORETURN, NULL))
- SET_HARD_REG_SET (kill);
+ {
+ SET_HARD_REG_SET (save_kill);
+ SET_HARD_REG_SET (restore_kill);
+ }
else if (code == CALL_INSN)
{
HARD_REG_SET hard_regs_to_save, used_regs;
@@ -866,13 +919,15 @@ calculate_local_save_info (void)
if (flag_ira && optimize && r < 0)
continue;
gcc_assert (r >= 0);
+
nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
mode = HARD_REGNO_CALLER_SAVE_MODE
- (r, nregs, PSEUDO_REGNO_MODE (regno));
+ (r, nregs, PSEUDO_REGNO_MODE (regno));
if (nregs == 1)
{
SET_HARD_REG_BIT (hard_regs_to_save, r);
save_mode[r] = mode;
+ save_pseudo[r] = regno;
}
else
{
@@ -881,6 +936,7 @@ calculate_local_save_info (void)
SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
save_mode[r + nregs]
= regno_save_mode[r + nregs][1];
+ save_pseudo[r + nregs] = regno;
}
}
}
@@ -902,7 +958,21 @@ calculate_local_save_info (void)
AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets);
get_call_invalidated_used_regs (insn, &used_regs, false);
AND_HARD_REG_SET (hard_regs_to_save, used_regs);
- IOR_HARD_REG_SET (gen, hard_regs_to_save);
+ IOR_HARD_REG_SET (restore_gen, hard_regs_to_save);
+ COPY_HARD_REG_SET (temp_set, hard_regs_to_save);
+ AND_COMPL_HARD_REG_SET (temp_set, save_kill);
+ AND_COMPL_HARD_REG_SET (temp_set, save_gen);
+ IOR_HARD_REG_SET (save_gen, temp_set);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (temp_set, i))
+ {
+ bb_info->save_in_mode[i] = save_mode[i];
+ bb_info->save_in_pseudo[i] = save_pseudo[i];
+ }
+ COPY_HARD_REG_SET (temp_set, hard_regs_to_save);
+ AND_COMPL_HARD_REG_SET (temp_set, save_kill);
+ AND_COMPL_HARD_REG_SET (temp_set, restore_kill);
+ IOR_HARD_REG_SET (free_gen, temp_set);
}
}
@@ -911,30 +981,87 @@ calculate_local_save_info (void)
basic_block bb = BASIC_BLOCK (chain->block);
edge e;
edge_iterator ei;
+ loop_p loop;
- if (! empty_save_in_p)
+ if (! empty_save_out_p)
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ empty_save_out_p = TRUE;
+ break;
+ }
+ bb_info->empty_save_out_p = empty_save_out_p;
+ empty_save_out_p = FALSE;
+ if (! empty_restore_in_p)
FOR_EACH_EDGE (e, ei, bb->preds)
if (e->flags & EDGE_ABNORMAL)
{
- empty_save_in_p = TRUE;
+ empty_restore_in_p = TRUE;
break;
}
- bb_info->empty_save_in_p = empty_save_in_p;
- empty_save_in_p = FALSE;
- CLEAR_HARD_REG_SET (bb_info->save_in);
- COPY_HARD_REG_SET (bb_info->gen, gen);
+ bb_info->empty_restore_in_p = empty_restore_in_p;
+ empty_restore_in_p = FALSE;
+ COPY_HARD_REG_SET (bb_info->save_gen, save_gen);
+ COPY_HARD_REG_SET (bb_info->restore_gen, restore_gen);
+ COPY_HARD_REG_SET (bb_info->free_gen, free_gen);
+ CLEAR_HARD_REG_SET (bb_info->restore_in);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- bb_info->save_in_mode[i] = VOIDmode;
- if (TEST_HARD_REG_BIT (gen, i))
- bb_info->save_out_mode[i] = save_mode[i];
+ bb_info->save_out_mode[i] = VOIDmode;
+ bb_info->save_out_pseudo[i] = -1;
+ if (!TEST_HARD_REG_BIT (save_gen, i))
+ {
+ bb_info->save_in_mode[i] = VOIDmode;
+ bb_info->save_in_pseudo[i] = -1;
+ }
+ bb_info->restore_in_mode[i] = VOIDmode;
+ bb_info->restore_in_pseudo[i] = -1;
+ if (TEST_HARD_REG_BIT (restore_gen, i))
+ {
+ bb_info->restore_out_mode[i] = save_mode[i];
+ bb_info->restore_out_pseudo[i] = save_pseudo[i];
+ }
else
- bb_info->save_out_mode[i] = VOIDmode;
+ {
+ bb_info->restore_out_mode[i] = VOIDmode;
+ bb_info->restore_out_pseudo[i] = -1;
+ }
}
- COPY_HARD_REG_SET (bb_info->kill, kill);
- SET_HARD_REG_SET (bb_info->save_out);
+ COPY_HARD_REG_SET (bb_info->save_kill, save_kill);
+ COPY_HARD_REG_SET (bb_info->restore_kill, restore_kill);
+ for (loop = bb->loop_father;
+ loop != current_loops->tree_root;
+ loop = loop_outer (loop))
+ {
+ struct loop_info *loop_info = LOOP_INFO (loop);
+
+ IOR_HARD_REG_SET (loop_info->mentioned_regs, save_kill);
+ IOR_HARD_REG_SET (loop_info->mentioned_regs, restore_kill);
+ }
+ SET_HARD_REG_SET (bb_info->save_in);
+ AND_COMPL_HARD_REG_SET (bb_info->save_in, call_fixed_reg_set);
+ SET_HARD_REG_SET (bb_info->restore_out);
+ AND_COMPL_HARD_REG_SET (bb_info->restore_out, call_fixed_reg_set);
+ SET_HARD_REG_SET (bb_info->free_in);
+ AND_COMPL_HARD_REG_SET (bb_info->free_in, call_fixed_reg_set);
/* We don't use LIVE for IRA. */
REG_SET_TO_HARD_REG_SET
+ (bb_info->live_at_end,
+ flag_ira ? DF_LR_OUT (bb) : DF_LIVE_OUT (bb));
+ EXECUTE_IF_SET_IN_REG_SET
+ ((flag_ira ? DF_LR_OUT (bb) : DF_LIVE_OUT (bb)),
+ FIRST_PSEUDO_REGISTER, regno, rsi)
+ {
+ int r = reg_renumber[regno];
+ int nregs;
+
+ if (r < 0)
+ continue;
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+ while (nregs-- > 0)
+ SET_HARD_REG_BIT (bb_info->live_at_end, r + nregs);
+ }
+ REG_SET_TO_HARD_REG_SET
(bb_info->live_at_start,
flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
EXECUTE_IF_SET_IN_REG_SET
@@ -951,10 +1078,17 @@ calculate_local_save_info (void)
SET_HARD_REG_BIT (bb_info->live_at_start, r + nregs);
}
CLEAR_HARD_REG_SET (bb_info->save_here);
- CLEAR_HARD_REG_SET (gen);
- CLEAR_HARD_REG_SET (kill);
+ CLEAR_HARD_REG_SET (bb_info->restore_here);
+ CLEAR_HARD_REG_SET (save_gen);
+ CLEAR_HARD_REG_SET (restore_gen);
+ CLEAR_HARD_REG_SET (free_gen);
+ CLEAR_HARD_REG_SET (save_kill);
+ CLEAR_HARD_REG_SET (restore_kill);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- save_mode[i] = VOIDmode;
+ {
+ save_mode[i] = VOIDmode;
+ save_pseudo[i] = -1;
+ }
}
}
}
@@ -962,44 +1096,47 @@ calculate_local_save_info (void)
/* The function used by the DF equation solver to propagate restore
info through block with BB_INDEX. */
static bool
-save_trans_fun (int bb_index)
+restore_trans_fun (int bb_index)
{
int i;
HARD_REG_SET temp_set;
struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
- COPY_HARD_REG_SET (temp_set, bb_info->save_in);
- AND_COMPL_HARD_REG_SET (temp_set, bb_info->kill);
+ COPY_HARD_REG_SET (temp_set, bb_info->restore_in);
+ AND_COMPL_HARD_REG_SET (temp_set, bb_info->restore_kill);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (temp_set, i)
- && ! TEST_HARD_REG_BIT (bb_info->gen, i))
+ && ! TEST_HARD_REG_BIT (bb_info->restore_gen, i))
{
- gcc_assert (bb_info->save_out_mode[i] == VOIDmode
- || (bb_info->save_out_mode[i]
- == bb_info->save_in_mode[i]));
- bb_info->save_out_mode[i] = bb_info->save_in_mode[i];
+ gcc_assert (bb_info->restore_out_mode[i] == VOIDmode
+ || ((bb_info->restore_out_mode[i]
+ == bb_info->restore_in_mode[i])
+ && (bb_info->restore_out_pseudo[i]
+ == bb_info->restore_in_pseudo[i])));
+ bb_info->restore_out_mode[i] = bb_info->restore_in_mode[i];
+ bb_info->restore_out_pseudo[i] = bb_info->restore_in_pseudo[i];
}
- IOR_HARD_REG_SET (temp_set, bb_info->gen);
- if (! hard_reg_set_equal_p (temp_set, bb_info->save_out))
+ IOR_HARD_REG_SET (temp_set, bb_info->restore_gen);
+ if (! hard_reg_set_equal_p (temp_set, bb_info->restore_out))
{
- COPY_HARD_REG_SET (bb_info->save_out, temp_set);
+ COPY_HARD_REG_SET (bb_info->restore_out, temp_set);
return true;
}
return false;
}
-/* The function used by the DF equation solver to set up save info
+/* The function used by the DF equation solver to set up restore info
for a block BB without predecessor. */
static void
-save_con_fun_0 (basic_block bb)
+restore_con_fun_0 (basic_block bb)
{
- CLEAR_HARD_REG_SET (BB_INFO (bb)->save_in);
+ CLEAR_HARD_REG_SET (BB_INFO (bb)->restore_in);
}
-/* The function used by the DF equation solver to propagate save info
- from successor to predecessor on edge E. */
+/* The function used by the DF equation solver to propagate restore info
+ from predecessor to successor on edge E. */
static void
-save_con_fun_n (edge e)
+restore_con_fun_n (edge e)
{
int i;
HARD_REG_SET temp_set;
@@ -1007,27 +1144,38 @@ save_con_fun_n (edge e)
basic_block bb = e->dest;
struct bb_info *bb_info = BB_INFO (bb);
- if (bb_info->empty_save_in_p)
+ if (bb_info->empty_restore_in_p)
return;
- COPY_HARD_REG_SET (temp_set, BB_INFO (pred)->save_out);
- AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (pred)->save_here);
+ if (bb->loop_depth > pred->loop_depth)
+ {
+ CLEAR_HARD_REG_SET (bb_info->restore_in);
+ return;
+ }
+ COPY_HARD_REG_SET (temp_set, BB_INFO (pred)->restore_out);
+ AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (pred)->restore_here);
AND_HARD_REG_SET (temp_set, bb_info->live_at_start);
if (EDGE_PRED (bb, 0) == e)
- COPY_HARD_REG_SET (bb_info->save_in, temp_set);
+ COPY_HARD_REG_SET (bb_info->restore_in, temp_set);
else
- AND_HARD_REG_SET (bb_info->save_in, temp_set);
+ AND_HARD_REG_SET (bb_info->restore_in, temp_set);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (temp_set, i))
{
gcc_assert
- (bb_info->save_in_mode[i] == VOIDmode
- || BB_INFO (pred)->save_out_mode[i] == VOIDmode
- || (bb_info->save_in_mode[i]
- == BB_INFO (pred)->save_out_mode[i]));
- if (BB_INFO (pred)->save_out_mode[i] != VOIDmode)
- bb_info->save_in_mode[i]
- = BB_INFO (pred)->save_out_mode[i];
+ (bb_info->restore_in_mode[i] == VOIDmode
+ || BB_INFO (pred)->restore_out_mode[i] == VOIDmode
+ || ((bb_info->restore_in_mode[i]
+ == BB_INFO (pred)->restore_out_mode[i])
+ && (bb_info->restore_in_pseudo[i]
+ == BB_INFO (pred)->restore_out_pseudo[i])));
+ if (BB_INFO (pred)->restore_out_mode[i] != VOIDmode)
+ {
+ bb_info->restore_in_mode[i]
+ = BB_INFO (pred)->restore_out_mode[i];
+ bb_info->restore_in_pseudo[i]
+ = BB_INFO (pred)->restore_out_pseudo[i];
+ }
}
}
@@ -1035,26 +1183,165 @@ save_con_fun_n (edge e)
ones. */
static bitmap all_blocks;
+/* The function calculates global restore information according
+ to the following equations:
+
+ bb.restore_in = empty for entry block or one with empty_restore_in_p
+ | ^(pred.restore_out - pred.restore_here) ^ bb.live_at_start
+ bb.restore_out = (bb.restore_in - bb.restore_kill) U bb.restore_gen.
+
+ The function also calculates restore_in_mode and restore_out_mode.
+*/
+static void
+calculate_restore_in_out (void)
+{
+ df_simple_dataflow (DF_FORWARD, NULL, restore_con_fun_0, restore_con_fun_n,
+ restore_trans_fun, all_blocks,
+ df_get_postorder (DF_FORWARD),
+ df_get_n_blocks (DF_FORWARD));
+}
+
+/* The function calculates RESTORE_HERE according to the equation
+ bb.restore_here = U ((bb.restore_out - succ.restore_in)
+ ^ succ.live_at_start). */
+static int
+calculate_restore_here (void)
+{
+ basic_block bb;
+ edge e;
+ edge_iterator ei;
+ HARD_REG_SET restore_here, temp_set;
+ int changed_p = FALSE;
+
+ FOR_EACH_BB (bb)
+ {
+ CLEAR_HARD_REG_SET (restore_here);
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ basic_block dest = e->dest;
+
+ COPY_HARD_REG_SET (temp_set, BB_INFO (bb)->restore_out);
+ AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (dest)->restore_in);
+ AND_HARD_REG_SET (temp_set, BB_INFO (dest)->live_at_start);
+ IOR_HARD_REG_SET (restore_here, temp_set);
+ }
+
+ if (! hard_reg_set_equal_p (restore_here, BB_INFO (bb)->restore_here))
+ {
+ COPY_HARD_REG_SET (BB_INFO (bb)->restore_here, restore_here);
+ changed_p = TRUE;
+ }
+ }
+ return changed_p;
+}
+
+/* The function used by the DF equation solver to propagate save
+ info through block with BB_INDEX. */
+static bool
+save_trans_fun (int bb_index)
+{
+ int i;
+ HARD_REG_SET temp_set;
+ struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
+
+ COPY_HARD_REG_SET (temp_set, bb_info->save_out);
+ AND_COMPL_HARD_REG_SET (temp_set, bb_info->save_kill);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (temp_set, i)
+ && ! TEST_HARD_REG_BIT (bb_info->save_gen, i))
+ {
+ gcc_assert (bb_info->save_in_mode[i] == VOIDmode
+ || ((bb_info->save_in_mode[i]
+ == bb_info->save_out_mode[i])
+ && (bb_info->save_in_pseudo[i]
+ == bb_info->save_out_pseudo[i])));
+ bb_info->save_in_mode[i] = bb_info->save_out_mode[i];
+ bb_info->save_in_pseudo[i] = bb_info->save_out_pseudo[i];
+ }
+ IOR_HARD_REG_SET (temp_set, bb_info->save_gen);
+ AND_COMPL_HARD_REG_SET (temp_set, bb_info->restore_in);
+ if (! hard_reg_set_equal_p (temp_set, bb_info->save_in))
+ {
+ COPY_HARD_REG_SET (bb_info->save_in, temp_set);
+ return true;
+ }
+ return false;
+}
+
+/* The function used by the DF equation solver to set up save info
+ for a block BB without successor. */
+static void
+save_con_fun_0 (basic_block bb)
+{
+ CLEAR_HARD_REG_SET (BB_INFO (bb)->save_out);
+}
+
+/* The function used by the DF equation solver to propagate save info
+ from successor to predecessor on edge E. */
+static void
+save_con_fun_n (edge e)
+{
+ int i;
+ HARD_REG_SET temp_set;
+ basic_block succ = e->dest;
+ basic_block bb = e->src;
+ struct bb_info *bb_info = BB_INFO (bb);
+
+ if (bb_info->empty_save_out_p)
+ return;
+
+ if (bb->loop_depth > succ->loop_depth)
+ {
+ CLEAR_HARD_REG_SET (bb_info->save_out);
+ return;
+ }
+ COPY_HARD_REG_SET (temp_set, BB_INFO (succ)->save_in);
+ AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (succ)->save_here);
+ AND_HARD_REG_SET (temp_set, bb_info->live_at_end);
+ if (EDGE_SUCC (bb, 0) == e)
+ COPY_HARD_REG_SET (bb_info->save_out, temp_set);
+ else
+ AND_HARD_REG_SET (bb_info->save_out, temp_set);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (temp_set, i))
+ {
+ gcc_assert
+ (bb_info->save_out_mode[i] == VOIDmode
+ || BB_INFO (succ)->save_in_mode[i] == VOIDmode
+ || ((bb_info->save_out_mode[i]
+ == BB_INFO (succ)->save_in_mode[i])
+ && (bb_info->save_out_pseudo[i]
+ == BB_INFO (succ)->save_in_pseudo[i])));
+ if (BB_INFO (succ)->save_in_mode[i] != VOIDmode)
+ {
+ bb_info->save_out_mode[i]
+ = BB_INFO (succ)->save_in_mode[i];
+ bb_info->save_out_pseudo[i]
+ = BB_INFO (succ)->save_in_pseudo[i];
+ }
+ }
+}
+
/* The function calculates global save information according
to the following equations:
- bb.save_in = empty for entry block or one with empty_save_in_p
- | ^ (pred.save_out - pred.save_here) ^ bb.live_at_start
- bb.save_out = (bb.save_in - bb.kill) U bb.gen.
+ bb.save_out = empty for exit block or one with empty_save_out_p
+ | ^(succ.save_in - succ.save_here) ^ bb.live_at_end
+ bb.save_in = ((bb.save_out - bb.save_kill) U bb.save_gen) - bb.restore_in.
The function also calculates save_in_mode and save_out_mode.
*/
static void
calculate_save_in_out (void)
{
- df_simple_dataflow (DF_FORWARD, NULL, save_con_fun_0, save_con_fun_n,
+ df_simple_dataflow (DF_BACKWARD, NULL, save_con_fun_0, save_con_fun_n,
save_trans_fun, all_blocks,
- df_get_postorder (DF_FORWARD),
- df_get_n_blocks (DF_FORWARD));
+ df_get_postorder (DF_BACKWARD),
+ df_get_n_blocks (DF_BACKWARD));
}
/* The function calculates SAVE_HERE according to the equation
- bb.save_here = U ((bb.save_out - succ.save_in) ^ succ.live_at_start). */
+ bb.save_here = U ((bb.save_in - pred.save_out) ^ pred.live_at_end). */
static int
calculate_save_here (void)
{
@@ -1067,13 +1354,13 @@ calculate_save_here (void)
FOR_EACH_BB (bb)
{
CLEAR_HARD_REG_SET (save_here);
- FOR_EACH_EDGE (e, ei, bb->succs)
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
- basic_block dest = e->dest;
+ basic_block src = e->src;
- COPY_HARD_REG_SET (temp_set, BB_INFO (bb)->save_out);
- AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (dest)->save_in);
- AND_HARD_REG_SET (temp_set, BB_INFO (dest)->live_at_start);
+ COPY_HARD_REG_SET (temp_set, BB_INFO (bb)->save_in);
+ AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (src)->save_out);
+ AND_HARD_REG_SET (temp_set, BB_INFO (src)->live_at_end);
IOR_HARD_REG_SET (save_here, temp_set);
}
@@ -1086,12 +1373,89 @@ calculate_save_here (void)
return changed_p;
}
-/* The function calculates the global save information used to put
+/* The function used by the DF equation solver to propagate free
+ info through block with BB_INDEX. */
+static bool
+free_trans_fun (int bb_index)
+{
+ HARD_REG_SET temp_set;
+ struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
+
+ COPY_HARD_REG_SET (temp_set, bb_info->free_out);
+ AND_COMPL_HARD_REG_SET (temp_set, bb_info->save_kill);
+ AND_COMPL_HARD_REG_SET (temp_set, bb_info->restore_kill);
+ IOR_HARD_REG_SET (temp_set, bb_info->free_gen);
+ AND_COMPL_HARD_REG_SET (temp_set, bb_info->save_here);
+ if (! hard_reg_set_equal_p (temp_set, bb_info->free_in))
+ {
+ COPY_HARD_REG_SET (bb_info->free_in, temp_set);
+ return true;
+ }
+ return false;
+}
+
+/* The function used by the DF equation solver to set up free info
+ for a block BB without successor. */
+static void
+free_con_fun_0 (basic_block bb)
+{
+ CLEAR_HARD_REG_SET (BB_INFO (bb)->free_out);
+}
+
+/* The function used by the DF equation solver to propagate free info
+ from successor to predecessor on edge E. */
+static void
+free_con_fun_n (edge e)
+{
+ HARD_REG_SET temp_set;
+ basic_block succ = e->dest;
+ basic_block bb = e->src;
+ struct bb_info *bb_info = BB_INFO (bb);
+
+ COPY_HARD_REG_SET (temp_set, BB_INFO (succ)->free_in);
+ if (EDGE_SUCC (bb, 0) == e)
+ COPY_HARD_REG_SET (bb_info->free_out, temp_set);
+ else
+ AND_HARD_REG_SET (bb_info->free_out, temp_set);
+}
+
+/* The function calculates global free information according
+ to the following equations:
+
+ bb.free_out = ^succ.free_in
+ bb.free_in = ((bb.free_out - bb.save_kill - bb.restore_kill) U bb.free_gen)
+ - bb.save_here)
+
+ The function also calculates free_in_mode and free_out_mode.
+*/
+static void
+calculate_free_in_out (void)
+{
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ struct bb_info *bb_info = BB_INFO (bb);
+
+ COPY_HARD_REG_SET (bb_info->free_in, bb_info->save_in);
+ IOR_HARD_REG_SET (bb_info->free_in, bb_info->restore_in);
+ COPY_HARD_REG_SET (bb_info->free_out, bb_info->save_out);
+ IOR_HARD_REG_SET (bb_info->free_out, bb_info->restore_out);
+ }
+ df_simple_dataflow (DF_BACKWARD, NULL, free_con_fun_0, free_con_fun_n,
+ free_trans_fun, all_blocks,
+ df_get_postorder (DF_BACKWARD),
+ df_get_n_blocks (DF_BACKWARD));
+}
+
+/* The function calculates the global save/restore information used to put
save/restore code without generating new blocks. This is a
bidirectional data flow problem (calculation of SAVE_IN and
- SAVE_OUT is a forward data flow problem and SAVE_HERE is backward
- one). It is complicated by necessity of calculation of modes for
- saving/restoring callee clobbered hard registers. */
+ SAVE_OUT is a backward data flow problem and SAVE_HERE is forward
+ one; calculation of RESTORE_IN and RESTORE_OUT is a forward data
+ flow problem and RESTORE_HERE is backward one). It is complicated
+ by necessity of calculation of modes for saving/restoring callee
+ clobbered hard registers. */
static void
make_global_save_analysis (void)
{
@@ -1106,27 +1470,45 @@ make_global_save_analysis (void)
calculate_local_save_info ();
for (iter = 1;; iter++)
{
+ calculate_restore_in_out ();
+ changed_p = calculate_restore_here ();
+ if (! changed_p)
+ break;
+ }
+ if (dump_file != NULL)
+ fprintf (dump_file, " Number of global restore analysis iterations %d\n",
+ iter);
+ for (iter = 1;; iter++)
+ {
calculate_save_in_out ();
changed_p = calculate_save_here ();
if (! changed_p)
break;
}
- BITMAP_FREE (all_blocks);
if (dump_file != NULL)
fprintf (dump_file, " Number of global save analysis iterations %d\n",
iter);
+ calculate_free_in_out ();
+ BITMAP_FREE (all_blocks);
}
/* Print hard registers in SET to file F. The registers are printed
- with its mode given in MODES. */
+ with its mode given in MODES and corresponding pseudo given in
+ PSEUDOS. */
static void
-print_hard_reg_set_and_mode (FILE *f, HARD_REG_SET set, unsigned char *modes)
+print_annotated_hard_reg_set (FILE *f, HARD_REG_SET set,
+ unsigned char *modes, int *pseudos)
{
int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (set, i))
- fprintf (f, " %d:%s %s", i, GET_MODE_NAME (modes[i]), reg_names[i]);
+ {
+ fprintf (f, " %d", i);
+ if (pseudos[i] >= 0)
+ fprintf (f, "(%d)", pseudos[i]);
+ fprintf (f, ":%s %s", GET_MODE_NAME (modes[i]), reg_names[i]);
+ }
}
/* Print hard registers in SET to file F. */
@@ -1146,24 +1528,61 @@ print_save_data (FILE *f)
{
basic_block bb;
struct bb_info *bb_info;
+ edge e;
+ edge_iterator ei;
FOR_EACH_BB (bb)
{
bb_info = BB_INFO (bb);
- fprintf (f, "bb %d:\n save_in:", bb->index);
- print_hard_reg_set_and_mode (f, bb_info->save_in,
- bb_info->save_in_mode);
+ fprintf (f, "bb %d (preds", bb->index);
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ fprintf (f, " %d", e->src->index);
+ }
+ fprintf (f, ") (succs");
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ fprintf (f, " %d", e->dest->index);
+ }
+ fprintf (f, ")\n empty_save_out_p=%d", bb_info->empty_save_out_p);
+ fprintf (f, ", empty_restore_in_p=%d", bb_info->empty_restore_in_p);
+ fprintf (f, "\n save_in:");
+ print_annotated_hard_reg_set
+ (f, bb_info->save_in, bb_info->save_in_mode, bb_info->save_in_pseudo);
fprintf (f, "\n save_out:");
- print_hard_reg_set_and_mode (f, bb_info->save_out,
- bb_info->save_out_mode);
+ print_annotated_hard_reg_set
+ (f, bb_info->save_out,
+ bb_info->save_out_mode, bb_info->save_out_pseudo);
+ fprintf (f, "\n restore_in:");
+ print_annotated_hard_reg_set
+ (f, bb_info->restore_in,
+ bb_info->restore_in_mode, bb_info->restore_in_pseudo);
+ fprintf (f, "\n restore_out:");
+ print_annotated_hard_reg_set
+ (f, bb_info->restore_out,
+ bb_info->restore_out_mode, bb_info->restore_out_pseudo);
+ fprintf (f, "\n free_in:");
+ print_hard_reg_set (f, bb_info->free_in);
+ fprintf (f, "\n free_out:");
+ print_hard_reg_set (f, bb_info->free_out);
fprintf (f, "\n live_at_start:");
print_hard_reg_set (f, bb_info->live_at_start);
+ fprintf (f, "\n live_at_end:");
+ print_hard_reg_set (f, bb_info->live_at_end);
fprintf (f, "\n save_here:");
print_hard_reg_set (f, bb_info->save_here);
- fprintf (f, "\n kill:");
- print_hard_reg_set (f, bb_info->kill);
- fprintf (f, "\n gen:");
- print_hard_reg_set (f, bb_info->gen);
+ fprintf (f, "\n restore_here:");
+ print_hard_reg_set (f, bb_info->restore_here);
+ fprintf (f, "\n save_kill:");
+ print_hard_reg_set (f, bb_info->save_kill);
+ fprintf (f, "\n restore_kill:");
+ print_hard_reg_set (f, bb_info->restore_kill);
+ fprintf (f, "\n save_gen:");
+ print_hard_reg_set (f, bb_info->save_gen);
+ fprintf (f, "\n restore_gen:");
+ print_hard_reg_set (f, bb_info->restore_gen);
+ fprintf (f, "\n free_gen:");
+ print_hard_reg_set (f, bb_info->save_gen);
fprintf (f, "\n\n");
}
}
@@ -1177,10 +1596,12 @@ debug_save_data (void)
/* Setup hard registers in SET to save. Setup also their save modes
- in SAVE_MODE from FROM_SAVE_MODE. */
+ in SAVE_MODE from FROM_SAVE_MODE and their pseudos in SAVE_PSEUDO
+ from FROM_SAVE_PSEUDO. */
static void
set_hard_reg_saved (HARD_REG_SET set, unsigned char *from_saved_mode,
- enum machine_mode *save_mode)
+ enum machine_mode *save_mode, int *from_saved_pseudo,
+ int *save_pseudo)
{
int regno;
@@ -1191,9 +1612,13 @@ set_hard_reg_saved (HARD_REG_SET set, un
{
n_regs_saved++;
save_mode[regno] = from_saved_mode[regno];
+ save_pseudo[regno] = from_saved_pseudo[regno];
}
else
- save_mode[regno] = VOIDmode;
+ {
+ save_mode[regno] = VOIDmode;
+ save_pseudo[regno] = -1;
+ }
}
@@ -1203,61 +1628,81 @@ set_hard_reg_saved (HARD_REG_SET set, un
void
save_call_clobbered_regs (void)
{
+ unsigned int regno;
/* Computed in mark_set_regs, holds all registers set by the current
instruction. */
- HARD_REG_SET this_insn_sets;
- struct insn_chain *chain, *next;
+ HARD_REG_SET this_insn_sets, hard_regs_to_save, saved;
+ struct insn_chain *chain, *last, *next, *prev, *last_restore_chain, *where;
+ struct bb_info *bb_info;
enum machine_mode save_mode[FIRST_PSEUDO_REGISTER];
+ loop_p loop;
+ loop_iterator li;
+ int save_pseudo[FIRST_PSEUDO_REGISTER];
+ int free_pseudo[FIRST_PSEUDO_REGISTER];
if (flag_ira && optimize && flag_ira_move_spills)
{
/* Do global analysis for better placement of spill code. */
alloc_aux_for_blocks (sizeof (struct bb_info));
+ FOR_EACH_LOOP (li, loop, 0)
+ {
+ loop->aux = xmalloc (sizeof (struct loop_info));
+ CLEAR_HARD_REG_SET (LOOP_INFO (loop)->mentioned_regs);
+ }
make_global_save_analysis ();
}
CLEAR_HARD_REG_SET (hard_regs_saved);
n_regs_saved = 0;
+ if (flag_ira && flag_ira_move_spills && reload_insn_chain != NULL)
+ {
+ bb_info = BB_INFO_BY_INDEX (reload_insn_chain->block);
+ set_hard_reg_saved (bb_info->restore_in,
+ bb_info->restore_in_mode, save_mode,
+ bb_info->restore_in_pseudo, save_pseudo);
+ }
+
+ last = NULL;
for (chain = reload_insn_chain; chain != 0; chain = next)
{
rtx insn = chain->insn;
enum rtx_code code = GET_CODE (insn);
+ last = chain;
next = chain->next;
- gcc_assert (!chain->is_caller_save_insn);
-
if (INSN_P (insn))
{
- /* If some registers have been saved, see if INSN references
- any of them. We must restore them before the insn if so. */
-
if (n_regs_saved)
{
- int regno;
-
- if (code == JUMP_INSN)
+ if ((!flag_ira || !flag_ira_move_spills) && code == JUMP_INSN)
/* Restore all registers if this is a JUMP_INSN. */
COPY_HARD_REG_SET (referenced_regs, hard_regs_saved);
else
{
CLEAR_HARD_REG_SET (referenced_regs);
+ CLEAR_HARD_REG_SET (set_regs);
mark_referenced_regs (PATTERN (insn));
AND_HARD_REG_SET (referenced_regs, hard_regs_saved);
}
+ /* If some registers have been saved, see if INSN
+ references any of them. We must restore them before
+ the insn if so. */
+
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (referenced_regs, regno))
{
- int before = regno;
-
+ unsigned int before = regno;
+
regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS,
- save_mode);
+ save_mode, save_pseudo);
if (flag_ira && optimize && flag_ira_move_spills)
{
gcc_assert (before == regno);
save_mode[before] = VOIDmode;
+ save_pseudo[before] = -1;
}
}
}
@@ -1266,8 +1711,7 @@ save_call_clobbered_regs (void)
&& ! SIBLING_CALL_P (insn)
&& ! find_reg_note (insn, REG_NORETURN, NULL))
{
- unsigned regno;
- HARD_REG_SET hard_regs_to_save, used_regs;
+ HARD_REG_SET used_regs;
reg_set_iterator rsi;
/* Use the register life information in CHAIN to compute which
@@ -1276,15 +1720,13 @@ save_call_clobbered_regs (void)
&chain->live_throughout);
/* Save hard registers always in the widest mode available. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
- {
- CLEAR_HARD_REG_SET (this_insn_sets);
- note_stores (PATTERN (insn), mark_set_regs,
- &this_insn_sets);
+ {
+ if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
save_mode[regno] = regno_save_mode[regno][1];
- }
- else
- save_mode[regno] = VOIDmode;
+ else
+ save_mode[regno] = VOIDmode;
+ save_pseudo[regno] = -1;
+ }
/* Look through all live pseudos, mark their hard registers
and choose proper mode for saving. */
@@ -1300,14 +1742,18 @@ save_call_clobbered_regs (void)
if (flag_ira && optimize && r < 0)
continue;
gcc_assert (r >= 0);
+
nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
mode = HARD_REGNO_CALLER_SAVE_MODE
- (r, nregs, PSEUDO_REGNO_MODE (regno));
+ (r, nregs, PSEUDO_REGNO_MODE (regno));
if (GET_MODE_BITSIZE (mode)
> GET_MODE_BITSIZE (save_mode[r]))
save_mode[r] = mode;
while (nregs-- > 0)
- SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+ {
+ SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+ save_pseudo[r + nregs] = regno;
+ }
}
/* Record all registers set in this call insn. These don't need
@@ -1324,11 +1770,18 @@ save_call_clobbered_regs (void)
get_call_invalidated_used_regs (insn, &used_regs, false);
AND_HARD_REG_SET (hard_regs_to_save, used_regs);
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
- regno += insert_save (chain, 1, regno, &hard_regs_to_save,
- save_mode);
-
+ if (flag_ira & flag_ira_move_spills)
+ IOR_HARD_REG_SET (hard_regs_saved, hard_regs_to_save);
+ else
+ {
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+ regno += insert_save (chain, 1, regno,
+ &hard_regs_to_save, save_mode,
+ save_pseudo);
+
+ }
+
/* Must recompute n_regs_saved. */
n_regs_saved = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
@@ -1339,7 +1792,6 @@ save_call_clobbered_regs (void)
if (chain->next == 0 || chain->next->block != chain->block)
{
- int regno;
struct bb_info *next_bb_info;
next_bb_info = (chain->next != NULL
@@ -1350,33 +1802,291 @@ save_call_clobbered_regs (void)
the restore before the insn, otherwise, put it after the insn. */
if (flag_ira && optimize && flag_ira_move_spills)
- set_hard_reg_saved (BB_INFO_BY_INDEX (chain->block)->save_here,
- BB_INFO_BY_INDEX (chain->block)->save_out_mode,
- save_mode);
+ set_hard_reg_saved
+ (BB_INFO_BY_INDEX (chain->block)->restore_here,
+ BB_INFO_BY_INDEX (chain->block)->restore_out_mode, save_mode,
+ BB_INFO_BY_INDEX (chain->block)->restore_out_pseudo,
+ save_pseudo);
if (n_regs_saved)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
{
- int before = regno;
+ unsigned int before = regno;
regno += insert_restore (chain, JUMP_P (insn),
- regno, MOVE_MAX_WORDS, save_mode);
+ regno, MOVE_MAX_WORDS, save_mode,
+ save_pseudo);
if (flag_ira && optimize && flag_ira_move_spills)
{
gcc_assert (before == regno);
save_mode[before] = VOIDmode;
+ save_pseudo[before] = -1;
}
}
if (flag_ira && optimize
&& flag_ira_move_spills && next_bb_info != NULL)
- set_hard_reg_saved (next_bb_info->save_in,
- next_bb_info->save_in_mode, save_mode);
+ set_hard_reg_saved (next_bb_info->restore_in,
+ next_bb_info->restore_in_mode, save_mode,
+ next_bb_info->restore_in_pseudo, save_pseudo);
}
}
+ if (!flag_ira || !flag_ira_move_spills)
+ return;
+
+ CLEAR_HARD_REG_SET (hard_regs_to_save);
+ n_regs_saved = 0;
+ last_restore_chain = NULL;
+
+ if (last != NULL)
+ {
+ bb_info = BB_INFO_BY_INDEX (last->block);
+ set_hard_reg_saved (bb_info->save_out,
+ bb_info->save_out_mode, save_mode,
+ bb_info->save_out_pseudo, save_pseudo);
+ COPY_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+ COPY_HARD_REG_SET (saved, bb_info->free_out);
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (!TEST_HARD_REG_BIT (saved, regno))
+ free_pseudo[regno] = -1;
+ else
+ {
+ if (TEST_HARD_REG_BIT (bb_info->save_out, regno))
+ free_pseudo [regno] = bb_info->save_out_pseudo [regno];
+ else
+ {
+ gcc_assert (TEST_HARD_REG_BIT (bb_info->restore_out, regno));
+ free_pseudo [regno] = bb_info->restore_out_pseudo [regno];
+ }
+ }
+ }
+ for (chain = last; chain != 0; chain = prev)
+ {
+ rtx insn = chain->insn;
+ enum rtx_code code = GET_CODE (insn);
+
+ prev = chain->prev;
+
+ if (INSN_P (insn))
+ {
+ bb_info = BB_INFO_BY_INDEX (chain->block);
+
+ CLEAR_HARD_REG_SET (referenced_regs);
+ CLEAR_HARD_REG_SET (set_regs);
+ mark_referenced_regs (PATTERN (insn));
+ AND_HARD_REG_SET (set_regs, hard_regs_to_save);
+ AND_COMPL_HARD_REG_SET (saved, referenced_regs);
+ AND_COMPL_HARD_REG_SET (saved, set_regs);
+
+ if (chain->is_caller_save_insn)
+ {
+ if (last_restore_chain == NULL)
+ last_restore_chain = chain;
+ }
+ else
+ {
+ /* If some registers have been saved, see if INSN
+ references any of them. We must restore them before
+ the insn if so. */
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (TEST_HARD_REG_BIT (set_regs, regno))
+ {
+ unsigned int before = regno;
+
+ /* We should put save insns before restore insns
+ between the two calls because the same stack
+ slot for different hard registers can be used
+ for restoring in the first call and saving for
+ the second call. */
+ regno += insert_save (last_restore_chain != NULL
+ ? last_restore_chain : chain,
+ last_restore_chain == NULL
+ && JUMP_P (chain->insn),
+ regno, &hard_regs_to_save,
+ save_mode, save_pseudo);
+ gcc_assert (before == regno);
+
+ CLEAR_HARD_REG_BIT (saved, regno);
+ CLEAR_HARD_REG_BIT (hard_regs_to_save, regno);
+ save_mode[before] = VOIDmode;
+ save_pseudo[before] = -1;
+ free_pseudo[before] = -1;
+ }
+ }
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (TEST_HARD_REG_BIT (saved, regno) && free_pseudo[regno] >= 0)
+ SET_REGNO_REG_SET (&chain->saved, free_pseudo[regno]);
+ if (chain->is_caller_save_insn && chain->saved_pseudo_regno >= 0)
+ {
+ int i;
+ enum machine_mode mode;
+
+ mode = GET_MODE (regno_reg_rtx[chain->saved_pseudo_regno]);
+ regno = reg_renumber[chain->saved_pseudo_regno];
+ add_to_hard_reg_set (&saved, mode, regno);
+ for (i = hard_regno_nregs[regno][mode] - 1; i >= 0; i--)
+ free_pseudo[regno + i] = chain->saved_pseudo_regno;
+ }
+ if (code == CALL_INSN
+ && ! SIBLING_CALL_P (insn)
+ && ! find_reg_note (insn, REG_NORETURN, NULL))
+ {
+ HARD_REG_SET used_regs;
+ reg_set_iterator rsi;
+
+ last_restore_chain = NULL;
+
+ /* Use the register life information in CHAIN to
+ compute which regs are live during the call. */
+ REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+ &chain->live_throughout);
+ /* Save hard registers always in the widest mode
+ available. */
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+ {
+ CLEAR_HARD_REG_SET (this_insn_sets);
+ note_stores (PATTERN (insn), mark_set_regs,
+ &this_insn_sets);
+ save_mode[regno] = regno_save_mode[regno][1];
+ }
+ else
+ save_mode[regno] = VOIDmode;
+ save_pseudo[regno] = -1;
+ }
+
+ /* Look through all live pseudos, mark their hard
+ registers and choose proper mode for saving. */
+ EXECUTE_IF_SET_IN_REG_SET
+ (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
+ {
+ int r = reg_renumber[regno];
+ int nregs;
+ enum machine_mode mode;
+
+ /* Remember live_throughout can contain spilled
+ registers when IRA is used. */
+ if (flag_ira && r < 0)
+ continue;
+ gcc_assert (r >= 0);
+
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+ mode = HARD_REGNO_CALLER_SAVE_MODE
+ (r, nregs, PSEUDO_REGNO_MODE (regno));
+ if (GET_MODE_BITSIZE (mode)
+ > GET_MODE_BITSIZE (save_mode[r]))
+ save_mode[r] = mode;
+ while (nregs-- > 0)
+ {
+ SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+ save_pseudo[r + nregs] = regno;
+ free_pseudo[r + nregs] = regno;
+ }
+ }
+
+ /* Record all registers set in this call insn. These
+ don't need to be saved. N.B. the call insn might set
+ a subreg of a multi-hard-reg pseudo; then the pseudo
+ is considered live during the call, but the subreg
+ that is set isn't. */
+ CLEAR_HARD_REG_SET (this_insn_sets);
+ note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+
+ /* Compute which hard regs must be saved before this call. */
+ AND_COMPL_HARD_REG_SET (hard_regs_to_save, call_fixed_reg_set);
+ AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets);
+ get_call_invalidated_used_regs (insn, &used_regs, false);
+ AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+ COPY_HARD_REG_SET (saved, hard_regs_to_save);
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (!TEST_HARD_REG_BIT (saved, regno))
+ {
+ free_pseudo[regno] = -1;
+ save_pseudo[regno] = -1;
+ save_mode[regno] = VOIDmode;
+ }
+ }
+ }
+
+ if (chain->prev == 0 || chain->prev->block != chain->block)
+ {
+ struct bb_info *prev_bb_info;
+
+ prev_bb_info = (chain->prev != NULL
+ ? BB_INFO_BY_INDEX (chain->prev->block) : NULL);
+
+ /* At the start of the basic block, we must save any
+ registers from save_here. */
+
+ set_hard_reg_saved
+ (BB_INFO_BY_INDEX (chain->block)->save_here,
+ BB_INFO_BY_INDEX (chain->block)->save_in_mode, save_mode,
+ BB_INFO_BY_INDEX (chain->block)->save_in_pseudo, save_pseudo);
+ COPY_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+
+ where = (last_restore_chain != NULL
+ ? last_restore_chain->next : chain);
+ /* An addr_vec is placed outside any basic block but its
+ chain has the same block as the block of subsequent insn.
+ So skip to the real start of the basic block. */
+ if (GET_CODE (where->insn) == CODE_LABEL && where->next != NULL
+ && JUMP_P (where->next->insn)
+ && (GET_CODE (PATTERN (where->next->insn)) == ADDR_DIFF_VEC
+ || GET_CODE (PATTERN (where->next->insn)) == ADDR_VEC)
+ && where->next->next != NULL)
+ where = where->next->next;
+
+ if (!hard_reg_set_empty_p (hard_regs_to_save))
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+ {
+ unsigned int before = regno;
+
+ regno += insert_save (where, INSN_P (where->insn), regno,
+ &hard_regs_to_save, save_mode,
+ save_pseudo);
+ gcc_assert (before == regno);
+ save_mode[before] = VOIDmode;
+ save_pseudo[before] = -1;
+ }
+
+ if (prev_bb_info != NULL)
+ {
+ last_restore_chain = NULL;
+ set_hard_reg_saved (prev_bb_info->save_out,
+ prev_bb_info->save_out_mode, save_mode,
+ prev_bb_info->save_out_pseudo, save_pseudo);
+ COPY_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+ COPY_HARD_REG_SET (saved, prev_bb_info->free_out);
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (!TEST_HARD_REG_BIT (saved, regno))
+ free_pseudo[regno] = -1;
+ else
+ {
+ if (TEST_HARD_REG_BIT (prev_bb_info->save_out, regno))
+ free_pseudo [regno]
+ = prev_bb_info->save_out_pseudo [regno];
+ else
+ {
+ gcc_assert (TEST_HARD_REG_BIT (prev_bb_info->restore_out, regno));
+ free_pseudo [regno]
+ = prev_bb_info->restore_out_pseudo [regno];
+ }
+ }
+ }
+ }
+ }
+
+ FOR_EACH_LOOP (li, loop, 0)
+ {
+ free (loop->aux);
+ }
if (flag_ira && optimize && flag_ira_move_spills)
free_aux_for_blocks ();
}
@@ -1467,6 +2177,7 @@ add_stored_regs (rtx reg, const_rtx sett
SET_REGNO_REG_SET ((regset) data, i);
}
+
/* Walk X and record all referenced registers in REFERENCED_REG. */
static void
mark_referenced_regs (rtx x)
@@ -1474,12 +2185,25 @@ mark_referenced_regs (rtx x)
enum rtx_code code = GET_CODE (x);
const char *fmt;
int i, j;
+ rtx dest;
if (code == SET)
mark_referenced_regs (SET_SRC (x));
if (code == SET || code == CLOBBER)
{
- x = SET_DEST (x);
+ dest = x = SET_DEST (x);
+ while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT)
+ dest = XEXP (dest, 0);
+ if (GET_CODE (dest) == REG)
+ {
+ int regno = REGNO (dest);
+ int hardregno = (regno < FIRST_PSEUDO_REGISTER ? regno
+ : reg_renumber[regno]);
+
+ if (hardregno >= 0)
+ add_to_hard_reg_set (&set_regs, GET_MODE (dest), hardregno);
+ }
code = GET_CODE (x);
if ((code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
|| code == PC || code == CC0
@@ -1529,10 +2253,12 @@ mark_referenced_regs (rtx x)
}
}
-/* Insert a sequence of insns to restore. Place these insns in front of
- CHAIN if BEFORE_P is nonzero, behind the insn otherwise. MAXRESTORE is
- the maximum number of registers which should be restored during this call.
- It should never be less than 1 since we only work with entire registers.
+/* Insert a sequence of insns to restore. Place these insns in front
+ of CHAIN if BEFORE_P is nonzero, behind the insn otherwise.
+ MAXRESTORE is the maximum number of registers which should be
+ restored during this call. It should never be less than 1 since we
+ only work with entire registers. SAVE_PSEUDO maps hard registers
+ into the corresponding pseudos.
Note that we have verified in init_caller_save that we can do this
with a simple SET, so use it. Set INSN_CODE to what we save there
@@ -1544,7 +2270,8 @@ mark_referenced_regs (rtx x)
static int
insert_restore (struct insn_chain *chain, int before_p, int regno,
- int maxrestore, enum machine_mode *save_mode)
+ int maxrestore, enum machine_mode *save_mode,
+ int *save_pseudo)
{
int i, k;
rtx pat = NULL_RTX;
@@ -1600,6 +2327,12 @@ insert_restore (struct insn_chain *chain
regno), mem);
code = reg_restore_code (regno, GET_MODE (mem));
new = insert_one_insn (chain, before_p, code, pat);
+ new->saved_pseudo_regno = save_pseudo[regno];
+
+ if (dump_file != NULL)
+ fprintf (dump_file, "inserting restore insn %u for pseudo %d %s %u\n",
+ INSN_UID (new->insn), save_pseudo[regno],
+ before_p ? "before" : "after", INSN_UID (chain->insn));
/* Clear status for all registers we restored. */
for (k = 0; k < i; k++)
@@ -1617,7 +2350,8 @@ insert_restore (struct insn_chain *chain
static int
insert_save (struct insn_chain *chain, int before_p, int regno,
- HARD_REG_SET (*to_save), enum machine_mode *save_mode)
+ HARD_REG_SET (*to_save), enum machine_mode *save_mode,
+ int *save_pseudo)
{
int i;
unsigned int k;
@@ -1673,6 +2407,12 @@ insert_save (struct insn_chain *chain, i
regno));
code = reg_save_code (regno, GET_MODE (mem));
new = insert_one_insn (chain, before_p, code, pat);
+ new->saved_pseudo_regno = save_pseudo[regno];
+
+ if (dump_file != NULL)
+ fprintf (dump_file, "inserting save insn %u for pseudo %d %s %u\n",
+ INSN_UID (new->insn), save_pseudo[regno],
+ before_p ? "before" : "after", INSN_UID (chain->insn));
/* Set hard_regs_saved and dead_or_set for all the registers we saved. */
for (k = 0; k < numregs; k++)
Index: global.c
===================================================================
--- global.c (revision 136136)
+++ global.c (working copy)
@@ -1395,6 +1395,7 @@ print_insn_chain (FILE *file, struct ins
fprintf (file, "insn=%d, ", INSN_UID(c->insn));
bitmap_print (file, &c->live_throughout, "live_throughout: ", ", ");
bitmap_print (file, &c->dead_or_set, "dead_or_set: ", "\n");
+ bitmap_print (file, &c->saved, "saved: ", "\n");
}
Index: ira-build.c
===================================================================
--- ira-build.c (revision 136136)
+++ ira-build.c (working copy)
@@ -624,8 +624,14 @@ set_allocno_cover_class (allocno_t a, en
int
conflict_vector_profitable_p (allocno_t a, int num)
{
- int nw = (ALLOCNO_MAX (a) - ALLOCNO_MIN (a) + INT_BITS) / INT_BITS;
+ int nw;
+ if (ALLOCNO_MAX (a) < ALLOCNO_MIN (a))
+ /* We prefer bit vector in such case because it does not result in
+ allocation. */
+ return FALSE;
+
+ nw = (ALLOCNO_MAX (a) - ALLOCNO_MIN (a) + INT_BITS) / INT_BITS;
return 2 * sizeof (allocno_t) * (num + 1) < 3 * nw * sizeof (INT_TYPE);
}
@@ -778,7 +784,7 @@ clear_allocno_conflicts (allocno_t a)
ALLOCNO_CONFLICT_ALLOCNOS_NUM (a) = 0;
((allocno_t *) ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a))[0] = NULL;
}
- else
+ else if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY_SIZE (a) != 0)
{
int nw;
Index: ira.c
===================================================================
--- ira.c (revision 136136)
+++ ira.c (working copy)
@@ -1889,14 +1889,9 @@ ira (FILE *f)
info. */
df_analyze ();
- {
- basic_block bb;
-
- FOR_ALL_BB (bb)
- bb->loop_father = NULL;
- current_loops = NULL;
- }
-
+ flow_loops_find (&ira_loops);
+ current_loops = &ira_loops;
+
setup_allocno_assignment_flags ();
initiate_ira_assign ();
reassign_conflict_allocnos (max_regno);
Index: Makefile.in
===================================================================
--- Makefile.in (revision 136136)
+++ Makefile.in (working copy)
@@ -2766,7 +2766,7 @@ postreload-gcse.o : postreload-gcse.c $(
caller-save.o : caller-save.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(FUNCTION_H) \
addresses.h $(RECOG_H) reload.h $(EXPR_H) toplev.h $(TM_P_H) $(DF_H) \
- output.h ira.h gt-caller-save.h
+ output.h $(CFGLOOP_H) ira.h gt-caller-save.h
bt-load.o : bt-load.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) except.h \
$(RTL_H) hard-reg-set.h $(REGS_H) $(TM_P_H) $(FIBHEAP_H) output.h $(EXPR_H) \
$(TARGET_H) $(FLAGS_H) $(INSN_ATTR_H) $(FUNCTION_H) tree-pass.h toplev.h \
Index: reload1.c
===================================================================
--- reload1.c (revision 136136)
+++ reload1.c (working copy)
@@ -258,6 +258,9 @@ static unsigned int spill_stack_slot_wid
/* Record which pseudos needed to be spilled. */
static regset_head spilled_pseudos;
+/* Record which pseudos changed their allocation in finish_spills. */
+static regset_head changed_allocation_pseudos;
+
/* Used for communication between order_regs_for_reload and count_pseudo.
Used to avoid counting one pseudo twice. */
static regset_head pseudos_counted;
@@ -504,6 +507,7 @@ init_reload (void)
reload_startobj = obstack_alloc (&reload_obstack, 0);
INIT_REG_SET (&spilled_pseudos);
+ INIT_REG_SET (&changed_allocation_pseudos);
INIT_REG_SET (&pseudos_counted);
}
@@ -521,6 +525,7 @@ new_insn_chain (void)
c = obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
INIT_REG_SET (&c->live_throughout);
INIT_REG_SET (&c->dead_or_set);
+ INIT_REG_SET (&c->saved);
}
else
{
@@ -1783,11 +1788,13 @@ order_regs_for_reload (struct insn_chain
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi)
{
- count_pseudo (i);
+ if (!REGNO_REG_SET_P (&chain->saved, i))
+ count_pseudo (i);
}
EXECUTE_IF_SET_IN_REG_SET
(&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
{
+ gcc_assert (!REGNO_REG_SET_P (&chain->saved, i));
count_pseudo (i);
}
CLEAR_REG_SET (&pseudos_counted);
@@ -1945,14 +1952,35 @@ find_reg (struct insn_chain *chain, int
rl->regno = best_reg;
EXECUTE_IF_SET_IN_REG_SET
+ (&chain->saved, FIRST_PSEUDO_REGISTER, j, rsi)
+ {
+ int nregs;
+ int r = reg_renumber[j];
+
+ if (r < 0)
+ continue;
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (j)];
+ if (dump_file != NULL
+ && ((best_reg <= r && r < best_reg + (int) rl->nregs)
+ || (r <= best_reg && best_reg < r + nregs)))
+ {
+ fprintf (dump_file, "using saved reg %d (of %u) for insn %u\n",
+ r, j, INSN_UID (chain->insn));
+ break;
+ }
+ }
+
+ EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, rsi)
{
- count_spilled_pseudo (best_reg, rl->nregs, j);
+ if (!REGNO_REG_SET_P (&chain->saved, j))
+ count_spilled_pseudo (best_reg, rl->nregs, j);
}
EXECUTE_IF_SET_IN_REG_SET
(&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, rsi)
{
+ gcc_assert (!REGNO_REG_SET_P (&chain->saved, j));
count_spilled_pseudo (best_reg, rl->nregs, j);
}
@@ -2052,13 +2080,18 @@ delete_caller_save_insns (void)
{
struct insn_chain *c = reload_insn_chain;
- while (c != 0)
+ CLEAR_HARD_REG_SET (used_spill_regs);
+ for (;;)
{
while (c != 0 && c->is_caller_save_insn)
{
struct insn_chain *next = c->next;
rtx insn = c->insn;
+ if (dump_file)
+ fprintf (dump_file, "removing caller save insn %u\n",
+ INSN_UID (insn));
+
if (c == reload_insn_chain)
reload_insn_chain = next;
delete_insn (insn);
@@ -2071,8 +2104,52 @@ delete_caller_save_insns (void)
unused_insn_chains = c;
c = next;
}
- if (c != 0)
- c = c->next;
+ if (c == 0)
+ break;
+ /* Invalidating spill hard registers got from caller-saved hard
+ registers. */
+ if (c->need_reload)
+ {
+ HARD_REG_SET saved;
+ int i;
+ unsigned int regno;
+ reg_set_iterator rsi;
+
+ CLEAR_HARD_REG_SET (saved);
+ EXECUTE_IF_SET_IN_REG_SET (&c->saved, FIRST_PSEUDO_REGISTER,
+ regno, rsi)
+ {
+ int r = reg_renumber[regno];
+
+ if (r < 0)
+ continue;
+ add_to_hard_reg_set (&saved, PSEUDO_REGNO_MODE (regno), r);
+ }
+ if (!hard_reg_set_empty_p (saved))
+ for (i = 0; i < c->n_reloads; i++)
+ {
+ int nregs;
+ struct reload *rl = &c->rld[i];
+ int r = rl->regno;
+
+ if (rl->regno < 0)
+ continue;
+ nregs = rl->nregs;
+ for (nregs--; nregs >= 0; nregs--)
+ if (TEST_HARD_REG_BIT (saved, r + nregs))
+ {
+ if (dump_file != NULL)
+ fprintf (dump_file,
+ "invalidating %d reg for insn %u reload\n",
+ rl->regno, INSN_UID (c->insn));
+ rl->regno = -1;
+ break;
+ }
+ }
+ AND_COMPL_HARD_REG_SET (c->used_spill_regs, saved);
+ IOR_HARD_REG_SET (used_spill_regs, c->used_spill_regs);
+ }
+ c = c->next;
}
}
@@ -3979,6 +4056,7 @@ finish_spills (int global)
EXECUTE_IF_SET_IN_REG_SET
(&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
{
+ gcc_assert (!REGNO_REG_SET_P (&chain->saved, i));
IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
chain->used_spill_regs);
}
@@ -4051,20 +4129,18 @@ finish_spills (int global)
REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
- /* Save the old value for the sanity test below. */
- COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
-
compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout);
compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set);
+ /* Value of chain->used_spill_regs from previous iteration
+ may be not included in the value calculated here because
+ of possible removing caller-saves insns (see function
+ delete_caller_save_insns. */
COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
-
- /* Make sure we only enlarge the set. */
- gcc_assert (hard_reg_set_subset_p (used_by_pseudos2,
- chain->used_spill_regs));
}
}
+ CLEAR_REG_SET (&changed_allocation_pseudos);
/* Let alter_reg modify the reg rtx's for the modified pseudos. */
for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
{
@@ -4072,6 +4148,8 @@ finish_spills (int global)
if (reg_old_renumber[i] == regno)
continue;
+ SET_REGNO_REG_SET (&changed_allocation_pseudos, i);
+
alter_reg (i, reg_old_renumber[i], false);
reg_old_renumber[i] = regno;
if (dump_file)
@@ -4459,8 +4537,8 @@ reload_as_needed (int live_known)
be partially clobbered by the call. */
else if (CALL_P (insn))
{
- AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
- AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+ AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
+ AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
}
}