#include <setjmp.h>
#include "rtl.h"
+#include "tm_p.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "real.h"
#include "insn-config.h"
#include "recog.h"
+#include "function.h"
#include "expr.h"
#include "toplev.h"
#include "output.h"
-#include "splay-tree.h"
+#include "hashtab.h"
+#include "ggc.h"
/* The basic idea of common subexpression elimination is to go
through the code, keeping a record of expressions that would
expressions encountered with the cheapest equivalent expression.
It is too complicated to keep track of the different possibilities
- when control paths merge; so, at each label, we forget all that is
- known and start fresh. This can be described as processing each
- basic block separately. Note, however, that these are not quite
- the same as the basic blocks found by a later pass and used for
- data flow analysis and register packing. We do not need to start fresh
- after a conditional jump instruction if there is no label there.
+ when control paths merge in this code; so, at each label, we forget all
+ that is known and start fresh. This can be described as processing each
+ extended basic block separately. We have a separate pass to perform
+ global CSE.
+
+ Note CSE can turn a conditional or computed jump into a nop or
+ an unconditional jump. When this occurs we arrange to run the jump
+ optimizer after CSE to delete the unreachable code.
We use two data structures to record the equivalent expressions:
a hash table for most expressions, and several vectors together
static int *reg_prev_eqv;
struct cse_reg_info {
- union {
- /* The number of times the register has been altered in the current
- basic block. */
- int reg_tick;
-
- /* The next cse_reg_info structure in the free list. */
- struct cse_reg_info* next;
- } variant;
+ /* The number of times the register has been altered in the current
+ basic block. */
+ int reg_tick;
+
+ /* The next cse_reg_info structure in the free or used list. */
+ struct cse_reg_info* next;
/* The REG_TICK value at which rtx's containing this register are
valid in the hash table. If this does not equal the current
/* The quantity number of the register's current contents. */
int reg_qty;
+
+ /* Search key */
+ int regno;
};
/* A free list of cse_reg_info entries. */
static struct cse_reg_info *cse_reg_info_free_list;
+/* A used list of cse_reg_info entries. */
+static struct cse_reg_info *cse_reg_info_used_list;
+static struct cse_reg_info *cse_reg_info_used_list_end;
+
/* A mapping from registers to cse_reg_info data structures. */
-static splay_tree cse_reg_info_tree;
+static hash_table_t cse_reg_info_tree;
/* The last lookup we did into the cse_reg_info_tree. This allows us
to cache repeated lookups. */
/* Get the number of times this register has been updated in this
basic block. */
-#define REG_TICK(N) ((GET_CSE_REG_INFO (N))->variant.reg_tick)
+#define REG_TICK(N) ((GET_CSE_REG_INFO (N))->reg_tick)
/* Get the point at which REG was recorded in the table. */
#define FIXED_BASE_PLUS_P(X) \
((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \
- || (X) == arg_pointer_rtx \
+ || ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\
|| (X) == virtual_stack_vars_rtx \
|| (X) == virtual_incoming_args_rtx \
|| (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (XEXP (X, 0) == frame_pointer_rtx \
|| XEXP (X, 0) == hard_frame_pointer_rtx \
- || XEXP (X, 0) == arg_pointer_rtx \
+ || ((X) == arg_pointer_rtx \
+ && fixed_regs[ARG_POINTER_REGNUM]) \
|| XEXP (X, 0) == virtual_stack_vars_rtx \
|| XEXP (X, 0) == virtual_incoming_args_rtx)) \
|| GET_CODE (X) == ADDRESSOF)
|| (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (XEXP (X, 0) == frame_pointer_rtx \
|| XEXP (X, 0) == hard_frame_pointer_rtx \
- || XEXP (X, 0) == arg_pointer_rtx \
+ || ((X) == arg_pointer_rtx \
+ && fixed_regs[ARG_POINTER_REGNUM]) \
|| XEXP (X, 0) == virtual_stack_vars_rtx \
|| XEXP (X, 0) == virtual_incoming_args_rtx)) \
|| (X) == stack_pointer_rtx \
extern void dump_class PROTO((struct table_elt*));
static void check_fold_consts PROTO((PTR));
static struct cse_reg_info* get_cse_reg_info PROTO((int));
-static void free_cse_reg_info PROTO((splay_tree_value));
-static void flush_hash_table PROTO((void));
+static unsigned int hash_cse_reg_info PROTO((hash_table_entry_t));
+static int cse_reg_info_equal_p PROTO((hash_table_entry_t,
+ hash_table_entry_t));
-extern int rtx_equal_function_value_matters;
+static void flush_hash_table PROTO((void));
\f
/* Dump the expressions in the equivalence class indicated by CLASSP.
This function is used only for debugging. */
{
register int i, j;
register enum rtx_code code;
- register char *fmt;
+ register const char *fmt;
register int total;
if (x == 0)
int regno;
{
struct cse_reg_info *cri;
- splay_tree_node n;
+ struct cse_reg_info **entry;
+ struct cse_reg_info temp;
/* See if we already have this entry. */
- n = splay_tree_lookup (cse_reg_info_tree,
- (splay_tree_key) regno);
- if (n)
- cri = (struct cse_reg_info *) (n->value);
+ temp.regno = regno;
+ entry = (struct cse_reg_info **) find_hash_table_entry (cse_reg_info_tree,
+ &temp, TRUE);
+
+ if (*entry)
+ cri = *entry;
else
{
/* Get a new cse_reg_info structure. */
if (cse_reg_info_free_list)
{
cri = cse_reg_info_free_list;
- cse_reg_info_free_list = cri->variant.next;
+ cse_reg_info_free_list = cri->next;
}
else
cri = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
/* Initialize it. */
- cri->variant.reg_tick = 0;
+ cri->reg_tick = 0;
cri->reg_in_table = -1;
cri->reg_qty = regno;
-
- splay_tree_insert (cse_reg_info_tree,
- (splay_tree_key) regno,
- (splay_tree_value) cri);
+ cri->regno = regno;
+ cri->next = cse_reg_info_used_list;
+ cse_reg_info_used_list = cri;
+ if (!cse_reg_info_used_list_end)
+ cse_reg_info_used_list_end = cri;
+
+ *entry = cri;
}
/* Cache this lookup; we tend to be looking up information about the
return cri;
}
-static void
-free_cse_reg_info (v)
- splay_tree_value v;
+static unsigned int
+hash_cse_reg_info (el_ptr)
+ hash_table_entry_t el_ptr;
{
- struct cse_reg_info *cri = (struct cse_reg_info *) v;
-
- cri->variant.next = cse_reg_info_free_list;
- cse_reg_info_free_list = cri;
+ return ((const struct cse_reg_info *) el_ptr)->regno;
+}
+
+static int
+cse_reg_info_equal_p (el_ptr1, el_ptr2)
+ hash_table_entry_t el_ptr1;
+ hash_table_entry_t el_ptr2;
+{
+ return (((const struct cse_reg_info *) el_ptr1)->regno
+ == ((const struct cse_reg_info *) el_ptr2)->regno);
}
/* Clear the hash table and initialize each register with its own quantity,
if (cse_reg_info_tree)
{
- splay_tree_delete (cse_reg_info_tree);
+ delete_hash_table (cse_reg_info_tree);
+ if (cse_reg_info_used_list)
+ {
+ cse_reg_info_used_list_end->next = cse_reg_info_free_list;
+ cse_reg_info_free_list = cse_reg_info_used_list;
+ cse_reg_info_used_list = cse_reg_info_used_list_end = 0;
+ }
cached_cse_reg_info = 0;
}
- cse_reg_info_tree = splay_tree_new (splay_tree_compare_ints, 0,
- free_cse_reg_info);
+ cse_reg_info_tree = create_hash_table (0, hash_cse_reg_info,
+ cse_reg_info_equal_p);
CLEAR_HARD_REG_SET (hard_regs_in_table);
{
register enum rtx_code code;
register int i, j;
- register char *fmt;
+ register const char *fmt;
register int changed = 0;
if (x == 0)
{
next = p->next_same_hash;
- if (p->in_memory)
- {
- remove_from_table (p, hash);
- continue;
- }
-
if (GET_CODE (p->exp) != REG
|| REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
continue;
register int i, j;
register unsigned hash = 0;
register enum rtx_code code;
- register char *fmt;
+ register const char *fmt;
/* repeat is used to turn tail-recursion into iteration. */
repeat:
if (GET_MODE (x) != VOIDmode)
for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
{
- unsigned tem = XINT (x, i);
+ unsigned HOST_WIDE_INT tem = XWINT (x, i);
hash += tem;
}
else
register unsigned tem = XINT (x, i);
hash += tem;
}
- else if (fmt[i] == '0')
+ else if (fmt[i] == '0' || fmt[i] == 't')
/* unused */;
else
abort ();
{
register int i, j;
register enum rtx_code code;
- register char *fmt;
+ register const char *fmt;
/* Note: it is incorrect to assume an expression is equivalent to itself
if VALIDATE is nonzero. */
break;
case '0':
+ case 't':
break;
default:
{
register int i;
register enum rtx_code code;
- register char *fmt;
+ register const char *fmt;
repeat:
if (x == y)
{
register int i;
register enum rtx_code code;
- register char *fmt;
+ register const char *fmt;
if (x == 0)
return x;
&& (((REGNO (new) < FIRST_PSEUDO_REGISTER)
!= (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
|| (insn_code = recog_memoized (insn)) < 0
- || insn_n_dups[insn_code] > 0))
+ || insn_data[insn_code].n_dups > 0))
validate_change (insn, &XEXP (x, i), new, 1);
else
XEXP (x, i) = new;
abort ();
}
- /* Clear the bits that don't belong in our mode,
- unless they and our sign bit are all one.
- So we get either a reasonable negative value or a reasonable
- unsigned value for this mode. */
- if (width < HOST_BITS_PER_WIDE_INT
- && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
- != ((HOST_WIDE_INT) (-1) << (width - 1))))
- val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
- /* If this would be an entire word for the target, but is not for
- the host, then sign-extend on the host so that the number will look
- the same way on the host that it would on the target.
-
- For example, when building a 64 bit alpha hosted 32 bit sparc
- targeted compiler, then we want the 32 bit unsigned value -1 to be
- represented as a 64 bit value -1, and not as 0x00000000ffffffff.
- The later confuses the sparc backend. */
-
- if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
- && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
- val |= ((HOST_WIDE_INT) (-1) << width);
+ val = trunc_int_for_mode (val, mode);
return GEN_INT (val);
}
set_float_handler (NULL_PTR);
- /* Clear the bits that don't belong in our mode,
- unless they and our sign bit are all one.
- So we get either a reasonable negative value or a reasonable
- unsigned value for this mode. */
- if (width < HOST_BITS_PER_WIDE_INT
- && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
- != ((HOST_WIDE_INT) (-1) << (width - 1))))
- val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
- /* If this would be an entire word for the target, but is not for
- the host, then sign-extend on the host so that the number will look
- the same way on the host that it would on the target.
-
- For example, when building a 64 bit alpha hosted 32 bit sparc
- targeted compiler, then we want the 32 bit unsigned value -1 to be
- represented as a 64 bit value -1, and not as 0x00000000ffffffff.
- The later confuses the sparc backend. */
-
- if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
- && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
- val |= ((HOST_WIDE_INT) (-1) << width);
+ val = trunc_int_for_mode (val, mode);
return GEN_INT (val);
}
if (GET_CODE (op1) == AND)
{
if (rtx_equal_p (op0, XEXP (op1, 0)))
- return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 1)));
+ return cse_gen_binary (AND, mode, op0,
+ gen_rtx_NOT (mode, XEXP (op1, 1)));
if (rtx_equal_p (op0, XEXP (op1, 1)))
- return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 0)));
+ return cse_gen_binary (AND, mode, op0,
+ gen_rtx_NOT (mode, XEXP (op1, 0)));
}
break;
return gen_rtx_MULT (mode, op0,
CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
#else
- return gen_rtx_MULT (mode, op0,
- CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
+ return
+ gen_rtx_MULT (mode, op0,
+ CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
#endif
}
}
case ROTATE:
/* Rotating ~0 always results in ~0. */
if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
- && INTVAL (op0) == GET_MODE_MASK (mode)
+ && (unsigned HOST_WIDE_INT) INTVAL (op0) == GET_MODE_MASK (mode)
&& ! side_effects_p (op1))
return op0;
case SMAX:
if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
- && (INTVAL (op1)
+ && ((unsigned HOST_WIDE_INT) INTVAL (op1)
== (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
&& ! side_effects_p (op0))
return op1;
abort ();
}
- /* Clear the bits that don't belong in our mode, unless they and our sign
- bit are all one. So we get either a reasonable negative value or a
- reasonable unsigned value for this mode. */
- if (width < HOST_BITS_PER_WIDE_INT
- && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
- != ((HOST_WIDE_INT) (-1) << (width - 1))))
- val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
- /* If this would be an entire word for the target, but is not for
- the host, then sign-extend on the host so that the number will look
- the same way on the host that it would on the target.
-
- For example, when building a 64 bit alpha hosted 32 bit sparc
- targeted compiler, then we want the 32 bit unsigned value -1 to be
- represented as a 64 bit value -1, and not as 0x00000000ffffffff.
- The later confuses the sparc backend. */
-
- if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
- && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
- val |= ((HOST_WIDE_INT) (-1) << width);
+ val = trunc_int_for_mode (val, mode);
return GEN_INT (val);
}
/* Unsigned values are never greater than the largest
unsigned value. */
if (GET_CODE (op1) == CONST_INT
- && INTVAL (op1) == GET_MODE_MASK (mode)
+ && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
&& INTEGRAL_MODE_P (mode))
return const_true_rtx;
break;
case GTU:
if (GET_CODE (op1) == CONST_INT
- && INTVAL (op1) == GET_MODE_MASK (mode)
+ && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
&& INTEGRAL_MODE_P (mode))
return const0_rtx;
break;
{
register enum rtx_code code;
register enum machine_mode mode;
- register char *fmt;
+ register const char *fmt;
register int i;
rtx new = 0;
int copied = 0;
hence not save anything) or be incorrect. */
if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT
&& INTVAL (const_arg1) < 0
- && - INTVAL (const_arg1) >= 0
+ /* This used to test
+
+ - INTVAL (const_arg1) >= 0
+
+ But The Sun V5.0 compilers mis-compiled that test. So
+ instead we test for the problematic value in a more direct
+ manner and hope the Sun compilers get it correct. */
+ && INTVAL (const_arg1) !=
+ ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
&& GET_CODE (folded_arg1) == REG)
{
rtx new_const = GEN_INT (- INTVAL (const_arg1));
unsigned dest_hash;
/* The SET_DEST, with SUBREG, etc., stripped. */
rtx inner_dest;
- /* Place where the pointer to the INNER_DEST was found. */
- rtx *inner_dest_loc;
/* Nonzero if the SET_SRC is in memory. */
char src_in_memory;
/* Nonzero if the SET_SRC is in a structure. */
rtx src_eqv = 0;
struct table_elt *src_eqv_elt = 0;
- int src_eqv_volatile;
- int src_eqv_in_memory;
- int src_eqv_in_struct;
- unsigned src_eqv_hash;
+ int src_eqv_volatile = 0;
+ int src_eqv_in_memory = 0;
+ int src_eqv_in_struct = 0;
+ unsigned src_eqv_hash = 0;
- struct set *sets;
+ struct set *sets = NULL_PTR;
this_insn = insn;
&& ((REGNO (new) < FIRST_PSEUDO_REGISTER)
!= (REGNO (src) < FIRST_PSEUDO_REGISTER)))
|| (insn_code = recog_memoized (insn)) < 0
- || insn_n_dups[insn_code] > 0)
+ || insn_data[insn_code].n_dups > 0)
validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
else
SET_SRC (sets[i].rtl) = new;
&& qty_first_reg[REG_QTY (REGNO (dest))] != REGNO (dest)
&& GET_CODE (src) == REG && REGNO (src) == REGNO (dest)
/* Don't do this if the original insn had a hard reg as
- SET_SRC. */
+ SET_SRC or SET_DEST. */
&& (GET_CODE (sets[i].src) != REG
- || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER))
+ || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
+ && (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
/* We can't call canon_reg here because it won't do anything if
SRC is a hard register. */
{
{
tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ /* Make sure that the rtx is not shared with any other insn. */
+ src_const = copy_rtx (src_const);
+
/* Record the actual constant value in a REG_EQUAL note, making
a new one if one does not already exist. */
if (tem)
if (note)
XEXP (note, 0) = const_insn;
else
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_WAS_0,
- const_insn,
- REG_NOTES (insn));
+ REG_NOTES (insn)
+ = gen_rtx_INSN_LIST (REG_WAS_0, const_insn,
+ REG_NOTES (insn));
}
}
}
/* Now deal with the destination. */
do_not_record = 0;
- sets[i].inner_dest_loc = &SET_DEST (sets[0].rtl);
/* Look within any SIGN_EXTRACT or ZERO_EXTRACT
to the MEM or REG within it. */
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == STRICT_LOW_PART)
- {
- sets[i].inner_dest_loc = &XEXP (dest, 0);
- dest = XEXP (dest, 0);
- }
+ dest = XEXP (dest, 0);
sets[i].inner_dest = dest;
the insn. */
else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx)
{
+ /* One less use of the label this insn used to jump to. */
+ if (JUMP_LABEL (insn) != 0)
+ --LABEL_NUSES (JUMP_LABEL (insn));
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
cse_jumps_altered = 1;
- /* One less use of the label this insn used to jump to. */
- if (JUMP_LABEL (insn) != 0)
- --LABEL_NUSES (JUMP_LABEL (insn));
/* No more processing for this set. */
sets[i].rtl = 0;
}
it. If it was a computed branch, delete it and re-emit. */
else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
{
- rtx p;
-
/* If this is not in the format for a simple branch and
we are the only SET in it, re-emit it. */
if (! simplejump_p (insn) && n_sets == 1)
rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
JUMP_LABEL (new) = XEXP (src, 0);
LABEL_NUSES (XEXP (src, 0))++;
- delete_insn (insn);
insn = new;
}
else
Until the right place is found, might as well do this here. */
INSN_CODE (insn) = -1;
- /* Now that we've converted this jump to an unconditional jump,
- there is dead code after it. Delete the dead code until we
- reach a BARRIER, the end of the function, or a label. Do
- not delete NOTEs except for NOTE_INSN_DELETED since later
- phases assume these notes are retained. */
+ never_reached_warning (insn);
- p = insn;
-
- while (NEXT_INSN (p) != 0
- && GET_CODE (NEXT_INSN (p)) != BARRIER
- && GET_CODE (NEXT_INSN (p)) != CODE_LABEL)
- {
- if (GET_CODE (NEXT_INSN (p)) != NOTE
- || NOTE_LINE_NUMBER (NEXT_INSN (p)) == NOTE_INSN_DELETED)
- delete_insn (NEXT_INSN (p));
- else
- p = NEXT_INSN (p);
- }
-
- /* If we don't have a BARRIER immediately after INSN, put one there.
- Much code assumes that there are no NOTEs between a JUMP_INSN and
- BARRIER. */
-
- if (NEXT_INSN (insn) == 0
- || GET_CODE (NEXT_INSN (insn)) != BARRIER)
- emit_barrier_before (NEXT_INSN (insn));
-
- /* We might have two BARRIERs separated by notes. Delete the second
- one if so. */
-
- if (p != insn && NEXT_INSN (p) != 0
- && GET_CODE (NEXT_INSN (p)) == BARRIER)
- delete_insn (NEXT_INSN (p));
+ /* Now emit a BARRIER after the unconditional jump. Do not bother
+ deleting any unreachable code, let jump/flow do that. */
+ if (NEXT_INSN (insn) != 0
+ && GET_CODE (NEXT_INSN (insn)) != BARRIER)
+ emit_barrier_after (insn);
cse_jumps_altered = 1;
sets[i].rtl = 0;
enum machine_mode mode
= GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
- if (sets[i].src_elt == 0)
+ /* Don't put a hard register source into the table if this is
+ the last insn of a libcall. */
+ if (sets[i].src_elt == 0
+ && (GET_CODE (src) != REG
+ || REGNO (src) >= FIRST_PSEUDO_REGISTER
+ || ! find_reg_note (insn, REG_RETVAL, NULL_RTX)))
{
register struct table_elt *elt;
rtx object;
{
enum rtx_code code = GET_CODE (x);
- char *fmt = GET_RTX_FORMAT (code);
+ const char *fmt = GET_RTX_FORMAT (code);
int i;
switch (code)
path_size--;
}
+ /* If the first instruction is marked with QImode, that means we've
+ already processed this block. Our caller will look at DATA->LAST
+ to figure out where to go next. We want to return the next block
+ in the instruction stream, not some branched-to block somewhere
+ else. We accomplish this by pretending our called forbid us to
+ follow jumps, or skip blocks. */
+ if (GET_MODE (insn) == QImode)
+ follow_jumps = skip_blocks = 0;
+
/* Scan to end of this basic block. */
while (p && GET_CODE (p) != CODE_LABEL)
{
|| global_regs[i])
SET_HARD_REG_BIT (regs_invalidated_by_call, i);
+ if (ggc_p)
+ ggc_push_context ();
+
/* Loop over basic blocks.
Compute the maximum number of qty's needed for each basic block
(which is 2 for each SET). */
cse_jumps_altered |= old_cse_jumps_altered;
}
+ if (ggc_p)
+ ggc_collect ();
+
#ifdef USE_C_ALLOCA
alloca (0);
#endif
}
+ if (ggc_p)
+ ggc_pop_context ();
+
/* Tell refers_to_mem_p that qty_const info is not available. */
qty_const = 0;
qty_first_reg = (int *) alloca ((max_qty - max_reg) * sizeof (int));
qty_last_reg = (int *) alloca ((max_qty - max_reg) * sizeof (int));
- qty_mode= (enum machine_mode *) alloca ((max_qty - max_reg) * sizeof (enum machine_mode));
+ qty_mode = (enum machine_mode *) alloca ((max_qty - max_reg)
+ * sizeof (enum machine_mode));
qty_const = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx));
qty_const_insn = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx));
qty_comparison_code
insn = NEXT_INSN (to);
- if (LABEL_NUSES (to) == 0)
- insn = delete_insn (to);
-
/* If TO was the last insn in the function, we are done. */
if (insn == 0)
return 0;
int incr;
{
enum rtx_code code;
- char *fmt;
+ const char *fmt;
int i, j;
if (x == 0)
/* Go from the last insn to the first and delete insns that only set unused
registers or copy a register to itself. As we delete an insn, remove
- usage counts for registers it uses. */
- for (insn = prev_real_insn (get_last_insn ()); insn; insn = prev)
+ usage counts for registers it uses.
+
+ The first jump optimization pass may leave a real insn as the last
+ insn in the function. We must not skip that insn or we may end
+ up deleting code that is not really dead. */
+ insn = get_last_insn ();
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ insn = prev_real_insn (insn);
+
+ for ( ; insn; insn = prev)
{
int live_insn = 0;
rtx note;
else if (GET_CODE (SET_DEST (PATTERN (insn))) != REG
|| REGNO (SET_DEST (PATTERN (insn))) < FIRST_PSEUDO_REGISTER
|| counts[REGNO (SET_DEST (PATTERN (insn)))] != 0
- || side_effects_p (SET_SRC (PATTERN (insn))))
+ || side_effects_p (SET_SRC (PATTERN (insn)))
+ /* An ADDRESSOF expression can turn into a use of the
+ internal arg pointer, so always consider the
+ internal arg pointer live. If it is truly dead,
+ flow will delete the initializing insn. */
+ || (SET_DEST (PATTERN (insn))
+ == current_function_internal_arg_pointer))
live_insn = 1;
}
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
else if (GET_CODE (SET_DEST (elt)) != REG
|| REGNO (SET_DEST (elt)) < FIRST_PSEUDO_REGISTER
|| counts[REGNO (SET_DEST (elt))] != 0
- || side_effects_p (SET_SRC (elt)))
+ || side_effects_p (SET_SRC (elt))
+ /* An ADDRESSOF expression can turn into a use of the
+ internal arg pointer, so always consider the
+ internal arg pointer live. If it is truly dead,
+ flow will delete the initializing insn. */
+ || (SET_DEST (elt)
+ == current_function_internal_arg_pointer))
live_insn = 1;
}
else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)