and global constant/copy propagation for GNU compiler.
Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC 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 2, or (at your option)
-any later version.
+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 2, or (at your option) any later
+version.
-GNU CC 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.
+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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
/* TODO
- reordering of memory allocation and freeing to be more space efficient
- do rough calc of how many regs are needed in each block, and a rough
calc of how many regs are available in each class and use that to
throttle back the code in cases where RTX_COST is minimal.
- - dead store elimination
- a store to the same address as a load does not kill the load if the
source of the store is also the destination of the load. Handling this
allows more load motion, particularly out of loops.
/* This array parallels modify_mem_list, but is kept canonicalized. */
static rtx * canon_modify_mem_list;
-
-/* For each block, non-zero if memory is set in that block.
- This is computed during hash table computation and is used by
- expr_killed_p and compute_transp.
- ??? Handling of memory is very simple, we don't make any attempt
- to optimize things (later).
- ??? This can be computed by compute_sets since the information
- doesn't change. */
-static char *mem_set_in_block;
-
/* Various variables for statistics gathering. */
/* Memory used in a pass.
static void find_used_regs PARAMS ((rtx *, void *));
static int try_replace_reg PARAMS ((rtx, rtx, rtx));
static struct expr *find_avail_set PARAMS ((int, rtx));
-static int cprop_jump PARAMS ((rtx, rtx, rtx));
+static int cprop_jump PARAMS ((basic_block, rtx, rtx, rtx));
#ifdef HAVE_cc0
-static int cprop_cc0_jump PARAMS ((rtx, struct reg_use *, rtx));
+static int cprop_cc0_jump PARAMS ((basic_block, rtx, struct reg_use *, rtx));
#endif
static void mems_conflict_for_gcse_p PARAMS ((rtx, rtx, void *));
static int load_killed_in_block_p PARAMS ((basic_block, int, rtx, int));
static void canon_list_insert PARAMS ((rtx, rtx, void *));
-static int cprop_insn PARAMS ((rtx, int));
+static int cprop_insn PARAMS ((basic_block, rtx, int));
static int cprop PARAMS ((int));
static int one_cprop_pass PARAMS ((int, int));
static void alloc_pre_mem PARAMS ((int, int));
/* Allocate vars to track sets of regs, memory per block. */
reg_set_in_block = (sbitmap *) sbitmap_vector_alloc (n_basic_blocks,
max_gcse_regno);
- mem_set_in_block = (char *) gmalloc (n_basic_blocks);
/* Allocate array to keep a list of insns which modify memory in each
basic block. */
modify_mem_list = (rtx *) gmalloc (n_basic_blocks * sizeof (rtx *));
free (reg_set_bitmap);
- free (reg_set_in_block);
- free (mem_set_in_block);
+ sbitmap_vector_free (reg_set_in_block);
/* re-Cache any INSN_LIST nodes we have allocated. */
{
int i;
\f
/* Hash table support. */
-/* For each register, the cuid of the first/last insn in the block to set it,
- or -1 if not set. */
+/* For each register, the cuid of the first/last insn in the block
+ that set it, or -1 if not set. */
#define NEVER_SET -1
-static int *reg_first_set;
-static int *reg_last_set;
-/* While computing "first/last set" info, this is the CUID of first/last insn
- to set memory or -1 if not set. `mem_last_set' is also used when
- performing GCSE to record whether memory has been set since the beginning
- of the block.
+struct reg_avail_info
+{
+ int last_bb;
+ int first_set;
+ int last_set;
+};
+
+static struct reg_avail_info *reg_avail_info;
+static int current_bb;
- Note that handling of memory is very simple, we don't make any attempt
- to optimize things (later). */
-static int mem_first_set;
-static int mem_last_set;
/* See whether X, the source of a set, is something we want to consider for
GCSE. */
switch (code)
{
case REG:
- if (avail_p)
- return (reg_last_set[REGNO (x)] == NEVER_SET
- || reg_last_set[REGNO (x)] < INSN_CUID (insn));
- else
- return (reg_first_set[REGNO (x)] == NEVER_SET
- || reg_first_set[REGNO (x)] >= INSN_CUID (insn));
+ {
+ struct reg_avail_info *info = ®_avail_info[REGNO (x)];
+
+ if (info->last_bb != current_bb)
+ return 1;
+ if (avail_p)
+ return info->last_set < INSN_CUID (insn);
+ else
+ return info->first_set >= INSN_CUID (insn);
+ }
case MEM:
- if (load_killed_in_block_p (BLOCK_FOR_INSN (insn), INSN_CUID (insn),
+ if (load_killed_in_block_p (BASIC_BLOCK (current_bb), INSN_CUID (insn),
x, avail_p))
return 0;
- if (avail_p && mem_last_set != NEVER_SET
- && mem_last_set >= INSN_CUID (insn))
- return 0;
- else if (! avail_p && mem_first_set != NEVER_SET
- && mem_first_set < INSN_CUID (insn))
- return 0;
else
return oprs_unchanged_p (XEXP (x, 0), insn, avail_p);
this insn. */
int antic_p = oprs_anticipatable_p (src, insn) && single_set (insn);
/* An expression is not available if its operands are
- subsequently modified, including this insn. */
- int avail_p = oprs_available_p (src, insn);
+ subsequently modified, including this insn. It's also not
+ available if this is a branch, because we can't insert
+ a set after the branch. */
+ int avail_p = (oprs_available_p (src, insn)
+ && ! JUMP_P (insn));
insert_expr_in_table (src, GET_MODE (dest), insn, antic_p, avail_p);
}
/* Record register first/last/block set information for REGNO in INSN.
- reg_first_set records the first place in the block where the register
+ first_set records the first place in the block where the register
is set and is used to compute "anticipatability".
- reg_last_set records the last place in the block where the register
+ last_set records the last place in the block where the register
is set and is used to compute "availability".
+ last_bb records the block for which first_set and last_set are
+ valid, as a quick test to invalidate them.
+
reg_set_in_block records whether the register is set in the block
and is used to compute "transparency". */
rtx insn;
int regno;
{
- if (reg_first_set[regno] == NEVER_SET)
- reg_first_set[regno] = INSN_CUID (insn);
+ struct reg_avail_info *info = ®_avail_info[regno];
+ int cuid = INSN_CUID (insn);
- reg_last_set[regno] = INSN_CUID (insn);
- SET_BIT (reg_set_in_block[BLOCK_NUM (insn)], regno);
+ info->last_set = cuid;
+ if (info->last_bb != current_bb)
+ {
+ info->last_bb = current_bb;
+ info->first_set = cuid;
+ SET_BIT (reg_set_in_block[current_bb], regno);
+ }
}
alloc_INSN_LIST (dest, canon_modify_mem_list[BLOCK_NUM (insn)]);
}
-/* Record memory first/last/block set information for INSN. */
/* Record memory modification information for INSN. We do not actually care
about the memory location(s) that are set, or even how they are set (consider
a CALL_INSN). We merely need to record which insns modify memory. */
record_last_mem_set_info (insn)
rtx insn;
{
- if (mem_first_set == NEVER_SET)
- mem_first_set = INSN_CUID (insn);
-
- mem_last_set = INSN_CUID (insn);
- mem_set_in_block[BLOCK_NUM (insn)] = 1;
+ /* load_killed_in_block_p will handle the case of calls clobbering
+ everything. */
modify_mem_list[BLOCK_NUM (insn)] =
alloc_INSN_LIST (insn, modify_mem_list[BLOCK_NUM (insn)]);
{
/* Note that traversals of this loop (other than for free-ing)
will break after encountering a CALL_INSN. So, there's no
- need to insert a pair of items, as canon_list_insert does. */
+ need to insert a pair of items, as canon_list_insert does. */
canon_modify_mem_list[BLOCK_NUM (insn)] =
alloc_INSN_LIST (insn, canon_modify_mem_list[BLOCK_NUM (insn)]);
}
compute_hash_table (set_p)
int set_p;
{
- int bb;
+ unsigned int i;
/* While we compute the hash table we also compute a bit array of which
registers are set in which blocks.
- We also compute which blocks set memory, in the absence of aliasing
- support [which is TODO].
??? This isn't needed during const/copy propagation, but it's cheap to
compute. Later. */
sbitmap_vector_zero (reg_set_in_block, n_basic_blocks);
- memset ((char *) mem_set_in_block, 0, n_basic_blocks);
/* re-Cache any INSN_LIST nodes we have allocated. */
{
}
}
/* Some working arrays used to track first and last set in each block. */
- /* ??? One could use alloca here, but at some size a threshold is crossed
- beyond which one should use malloc. Are we at that threshold here? */
- reg_first_set = (int *) gmalloc (max_gcse_regno * sizeof (int));
- reg_last_set = (int *) gmalloc (max_gcse_regno * sizeof (int));
+ reg_avail_info = (struct reg_avail_info*)
+ gmalloc (max_gcse_regno * sizeof (struct reg_avail_info));
- for (bb = 0; bb < n_basic_blocks; bb++)
+ for (i = 0; i < max_gcse_regno; ++i)
+ reg_avail_info[i].last_bb = NEVER_SET;
+
+ for (current_bb = 0; current_bb < n_basic_blocks; current_bb++)
{
rtx insn;
unsigned int regno;
int in_libcall_block;
- unsigned int i;
/* First pass over the instructions records information used to
determine when registers and memory are first and last set.
- ??? The mem_set_in_block and hard-reg reg_set_in_block computation
+ ??? hard-reg reg_set_in_block computation
could be moved to compute_sets since they currently don't change. */
- for (i = 0; i < max_gcse_regno; i++)
- reg_first_set[i] = reg_last_set[i] = NEVER_SET;
-
- mem_first_set = NEVER_SET;
- mem_last_set = NEVER_SET;
-
- for (insn = BLOCK_HEAD (bb);
- insn && insn != NEXT_INSN (BLOCK_END (bb));
+ for (insn = BLOCK_HEAD (current_bb);
+ insn && insn != NEXT_INSN (BLOCK_END (current_bb));
insn = NEXT_INSN (insn))
{
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
- {
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- record_last_reg_set_info (insn, regno);
- continue;
- }
-#endif
-
if (! INSN_P (insn))
continue;
if (GET_CODE (insn) == CALL_INSN)
{
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if ((call_used_regs[regno]
- && regno != STACK_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && regno != HARD_FRAME_POINTER_REGNUM
-#endif
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
-#endif
-#if !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
- && ! (regno == PIC_OFFSET_TABLE_REGNUM && flag_pic)
+ bool clobbers_all = false;
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP
+ && find_reg_note (insn, REG_SETJMP, NULL_RTX))
+ clobbers_all = true;
#endif
- && regno != FRAME_POINTER_REGNUM)
- || global_regs[regno])
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (clobbers_all
+ || TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
record_last_reg_set_info (insn, regno);
- if (! CONST_CALL_P (insn))
- record_last_mem_set_info (insn);
+ mark_call (insn);
}
note_stores (PATTERN (insn), record_last_set_info, insn);
/* The next pass builds the hash table. */
- for (insn = BLOCK_HEAD (bb), in_libcall_block = 0;
- insn && insn != NEXT_INSN (BLOCK_END (bb));
+ for (insn = BLOCK_HEAD (current_bb), in_libcall_block = 0;
+ insn && insn != NEXT_INSN (BLOCK_END (current_bb));
insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- in_libcall_block = 1;
- else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- in_libcall_block = 0;
- hash_scan_insn (insn, set_p, in_libcall_block);
+ in_libcall_block = 1;
+ else if (set_p && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
+ hash_scan_insn (insn, set_p, in_libcall_block);
+ if (!set_p && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
}
}
- free (reg_first_set);
- free (reg_last_set);
-
- /* Catch bugs early. */
- reg_first_set = reg_last_set = 0;
+ free (reg_avail_info);
+ reg_avail_info = NULL;
}
/* Allocate space for the set hash table.
/* Also keep a record of the last instruction to modify memory.
For now this is very trivial, we only record whether any memory
location has been modified. */
- mem_last_set = 0;
{
int i;
if (load_killed_in_block_p (BLOCK_FOR_INSN (insn),
INSN_CUID (insn), x, 0))
return 0;
- if (mem_last_set != 0)
- return 0;
else
return oprs_not_set_p (XEXP (x, 0), insn);
mark_call (insn)
rtx insn;
{
- mem_last_set = INSN_CUID (insn);
- if (! CONST_CALL_P (insn))
+ if (! CONST_OR_PURE_CALL_P (insn))
record_last_mem_set_info (insn);
}
else if (GET_CODE (dest) == MEM)
record_last_mem_set_info (insn);
- if (GET_CODE (dest) == REG)
- SET_BIT (reg_set_bitmap, REGNO (dest));
- else if (GET_CODE (dest) == MEM)
- mem_last_set = INSN_CUID (insn);
-
if (GET_CODE (SET_SRC (pat)) == CALL)
mark_call (insn);
}
if (GET_CODE (clob) == REG)
SET_BIT (reg_set_bitmap, REGNO (clob));
else
- mem_last_set = INSN_CUID (insn);
- if (GET_CODE (clob) == REG)
- SET_BIT (reg_set_bitmap, REGNO (clob));
- else
record_last_mem_set_info (insn);
}
static void
free_rd_mem ()
{
- free (rd_kill);
- free (rd_gen);
- free (reaching_defs);
- free (rd_out);
+ sbitmap_vector_free (rd_kill);
+ sbitmap_vector_free (rd_gen);
+ sbitmap_vector_free (reaching_defs);
+ sbitmap_vector_free (rd_out);
}
/* Add INSN to the kills of BB. REGNO, set in BB, is killed by INSN. */
if (GET_CODE (insn) == CALL_INSN)
{
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- {
- if ((call_used_regs[regno]
- && regno != STACK_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && regno != HARD_FRAME_POINTER_REGNUM
-#endif
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && ! (regno == ARG_POINTER_REGNUM
- && fixed_regs[regno])
-#endif
-#if !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
- && ! (regno == PIC_OFFSET_TABLE_REGNUM && flag_pic)
-#endif
- && regno != FRAME_POINTER_REGNUM)
- || global_regs[regno])
- handle_rd_kill_set (insn, regno, BASIC_BLOCK (bb));
- }
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ handle_rd_kill_set (insn, regno, BASIC_BLOCK (bb));
}
if (GET_CODE (pat) == PARALLEL)
static void
free_avail_expr_mem ()
{
- free (ae_kill);
- free (ae_gen);
- free (ae_in);
- free (ae_out);
+ sbitmap_vector_free (ae_kill);
+ sbitmap_vector_free (ae_gen);
+ sbitmap_vector_free (ae_in);
+ sbitmap_vector_free (ae_out);
}
/* Compute the set of available expressions generated in each basic block. */
case MEM:
if (load_killed_in_block_p (bb, get_max_uid () + 1, x, 0))
return 1;
- if (mem_set_in_block[bb->index])
- return 1;
else
return expr_killed_p (XEXP (x, 0), bb);
}
/* This wrapper for expr_reaches_here_p_work() is to ensure that any
- memory allocated for that function is returned. */
+ memory allocated for that function is returned. */
static int
expr_reaches_here_p (occr, expr, bb, check_self_loop)
static void
free_cprop_mem ()
{
- free (cprop_pavloc);
- free (cprop_absaltered);
- free (cprop_avin);
- free (cprop_avout);
+ sbitmap_vector_free (cprop_pavloc);
+ sbitmap_vector_free (cprop_absaltered);
+ sbitmap_vector_free (cprop_avin);
+ sbitmap_vector_free (cprop_avout);
}
/* For each block, compute whether X is transparent. X is either an
list_entry = XEXP (list_entry, 1);
}
}
- if (set_p)
- {
- for (bb = 0; bb < n_basic_blocks; bb++)
- if (mem_set_in_block[bb])
- SET_BIT (bmap[bb], indx);
- }
- else
- {
- for (bb = 0; bb < n_basic_blocks; bb++)
- if (mem_set_in_block[bb])
- RESET_BIT (bmap[bb], indx);
- }
x = XEXP (x, 0);
goto repeat;
nonzero if a change was made. We know INSN has just a SET. */
static int
-cprop_jump (insn, from, src)
+cprop_jump (bb, insn, from, src)
rtx insn;
rtx from;
rtx src;
+ basic_block bb;
{
rtx set = PATTERN (insn);
rtx new = simplify_replace_rtx (SET_SRC (set), from, src);
print_rtl (gcse_file, src);
fprintf (gcse_file, "\n");
}
+ purge_dead_edges (bb);
return 1;
}
Returns nonzero if a change was made. */
static int
-cprop_cc0_jump (insn, reg_used, src)
+cprop_cc0_jump (bb, insn, reg_used, src)
+ basic_block bb;
rtx insn;
struct reg_use *reg_used;
rtx src;
rtx new_src = simplify_replace_rtx (SET_SRC (PATTERN (insn)),
reg_used->reg_rtx, src);
- if (! cprop_jump (jump, cc0_rtx, new_src))
+ if (! cprop_jump (bb, jump, cc0_rtx, new_src))
return 0;
/* If we succeeded, delete the cc0 setter. */
The result is non-zero if a change was made. */
static int
-cprop_insn (insn, alter_jumps)
+cprop_insn (bb, insn, alter_jumps)
+ basic_block bb;
rtx insn;
int alter_jumps;
{
note = find_reg_equal_equiv_note (insn);
- /* We may win even when propagating constants into notes. */
+ /* We may win even when propagating constants into notes. */
if (note)
find_used_regs (&XEXP (note, 0), NULL);
struct expr *set;
/* Ignore registers created by GCSE.
- We do this because ... */
+ We do this because ... */
if (regno >= max_gcse_regno)
continue;
&& GET_CODE (insn) == JUMP_INSN
&& condjump_p (insn)
&& ! simplejump_p (insn))
- changed |= cprop_jump (insn, reg_used->reg_rtx, src);
+ changed |= cprop_jump (bb, insn, reg_used->reg_rtx, src);
#ifdef HAVE_cc0
/* Similar code for machines that use a pair of CC0 setter and
&& GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
&& condjump_p (NEXT_INSN (insn))
&& ! simplejump_p (NEXT_INSN (insn))
- && cprop_cc0_jump (insn, reg_used, src))
+ && cprop_cc0_jump (bb, insn, reg_used, src))
{
changed = 1;
break;
insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
- changed |= cprop_insn (insn, alter_jumps);
+ changed |= cprop_insn (BASIC_BLOCK (bb), insn, alter_jumps);
/* Keep track of everything modified by this insn. */
/* ??? Need to be careful w.r.t. mods done to INSN. Don't
static void
free_pre_mem ()
{
- free (transp);
- free (comp);
+ sbitmap_vector_free (transp);
+ sbitmap_vector_free (comp);
/* ANTLOC and AE_KILL are freed just after pre_lcm finishes. */
if (pre_optimal)
- free (pre_optimal);
+ sbitmap_vector_free (pre_optimal);
if (pre_redundant)
- free (pre_redundant);
+ sbitmap_vector_free (pre_redundant);
if (pre_insert_map)
- free (pre_insert_map);
+ sbitmap_vector_free (pre_insert_map);
if (pre_delete_map)
- free (pre_delete_map);
-
+ sbitmap_vector_free (pre_delete_map);
if (ae_in)
- free (ae_in);
+ sbitmap_vector_free (ae_in);
if (ae_out)
- free (ae_out);
+ sbitmap_vector_free (ae_out);
transp = comp = NULL;
pre_optimal = pre_redundant = pre_insert_map = pre_delete_map = NULL;
edge_list = pre_edge_lcm (gcse_file, n_exprs, transp, comp, antloc,
ae_kill, &pre_insert_map, &pre_delete_map);
- free (antloc);
+ sbitmap_vector_free (antloc);
antloc = NULL;
- free (ae_kill);
+ sbitmap_vector_free (ae_kill);
ae_kill = NULL;
free (trapping_expr);
}
}
/* The wrapper for pre_expr_reaches_here_work that ensures that any
- memory allocated for that function is returned. */
+ memory allocated for that function is returned. */
static int
pre_expr_reaches_here_p (occr_bb, expr, bb)
of exception handling. */
else if (GET_CODE (insn) == CALL_INSN)
{
- HARD_REG_SET parm_regs;
- int nparm_regs;
- rtx p;
-
/* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
we search backward and place the instructions before the first
parameter is loaded. Do this for everyone for consistency and a
/* Since different machines initialize their parameter registers
in different orders, assume nothing. Collect the set of all
parameter registers. */
- CLEAR_HARD_REG_SET (parm_regs);
- nparm_regs = 0;
- for (p = CALL_INSN_FUNCTION_USAGE (insn); p ; p = XEXP (p, 1))
- if (GET_CODE (XEXP (p, 0)) == USE
- && GET_CODE (XEXP (XEXP (p, 0), 0)) == REG)
- {
- if (REGNO (XEXP (XEXP (p, 0), 0)) >= FIRST_PSEUDO_REGISTER)
- abort ();
-
- /* We only care about registers which can hold function
- arguments. */
- if (! FUNCTION_ARG_REGNO_P (REGNO (XEXP (XEXP (p, 0), 0))))
- continue;
+ insn = find_first_parameter_load (insn, bb->head);
- SET_HARD_REG_BIT (parm_regs, REGNO (XEXP (XEXP (p, 0), 0)));
- nparm_regs++;
- }
-
- /* Search backward for the first set of a register in this set. */
- while (nparm_regs && bb->head != insn)
- {
- insn = PREV_INSN (insn);
- p = single_set (insn);
- if (p && GET_CODE (SET_DEST (p)) == REG
- && REGNO (SET_DEST (p)) < FIRST_PSEUDO_REGISTER
- && TEST_HARD_REG_BIT (parm_regs, REGNO (SET_DEST (p))))
- {
- CLEAR_HARD_REG_BIT (parm_regs, REGNO (SET_DEST (p)));
- nparm_regs--;
- }
- }
-
/* If we found all the parameter loads, then we want to insert
before the first parameter load.
}
}
- free (inserted);
+ sbitmap_vector_free (inserted);
return did_insert;
}
if (!set)
abort ();
- new_insn = emit_insn_after (gen_rtx_SET (VOIDmode, reg, SET_DEST (set)),
- insn);
+ new_insn = emit_insn_after (gen_move_insn (reg, SET_DEST (set)), insn);
/* Keep block number table up to date. */
set_block_for_new_insns (new_insn, bb);
"PRE: bb %d, insn %d, copy expression %d in insn %d to reg %d\n",
BLOCK_NUM (insn), INSN_UID (new_insn), indx,
INSN_UID (insn), regno);
+ update_ld_motion_stores (expr);
}
/* Copy available expressions that reach the redundant expression
We no longer ignore such label references (see LABEL_REF handling in
mark_jump_label for additional information). */
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
REG_NOTES (insn));
if (LABEL_P (XEXP (x, 0)))
LABEL_NUSES (XEXP (x, 0))++;
free (block_reg);
/* Free bitmaps. */
- free (npi.nonnull_local);
- free (npi.nonnull_killed);
- free (nonnull_avin);
- free (nonnull_avout);
+ sbitmap_vector_free (npi.nonnull_local);
+ sbitmap_vector_free (npi.nonnull_killed);
+ sbitmap_vector_free (nonnull_avin);
+ sbitmap_vector_free (nonnull_avout);
}
/* Code Hoisting variables and subroutines. */
static void
free_code_hoist_mem ()
{
- free (antloc);
- free (transp);
- free (comp);
+ sbitmap_vector_free (antloc);
+ sbitmap_vector_free (transp);
+ sbitmap_vector_free (comp);
- free (hoist_vbein);
- free (hoist_vbeout);
- free (hoist_exprs);
- free (transpout);
+ sbitmap_vector_free (hoist_vbein);
+ sbitmap_vector_free (hoist_vbeout);
+ sbitmap_vector_free (hoist_exprs);
+ sbitmap_vector_free (transpout);
- free (dominators);
+ sbitmap_vector_free (dominators);
}
/* Compute the very busy expressions at entry/exit from each block.
insn && insn != PREV_INSN (BLOCK_HEAD (bb));
insn = PREV_INSN (insn))
{
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
- {
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- SET_BIT (reg_set_in_block[bb], regno);
- continue;
- }
-#endif
- /* Ignore anything that is not a normal insn. */
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ /* Ignore anything that is not a normal insn. */
+ if (! INSN_P (insn))
continue;
if (GET_CODE (insn) == CALL_INSN)
{
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if ((call_used_regs[regno]
- && regno != STACK_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && regno != HARD_FRAME_POINTER_REGNUM
-#endif
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
-#endif
-#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
- && ! (regno == PIC_OFFSET_TABLE_REGNUM && flag_pic)
+ bool clobbers_all = false;
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP
+ && find_reg_note (insn, REG_SETJMP, NULL_RTX))
+ clobbers_all = true;
#endif
- && regno != FRAME_POINTER_REGNUM)
- || global_regs[regno])
- SET_BIT (reg_set_in_block[bb], regno);
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (clobbers_all
+ || TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ SET_BIT (reg_set_in_block[bb], regno);
}
pat = PATTERN (insn);
int i,j;
int ret = 0;
+ if (!x)
+ return 0;
+
if (GET_CODE (x) == SET)
x = SET_SRC (x);
if (GET_CODE (insn) == CALL_INSN)
{
- if (CONST_CALL_P (insn))
+ if (CONST_OR_PURE_CALL_P (insn))
return 0;
else
return 1;
{
if (store_killed_after (ptr->pattern, BLOCK_HEAD (b), BASIC_BLOCK (b)))
{
- /* The anticipatable expression is not killed if it's gen'd. */
+ /* The anticipatable expression is not killed if it's gen'd. */
/*
We leave this check out for now. If we have a code sequence
in a block which looks like:
free_ldst_mems ();
if (ae_gen)
- free (ae_gen);
+ sbitmap_vector_free (ae_gen);
if (ae_kill)
- free (ae_kill);
+ sbitmap_vector_free (ae_kill);
if (transp)
- free (transp);
+ sbitmap_vector_free (transp);
if (st_antloc)
- free (st_antloc);
+ sbitmap_vector_free (st_antloc);
if (pre_insert_map)
- free (pre_insert_map);
+ sbitmap_vector_free (pre_insert_map);
if (pre_delete_map)
- free (pre_delete_map);
+ sbitmap_vector_free (pre_delete_map);
if (reg_set_in_block)
- free (reg_set_in_block);
+ sbitmap_vector_free (reg_set_in_block);
ae_gen = ae_kill = transp = st_antloc = NULL;
pre_insert_map = pre_delete_map = reg_set_in_block = NULL;
num_stores = compute_store_table ();
if (num_stores == 0)
{
- free (reg_set_in_block);
+ sbitmap_vector_free (reg_set_in_block);
end_alias_analysis ();
return;
}