/* Emit RTL for the GCC expander.
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "diagnostic-core.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "varasm.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "cfgrtl.h"
#include "basic-block.h"
#include "tree-eh.h"
#include "tm_p.h"
#include "flags.h"
-#include "function.h"
#include "stringpool.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
#include "regs.h"
-#include "hard-reg-set.h"
-#include "hashtab.h"
-#include "insn-config.h"
#include "recog.h"
#include "bitmap.h"
#include "debug.h"
#include "df.h"
#include "params.h"
#include "target.h"
+#include "builtins.h"
+#include "rtl-iter.h"
struct target_rtl default_target_rtl;
#if SWITCHABLE_TARGET
/* Commonly used modes. */
-enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */
-enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */
-enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */
-enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */
+machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */
+machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */
+machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */
+machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */
/* Datastructures maintained for currently processed function in RTL form. */
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. */
-static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
- htab_t const_int_htab;
+struct const_int_hasher : ggc_cache_ptr_hash<rtx_def>
+{
+ typedef HOST_WIDE_INT compare_type;
+
+ static hashval_t hash (rtx i);
+ static bool equal (rtx i, HOST_WIDE_INT h);
+};
+
+static GTY ((cache)) hash_table<const_int_hasher> *const_int_htab;
+
+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. */
-static GTY ((if_marked ("ggc_marked_p"), param_is (struct reg_attrs)))
- htab_t reg_attrs_htab;
+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. */
-static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
- htab_t const_double_htab;
+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. */
-static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
- htab_t const_fixed_htab;
+struct const_fixed_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_fixed_hasher> *const_fixed_htab;
#define cur_insn_uid (crtl->emit.x_cur_insn_uid)
#define cur_debug_insn_uid (crtl->emit.x_cur_debug_insn_uid)
#define first_label_num (crtl->emit.x_first_label_num)
-static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
static void set_used_decls (tree);
static void mark_label_nuses (rtx);
-static hashval_t const_int_htab_hash (const void *);
-static int const_int_htab_eq (const void *, const void *);
-static hashval_t const_double_htab_hash (const void *);
-static int const_double_htab_eq (const void *, const void *);
+#if TARGET_SUPPORTS_WIDE_INT
+static rtx lookup_const_wide_int (rtx);
+#endif
static rtx lookup_const_double (rtx);
-static hashval_t const_fixed_htab_hash (const void *);
-static int const_fixed_htab_eq (const void *, const void *);
static rtx lookup_const_fixed (rtx);
-static hashval_t reg_attrs_htab_hash (const void *);
-static int reg_attrs_htab_eq (const void *, const void *);
static reg_attrs *get_reg_attrs (tree, int);
-static rtx gen_const_vector (enum machine_mode, int);
+static rtx gen_const_vector (machine_mode, int);
static void copy_rtx_if_shared_1 (rtx *orig);
/* Probability of the conditional branch currently proceeded by try_split.
\f
/* Returns a hash code for X (which is a really a CONST_INT). */
-static hashval_t
-const_int_htab_hash (const void *x)
+hashval_t
+const_int_hasher::hash (rtx x)
{
- return (hashval_t) INTVAL ((const_rtx) x);
+ return (hashval_t) INTVAL (x);
}
/* Returns nonzero 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 (const void *x, const void *y)
+bool
+const_int_hasher::equal (rtx x, HOST_WIDE_INT y)
{
- return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
+ return (INTVAL (x) == y);
}
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns a hash code for X (which is a really a CONST_WIDE_INT). */
+
+hashval_t
+const_wide_int_hasher::hash (rtx x)
+{
+ int i;
+ unsigned HOST_WIDE_INT hash = 0;
+ const_rtx xr = x;
+
+ for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+ hash += CONST_WIDE_INT_ELT (xr, i);
+
+ return (hashval_t) hash;
+}
+
+/* Returns nonzero if the value represented by X (which is really a
+ CONST_WIDE_INT) is the same as that given by Y (which is really a
+ CONST_WIDE_INT). */
+
+bool
+const_wide_int_hasher::equal (rtx x, rtx y)
+{
+ int i;
+ const_rtx xr = x;
+ const_rtx yr = y;
+ if (CONST_WIDE_INT_NUNITS (xr) != CONST_WIDE_INT_NUNITS (yr))
+ return false;
+
+ for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+ if (CONST_WIDE_INT_ELT (xr, i) != CONST_WIDE_INT_ELT (yr, i))
+ return false;
+
+ return true;
+}
+#endif
+
/* Returns a hash code for X (which is really a CONST_DOUBLE). */
-static hashval_t
-const_double_htab_hash (const void *x)
+hashval_t
+const_double_hasher::hash (rtx x)
{
- const_rtx const value = (const_rtx) x;
+ const_rtx const value = x;
hashval_t h;
- if (GET_MODE (value) == VOIDmode)
+ if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (value) == VOIDmode)
h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
else
{
/* Returns nonzero if the value represented by X (really a ...)
is the same as that represented by Y (really a ...) */
-static int
-const_double_htab_eq (const void *x, const void *y)
+bool
+const_double_hasher::equal (rtx x, rtx y)
{
- const_rtx const a = (const_rtx)x, b = (const_rtx)y;
+ const_rtx const a = x, b = y;
if (GET_MODE (a) != GET_MODE (b))
return 0;
- if (GET_MODE (a) == VOIDmode)
+ if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (a) == VOIDmode)
return (CONST_DOUBLE_LOW (a) == CONST_DOUBLE_LOW (b)
&& CONST_DOUBLE_HIGH (a) == CONST_DOUBLE_HIGH (b));
else
/* Returns a hash code for X (which is really a CONST_FIXED). */
-static hashval_t
-const_fixed_htab_hash (const void *x)
+hashval_t
+const_fixed_hasher::hash (rtx x)
{
- const_rtx const value = (const_rtx) x;
+ const_rtx const value = x;
hashval_t h;
h = fixed_hash (CONST_FIXED_VALUE (value));
return h;
}
-/* Returns nonzero if the value represented by X (really a ...)
- is the same as that represented by Y (really a ...). */
+/* Returns nonzero if the value represented by X is the same as that
+ represented by Y. */
-static int
-const_fixed_htab_eq (const void *x, const void *y)
+bool
+const_fixed_hasher::equal (rtx x, rtx y)
{
- const_rtx const a = (const_rtx) x, b = (const_rtx) y;
+ const_rtx const a = x, b = y;
if (GET_MODE (a) != GET_MODE (b))
return 0;
/* Return true if the given memory attributes are equal. */
-static bool
+bool
mem_attrs_eq_p (const struct mem_attrs *p, const struct mem_attrs *q)
{
+ if (p == q)
+ return true;
+ if (!p || !q)
+ return false;
return (p->alias == q->alias
&& p->offset_known_p == q->offset_known_p
&& (!p->offset_known_p || p->offset == q->offset)
if (!MEM_ATTRS (mem)
|| !mem_attrs_eq_p (attrs, MEM_ATTRS (mem)))
{
- MEM_ATTRS (mem) = ggc_alloc_mem_attrs ();
+ MEM_ATTRS (mem) = ggc_alloc<mem_attrs> ();
memcpy (MEM_ATTRS (mem), attrs, sizeof (mem_attrs));
}
}
/* Returns a hash code for X (which is a really a reg_attrs *). */
-static hashval_t
-reg_attrs_htab_hash (const void *x)
+hashval_t
+reg_attr_hasher::hash (reg_attrs *x)
{
- const reg_attrs *const p = (const reg_attrs *) x;
+ const reg_attrs *const p = x;
return ((p->offset * 1000) ^ (intptr_t) p->decl);
}
-/* Returns nonzero if the value represented by X (which is really a
- reg_attrs *) is the same as that given by Y (which is also really a
- reg_attrs *). */
+/* Returns nonzero if the value represented by X is the same as that given by
+ Y. */
-static int
-reg_attrs_htab_eq (const void *x, const void *y)
+bool
+reg_attr_hasher::equal (reg_attrs *x, reg_attrs *y)
{
- const reg_attrs *const p = (const reg_attrs *) x;
- const reg_attrs *const q = (const reg_attrs *) y;
+ const reg_attrs *const p = x;
+ const reg_attrs *const q = y;
return (p->decl == q->decl && p->offset == q->offset);
}
get_reg_attrs (tree decl, int offset)
{
reg_attrs attrs;
- void **slot;
/* If everything is the default, we can just return zero. */
if (decl == 0 && offset == 0)
attrs.decl = decl;
attrs.offset = offset;
- slot = htab_find_slot (reg_attrs_htab, &attrs, INSERT);
+ reg_attrs **slot = reg_attrs_htab->find_slot (&attrs, INSERT);
if (*slot == 0)
{
- *slot = ggc_alloc_reg_attrs ();
+ *slot = ggc_alloc<reg_attrs> ();
memcpy (*slot, &attrs, sizeof (reg_attrs));
}
- return (reg_attrs *) *slot;
+ return *slot;
}
#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 (enum 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;
}
functions do the raw handling. If you add to this list, modify
special_rtx in gengenrtl.c as well. */
-rtx
-gen_rtx_CONST_INT (enum machine_mode mode ATTRIBUTE_UNUSED, HOST_WIDE_INT arg)
+rtx_expr_list *
+gen_rtx_EXPR_LIST (machine_mode mode, rtx expr, rtx expr_list)
{
- void **slot;
+ return as_a <rtx_expr_list *> (gen_rtx_fmt_ee (EXPR_LIST, mode, expr,
+ expr_list));
+}
+rtx_insn_list *
+gen_rtx_INSN_LIST (machine_mode mode, rtx insn, rtx insn_list)
+{
+ return as_a <rtx_insn_list *> (gen_rtx_fmt_ue (INSN_LIST, mode, insn,
+ insn_list));
+}
+
+rtx_insn *
+gen_rtx_INSN (machine_mode mode, rtx_insn *prev_insn, rtx_insn *next_insn,
+ basic_block bb, rtx pattern, int location, int code,
+ rtx reg_notes)
+{
+ return as_a <rtx_insn *> (gen_rtx_fmt_uuBeiie (INSN, mode,
+ prev_insn, next_insn,
+ bb, pattern, location, code,
+ reg_notes));
+}
+
+rtx
+gen_rtx_CONST_INT (machine_mode mode ATTRIBUTE_UNUSED, HOST_WIDE_INT arg)
+{
if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
return const_int_rtx[arg + MAX_SAVED_CONST_INT];
#endif
/* Look up the CONST_INT in the hash table. */
- slot = htab_find_slot_with_hash (const_int_htab, &arg,
- (hashval_t) arg, INSERT);
+ rtx *slot = const_int_htab->find_slot_with_hash (arg, (hashval_t) arg,
+ INSERT);
if (*slot == 0)
*slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
- return (rtx) *slot;
+ return *slot;
}
rtx
-gen_int_mode (HOST_WIDE_INT c, enum machine_mode mode)
+gen_int_mode (HOST_WIDE_INT c, machine_mode mode)
{
return GEN_INT (trunc_int_for_mode (c, mode));
}
static rtx
lookup_const_double (rtx real)
{
- void **slot = htab_find_slot (const_double_htab, real, INSERT);
+ rtx *slot = const_double_htab->find_slot (real, INSERT);
if (*slot == 0)
*slot = real;
- return (rtx) *slot;
+ return *slot;
}
/* Return a CONST_DOUBLE rtx for a floating-point value specified by
VALUE in mode MODE. */
rtx
-const_double_from_real_value (REAL_VALUE_TYPE value, enum machine_mode mode)
+const_double_from_real_value (REAL_VALUE_TYPE value, machine_mode mode)
{
rtx real = rtx_alloc (CONST_DOUBLE);
PUT_MODE (real, mode);
static rtx
lookup_const_fixed (rtx fixed)
{
- void **slot = htab_find_slot (const_fixed_htab, fixed, INSERT);
+ rtx *slot = const_fixed_htab->find_slot (fixed, INSERT);
if (*slot == 0)
*slot = fixed;
- return (rtx) *slot;
+ return *slot;
}
/* Return a CONST_FIXED rtx for a fixed-point value specified by
VALUE in mode MODE. */
rtx
-const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
+const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, machine_mode mode)
{
rtx fixed = rtx_alloc (CONST_FIXED);
PUT_MODE (fixed, mode);
return lookup_const_fixed (fixed);
}
+#if TARGET_SUPPORTS_WIDE_INT == 0
/* Constructs double_int from rtx CST. */
double_int
return r;
}
+#endif
+
+#if TARGET_SUPPORTS_WIDE_INT
+/* Determine whether CONST_WIDE_INT WINT already exists in the hash table.
+ If so, return its counterpart; otherwise add it to the hash table and
+ return it. */
+static rtx
+lookup_const_wide_int (rtx wint)
+{
+ rtx *slot = const_wide_int_htab->find_slot (wint, INSERT);
+ if (*slot == 0)
+ *slot = wint;
+
+ return *slot;
+}
+#endif
-/* Return a CONST_DOUBLE or CONST_INT for a value specified as
- a double_int. */
+/* Return an rtx constant for V, given that the constant has mode MODE.
+ The returned rtx will be a CONST_INT if V fits, otherwise it will be
+ a CONST_DOUBLE (if !TARGET_SUPPORTS_WIDE_INT) or a CONST_WIDE_INT
+ (if TARGET_SUPPORTS_WIDE_INT). */
rtx
-immed_double_int_const (double_int i, enum machine_mode mode)
+immed_wide_int_const (const wide_int_ref &v, machine_mode mode)
{
- return immed_double_const (i.low, i.high, mode);
+ unsigned int len = v.get_len ();
+ unsigned int prec = GET_MODE_PRECISION (mode);
+
+ /* Allow truncation but not extension since we do not know if the
+ number is signed or unsigned. */
+ gcc_assert (prec <= v.get_precision ());
+
+ if (len < 2 || prec <= HOST_BITS_PER_WIDE_INT)
+ return gen_int_mode (v.elt (0), mode);
+
+#if TARGET_SUPPORTS_WIDE_INT
+ {
+ unsigned int i;
+ rtx value;
+ unsigned int blocks_needed
+ = (prec + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
+
+ if (len > blocks_needed)
+ len = blocks_needed;
+
+ value = const_wide_int_alloc (len);
+
+ /* It is so tempting to just put the mode in here. Must control
+ myself ... */
+ PUT_MODE (value, VOIDmode);
+ CWI_PUT_NUM_ELEM (value, len);
+
+ for (i = 0; i < len; i++)
+ CONST_WIDE_INT_ELT (value, i) = v.elt (i);
+
+ return lookup_const_wide_int (value);
+ }
+#else
+ return immed_double_const (v.elt (0), v.elt (1), mode);
+#endif
}
+#if TARGET_SUPPORTS_WIDE_INT == 0
/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
of ints: I0 is the low-order word and I1 is the high-order word.
For values that are larger than HOST_BITS_PER_DOUBLE_INT, the
CONST_DOUBLE_FROM_REAL_VALUE. */
rtx
-immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
+immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, machine_mode mode)
{
rtx value;
unsigned int i;
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
/* We can get a 0 for an error mark. */
|| GET_MODE_CLASS (mode) == MODE_VECTOR_INT
- || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT);
+ || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+ || GET_MODE_CLASS (mode) == MODE_POINTER_BOUNDS);
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
return gen_int_mode (i0, mode);
return lookup_const_double (value);
}
+#endif
rtx
-gen_rtx_REG (enum machine_mode mode, unsigned int regno)
+gen_rtx_REG (machine_mode mode, unsigned int regno)
{
/* In case the MD file explicitly references the frame pointer, have
all such references point to the same frame pointer. This is
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
-gen_rtx_MEM (enum machine_mode mode, rtx addr)
+gen_rtx_MEM (machine_mode mode, rtx addr)
{
rtx rt = gen_rtx_raw_MEM (mode, addr);
/* Generate a memory referring to non-trapping constant memory. */
rtx
-gen_const_mem (enum machine_mode mode, rtx addr)
+gen_const_mem (machine_mode mode, rtx addr)
{
rtx mem = gen_rtx_MEM (mode, addr);
MEM_READONLY_P (mem) = 1;
save areas. */
rtx
-gen_frame_mem (enum machine_mode mode, rtx addr)
+gen_frame_mem (machine_mode mode, rtx addr)
{
rtx mem = gen_rtx_MEM (mode, addr);
MEM_NOTRAP_P (mem) = 1;
of the fixed stack frame. For example, something which is pushed
by a target splitter. */
rtx
-gen_tmp_stack_mem (enum machine_mode mode, rtx addr)
+gen_tmp_stack_mem (machine_mode mode, rtx addr)
{
rtx mem = gen_rtx_MEM (mode, addr);
MEM_NOTRAP_P (mem) = 1;
this construct would be valid, and false otherwise. */
bool
-validate_subreg (enum machine_mode omode, enum machine_mode imode,
+validate_subreg (machine_mode omode, machine_mode imode,
const_rtx reg, unsigned int offset)
{
unsigned int isize = GET_MODE_SIZE (imode);
if (osize < UNITS_PER_WORD
&& ! (lra_in_progress && (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))))
{
- enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
+ machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
unsigned int low_off = subreg_lowpart_offset (omode, wmode);
if (offset % UNITS_PER_WORD != low_off)
return false;
}
rtx
-gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
+gen_rtx_SUBREG (machine_mode mode, rtx reg, int offset)
{
gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset));
return gen_rtx_raw_SUBREG (mode, reg, offset);
is smaller than mode of REG, otherwise paradoxical SUBREG. */
rtx
-gen_lowpart_SUBREG (enum machine_mode mode, rtx reg)
+gen_lowpart_SUBREG (machine_mode mode, rtx reg)
{
- enum machine_mode inmode;
+ machine_mode inmode;
inmode = GET_MODE (reg);
if (inmode == VOIDmode)
return gen_rtx_SUBREG (mode, reg,
subreg_lowpart_offset (mode, inmode));
}
+
+rtx
+gen_rtx_VAR_LOCATION (machine_mode mode, tree decl, rtx loc,
+ enum var_init_status status)
+{
+ rtx x = gen_rtx_fmt_te (VAR_LOCATION, mode, decl, loc);
+ PAT_VAR_LOCATION_STATUS (x) = status;
+ return x;
+}
\f
/* Create an rtvec and stores within it the RTXen passed in the arguments. */
return rt_val;
}
+
+rtvec
+gen_rtvec_v (int n, rtx_insn **argp)
+{
+ int i;
+ rtvec rt_val;
+
+ /* Don't allocate an empty rtvec... */
+ if (n == 0)
+ return NULL_RTVEC;
+
+ rt_val = rtvec_alloc (n);
+
+ for (i = 0; i < n; i++)
+ rt_val->elem[i] = *argp++;
+
+ return rt_val;
+}
+
\f
/* Return the number of bytes between the start of an OUTER_MODE
in-memory value and the start of an INNER_MODE in-memory value,
on big-endian targets. */
int
-byte_lowpart_offset (enum machine_mode outer_mode,
- enum machine_mode inner_mode)
+byte_lowpart_offset (machine_mode outer_mode,
+ machine_mode inner_mode)
{
if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode))
return subreg_lowpart_offset (outer_mode, inner_mode);
This pseudo is assigned the next sequential register number. */
rtx
-gen_reg_rtx (enum machine_mode mode)
+gen_reg_rtx (machine_mode mode)
{
rtx val;
unsigned int align = GET_MODE_ALIGNMENT (mode);
which makes much better code. Besides, allocating DCmode
pseudos overstrains reload on some machines like the 386. */
rtx realpart, imagpart;
- enum machine_mode partmode = GET_MODE_INNER (mode);
+ machine_mode partmode = GET_MODE_INNER (mode);
realpart = gen_reg_rtx (partmode);
imagpart = gen_reg_rtx (partmode);
added to the REG_OFFSET. */
rtx
-gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
+gen_rtx_REG_offset (rtx reg, machine_mode mode, unsigned int regno,
int offset)
{
rtx new_rtx = gen_rtx_REG (mode, regno);
with OFFSET added to the REG_OFFSET. */
rtx
-gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
+gen_reg_rtx_offset (rtx reg, machine_mode mode, int offset)
{
rtx new_rtx = gen_reg_rtx (mode);
new register is a (possibly paradoxical) lowpart of the old one. */
void
-adjust_reg_mode (rtx reg, enum machine_mode mode)
+adjust_reg_mode (rtx reg, machine_mode mode)
{
update_reg_offset (reg, reg, byte_lowpart_offset (mode, GET_MODE (reg)));
PUT_MODE (reg, mode);
If this is not a case we can handle, return 0. */
rtx
-gen_lowpart_common (enum machine_mode mode, rtx x)
+gen_lowpart_common (machine_mode mode, rtx x)
{
int msize = GET_MODE_SIZE (mode);
int xsize;
int offset = 0;
- enum machine_mode innermode;
+ machine_mode innermode;
/* Unfortunately, this routine doesn't take a parameter for the mode of X,
so we have to make one up. Yuk. */
}
\f
rtx
-gen_highpart (enum machine_mode mode, rtx x)
+gen_highpart (machine_mode mode, rtx x)
{
unsigned int msize = GET_MODE_SIZE (mode);
rtx result;
/* Like gen_highpart, but accept mode of EXP operand in case EXP can
be VOIDmode constant. */
rtx
-gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx exp)
+gen_highpart_mode (machine_mode outermode, machine_mode innermode, rtx exp)
{
if (GET_MODE (exp) != VOIDmode)
{
/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value. */
unsigned int
-subreg_lowpart_offset (enum machine_mode outermode, enum machine_mode innermode)
+subreg_lowpart_offset (machine_mode outermode, machine_mode innermode)
{
unsigned int offset = 0;
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
/* Return offset in bytes to get OUTERMODE high part
of the value in mode INNERMODE stored in memory in target format. */
unsigned int
-subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode)
+subreg_highpart_offset (machine_mode outermode, machine_mode innermode)
{
unsigned int offset = 0;
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
*/
rtx
-operand_subword (rtx op, unsigned int offset, int validate_address, enum machine_mode mode)
+operand_subword (rtx op, unsigned int offset, int validate_address, machine_mode mode)
{
if (mode == VOIDmode)
mode = GET_MODE (op);
MODE is the mode of OP, in case it is CONST_INT. */
rtx
-operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode)
+operand_subword_force (rtx op, unsigned int offset, machine_mode mode)
{
rtx result = operand_subword (op, offset, 1, mode);
/* Return a memory reference like MEMREF, but with its mode changed to MODE
and its address changed to ADDR. (VOIDmode means don't change the mode.
NULL for ADDR means don't change the address.) VALIDATE is nonzero if the
- returned memory location is required to be valid. The memory
- attributes are not changed. */
+ returned memory location is required to be valid. INPLACE is true if any
+ changes can be made directly to MEMREF or false if MEMREF must be treated
+ as immutable.
+
+ The memory attributes are not changed. */
static rtx
-change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
+change_address_1 (rtx memref, machine_mode mode, rtx addr, int validate,
+ bool inplace)
{
addr_space_t as;
rtx new_rtx;
if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
return memref;
+ if (inplace)
+ {
+ XEXP (memref, 0) = addr;
+ return memref;
+ }
+
new_rtx = gen_rtx_MEM (mode, addr);
MEM_COPY_ATTRIBUTES (new_rtx, memref);
return new_rtx;
way we are changing MEMREF, so we only preserve the alias set. */
rtx
-change_address (rtx memref, enum machine_mode mode, rtx addr)
+change_address (rtx memref, machine_mode mode, rtx addr)
{
- rtx new_rtx = change_address_1 (memref, mode, addr, 1);
- enum machine_mode mmode = GET_MODE (new_rtx);
+ rtx new_rtx = change_address_1 (memref, mode, addr, 1, false);
+ machine_mode mmode = GET_MODE (new_rtx);
struct mem_attrs attrs, *defattrs;
attrs = *get_mem_attrs (memref);
has no inherent size. */
rtx
-adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
+adjust_address_1 (rtx memref, machine_mode mode, HOST_WIDE_INT offset,
int validate, int adjust_address, int adjust_object,
HOST_WIDE_INT size)
{
rtx addr = XEXP (memref, 0);
rtx new_rtx;
- enum machine_mode address_mode;
+ machine_mode address_mode;
int pbits;
struct mem_attrs attrs = *get_mem_attrs (memref), *defattrs;
unsigned HOST_WIDE_INT max_align;
#ifdef POINTERS_EXTEND_UNSIGNED
- enum machine_mode pointer_mode
+ machine_mode pointer_mode
= targetm.addr_space.pointer_mode (attrs.addrspace);
#endif
addr = plus_constant (address_mode, addr, offset);
}
- new_rtx = change_address_1 (memref, mode, addr, validate);
+ new_rtx = change_address_1 (memref, mode, addr, validate, false);
/* If the address is a REG, change_address_1 rightfully returns memref,
but this would destroy memref's MEM_ATTRS. */
nonzero, the memory address is forced to be valid. */
rtx
-adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr,
+adjust_automodify_address_1 (rtx memref, machine_mode mode, rtx addr,
HOST_WIDE_INT offset, int validate)
{
- memref = change_address_1 (memref, VOIDmode, addr, validate);
+ memref = change_address_1 (memref, VOIDmode, addr, validate, false);
return adjust_address_1 (memref, mode, offset, validate, 0, 0, 0);
}
offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
{
rtx new_rtx, addr = XEXP (memref, 0);
- enum machine_mode address_mode;
+ machine_mode address_mode;
struct mem_attrs attrs, *defattrs;
attrs = *get_mem_attrs (memref);
}
update_temp_slot_address (XEXP (memref, 0), new_rtx);
- new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1);
+ new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1, false);
/* If there are no changes, just return the original memory reference. */
if (new_rtx == memref)
/* Return a memory reference like MEMREF, but with its address changed to
ADDR. The caller is asserting that the actual piece of memory pointed
to is the same, just the form of the address is being changed, such as
- by putting something into a register. */
+ by putting something into a register. INPLACE is true if any changes
+ can be made directly to MEMREF or false if MEMREF must be treated as
+ immutable. */
rtx
-replace_equiv_address (rtx memref, rtx addr)
+replace_equiv_address (rtx memref, rtx addr, bool inplace)
{
/* change_address_1 copies the memory attribute structure without change
and that's exactly what we want here. */
update_temp_slot_address (XEXP (memref, 0), addr);
- return change_address_1 (memref, VOIDmode, addr, 1);
+ return change_address_1 (memref, VOIDmode, addr, 1, inplace);
}
/* Likewise, but the reference is not required to be valid. */
rtx
-replace_equiv_address_nv (rtx memref, rtx addr)
+replace_equiv_address_nv (rtx memref, rtx addr, bool inplace)
{
- return change_address_1 (memref, VOIDmode, addr, 0);
+ return change_address_1 (memref, VOIDmode, addr, 0, inplace);
}
/* Return a memory reference like MEMREF, but with its mode widened to
operations plus masking logic. */
rtx
-widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
+widen_memory_access (rtx memref, machine_mode mode, HOST_WIDE_INT offset)
{
rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1, 0, 0);
struct mem_attrs attrs;
\f
/* Return a newly created CODE_LABEL rtx with a unique label number. */
-rtx
+rtx_code_label *
gen_label_rtx (void)
{
- return gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, NULL_RTX,
- NULL, label_num++, NULL);
+ return as_a <rtx_code_label *> (
+ gen_rtx_CODE_LABEL (VOIDmode, NULL_RTX, NULL_RTX,
+ NULL, label_num++, NULL));
}
\f
/* For procedure integration. */
Used for an inline-procedure after copying the insn chain. */
void
-set_new_first_and_last_insn (rtx first, rtx last)
+set_new_first_and_last_insn (rtx_insn *first, rtx_insn *last)
{
- rtx insn;
+ rtx_insn *insn;
set_first_insn (first);
set_last_insn (last);
structure. This routine should only be called once. */
static void
-unshare_all_rtl_1 (rtx insn)
+unshare_all_rtl_1 (rtx_insn *insn)
{
/* Unshare just about everything else. */
unshare_all_rtl_in_chain (insn);
This special care is necessary when the stack slot MEM does not
actually appear in the insn chain. If it does appear, its address
is unshared from all else at that point. */
- stack_slot_list = copy_rtx_if_shared (stack_slot_list);
+ stack_slot_list = safe_as_a <rtx_expr_list *> (
+ copy_rtx_if_shared (stack_slot_list));
}
/* Go through all the RTL insn bodies and copy any invalid shared
should be done sparingly. */
void
-unshare_all_rtl_again (rtx insn)
+unshare_all_rtl_again (rtx_insn *insn)
{
- rtx p;
+ rtx_insn *p;
tree decl;
for (p = insn; p; p = NEXT_INSN (p))
static void
reset_all_used_flags (void)
{
- rtx p;
+ rtx_insn *p;
for (p = get_insns (); p; p = NEXT_INSN (p))
if (INSN_P (p))
{
gcc_assert (REG_NOTES (p) == NULL);
for (int i = 0; i < XVECLEN (pat, 0); i++)
- reset_insn_used_flags (XVECEXP (pat, 0, i));
+ {
+ rtx insn = XVECEXP (pat, 0, i);
+ if (INSN_P (insn))
+ reset_insn_used_flags (insn);
+ }
}
}
}
DEBUG_FUNCTION void
verify_rtl_sharing (void)
{
- rtx p;
+ rtx_insn *p;
timevar_push (TV_VERIFY_RTL_SHARING);
verify_insn_sharing (p);
else
for (int i = 0; i < XVECLEN (pat, 0); i++)
- verify_insn_sharing (XVECEXP (pat, 0, i));
+ {
+ rtx insn = XVECEXP (pat, 0, i);
+ if (INSN_P (insn))
+ verify_insn_sharing (insn);
+ }
}
reset_all_used_flags ();
Assumes the mark bits are cleared at entry. */
void
-unshare_all_rtl_in_chain (rtx insn)
+unshare_all_rtl_in_chain (rtx_insn *insn)
{
for (; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
/* Return the last insn emitted, even if it is in a sequence now pushed. */
-rtx
+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 the first nonnote insn emitted in current sequence or current
function. This routine looks inside SEQUENCEs. */
-rtx
+rtx_insn *
get_first_nonnote_insn (void)
{
- rtx insn = get_insns ();
+ rtx_insn *insn = get_insns ();
if (insn)
{
{
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
- insn = XVECEXP (PATTERN (insn), 0, 0);
+ insn = as_a <rtx_sequence *> (PATTERN (insn))->insn (0);
}
}
/* Return the last nonnote insn emitted in current sequence or current
function. This routine looks inside SEQUENCEs. */
-rtx
+rtx_insn *
get_last_nonnote_insn (void)
{
- rtx insn = get_last_insn ();
+ rtx_insn *insn = get_last_insn ();
if (insn)
{
continue;
else
{
- if (NONJUMP_INSN_P (insn)
- && GET_CODE (PATTERN (insn)) == SEQUENCE)
- insn = XVECEXP (PATTERN (insn), 0,
- XVECLEN (PATTERN (insn), 0) - 1);
+ if (NONJUMP_INSN_P (insn))
+ if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
+ insn = seq->insn (seq->len () - 1);
}
}
/* Return the next insn. If it is a SEQUENCE, return the first insn
of the sequence. */
-rtx
-next_insn (rtx insn)
+rtx_insn *
+next_insn (rtx_insn *insn)
{
if (insn)
{
insn = NEXT_INSN (insn);
if (insn && NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
- insn = XVECEXP (PATTERN (insn), 0, 0);
+ insn = as_a <rtx_sequence *> (PATTERN (insn))->insn (0);
}
return insn;
/* Return the previous insn. If it is a SEQUENCE, return the last insn
of the sequence. */
-rtx
-previous_insn (rtx insn)
+rtx_insn *
+previous_insn (rtx_insn *insn)
{
if (insn)
{
insn = PREV_INSN (insn);
- if (insn && NONJUMP_INSN_P (insn)
- && GET_CODE (PATTERN (insn)) == SEQUENCE)
- insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1);
+ if (insn && NONJUMP_INSN_P (insn))
+ if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
+ insn = seq->insn (seq->len () - 1);
}
return insn;
/* Return the next insn after INSN that is not a NOTE. This routine does not
look inside SEQUENCEs. */
-rtx
-next_nonnote_insn (rtx insn)
+rtx_insn *
+next_nonnote_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
while (insn)
{
insn = NEXT_INSN (insn);
search before we enter another basic block. This routine does not
look inside SEQUENCEs. */
-rtx
-next_nonnote_insn_bb (rtx insn)
+rtx_insn *
+next_nonnote_insn_bb (rtx_insn *insn)
{
while (insn)
{
if (insn == 0 || !NOTE_P (insn))
break;
if (NOTE_INSN_BASIC_BLOCK_P (insn))
- return NULL_RTX;
+ return NULL;
}
return insn;
/* Return the previous insn before INSN that is not a NOTE. This routine does
not look inside SEQUENCEs. */
-rtx
-prev_nonnote_insn (rtx insn)
+rtx_insn *
+prev_nonnote_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = PREV_INSN (insn);
the search before we enter another basic block. This routine does
not look inside SEQUENCEs. */
-rtx
-prev_nonnote_insn_bb (rtx insn)
+rtx_insn *
+prev_nonnote_insn_bb (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = PREV_INSN (insn);
if (insn == 0 || !NOTE_P (insn))
break;
if (NOTE_INSN_BASIC_BLOCK_P (insn))
- return NULL_RTX;
+ return NULL;
}
return insn;
/* Return the next insn after INSN that is not a DEBUG_INSN. This
routine does not look inside SEQUENCEs. */
-rtx
-next_nondebug_insn (rtx insn)
+rtx_insn *
+next_nondebug_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = NEXT_INSN (insn);
/* Return the previous insn before INSN that is not a DEBUG_INSN.
This routine does not look inside SEQUENCEs. */
-rtx
-prev_nondebug_insn (rtx insn)
+rtx_insn *
+prev_nondebug_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = PREV_INSN (insn);
/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN.
This routine does not look inside SEQUENCEs. */
-rtx
-next_nonnote_nondebug_insn (rtx insn)
+rtx_insn *
+next_nonnote_nondebug_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = NEXT_INSN (insn);
/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN.
This routine does not look inside SEQUENCEs. */
-rtx
-prev_nonnote_nondebug_insn (rtx insn)
+rtx_insn *
+prev_nonnote_nondebug_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = PREV_INSN (insn);
or 0, if there is none. This routine does not look inside
SEQUENCEs. */
-rtx
-next_real_insn (rtx insn)
+rtx_insn *
+next_real_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = NEXT_INSN (insn);
or 0, if there is none. This routine does not look inside
SEQUENCEs. */
-rtx
-prev_real_insn (rtx insn)
+rtx_insn *
+prev_real_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = PREV_INSN (insn);
/* Return the last CALL_INSN in the current list, or 0 if there is none.
This routine does not look inside SEQUENCEs. */
-rtx
+rtx_call_insn *
last_call_insn (void)
{
- rtx insn;
+ rtx_insn *insn;
for (insn = get_last_insn ();
insn && !CALL_P (insn);
insn = PREV_INSN (insn))
;
- return insn;
+ return safe_as_a <rtx_call_insn *> (insn);
}
/* Find the next insn after INSN that really does something. This routine
&& GET_CODE (PATTERN (insn)) != CLOBBER))));
}
-rtx
-next_active_insn (rtx insn)
+rtx_insn *
+next_active_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = NEXT_INSN (insn);
does not look inside SEQUENCEs. After reload this also skips over
standalone USE and CLOBBER insn. */
-rtx
-prev_active_insn (rtx insn)
+rtx_insn *
+prev_active_insn (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
while (insn)
{
insn = PREV_INSN (insn);
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).
Return 0 if we can't find the insn. */
-rtx
-next_cc0_user (rtx insn)
+rtx_insn *
+next_cc0_user (rtx uncast_insn)
{
+ rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
+
rtx note = find_reg_note (insn, REG_CC_USER, NULL_RTX);
if (note)
- return XEXP (note, 0);
+ return safe_as_a <rtx_insn *> (XEXP (note, 0));
insn = next_nonnote_insn (insn);
if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
- insn = XVECEXP (PATTERN (insn), 0, 0);
+ insn = as_a <rtx_sequence *> (PATTERN (insn))->insn (0);
if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
return insn;
/* Find the insn that set CC0 for INSN. Unless INSN has a REG_CC_SETTER
note, it is the previous insn. */
-rtx
-prev_cc0_setter (rtx insn)
+rtx_insn *
+prev_cc0_setter (rtx_insn *insn)
{
rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
if (note)
- return XEXP (note, 0);
+ return safe_as_a <rtx_insn *> (XEXP (note, 0));
insn = prev_nonnote_insn (insn);
gcc_assert (sets_cc0_p (PATTERN (insn)));
return insn;
}
-#endif
#ifdef AUTO_INC_DEC
/* Find a RTX_AUTOINC class rtx which matches DATA. */
static int
-find_auto_inc (rtx *xp, void *data)
+find_auto_inc (const_rtx x, const_rtx reg)
{
- rtx x = *xp;
- rtx reg = (rtx) data;
-
- if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC)
- return 0;
-
- switch (GET_CODE (x))
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, NONCONST)
{
- case PRE_DEC:
- case PRE_INC:
- case POST_DEC:
- case POST_INC:
- case PRE_MODIFY:
- case POST_MODIFY:
- if (rtx_equal_p (reg, XEXP (x, 0)))
- return 1;
- break;
-
- default:
- gcc_unreachable ();
+ const_rtx x = *iter;
+ if (GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC
+ && rtx_equal_p (reg, XEXP (x, 0)))
+ return true;
}
- return -1;
+ return false;
}
#endif
const char *fmt;
code = GET_CODE (x);
- if (code == LABEL_REF && LABEL_P (XEXP (x, 0)))
- LABEL_NUSES (XEXP (x, 0))++;
+ if (code == LABEL_REF && LABEL_P (LABEL_REF_LABEL (x)))
+ LABEL_NUSES (LABEL_REF_LABEL (x))++;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
replacement insn depending on the value of LAST. Otherwise, it
returns TRIAL. If the insn to be returned can be split, it will be. */
-rtx
-try_split (rtx pat, rtx trial, int last)
+rtx_insn *
+try_split (rtx pat, rtx_insn *trial, int last)
{
- rtx before = PREV_INSN (trial);
- rtx after = NEXT_INSN (trial);
- int has_barrier = 0;
- rtx note, seq, tem;
+ rtx_insn *before = PREV_INSN (trial);
+ rtx_insn *after = NEXT_INSN (trial);
+ rtx note;
+ rtx_insn *seq, *tem;
int probability;
- rtx insn_last, insn;
+ 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 = -1;
- /* If we are splitting a JUMP_INSN, it might be followed by a BARRIER.
- We may need to handle this specially. */
- if (after && BARRIER_P (after))
- {
- has_barrier = 1;
- after = NEXT_INSN (after);
- }
-
if (!seq)
return trial;
may have introduced invalid RTL sharing, so unshare the sequence now. */
unshare_all_rtl_in_chain (seq);
- /* Mark labels. */
+ /* Mark labels and copy flags. */
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
{
if (JUMP_P (insn))
{
+ if (JUMP_P (trial))
+ CROSSING_JUMP_P (insn) = CROSSING_JUMP_P (trial);
mark_jump_label (PATTERN (insn), insn, 0);
njumps++;
if (probability != -1
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
if (CALL_P (insn))
{
- rtx next, *p;
+ rtx_insn *next;
+ rtx *p;
gcc_assert (call_insn == NULL_RTX);
call_insn = insn;
break;
case REG_NON_LOCAL_GOTO:
- case REG_CROSSING_JUMP:
for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (JUMP_P (insn))
{
rtx reg = XEXP (note, 0);
if (!FIND_REG_INC_NOTE (insn, reg)
- && for_each_rtx (&PATTERN (insn), find_auto_inc, reg) > 0)
+ && find_auto_inc (PATTERN (insn), reg))
add_reg_note (insn, REG_INC, reg);
}
break;
#endif
case REG_ARGS_SIZE:
- fixup_args_size_notes (NULL_RTX, insn_last, INTVAL (XEXP (note, 0)));
+ fixup_args_size_notes (NULL, insn_last, INTVAL (XEXP (note, 0)));
break;
case REG_CALL_DECL:
tem = emit_insn_after_setloc (seq, trial, INSN_LOCATION (trial));
delete_insn (trial);
- if (has_barrier)
- emit_barrier_after (tem);
/* Recursively call try_split for each new insn created; by the
time control returns here that insn will be fully split, so
We can't use next_active_insn here since AFTER may be a note.
Ignore deleted insns, which can be occur if not optimizing. */
for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
- if (! INSN_DELETED_P (tem) && INSN_P (tem))
+ if (! tem->deleted () && INSN_P (tem))
tem = try_split (PATTERN (tem), tem, 1);
/* Return either the first or the last insn, depending on which was
/* Make and return an INSN rtx, initializing all its slots.
Store PATTERN in the pattern slots. */
-rtx
+rtx_insn *
make_insn_raw (rtx pattern)
{
- rtx insn;
+ rtx_insn *insn;
- insn = rtx_alloc (INSN);
+ insn = as_a <rtx_insn *> (rtx_alloc (INSN));
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
/* Like `make_insn_raw' but make a DEBUG_INSN instead of an insn. */
-static rtx
+static rtx_insn *
make_debug_insn_raw (rtx pattern)
{
- rtx insn;
+ rtx_debug_insn *insn;
- insn = rtx_alloc (DEBUG_INSN);
+ insn = as_a <rtx_debug_insn *> (rtx_alloc (DEBUG_INSN));
INSN_UID (insn) = cur_debug_insn_uid++;
if (cur_debug_insn_uid > MIN_NONDEBUG_INSN_UID)
INSN_UID (insn) = cur_insn_uid++;
/* Like `make_insn_raw' but make a JUMP_INSN instead of an insn. */
-static rtx
+static rtx_insn *
make_jump_insn_raw (rtx pattern)
{
- rtx insn;
+ rtx_jump_insn *insn;
- insn = rtx_alloc (JUMP_INSN);
+ insn = as_a <rtx_jump_insn *> (rtx_alloc (JUMP_INSN));
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
/* Like `make_insn_raw' but make a CALL_INSN instead of an insn. */
-static rtx
+static rtx_insn *
make_call_insn_raw (rtx pattern)
{
- rtx insn;
+ rtx_call_insn *insn;
- insn = rtx_alloc (CALL_INSN);
+ insn = as_a <rtx_call_insn *> (rtx_alloc (CALL_INSN));
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
/* Like `make_insn_raw' but make a NOTE instead of an insn. */
-static rtx
+static rtx_note *
make_note_raw (enum insn_note subtype)
{
/* Some notes are never created this way at all. These notes are
gcc_assert (subtype != NOTE_INSN_DELETED_LABEL
&& subtype != NOTE_INSN_DELETED_DEBUG_LABEL);
- rtx note = rtx_alloc (NOTE);
+ rtx_note *note = as_a <rtx_note *> (rtx_alloc (NOTE));
INSN_UID (note) = cur_insn_uid++;
NOTE_KIND (note) = subtype;
BLOCK_FOR_INSN (note) = NULL;
but also BARRIERs and JUMP_TABLE_DATAs. PREV and NEXT may be NULL. */
static inline void
-link_insn_into_chain (rtx insn, rtx prev, rtx next)
+link_insn_into_chain (rtx_insn *insn, rtx_insn *prev, rtx_insn *next)
{
- PREV_INSN (insn) = prev;
- NEXT_INSN (insn) = next;
+ SET_PREV_INSN (insn) = prev;
+ SET_NEXT_INSN (insn) = next;
if (prev != NULL)
{
- NEXT_INSN (prev) = insn;
+ SET_NEXT_INSN (prev) = insn;
if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
{
- rtx sequence = PATTERN (prev);
- NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
+ rtx_sequence *sequence = as_a <rtx_sequence *> (PATTERN (prev));
+ SET_NEXT_INSN (sequence->insn (sequence->len () - 1)) = insn;
}
}
if (next != NULL)
{
- PREV_INSN (next) = insn;
+ SET_PREV_INSN (next) = insn;
if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
- PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn;
+ {
+ rtx_sequence *sequence = as_a <rtx_sequence *> (PATTERN (next));
+ SET_PREV_INSN (sequence->insn (0)) = insn;
+ }
}
if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
{
- rtx sequence = PATTERN (insn);
- PREV_INSN (XVECEXP (sequence, 0, 0)) = prev;
- NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next;
+ rtx_sequence *sequence = as_a <rtx_sequence *> (PATTERN (insn));
+ SET_PREV_INSN (sequence->insn (0)) = prev;
+ SET_NEXT_INSN (sequence->insn (sequence->len () - 1)) = next;
}
}
INSN may be an INSN, JUMP_INSN, CALL_INSN, CODE_LABEL, BARRIER or NOTE. */
void
-add_insn (rtx insn)
+add_insn (rtx_insn *insn)
{
- rtx prev = get_last_insn ();
+ rtx_insn *prev = get_last_insn ();
link_insn_into_chain (insn, prev, NULL);
if (NULL == get_insns ())
set_first_insn (insn);
/* Add INSN into the doubly-linked list after insn AFTER. */
static void
-add_insn_after_nobb (rtx insn, rtx after)
+add_insn_after_nobb (rtx_insn *insn, rtx_insn *after)
{
- rtx next = NEXT_INSN (after);
+ rtx_insn *next = NEXT_INSN (after);
- gcc_assert (!optimize || !INSN_DELETED_P (after));
+ gcc_assert (!optimize || !after->deleted ());
link_insn_into_chain (insn, after, next);
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;
+ }
}
}
/* Add INSN into the doubly-linked list before insn BEFORE. */
static void
-add_insn_before_nobb (rtx insn, rtx before)
+add_insn_before_nobb (rtx_insn *insn, rtx_insn *before)
{
- rtx prev = PREV_INSN (before);
+ rtx_insn *prev = PREV_INSN (before);
- gcc_assert (!optimize || !INSN_DELETED_P (before));
+ gcc_assert (!optimize || !before->deleted ());
link_insn_into_chain (insn, prev, before);
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);
}
}
they know how to update a SEQUENCE. */
void
-add_insn_after (rtx insn, rtx after, basic_block bb)
+add_insn_after (rtx uncast_insn, rtx uncast_after, basic_block bb)
{
+ rtx_insn *insn = as_a <rtx_insn *> (uncast_insn);
+ rtx_insn *after = as_a <rtx_insn *> (uncast_after);
add_insn_after_nobb (insn, after);
if (!BARRIER_P (after)
&& !BARRIER_P (insn)
they know how to update a SEQUENCE. */
void
-add_insn_before (rtx insn, rtx before, basic_block bb)
+add_insn_before (rtx uncast_insn, rtx uncast_before, basic_block bb)
{
+ rtx_insn *insn = as_a <rtx_insn *> (uncast_insn);
+ rtx_insn *before = as_a <rtx_insn *> (uncast_before);
add_insn_before_nobb (insn, before);
if (!bb
set_insn_deleted (rtx insn)
{
if (INSN_P (insn))
- df_insn_delete (insn);
+ df_insn_delete (as_a <rtx_insn *> (insn));
PUT_CODE (insn, NOTE);
NOTE_KIND (insn) = NOTE_INSN_DELETED;
}
To really delete an insn and related DF information, use delete_insn. */
void
-remove_insn (rtx insn)
+remove_insn (rtx uncast_insn)
{
- rtx next = NEXT_INSN (insn);
- rtx prev = PREV_INSN (insn);
+ rtx_insn *insn = as_a <rtx_insn *> (uncast_insn);
+ rtx_insn *next = NEXT_INSN (insn);
+ rtx_insn *prev = PREV_INSN (insn);
basic_block bb;
if (prev)
{
- NEXT_INSN (prev) = next;
+ SET_NEXT_INSN (prev) = next;
if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
{
- rtx sequence = PATTERN (prev);
- NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next;
+ rtx_sequence *sequence = as_a <rtx_sequence *> (PATTERN (prev));
+ SET_NEXT_INSN (sequence->insn (sequence->len () - 1)) = next;
}
}
- else if (get_insns () == insn)
- {
- if (next)
- 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)
{
- PREV_INSN (next) = prev;
+ SET_PREV_INSN (next) = prev;
if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
- PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
+ {
+ rtx_sequence *sequence = as_a <rtx_sequence *> (PATTERN (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. */
FROM becomes the new last instruction. */
void
-delete_insns_since (rtx from)
+delete_insns_since (rtx_insn *from)
{
if (from == 0)
set_first_insn (0);
else
- NEXT_INSN (from) = 0;
+ SET_NEXT_INSN (from) = 0;
set_last_insn (from);
}
called after delay-slot filling has been done. */
void
-reorder_insns_nobb (rtx from, rtx to, rtx after)
+reorder_insns_nobb (rtx_insn *from, rtx_insn *to, rtx_insn *after)
{
#ifdef ENABLE_CHECKING
- rtx x;
+ rtx_insn *x;
for (x = from; x != to; x = NEXT_INSN (x))
gcc_assert (after != x);
gcc_assert (after != to);
/* Splice this bunch out of where it is now. */
if (PREV_INSN (from))
- NEXT_INSN (PREV_INSN (from)) = NEXT_INSN (to);
+ SET_NEXT_INSN (PREV_INSN (from)) = NEXT_INSN (to);
if (NEXT_INSN (to))
- PREV_INSN (NEXT_INSN (to)) = PREV_INSN (from);
+ SET_PREV_INSN (NEXT_INSN (to)) = PREV_INSN (from);
if (get_last_insn () == to)
set_last_insn (PREV_INSN (from));
if (get_insns () == from)
/* Make the new neighbors point to it and it to them. */
if (NEXT_INSN (after))
- PREV_INSN (NEXT_INSN (after)) = to;
+ SET_PREV_INSN (NEXT_INSN (after)) = to;
- NEXT_INSN (to) = NEXT_INSN (after);
- PREV_INSN (from) = after;
- NEXT_INSN (after) = from;
+ SET_NEXT_INSN (to) = NEXT_INSN (after);
+ SET_PREV_INSN (from) = after;
+ SET_NEXT_INSN (after) = from;
if (after == get_last_insn ())
set_last_insn (to);
}
/* Same as function above, but take care to update BB boundaries. */
void
-reorder_insns (rtx from, rtx to, rtx after)
+reorder_insns (rtx_insn *from, rtx_insn *to, rtx_insn *after)
{
- rtx prev = PREV_INSN (from);
+ rtx_insn *prev = PREV_INSN (from);
basic_block bb, bb2;
reorder_insns_nobb (from, to, after);
if (!BARRIER_P (after)
&& (bb = BLOCK_FOR_INSN (after)))
{
- rtx x;
+ rtx_insn *x;
df_set_bb_dirty (bb);
if (!BARRIER_P (from)
SEQUENCE rtl results in much fragmented RTL memory since the SEQUENCE
generated would almost certainly die right after it was created. */
-static rtx
+static rtx_insn *
emit_pattern_before_noloc (rtx x, rtx before, rtx last, basic_block bb,
- rtx (*make_raw) (rtx))
+ rtx_insn *(*make_raw) (rtx))
{
- rtx insn;
+ rtx_insn *insn;
gcc_assert (before);
if (x == NULL_RTX)
- return last;
+ return safe_as_a <rtx_insn *> (last);
switch (GET_CODE (x))
{
case CODE_LABEL:
case BARRIER:
case NOTE:
- insn = x;
+ insn = as_a <rtx_insn *> (x);
while (insn)
{
- rtx next = NEXT_INSN (insn);
+ rtx_insn *next = NEXT_INSN (insn);
add_insn_before (insn, before, bb);
last = insn;
insn = next;
break;
}
- return last;
+ return safe_as_a <rtx_insn *> (last);
}
/* Make X be output before the instruction BEFORE. */
-rtx
-emit_insn_before_noloc (rtx x, rtx before, basic_block bb)
+rtx_insn *
+emit_insn_before_noloc (rtx x, rtx_insn *before, basic_block bb)
{
return emit_pattern_before_noloc (x, before, before, bb, make_insn_raw);
}
/* Make an instruction with body X and code JUMP_INSN
and output it before the instruction BEFORE. */
-rtx
-emit_jump_insn_before_noloc (rtx x, rtx before)
+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
and output it before the instruction BEFORE. */
-rtx
-emit_call_insn_before_noloc (rtx x, rtx before)
+rtx_insn *
+emit_call_insn_before_noloc (rtx x, rtx_insn *before)
{
return emit_pattern_before_noloc (x, before, NULL_RTX, NULL,
make_call_insn_raw);
/* Make an instruction with body X and code DEBUG_INSN
and output it before the instruction BEFORE. */
-rtx
+rtx_insn *
emit_debug_insn_before_noloc (rtx x, rtx before)
{
return emit_pattern_before_noloc (x, before, NULL_RTX, NULL,
/* Make an insn of code BARRIER
and output it before the insn BEFORE. */
-rtx
+rtx_barrier *
emit_barrier_before (rtx before)
{
- rtx insn = rtx_alloc (BARRIER);
+ rtx_barrier *insn = as_a <rtx_barrier *> (rtx_alloc (BARRIER));
INSN_UID (insn) = cur_insn_uid++;
/* Emit the label LABEL before the insn BEFORE. */
-rtx
-emit_label_before (rtx label, rtx before)
+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 label;
+ return as_a <rtx_code_label *> (label);
}
\f
/* Helper for emit_insn_after, handles lists of instructions
efficiently. */
-static rtx
-emit_insn_after_1 (rtx first, rtx after, basic_block bb)
+static rtx_insn *
+emit_insn_after_1 (rtx_insn *first, rtx uncast_after, basic_block bb)
{
- rtx last;
- rtx after_after;
+ rtx_insn *after = safe_as_a <rtx_insn *> (uncast_after);
+ rtx_insn *last;
+ rtx_insn *after_after;
if (!bb && !BARRIER_P (after))
bb = BLOCK_FOR_INSN (after);
after_after = NEXT_INSN (after);
- NEXT_INSN (after) = first;
- PREV_INSN (first) = after;
- NEXT_INSN (last) = after_after;
+ SET_NEXT_INSN (after) = first;
+ SET_PREV_INSN (first) = after;
+ SET_NEXT_INSN (last) = after_after;
if (after_after)
- PREV_INSN (after_after) = last;
+ SET_PREV_INSN (after_after) = last;
if (after == get_last_insn ())
set_last_insn (last);
return last;
}
-static rtx
-emit_pattern_after_noloc (rtx x, rtx after, basic_block bb,
- rtx (*make_raw)(rtx))
+static rtx_insn *
+emit_pattern_after_noloc (rtx x, rtx uncast_after, basic_block bb,
+ rtx_insn *(*make_raw)(rtx))
{
- rtx last = after;
+ rtx_insn *after = safe_as_a <rtx_insn *> (uncast_after);
+ rtx_insn *last = after;
gcc_assert (after);
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after, bb);
+ last = emit_insn_after_1 (as_a <rtx_insn *> (x), after, bb);
break;
#ifdef ENABLE_RTL_CHECKING
/* Make X be output after the insn AFTER and set the BB of insn. If
BB is NULL, an attempt is made to infer the BB from AFTER. */
-rtx
+rtx_insn *
emit_insn_after_noloc (rtx x, rtx after, basic_block bb)
{
return emit_pattern_after_noloc (x, after, bb, make_insn_raw);
/* Make an insn of code JUMP_INSN with body X
and output it after the insn AFTER. */
-rtx
+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
and output it after the instruction AFTER. */
-rtx
+rtx_insn *
emit_call_insn_after_noloc (rtx x, rtx after)
{
return emit_pattern_after_noloc (x, after, NULL, make_call_insn_raw);
/* Make an instruction with body X and code CALL_INSN
and output it after the instruction AFTER. */
-rtx
+rtx_insn *
emit_debug_insn_after_noloc (rtx x, rtx after)
{
return emit_pattern_after_noloc (x, after, NULL, make_debug_insn_raw);
/* Make an insn of code BARRIER
and output it after the insn AFTER. */
-rtx
+rtx_barrier *
emit_barrier_after (rtx after)
{
- rtx insn = rtx_alloc (BARRIER);
+ rtx_barrier *insn = as_a <rtx_barrier *> (rtx_alloc (BARRIER));
INSN_UID (insn) = cur_insn_uid++;
/* Emit the label LABEL after the insn AFTER. */
-rtx
-emit_label_after (rtx label, rtx after)
+rtx_insn *
+emit_label_after (rtx label, rtx_insn *after)
{
gcc_checking_assert (INSN_UID (label) == 0);
INSN_UID (label) = cur_insn_uid++;
add_insn_after (label, after, NULL);
- return label;
+ return as_a <rtx_insn *> (label);
}
\f
/* Notes require a bit of special handling: Some notes need to have their
/* Emit a note of subtype SUBTYPE after the insn AFTER. */
-rtx
-emit_note_after (enum insn_note subtype, rtx after)
+rtx_note *
+emit_note_after (enum insn_note subtype, rtx_insn *after)
{
- rtx note = make_note_raw (subtype);
+ 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
-emit_note_before (enum insn_note subtype, rtx before)
+rtx_note *
+emit_note_before (enum insn_note subtype, rtx_insn *before)
{
- rtx note = make_note_raw (subtype);
+ 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);
/* Insert PATTERN after AFTER, setting its INSN_LOCATION to LOC.
MAKE_RAW indicates how to turn PATTERN into a real insn. */
-static rtx
-emit_pattern_after_setloc (rtx pattern, rtx after, int loc,
- rtx (*make_raw) (rtx))
+static rtx_insn *
+emit_pattern_after_setloc (rtx pattern, rtx uncast_after, int loc,
+ rtx_insn *(*make_raw) (rtx))
{
- rtx last = emit_pattern_after_noloc (pattern, after, NULL, make_raw);
+ rtx_insn *after = safe_as_a <rtx_insn *> (uncast_after);
+ rtx_insn *last = emit_pattern_after_noloc (pattern, after, NULL, make_raw);
if (pattern == NULL_RTX || !loc)
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;
into a real insn. SKIP_DEBUG_INSNS indicates whether to insert after
any DEBUG_INSNs. */
-static rtx
-emit_pattern_after (rtx pattern, rtx after, bool skip_debug_insns,
- rtx (*make_raw) (rtx))
+static rtx_insn *
+emit_pattern_after (rtx pattern, rtx uncast_after, bool skip_debug_insns,
+ rtx_insn *(*make_raw) (rtx))
{
- rtx prev = after;
+ rtx_insn *after = safe_as_a <rtx_insn *> (uncast_after);
+ rtx_insn *prev = after;
if (skip_debug_insns)
while (DEBUG_INSN_P (prev))
}
/* Like emit_insn_after_noloc, but set INSN_LOCATION according to LOC. */
-rtx
+rtx_insn *
emit_insn_after_setloc (rtx pattern, rtx after, int loc)
{
return emit_pattern_after_setloc (pattern, after, loc, make_insn_raw);
}
/* Like emit_insn_after_noloc, but set INSN_LOCATION according to AFTER. */
-rtx
+rtx_insn *
emit_insn_after (rtx pattern, rtx after)
{
return emit_pattern_after (pattern, after, true, make_insn_raw);
}
/* Like emit_jump_insn_after_noloc, but set INSN_LOCATION according to LOC. */
-rtx
+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
+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. */
-rtx
+rtx_insn *
emit_call_insn_after_setloc (rtx pattern, rtx after, int loc)
{
return emit_pattern_after_setloc (pattern, after, loc, make_call_insn_raw);
}
/* Like emit_call_insn_after_noloc, but set INSN_LOCATION according to AFTER. */
-rtx
+rtx_insn *
emit_call_insn_after (rtx pattern, rtx after)
{
return emit_pattern_after (pattern, after, true, make_call_insn_raw);
}
/* Like emit_debug_insn_after_noloc, but set INSN_LOCATION according to LOC. */
-rtx
+rtx_insn *
emit_debug_insn_after_setloc (rtx pattern, rtx after, int loc)
{
return emit_pattern_after_setloc (pattern, after, loc, make_debug_insn_raw);
}
/* Like emit_debug_insn_after_noloc, but set INSN_LOCATION according to AFTER. */
-rtx
+rtx_insn *
emit_debug_insn_after (rtx pattern, rtx after)
{
return emit_pattern_after (pattern, after, false, make_debug_insn_raw);
indicates if PATTERN is meant for an INSN as opposed to a JUMP_INSN,
CALL_INSN, etc. */
-static rtx
-emit_pattern_before_setloc (rtx pattern, rtx before, int loc, bool insnp,
- rtx (*make_raw) (rtx))
+static rtx_insn *
+emit_pattern_before_setloc (rtx pattern, rtx uncast_before, int loc, bool insnp,
+ rtx_insn *(*make_raw) (rtx))
{
- rtx first = PREV_INSN (before);
- rtx last = emit_pattern_before_noloc (pattern, before,
- insnp ? before : NULL_RTX,
- NULL, make_raw);
+ rtx_insn *before = as_a <rtx_insn *> (uncast_before);
+ rtx_insn *first = PREV_INSN (before);
+ rtx_insn *last = emit_pattern_before_noloc (pattern, before,
+ insnp ? before : NULL_RTX,
+ NULL, make_raw);
if (pattern == NULL_RTX || !loc)
return last;
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;
before any DEBUG_INSNs. INSNP indicates if PATTERN is meant for an
INSN as opposed to a JUMP_INSN, CALL_INSN, etc. */
-static rtx
-emit_pattern_before (rtx pattern, rtx before, bool skip_debug_insns,
- bool insnp, rtx (*make_raw) (rtx))
+static rtx_insn *
+emit_pattern_before (rtx pattern, rtx uncast_before, bool skip_debug_insns,
+ bool insnp, rtx_insn *(*make_raw) (rtx))
{
- rtx next = before;
+ rtx_insn *before = safe_as_a <rtx_insn *> (uncast_before);
+ rtx_insn *next = before;
if (skip_debug_insns)
while (DEBUG_INSN_P (next))
}
/* Like emit_insn_before_noloc, but set INSN_LOCATION according to LOC. */
-rtx
-emit_insn_before_setloc (rtx pattern, rtx before, int loc)
+rtx_insn *
+emit_insn_before_setloc (rtx pattern, rtx_insn *before, int loc)
{
return emit_pattern_before_setloc (pattern, before, loc, true,
make_insn_raw);
}
/* Like emit_insn_before_noloc, but set INSN_LOCATION according to BEFORE. */
-rtx
+rtx_insn *
emit_insn_before (rtx pattern, rtx before)
{
return emit_pattern_before (pattern, before, true, true, make_insn_raw);
}
/* like emit_insn_before_noloc, but set INSN_LOCATION according to LOC. */
-rtx
-emit_jump_insn_before_setloc (rtx pattern, rtx before, int loc)
+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
+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. */
-rtx
-emit_call_insn_before_setloc (rtx pattern, rtx before, int loc)
+rtx_insn *
+emit_call_insn_before_setloc (rtx pattern, rtx_insn *before, int loc)
{
return emit_pattern_before_setloc (pattern, before, loc, false,
make_call_insn_raw);
/* Like emit_call_insn_before_noloc,
but set insn_location according to BEFORE. */
-rtx
-emit_call_insn_before (rtx pattern, rtx before)
+rtx_insn *
+emit_call_insn_before (rtx pattern, rtx_insn *before)
{
return emit_pattern_before (pattern, before, true, false,
make_call_insn_raw);
}
/* Like emit_insn_before_noloc, but set INSN_LOCATION according to LOC. */
-rtx
+rtx_insn *
emit_debug_insn_before_setloc (rtx pattern, rtx before, int loc)
{
return emit_pattern_before_setloc (pattern, before, loc, false,
/* Like emit_debug_insn_before_noloc,
but set insn_location according to BEFORE. */
-rtx
-emit_debug_insn_before (rtx pattern, rtx before)
+rtx_insn *
+emit_debug_insn_before (rtx pattern, rtx_insn *before)
{
return emit_pattern_before (pattern, before, false, false,
make_debug_insn_raw);
Returns the last insn emitted. */
-rtx
+rtx_insn *
emit_insn (rtx x)
{
- rtx last = get_last_insn ();
- rtx insn;
+ rtx_insn *last = get_last_insn ();
+ rtx_insn *insn;
if (x == NULL_RTX)
return last;
case CODE_LABEL:
case BARRIER:
case NOTE:
- insn = x;
+ insn = as_a <rtx_insn *> (x);
while (insn)
{
- rtx next = NEXT_INSN (insn);
+ rtx_insn *next = NEXT_INSN (insn);
add_insn (insn);
last = insn;
insn = next;
/* Make an insn of code DEBUG_INSN with pattern X
and add it to the end of the doubly-linked list. */
-rtx
+rtx_insn *
emit_debug_insn (rtx x)
{
- rtx last = get_last_insn ();
- rtx insn;
+ rtx_insn *last = get_last_insn ();
+ rtx_insn *insn;
if (x == NULL_RTX)
return last;
case CODE_LABEL:
case BARRIER:
case NOTE:
- insn = x;
+ insn = as_a <rtx_insn *> (x);
while (insn)
{
- rtx next = NEXT_INSN (insn);
+ rtx_insn *next = NEXT_INSN (insn);
add_insn (insn);
last = insn;
insn = next;
/* Make an insn of code JUMP_INSN with pattern X
and add it to the end of the doubly-linked list. */
-rtx
+rtx_insn *
emit_jump_insn (rtx x)
{
- rtx last = NULL_RTX, insn;
+ rtx_insn *last = NULL;
+ rtx_insn *insn;
switch (GET_CODE (x))
{
case CODE_LABEL:
case BARRIER:
case NOTE:
- insn = x;
+ insn = as_a <rtx_insn *> (x);
while (insn)
{
- rtx next = NEXT_INSN (insn);
+ rtx_insn *next = NEXT_INSN (insn);
add_insn (insn);
last = insn;
insn = next;
/* Make an insn of code CALL_INSN with pattern X
and add it to the end of the doubly-linked list. */
-rtx
+rtx_insn *
emit_call_insn (rtx x)
{
- rtx insn;
+ rtx_insn *insn;
switch (GET_CODE (x))
{
/* Add the label LABEL to the end of the doubly-linked list. */
-rtx
-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 (label);
/* Make an insn of code JUMP_TABLE_DATA
and add it to the end of the doubly-linked list. */
-rtx
+rtx_jump_table_data *
emit_jump_table_data (rtx table)
{
- rtx jump_table_data = rtx_alloc (JUMP_TABLE_DATA);
+ rtx_jump_table_data *jump_table_data =
+ as_a <rtx_jump_table_data *> (rtx_alloc (JUMP_TABLE_DATA));
INSN_UID (jump_table_data) = cur_insn_uid++;
PATTERN (jump_table_data) = table;
BLOCK_FOR_INSN (jump_table_data) = NULL;
/* Make an insn of code BARRIER
and add it to the end of the doubly-linked list. */
-rtx
+rtx_barrier *
emit_barrier (void)
{
- rtx barrier = rtx_alloc (BARRIER);
+ rtx_barrier *barrier = as_a <rtx_barrier *> (rtx_alloc (BARRIER));
INSN_UID (barrier) = cur_insn_uid++;
add_insn (barrier);
return barrier;
/* Emit a copy of note ORIG. */
-rtx
-emit_note_copy (rtx orig)
+rtx_note *
+emit_note_copy (rtx_note *orig)
{
enum insn_note kind = (enum insn_note) NOTE_KIND (orig);
- rtx note = make_note_raw (kind);
+ rtx_note *note = make_note_raw (kind);
NOTE_DATA (note) = NOTE_DATA (orig);
add_insn (note);
return note;
/* Make an insn of code NOTE or type NOTE_NO
and add it to the end of the doubly-linked list. */
-rtx
+rtx_note *
emit_note (enum insn_note kind)
{
- rtx note = make_note_raw (kind);
+ rtx_note *note = make_note_raw (kind);
add_insn (note);
return note;
}
/* Emit a clobber of lvalue X. */
-rtx
+rtx_insn *
emit_clobber (rtx x)
{
/* CONCATs should not appear in the insn stream. */
/* Return a sequence of insns to clobber lvalue X. */
-rtx
+rtx_insn *
gen_clobber (rtx x)
{
- rtx seq;
+ rtx_insn *seq;
start_sequence ();
emit_clobber (x);
/* Emit a use of rvalue X. */
-rtx
+rtx_insn *
emit_use (rtx x)
{
/* CONCATs should not appear in the insn stream. */
/* Return a sequence of insns to use rvalue X. */
-rtx
+rtx_insn *
gen_use (rtx x)
{
- rtx seq;
+ rtx_insn *seq;
start_sequence ();
emit_use (x);
return seq;
}
+/* Notes like REG_EQUAL and REG_EQUIV refer to a set in an instruction.
+ Return the set in INSN that such notes describe, or NULL if the notes
+ have no meaning for INSN. */
+
+rtx
+set_for_reg_notes (rtx insn)
+{
+ rtx pat, reg;
+
+ if (!INSN_P (insn))
+ return NULL_RTX;
+
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ /* We do not use single_set because that ignores SETs of unused
+ registers. REG_EQUAL and REG_EQUIV notes really do require the
+ PARALLEL to have a single SET. */
+ if (multiple_sets (insn))
+ return NULL_RTX;
+ pat = XVECEXP (pat, 0, 0);
+ }
+
+ if (GET_CODE (pat) != SET)
+ return NULL_RTX;
+
+ reg = SET_DEST (pat);
+
+ /* Notes apply to the contents of a STRICT_LOW_PART. */
+ if (GET_CODE (reg) == STRICT_LOW_PART)
+ reg = XEXP (reg, 0);
+
+ /* Check that we have a register. */
+ if (!(REG_P (reg) || GET_CODE (reg) == SUBREG))
+ return NULL_RTX;
+
+ return pat;
+}
+
/* Place a note of KIND on insn INSN with DATUM as the datum. If a
note of this type already exists, remove it first. */
{
case REG_EQUAL:
case REG_EQUIV:
- /* Don't add REG_EQUAL/REG_EQUIV notes if the insn
- has multiple sets (some callers assume single_set
- means the insn only has one set, when in fact it
- means the insn only has one * useful * set). */
- if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
- {
- gcc_assert (!note);
- return NULL_RTX;
- }
+ if (!set_for_reg_notes (insn))
+ return NULL_RTX;
/* Don't add ASM_OPERAND REG_EQUAL/REG_EQUIV notes.
It serves no useful purpose and breaks eliminate_regs. */
if (GET_CODE (datum) == ASM_OPERANDS)
return NULL_RTX;
- if (note)
- {
- XEXP (note, 0) = datum;
- df_notes_rescan (insn);
- return note;
- }
+ /* Notes with side effects are dangerous. Even if the side-effect
+ initially mirrors one in PATTERN (INSN), later optimizations
+ might alter the way that the final register value is calculated
+ and so move or alter the side-effect in some way. The note would
+ then no longer be a valid substitution for SET_SRC. */
+ if (side_effects_p (datum))
+ return NULL_RTX;
break;
default:
- if (note)
- {
- XEXP (note, 0) = datum;
- return note;
- }
break;
}
- add_reg_note (insn, kind, datum);
+ if (note)
+ XEXP (note, 0) = datum;
+ else
+ {
+ add_reg_note (insn, kind, datum);
+ note = REG_NOTES (insn);
+ }
switch (kind)
{
case REG_EQUAL:
case REG_EQUIV:
- df_notes_rescan (insn);
+ df_notes_rescan (as_a <rtx_insn *> (insn));
break;
default:
break;
}
- return REG_NOTES (insn);
+ return note;
}
/* Like set_unique_reg_note, but don't do anything unless INSN sets DST. */
rtx
set_dst_reg_note (rtx insn, enum reg_note kind, rtx datum, rtx dst)
{
- rtx set = single_set (insn);
+ rtx set = set_for_reg_notes (insn);
if (set && SET_DEST (set) == dst)
return set_unique_reg_note (insn, kind, datum);
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
-emit (rtx x)
+rtx_insn *
+emit (rtx x, bool allow_barrier_p)
{
enum rtx_code code = classify_insn (x);
return emit_insn (x);
case JUMP_INSN:
{
- rtx insn = emit_jump_insn (x);
- if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
+ rtx_insn *insn = emit_jump_insn (x);
+ if (allow_barrier_p
+ && (any_uncondjump_p (insn) || GET_CODE (x) == RETURN))
return emit_barrier ();
return insn;
}
free_sequence_stack = tem->next;
}
else
- tem = ggc_alloc_sequence_stack ();
+ 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);
start_sequence for more information about how to use this function. */
void
-push_to_sequence (rtx first)
+push_to_sequence (rtx_insn *first)
{
- rtx last;
+ rtx_insn *last;
start_sequence ();
looping through the list. */
void
-push_to_sequence2 (rtx first, rtx last)
+push_to_sequence2 (rtx_insn *first, rtx_insn *last)
{
start_sequence ();
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. */
/* Return a copy of INSN that can be used in a SEQUENCE delay slot,
on that assumption that INSN itself remains in its original place. */
-rtx
-copy_delay_slot_insn (rtx insn)
+rtx_insn *
+copy_delay_slot_insn (rtx_insn *insn)
{
/* Copy INSN with its rtx_code, all its notes, location etc. */
- insn = copy_rtx (insn);
+ insn = as_a <rtx_insn *> (copy_rtx (insn));
INSN_UID (insn) = cur_insn_uid++;
return insn;
}
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. */
crtl->emit.regno_pointer_align
= XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
- regno_reg_rtx = ggc_alloc_vec_rtx (crtl->emit.regno_pointer_align_length);
+ regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
/* Put copies of all the hard registers into regno_reg_rtx. */
memcpy (regno_reg_rtx,
/* Generate a vector constant for mode MODE and constant value CONSTANT. */
static rtx
-gen_const_vector (enum machine_mode mode, int constant)
+gen_const_vector (machine_mode mode, int constant)
{
rtx tem;
rtvec v;
int units, i;
- enum machine_mode inner;
+ machine_mode inner;
units = GET_MODE_NUNITS (mode);
inner = GET_MODE_INNER (mode);
/* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when
all elements are zero, and the one vector when all elements are one. */
rtx
-gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v)
+gen_rtx_CONST_VECTOR (machine_mode mode, rtvec v)
{
- enum machine_mode inner = GET_MODE_INNER (mode);
+ machine_mode inner = GET_MODE_INNER (mode);
int nunits = GET_MODE_NUNITS (mode);
rtx x;
int i;
init_emit_regs (void)
{
int i;
- enum machine_mode mode;
+ machine_mode mode;
mem_attrs *attrs;
/* Reset register attributes */
- htab_empty (reg_attrs_htab);
+ reg_attrs_htab->empty ();
/* We need reg_raw_mode, so initialize the modes now. */
init_reg_modes_target ();
= 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++)
{
- mode = (enum machine_mode) i;
- attrs = ggc_alloc_cleared_mem_attrs ();
+ mode = (machine_mode) i;
+ attrs = ggc_cleared_alloc<mem_attrs> ();
attrs->align = BITS_PER_UNIT;
attrs->addrspace = ADDR_SPACE_GENERIC;
if (mode != BLKmode)
}
}
-/* Create some permanent unique rtl objects shared between all functions. */
+/* Initialize global machine_mode variables. */
void
-init_emit_once (void)
+init_derived_machine_modes (void)
{
- int i;
- enum machine_mode mode;
- enum machine_mode double_mode;
-
- /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
- hash tables. */
- const_int_htab = htab_create_ggc (37, const_int_htab_hash,
- const_int_htab_eq, NULL);
-
- const_double_htab = htab_create_ggc (37, const_double_htab_hash,
- const_double_htab_eq, NULL);
-
- const_fixed_htab = htab_create_ggc (37, const_fixed_htab_hash,
- const_fixed_htab_eq, NULL);
-
- reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash,
- reg_attrs_htab_eq, NULL);
-
- /* Compute the word and byte modes. */
-
byte_mode = VOIDmode;
word_mode = VOIDmode;
- double_mode = VOIDmode;
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ for (machine_mode mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
word_mode = mode;
}
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
- mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- {
- if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
- && double_mode == VOIDmode)
- double_mode = mode;
- }
-
ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
+}
+
+/* Create some permanent unique rtl objects shared between all functions. */
+
+void
+init_emit_once (void)
+{
+ int i;
+ machine_mode mode;
+ machine_mode double_mode;
+
+ /* Initialize the CONST_INT, CONST_WIDE_INT, CONST_DOUBLE,
+ CONST_FIXED, and memory attribute hash tables. */
+ const_int_htab = hash_table<const_int_hasher>::create_ggc (37);
+
+#if TARGET_SUPPORTS_WIDE_INT
+ const_wide_int_htab = hash_table<const_wide_int_hasher>::create_ggc (37);
+#endif
+ const_double_htab = hash_table<const_double_hasher>::create_ggc (37);
+
+ const_fixed_htab = hash_table<const_fixed_hasher>::create_ggc (37);
+
+ reg_attrs_htab = hash_table<reg_attr_hasher>::create_ggc (37);
#ifdef INIT_EXPANDERS
/* This is to initialize {init|mark|free}_machine_status before the first
else
const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE);
- REAL_VALUE_FROM_INT (dconst0, 0, 0, double_mode);
- REAL_VALUE_FROM_INT (dconst1, 1, 0, double_mode);
- REAL_VALUE_FROM_INT (dconst2, 2, 0, double_mode);
+ double_mode = mode_for_size (DOUBLE_TYPE_SIZE, MODE_FLOAT, 0);
+
+ real_from_integer (&dconst0, double_mode, 0, SIGNED);
+ real_from_integer (&dconst1, double_mode, 1, SIGNED);
+ real_from_integer (&dconst2, double_mode, 2, SIGNED);
dconstm1 = dconst1;
dconstm1.sign = 1;
for (mode = MIN_MODE_PARTIAL_INT;
mode <= MAX_MODE_PARTIAL_INT;
- mode = (enum machine_mode)((int)(mode) + 1))
+ mode = (machine_mode)((int)(mode) + 1))
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
}
for (mode = MIN_MODE_PARTIAL_INT;
mode <= MAX_MODE_PARTIAL_INT;
- mode = (enum machine_mode)((int)(mode) + 1))
+ mode = (machine_mode)((int)(mode) + 1))
const_tiny_rtx[3][(int) mode] = constm1_rtx;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_INT);
}
for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
- if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
+ if (GET_MODE_CLASS ((machine_mode) i) == MODE_CC)
const_tiny_rtx[0][i] = const0_rtx;
const_tiny_rtx[0][(int) BImode] = const0_rtx;
if (STORE_FLAG_VALUE == 1)
const_tiny_rtx[1][(int) BImode] = const1_rtx;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_POINTER_BOUNDS);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ wide_int wi_zero = wi::zero (GET_MODE_PRECISION (mode));
+ const_tiny_rtx[0][mode] = immed_wide_int_const (wi_zero, mode);
+ }
+
pc_rtx = gen_rtx_fmt_ (PC, VOIDmode);
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.
Care updating of libcall regions if present. */
-rtx
-emit_copy_of_insn_after (rtx insn, rtx after)
+rtx_insn *
+emit_copy_of_insn_after (rtx_insn *insn, rtx_insn *after)
{
- rtx new_rtx, link;
+ rtx_insn *new_rtx;
+ rtx link;
switch (GET_CODE (insn))
{
case JUMP_INSN:
new_rtx = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
+ CROSSING_JUMP_P (new_rtx) = CROSSING_JUMP_P (insn);
break;
case DEBUG_INSN:
static GTY((deletable)) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
rtx
-gen_hard_reg_clobber (enum machine_mode mode, unsigned int regno)
+gen_hard_reg_clobber (machine_mode mode, unsigned int regno)
{
if (hard_reg_clobbers[mode][regno])
return hard_reg_clobbers[mode][regno];
/* Return lexical scope block insn belongs to. */
tree
-insn_scope (const_rtx insn)
+insn_scope (const rtx_insn *insn)
{
return LOCATION_BLOCK (INSN_LOCATION (insn));
}
/* Return line number of the statement that produced this insn. */
int
-insn_line (const_rtx insn)
+insn_line (const rtx_insn *insn)
{
return LOCATION_LINE (INSN_LOCATION (insn));
}
/* Return source file of the statement that produced this insn. */
const char *
-insn_file (const_rtx insn)
+insn_file (const rtx_insn *insn)
{
return LOCATION_FILE (INSN_LOCATION (insn));
}
+/* Return expanded location of the statement that produced this insn. */
+expanded_location
+insn_location (const rtx_insn *insn)
+{
+ return expand_location (INSN_LOCATION (insn));
+}
+
/* Return true if memory model MODEL requires a pre-operation (release-style)
barrier or a post-operation (acquire-style) barrier. While not universal,
this function matches behavior of several targets. */
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: