#include "tm.h"
#include "diagnostic-core.h"
#include "rtl.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
#include "alias.h"
#include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
-#include "real.h"
#include "tree.h"
#include "fold-const.h"
#include "varasm.h"
#include "tm_p.h"
#include "flags.h"
#include "stringpool.h"
-#include "hashtab.h"
-#include "statistics.h"
-#include "fixed-value.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
rtx simple_return_rtx;
rtx cc0_rtx;
+/* Marker used for denoting an INSN, which should never be accessed (i.e.,
+ this pointer should normally never be dereferenced), but is required to be
+ distinct from NULL_RTX. Currently used by peephole2 pass. */
+rtx_insn *invalid_insn_rtx;
+
/* A hash table storing CONST_INTs whose absolute value is greater
than MAX_SAVED_CONST_INT. */
-struct const_int_hasher : ggc_cache_hasher<rtx>
+struct const_int_hasher : ggc_cache_ptr_hash<rtx_def>
{
typedef HOST_WIDE_INT compare_type;
static GTY ((cache)) hash_table<const_int_hasher> *const_int_htab;
-struct const_wide_int_hasher : ggc_cache_hasher<rtx>
+struct const_wide_int_hasher : ggc_cache_ptr_hash<rtx_def>
{
static hashval_t hash (rtx x);
static bool equal (rtx x, rtx y);
static GTY ((cache)) hash_table<const_wide_int_hasher> *const_wide_int_htab;
/* A hash table storing register attribute structures. */
-struct reg_attr_hasher : ggc_cache_hasher<reg_attrs *>
+struct reg_attr_hasher : ggc_cache_ptr_hash<reg_attrs>
{
static hashval_t hash (reg_attrs *x);
static bool equal (reg_attrs *a, reg_attrs *b);
static GTY ((cache)) hash_table<reg_attr_hasher> *reg_attrs_htab;
/* A hash table storing all CONST_DOUBLEs. */
-struct const_double_hasher : ggc_cache_hasher<rtx>
+struct const_double_hasher : ggc_cache_ptr_hash<rtx_def>
{
static hashval_t hash (rtx x);
static bool equal (rtx x, rtx y);
static GTY ((cache)) hash_table<const_double_hasher> *const_double_htab;
/* A hash table storing all CONST_FIXEDs. */
-struct const_fixed_hasher : ggc_cache_hasher<rtx>
+struct const_fixed_hasher : ggc_cache_ptr_hash<rtx_def>
{
static hashval_t hash (rtx x);
static bool equal (rtx x, rtx y);
#endif
+/* Set the mode and register number of X to MODE and REGNO. */
+
+void
+set_mode_and_regno (rtx x, machine_mode mode, unsigned int regno)
+{
+ unsigned int nregs = (HARD_REGISTER_NUM_P (regno)
+ ? hard_regno_nregs[regno][mode]
+ : 1);
+ PUT_MODE_RAW (x, mode);
+ set_regno_raw (x, regno, nregs);
+}
+
/* Generate a new REG rtx. Make sure ORIGINAL_REGNO is set properly, and
don't attempt to share with the various global pieces of rtl (such as
frame_pointer_rtx). */
rtx
-gen_raw_REG (machine_mode mode, int regno)
+gen_raw_REG (machine_mode mode, unsigned int regno)
{
- rtx x = gen_rtx_raw_REG (mode, regno);
+ rtx x = rtx_alloc_stat (REG MEM_STAT_INFO);
+ set_mode_and_regno (x, mode, regno);
+ REG_ATTRS (x) = NULL;
ORIGINAL_REGNO (x) = regno;
return x;
}
if (regno == FRAME_POINTER_REGNUM
&& (!reload_completed || frame_pointer_needed))
return frame_pointer_rtx;
-#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
- if (regno == HARD_FRAME_POINTER_REGNUM
+
+ if (!HARD_FRAME_POINTER_IS_FRAME_POINTER
+ && regno == HARD_FRAME_POINTER_REGNUM
&& (!reload_completed || frame_pointer_needed))
return hard_frame_pointer_rtx;
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && !HARD_FRAME_POINTER_IS_ARG_POINTER
- if (regno == ARG_POINTER_REGNUM)
+#if !HARD_FRAME_POINTER_IS_ARG_POINTER
+ if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && regno == ARG_POINTER_REGNUM)
return arg_pointer_rtx;
#endif
#ifdef RETURN_ADDRESS_POINTER_REGNUM
rtx_insn *
get_last_insn_anywhere (void)
{
- struct sequence_stack *stack;
- if (get_last_insn ())
- return get_last_insn ();
- for (stack = seq_stack; stack; stack = stack->next)
- if (stack->last != 0)
- return stack->last;
+ struct sequence_stack *seq;
+ for (seq = get_current_sequence (); seq; seq = seq->next)
+ if (seq->last != 0)
+ return seq->last;
return 0;
}
return insn;
}
\f
-#ifdef HAVE_cc0
/* Return the next insn that uses CC0 after INSN, which is assumed to
set it. This is the inverse of prev_cc0_setter (i.e., prev_cc0_setter
applied to the result of this function should yield INSN).
note, it is the previous insn. */
rtx_insn *
-prev_cc0_setter (rtx uncast_insn)
+prev_cc0_setter (rtx_insn *insn)
{
- rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
-
rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
if (note)
return insn;
}
-#endif
#ifdef AUTO_INC_DEC
/* Find a RTX_AUTOINC class rtx which matches DATA. */
returns TRIAL. If the insn to be returned can be split, it will be. */
rtx_insn *
-try_split (rtx pat, rtx uncast_trial, int last)
+try_split (rtx pat, rtx_insn *trial, int last)
{
- rtx_insn *trial = as_a <rtx_insn *> (uncast_trial);
rtx_insn *before = PREV_INSN (trial);
rtx_insn *after = NEXT_INSN (trial);
rtx note;
int probability;
rtx_insn *insn_last, *insn;
int njumps = 0;
- rtx call_insn = NULL_RTX;
+ rtx_insn *call_insn = NULL;
/* We're not good at redistributing frame information. */
if (RTX_FRAME_RELATED_P (trial))
split_branch_probability = XINT (note, 0);
probability = split_branch_probability;
- seq = safe_as_a <rtx_insn *> (split_insns (pat, trial));
+ seq = split_insns (pat, trial);
split_branch_probability = -1;
if (next == NULL)
{
- if (get_last_insn () == after)
- set_last_insn (insn);
- else
- {
- struct sequence_stack *stack = seq_stack;
- /* Scan all pending sequences too. */
- for (; stack; stack = stack->next)
- if (after == stack->last)
- {
- stack->last = insn;
- break;
- }
- }
+ struct sequence_stack *seq;
+
+ for (seq = get_current_sequence (); seq; seq = seq->next)
+ if (after == seq->last)
+ {
+ seq->last = insn;
+ break;
+ }
}
}
if (prev == NULL)
{
- if (get_insns () == before)
- set_first_insn (insn);
- else
- {
- struct sequence_stack *stack = seq_stack;
- /* Scan all pending sequences too. */
- for (; stack; stack = stack->next)
- if (before == stack->first)
- {
- stack->first = insn;
- break;
- }
+ struct sequence_stack *seq;
- gcc_assert (stack);
- }
+ for (seq = get_current_sequence (); seq; seq = seq->next)
+ if (before == seq->first)
+ {
+ seq->first = insn;
+ break;
+ }
+
+ gcc_assert (seq);
}
}
SET_NEXT_INSN (sequence->insn (sequence->len () - 1)) = next;
}
}
- else if (get_insns () == insn)
- {
- if (next)
- SET_PREV_INSN (next) = NULL;
- set_first_insn (next);
- }
else
{
- struct sequence_stack *stack = seq_stack;
- /* Scan all pending sequences too. */
- for (; stack; stack = stack->next)
- if (insn == stack->first)
+ struct sequence_stack *seq;
+
+ for (seq = get_current_sequence (); seq; seq = seq->next)
+ if (insn == seq->first)
{
- stack->first = next;
+ seq->first = next;
break;
}
- gcc_assert (stack);
+ gcc_assert (seq);
}
if (next)
SET_PREV_INSN (sequence->insn (0)) = prev;
}
}
- else if (get_last_insn () == insn)
- set_last_insn (prev);
else
{
- struct sequence_stack *stack = seq_stack;
- /* Scan all pending sequences too. */
- for (; stack; stack = stack->next)
- if (insn == stack->last)
+ struct sequence_stack *seq;
+
+ for (seq = get_current_sequence (); seq; seq = seq->next)
+ if (insn == seq->last)
{
- stack->last = prev;
+ seq->last = prev;
break;
}
- gcc_assert (stack);
+ gcc_assert (seq);
}
/* Fix up basic block boundaries, if necessary. */
/* Make an instruction with body X and code JUMP_INSN
and output it before the instruction BEFORE. */
-rtx_insn *
+rtx_jump_insn *
emit_jump_insn_before_noloc (rtx x, rtx_insn *before)
{
- return emit_pattern_before_noloc (x, before, NULL_RTX, NULL,
- make_jump_insn_raw);
+ return as_a <rtx_jump_insn *> (
+ emit_pattern_before_noloc (x, before, NULL_RTX, NULL,
+ make_jump_insn_raw));
}
/* Make an instruction with body X and code CALL_INSN
/* Emit the label LABEL before the insn BEFORE. */
-rtx_insn *
+rtx_code_label *
emit_label_before (rtx label, rtx_insn *before)
{
gcc_checking_assert (INSN_UID (label) == 0);
INSN_UID (label) = cur_insn_uid++;
add_insn_before (label, before, NULL);
- return as_a <rtx_insn *> (label);
+ return as_a <rtx_code_label *> (label);
}
\f
/* Helper for emit_insn_after, handles lists of instructions
/* Make an insn of code JUMP_INSN with body X
and output it after the insn AFTER. */
-rtx_insn *
+rtx_jump_insn *
emit_jump_insn_after_noloc (rtx x, rtx after)
{
- return emit_pattern_after_noloc (x, after, NULL, make_jump_insn_raw);
+ return as_a <rtx_jump_insn *> (
+ emit_pattern_after_noloc (x, after, NULL, make_jump_insn_raw));
}
/* Make an instruction with body X and code CALL_INSN
/* Emit a note of subtype SUBTYPE after the insn AFTER. */
rtx_note *
-emit_note_after (enum insn_note subtype, rtx uncast_after)
+emit_note_after (enum insn_note subtype, rtx_insn *after)
{
- rtx_insn *after = as_a <rtx_insn *> (uncast_after);
rtx_note *note = make_note_raw (subtype);
basic_block bb = BARRIER_P (after) ? NULL : BLOCK_FOR_INSN (after);
bool on_bb_boundary_p = (bb != NULL && BB_END (bb) == after);
/* Emit a note of subtype SUBTYPE before the insn BEFORE. */
rtx_note *
-emit_note_before (enum insn_note subtype, rtx uncast_before)
+emit_note_before (enum insn_note subtype, rtx_insn *before)
{
- rtx_insn *before = as_a <rtx_insn *> (uncast_before);
rtx_note *note = make_note_raw (subtype);
basic_block bb = BARRIER_P (before) ? NULL : BLOCK_FOR_INSN (before);
bool on_bb_boundary_p = (bb != NULL && BB_HEAD (bb) == before);
rtx_insn *(*make_raw) (rtx))
{
rtx_insn *after = safe_as_a <rtx_insn *> (uncast_after);
- rtx last = emit_pattern_after_noloc (pattern, after, NULL, make_raw);
+ rtx_insn *last = emit_pattern_after_noloc (pattern, after, NULL, make_raw);
if (pattern == NULL_RTX || !loc)
- return safe_as_a <rtx_insn *> (last);
+ return last;
after = NEXT_INSN (after);
while (1)
{
- if (active_insn_p (after) && !INSN_LOCATION (after))
+ if (active_insn_p (after)
+ && !JUMP_TABLE_DATA_P (after) /* FIXME */
+ && !INSN_LOCATION (after))
INSN_LOCATION (after) = loc;
if (after == last)
break;
after = NEXT_INSN (after);
}
- return safe_as_a <rtx_insn *> (last);
+ return last;
}
/* Insert PATTERN after AFTER. MAKE_RAW indicates how to turn PATTERN
}
/* Like emit_jump_insn_after_noloc, but set INSN_LOCATION according to LOC. */
-rtx_insn *
+rtx_jump_insn *
emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc)
{
- return emit_pattern_after_setloc (pattern, after, loc, make_jump_insn_raw);
+ return as_a <rtx_jump_insn *> (
+ emit_pattern_after_setloc (pattern, after, loc, make_jump_insn_raw));
}
/* Like emit_jump_insn_after_noloc, but set INSN_LOCATION according to AFTER. */
-rtx_insn *
+rtx_jump_insn *
emit_jump_insn_after (rtx pattern, rtx after)
{
- return emit_pattern_after (pattern, after, true, make_jump_insn_raw);
+ return as_a <rtx_jump_insn *> (
+ emit_pattern_after (pattern, after, true, make_jump_insn_raw));
}
/* Like emit_call_insn_after_noloc, but set INSN_LOCATION according to LOC. */
first = NEXT_INSN (first);
while (1)
{
- if (active_insn_p (first) && !INSN_LOCATION (first))
+ if (active_insn_p (first)
+ && !JUMP_TABLE_DATA_P (first) /* FIXME */
+ && !INSN_LOCATION (first))
INSN_LOCATION (first) = loc;
if (first == last)
break;
}
/* like emit_insn_before_noloc, but set INSN_LOCATION according to LOC. */
-rtx_insn *
+rtx_jump_insn *
emit_jump_insn_before_setloc (rtx pattern, rtx_insn *before, int loc)
{
- return emit_pattern_before_setloc (pattern, before, loc, false,
- make_jump_insn_raw);
+ return as_a <rtx_jump_insn *> (
+ emit_pattern_before_setloc (pattern, before, loc, false,
+ make_jump_insn_raw));
}
/* Like emit_jump_insn_before_noloc, but set INSN_LOCATION according to BEFORE. */
-rtx_insn *
+rtx_jump_insn *
emit_jump_insn_before (rtx pattern, rtx before)
{
- return emit_pattern_before (pattern, before, true, false,
- make_jump_insn_raw);
+ return as_a <rtx_jump_insn *> (
+ emit_pattern_before (pattern, before, true, false,
+ make_jump_insn_raw));
}
/* Like emit_insn_before_noloc, but set INSN_LOCATION according to LOC. */
/* Like emit_debug_insn_before_noloc,
but set insn_location according to BEFORE. */
rtx_insn *
-emit_debug_insn_before (rtx pattern, rtx before)
+emit_debug_insn_before (rtx pattern, rtx_insn *before)
{
return emit_pattern_before (pattern, before, false, false,
make_debug_insn_raw);
/* Add the label LABEL to the end of the doubly-linked list. */
-rtx_insn *
-emit_label (rtx label)
+rtx_code_label *
+emit_label (rtx uncast_label)
{
+ rtx_code_label *label = as_a <rtx_code_label *> (uncast_label);
+
gcc_checking_assert (INSN_UID (label) == 0);
INSN_UID (label) = cur_insn_uid++;
- add_insn (as_a <rtx_insn *> (label));
- return as_a <rtx_insn *> (label);
+ add_insn (label);
+ return label;
}
/* Make an insn of code JUMP_TABLE_DATA
return NULL_RTX;
}
\f
-/* Return an indication of which type of insn should have X as a body.
- The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */
-
-static enum rtx_code
-classify_insn (rtx x)
-{
- if (LABEL_P (x))
- return CODE_LABEL;
- if (GET_CODE (x) == CALL)
- return CALL_INSN;
- if (ANY_RETURN_P (x))
- return JUMP_INSN;
- if (GET_CODE (x) == SET)
- {
- if (SET_DEST (x) == pc_rtx)
- return JUMP_INSN;
- else if (GET_CODE (SET_SRC (x)) == CALL)
- return CALL_INSN;
- else
- return INSN;
- }
- if (GET_CODE (x) == PARALLEL)
- {
- int j;
- for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
- if (GET_CODE (XVECEXP (x, 0, j)) == CALL)
- return CALL_INSN;
- else if (GET_CODE (XVECEXP (x, 0, j)) == SET
- && SET_DEST (XVECEXP (x, 0, j)) == pc_rtx)
- return JUMP_INSN;
- else if (GET_CODE (XVECEXP (x, 0, j)) == SET
- && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL)
- return CALL_INSN;
- }
- return INSN;
-}
+/* Emit the rtl pattern X as an appropriate kind of insn. Also emit a
+ following barrier if the instruction needs one and if ALLOW_BARRIER_P
+ is true.
-/* Emit the rtl pattern X as an appropriate kind of insn.
If X is a label, it is simply added into the insn chain. */
rtx_insn *
-emit (rtx x)
+emit (rtx x, bool allow_barrier_p)
{
enum rtx_code code = classify_insn (x);
case JUMP_INSN:
{
rtx_insn *insn = emit_jump_insn (x);
- if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
+ if (allow_barrier_p
+ && (any_uncondjump_p (insn) || GET_CODE (x) == RETURN))
return emit_barrier ();
return insn;
}
else
tem = ggc_alloc<sequence_stack> ();
- tem->next = seq_stack;
+ tem->next = get_current_sequence ()->next;
tem->first = get_insns ();
tem->last = get_last_insn ();
-
- seq_stack = tem;
+ get_current_sequence ()->next = tem;
set_first_insn (0);
set_last_insn (0);
void
push_topmost_sequence (void)
{
- struct sequence_stack *stack, *top = NULL;
+ struct sequence_stack *top;
start_sequence ();
- for (stack = seq_stack; stack; stack = stack->next)
- top = stack;
-
+ top = get_topmost_sequence ();
set_first_insn (top->first);
set_last_insn (top->last);
}
void
pop_topmost_sequence (void)
{
- struct sequence_stack *stack, *top = NULL;
-
- for (stack = seq_stack; stack; stack = stack->next)
- top = stack;
+ struct sequence_stack *top;
+ top = get_topmost_sequence ();
top->first = get_insns ();
top->last = get_last_insn ();
void
end_sequence (void)
{
- struct sequence_stack *tem = seq_stack;
+ struct sequence_stack *tem = get_current_sequence ()->next;
set_first_insn (tem->first);
set_last_insn (tem->last);
- seq_stack = tem->next;
+ get_current_sequence ()->next = tem->next;
memset (tem, 0, sizeof (*tem));
tem->next = free_sequence_stack;
int
in_sequence_p (void)
{
- return seq_stack != 0;
+ return get_current_sequence ()->next != 0;
}
\f
/* Put the various virtual registers into REGNO_REG_RTX. */
cur_debug_insn_uid = 1;
reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
first_label_num = label_num;
- seq_stack = NULL;
+ get_current_sequence ()->next = NULL;
/* Init the tables that describe all the pseudo regs. */
= gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
#endif
+ pic_offset_table_rtx = NULL_RTX;
if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
- else
- pic_offset_table_rtx = NULL_RTX;
for (i = 0; i < (int) MAX_MACHINE_MODE; i++)
{
ret_rtx = gen_rtx_fmt_ (RETURN, VOIDmode);
simple_return_rtx = gen_rtx_fmt_ (SIMPLE_RETURN, VOIDmode);
cc0_rtx = gen_rtx_fmt_ (CC0, VOIDmode);
+ invalid_insn_rtx = gen_rtx_INSN (VOIDmode,
+ /*prev_insn=*/NULL,
+ /*next_insn=*/NULL,
+ /*bb=*/NULL,
+ /*pattern=*/NULL_RTX,
+ /*location=*/-1,
+ CODE_FOR_nothing,
+ /*reg_notes=*/NULL_RTX);
}
\f
/* Produce exact duplicate of insn INSN after AFTER.
bool
need_atomic_barrier_p (enum memmodel model, bool pre)
{
- switch (model & MEMMODEL_MASK)
+ switch (model & MEMMODEL_BASE_MASK)
{
case MEMMODEL_RELAXED:
case MEMMODEL_CONSUME: