#include "expr.h"
#include "regs.h"
#include "hard-reg-set.h"
+#include "hashtab.h"
#include "insn-config.h"
#include "recog.h"
#include "real.h"
rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
+/* A hash table storing CONST_INTs whose absolute value is greater
+ than MAX_SAVED_CONST_INT. */
+
+static htab_t const_int_htab;
+
/* start_sequence and gen_sequence can make a lot of rtx expressions which are
shortly thrown away. We use two mechanisms to prevent this waste:
static rtx find_line_note PARAMS ((rtx));
static void mark_sequence_stack PARAMS ((struct sequence_stack *));
static void unshare_all_rtl_1 PARAMS ((rtx));
+static hashval_t const_int_htab_hash PARAMS ((const void *));
+static int const_int_htab_eq PARAMS ((const void *,
+ const void *));
+static int rtx_htab_mark_1 PARAMS ((void **, void *));
+static void rtx_htab_mark PARAMS ((void *));
+
\f
+/* Returns a hash code for X (which is a really a CONST_INT). */
+
+static hashval_t
+const_int_htab_hash (x)
+ const void *x;
+{
+ return (hashval_t) INTVAL ((const struct rtx_def *) x);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+ CONST_INT) is the same as that given by Y (which is really a
+ HOST_WIDE_INT *). */
+
+static int
+const_int_htab_eq (x, y)
+ const void *x;
+ const void *y;
+{
+ return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y));
+}
+
+/* Mark the hash-table element X (which is really a pointer to an
+ rtx). */
+
+static int
+rtx_htab_mark_1 (x, data)
+ void **x;
+ void *data ATTRIBUTE_UNUSED;
+{
+ ggc_mark_rtx (*x);
+ return 1;
+}
+
+/* Mark all the elements of HTAB (which is really an htab_t full of
+ rtxs). */
+
+static void
+rtx_htab_mark (htab)
+ void *htab;
+{
+ htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL);
+}
+
/* There are some RTL codes that require special attention; the generation
functions do the raw handling. If you add to this list, modify
special_rtx in gengenrtl.c as well. */
rtx
gen_rtx_CONST_INT (mode, arg)
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
HOST_WIDE_INT arg;
{
+ void **slot;
+
if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
return const_int_rtx[arg + MAX_SAVED_CONST_INT];
return const_true_rtx;
#endif
- return gen_rtx_raw_CONST_INT (mode, arg);
+ /* Look up the CONST_INT in the hash table. */
+ slot = htab_find_slot_with_hash (const_int_htab, &arg, (hashval_t) arg, 1);
+ if (*slot == 0)
+ {
+ if (!ggc_p)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
+ pop_obstacks ();
+ }
+ else
+ *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
+ }
+
+ return (rtx) *slot;
}
-/* CONST_DOUBLEs needs special handling because its length is known
+/* CONST_DOUBLEs needs special handling because their length is known
only at run-time. */
+
rtx
gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2)
enum machine_mode mode;
if (GET_CODE (x) != SUBREG)
abort ();
- return SUBREG_WORD (x) * UNITS_PER_WORD < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x)));
+ return ((unsigned int) SUBREG_WORD (x) * UNITS_PER_WORD
+ < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
}
\f
/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value,
rtx
operand_subword (op, i, validate_address, mode)
rtx op;
- int i;
+ unsigned int i;
int validate_address;
enum machine_mode mode;
{
return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
else if (GET_CODE (op) == CONCAT)
{
- int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
+ unsigned int partwords
+ = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
+
if (i < partwords)
return operand_subword (XEXP (op, 0), i, validate_address, mode);
return operand_subword (XEXP (op, 1), i - partwords,
rtx
operand_subword_force (op, i, mode)
rtx op;
- int i;
+ unsigned int i;
enum machine_mode mode;
{
rtx result = operand_subword (op, i, 1, mode);
/* Make sure that virtual parameters are not shared. */
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
- {
- copy_rtx_if_shared (DECL_RTL (decl));
- }
+ copy_rtx_if_shared (DECL_RTL (decl));
/* Unshare just about everything else. */
unshare_all_rtl_1 (insn);
rtx insn;
rtx next;
- /* Remove NOTE_INSN_DELETED notes. We must not remove the first
- instruction in the function because the compiler depends on the
- first instruction being a note. */
+ /* We must not remove the first instruction in the function because
+ the compiler depends on the first instruction being a note. */
for (insn = NEXT_INSN (get_insns ()); insn; insn = next)
{
/* Remember what's next. */
if (GET_CODE (insn) != NOTE)
continue;
+ /* By now, all notes indicating lexical blocks should have
+ NOTE_BLOCK filled in. */
+ if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+ && NOTE_BLOCK (insn) == NULL_TREE)
+ abort ();
+
+ /* Remove NOTE_INSN_DELETED notes. */
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
remove_insn (insn);
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
nesting structure. */
if (NOTE_BLOCK (prev) != NOTE_BLOCK (insn))
abort ();
-
- remove_insn (prev);
- remove_insn (insn);
+
+ /* Never delete the BLOCK for the outermost scope
+ of the function; we can refer to names from
+ that scope even if the block notes are messed up. */
+ if (! is_body_block (NOTE_BLOCK (insn)))
+ {
+ debug_ignore_block (NOTE_BLOCK (insn));
+
+ remove_insn (prev);
+ remove_insn (insn);
+ }
break;
}
else if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_END)
rtx
emit_line_note_after (file, line, after)
- char *file;
+ const char *file;
int line;
rtx after;
{
rtx
emit_line_note (file, line)
- char *file;
+ const char *file;
int line;
{
set_file_and_line_for_stmt (file, line);
rtx
emit_note (file, line)
- char *file;
+ const char *file;
int line;
{
register rtx note;
rtx
emit_line_note_force (file, line)
- char *file;
+ const char *file;
int line;
{
last_linenum = -1;
last_insn = last;
}
+/* Set up the insn chain from a chain stort in FIRST to LAST. */
+
+void
+push_to_full_sequence (first, last)
+ rtx first, last;
+{
+ start_sequence ();
+ first_insn = first;
+ last_insn = last;
+ /* We really should have the end of the insn chain here. */
+ if (last && NEXT_INSN (last))
+ abort ();
+}
+
/* Set up the outer-level insn chain
as the current sequence, saving the previously current one. */
free (tem);
}
+/* This works like end_sequence, but records the old sequence in FIRST
+ and LAST. */
+
+void
+end_full_sequence (first, last)
+ rtx *first, *last;
+{
+ *first = first_insn;
+ *last = last_insn;
+ end_sequence();
+}
+
/* Return 1 if currently emitting into a sequence. */
int
REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1;
#ifdef STACK_BOUNDARY
- REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM)
- = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-
- REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM)
- = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM)
- = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM)
- = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
- = STACK_BOUNDARY / BITS_PER_UNIT;
- REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = UNITS_PER_WORD;
+ REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY;
+
+ REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM) = STACK_BOUNDARY;
+ REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = BITS_PER_WORD;
#endif
#ifdef INIT_EXPANDERS
ggc_add_rtx_root (&static_chain_rtx, 1);
ggc_add_rtx_root (&static_chain_incoming_rtx, 1);
ggc_add_rtx_root (&return_address_pointer_rtx, 1);
+
+ /* Initialize the CONST_INT hash table. */
+ const_int_htab = htab_create (37, const_int_htab_hash,
+ const_int_htab_eq, NULL);
+ ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab),
+ rtx_htab_mark);
}
\f
/* Query and clear/ restore no_line_numbers. This is used by the