-/* Emit RTL for the GNU C-Compiler expander.
+/* Emit RTL for the GCC expander.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
/* Middle-to-low level generation of rtx code and insns.
- This file contains the functions `gen_rtx', `gen_reg_rtx'
- and `gen_label_rtx' that are the usual ways of creating rtl
- expressions for most purposes.
-
- It also has the functions for creating insns and linking
- them in the doubly-linked chain.
+ This file contains support functions for creating rtl expressions
+ and manipulating them in the doubly-linked chain of insns.
The patterns of the insns are created by machine-dependent
routines in insn-emit.c, which is generated automatically from
- the machine description. These routines use `gen_rtx' to make
- the individual rtx's of the pattern; what is machine dependent
- is the kind of rtx's they make and what arguments they use. */
+ the machine description. These routines make the individual rtx's
+ of the pattern with `gen_rtx_fmt_ee' and others in genrtl.[ch],
+ which are automatically generated from rtl.def; what is machine
+ dependent is the kind of rtx's they make and what arguments they
+ use. */
#include "config.h"
#include "system.h"
static int last_label_num;
-/* Value label_num had when set_new_first_and_last_label_number was called.
+/* Value label_num had when set_new_last_label_num was called.
If label_num has not changed since then, last_label_num is valid. */
static int base_label_num;
REAL_VALUE_TYPE dconst0;
REAL_VALUE_TYPE dconst1;
REAL_VALUE_TYPE dconst2;
+REAL_VALUE_TYPE dconst3;
+REAL_VALUE_TYPE dconst10;
REAL_VALUE_TYPE dconstm1;
REAL_VALUE_TYPE dconstm2;
REAL_VALUE_TYPE dconsthalf;
+REAL_VALUE_TYPE dconstthird;
+REAL_VALUE_TYPE dconstpi;
+REAL_VALUE_TYPE dconste;
/* All references to the following fixed hard registers go through
these unique rtl objects. On machines where the frame-pointer and
In an inline procedure, the stack and frame pointer rtxs may not be
used for anything else. */
-rtx struct_value_rtx; /* (REG:Pmode STRUCT_VALUE_REGNUM) */
-rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */
rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */
rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */
rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */
#define first_insn (cfun->emit->x_first_insn)
#define last_insn (cfun->emit->x_last_insn)
#define cur_insn_uid (cfun->emit->x_cur_insn_uid)
-#define last_linenum (cfun->emit->x_last_linenum)
-#define last_filename (cfun->emit->x_last_filename)
+#define last_location (cfun->emit->x_last_location)
#define first_label_num (cfun->emit->x_first_label_num)
-static rtx make_jump_insn_raw PARAMS ((rtx));
-static rtx make_call_insn_raw PARAMS ((rtx));
-static rtx find_line_note PARAMS ((rtx));
-static rtx change_address_1 PARAMS ((rtx, enum machine_mode, rtx,
- int));
-static void unshare_all_rtl_1 PARAMS ((rtx));
-static void unshare_all_decls PARAMS ((tree));
-static void reset_used_decls PARAMS ((tree));
-static void mark_label_nuses PARAMS ((rtx));
-static hashval_t const_int_htab_hash PARAMS ((const void *));
-static int const_int_htab_eq PARAMS ((const void *,
- const void *));
-static hashval_t const_double_htab_hash PARAMS ((const void *));
-static int const_double_htab_eq PARAMS ((const void *,
- const void *));
-static rtx lookup_const_double PARAMS ((rtx));
-static hashval_t mem_attrs_htab_hash PARAMS ((const void *));
-static int mem_attrs_htab_eq PARAMS ((const void *,
- const void *));
-static mem_attrs *get_mem_attrs PARAMS ((HOST_WIDE_INT, tree, rtx,
- rtx, unsigned int,
- enum machine_mode));
-static hashval_t reg_attrs_htab_hash PARAMS ((const void *));
-static int reg_attrs_htab_eq PARAMS ((const void *,
- const void *));
-static reg_attrs *get_reg_attrs PARAMS ((tree, int));
-static tree component_ref_for_mem_expr PARAMS ((tree));
-static rtx gen_const_vector_0 PARAMS ((enum machine_mode));
-static rtx gen_complex_constant_part PARAMS ((enum machine_mode,
- rtx, int));
+static rtx make_jump_insn_raw (rtx);
+static rtx make_call_insn_raw (rtx);
+static rtx find_line_note (rtx);
+static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
+static void unshare_all_decls (tree);
+static void reset_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 *);
+static rtx lookup_const_double (rtx);
+static hashval_t mem_attrs_htab_hash (const void *);
+static int mem_attrs_htab_eq (const void *, const void *);
+static mem_attrs *get_mem_attrs (HOST_WIDE_INT, tree, rtx, rtx, unsigned int,
+ enum machine_mode);
+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 tree component_ref_for_mem_expr (tree);
+static rtx gen_const_vector_0 (enum machine_mode);
+static rtx gen_complex_constant_part (enum machine_mode, rtx, int);
+static void copy_rtx_if_shared_1 (rtx *orig);
/* Probability of the conditional branch currently proceeded by try_split.
Set to -1 otherwise. */
/* Returns a hash code for X (which is a really a CONST_INT). */
static hashval_t
-const_int_htab_hash (x)
- const void *x;
+const_int_htab_hash (const void *x)
{
- return (hashval_t) INTVAL ((struct rtx_def *) x);
+ return (hashval_t) INTVAL ((rtx) x);
}
/* Returns nonzero if the value represented by X (which is really a
HOST_WIDE_INT *). */
static int
-const_int_htab_eq (x, y)
- const void *x;
- const void *y;
+const_int_htab_eq (const void *x, const void *y)
{
return (INTVAL ((rtx) x) == *((const HOST_WIDE_INT *) y));
}
/* Returns a hash code for X (which is really a CONST_DOUBLE). */
static hashval_t
-const_double_htab_hash (x)
- const void *x;
+const_double_htab_hash (const void *x)
{
rtx value = (rtx) x;
hashval_t h;
/* 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 (x, y)
- const void *x;
- const void *y;
+const_double_htab_eq (const void *x, const void *y)
{
rtx a = (rtx)x, b = (rtx)y;
/* Returns a hash code for X (which is a really a mem_attrs *). */
static hashval_t
-mem_attrs_htab_hash (x)
- const void *x;
+mem_attrs_htab_hash (const void *x)
{
mem_attrs *p = (mem_attrs *) x;
mem_attrs *). */
static int
-mem_attrs_htab_eq (x, y)
- const void *x;
- const void *y;
+mem_attrs_htab_eq (const void *x, const void *y)
{
mem_attrs *p = (mem_attrs *) x;
mem_attrs *q = (mem_attrs *) y;
MEM of mode MODE. */
static mem_attrs *
-get_mem_attrs (alias, expr, offset, size, align, mode)
- HOST_WIDE_INT alias;
- tree expr;
- rtx offset;
- rtx size;
- unsigned int align;
- enum machine_mode mode;
+get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size,
+ unsigned int align, enum machine_mode mode)
{
mem_attrs attrs;
void **slot;
/* Returns a hash code for X (which is a really a reg_attrs *). */
static hashval_t
-reg_attrs_htab_hash (x)
- const void *x;
+reg_attrs_htab_hash (const void *x)
{
reg_attrs *p = (reg_attrs *) x;
reg_attrs *). */
static int
-reg_attrs_htab_eq (x, y)
- const void *x;
- const void *y;
+reg_attrs_htab_eq (const void *x, const void *y)
{
reg_attrs *p = (reg_attrs *) x;
reg_attrs *q = (reg_attrs *) y;
MEM of mode MODE. */
static reg_attrs *
-get_reg_attrs (decl, offset)
- tree decl;
- int offset;
+get_reg_attrs (tree decl, int offset)
{
reg_attrs attrs;
void **slot;
frame_pointer_rtx). */
rtx
-gen_raw_REG (mode, regno)
- enum machine_mode mode;
- int regno;
+gen_raw_REG (enum machine_mode mode, int regno)
{
rtx x = gen_rtx_raw_REG (mode, regno);
ORIGINAL_REGNO (x) = regno;
special_rtx in gengenrtl.c as well. */
rtx
-gen_rtx_CONST_INT (mode, arg)
- enum machine_mode mode ATTRIBUTE_UNUSED;
- HOST_WIDE_INT arg;
+gen_rtx_CONST_INT (enum machine_mode mode ATTRIBUTE_UNUSED, HOST_WIDE_INT arg)
{
void **slot;
}
rtx
-gen_int_mode (c, mode)
- HOST_WIDE_INT c;
- enum machine_mode mode;
+gen_int_mode (HOST_WIDE_INT c, enum machine_mode mode)
{
return GEN_INT (trunc_int_for_mode (c, mode));
}
hash table. If so, return its counterpart; otherwise add it
to the hash table and return it. */
static rtx
-lookup_const_double (real)
- rtx real;
+lookup_const_double (rtx real)
{
void **slot = htab_find_slot (const_double_htab, real, INSERT);
if (*slot == 0)
/* Return a CONST_DOUBLE rtx for a floating-point value specified by
VALUE in mode MODE. */
rtx
-const_double_from_real_value (value, mode)
- REAL_VALUE_TYPE value;
- enum machine_mode mode;
+const_double_from_real_value (REAL_VALUE_TYPE value, enum machine_mode mode)
{
rtx real = rtx_alloc (CONST_DOUBLE);
PUT_MODE (real, mode);
REAL_VALUE_TYPE and use CONST_DOUBLE_FROM_REAL_VALUE. */
rtx
-immed_double_const (i0, i1, mode)
- HOST_WIDE_INT i0, i1;
- enum machine_mode mode;
+immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
{
rtx value;
unsigned int i;
}
rtx
-gen_rtx_REG (mode, regno)
- enum machine_mode mode;
- unsigned int regno;
+gen_rtx_REG (enum 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
}
rtx
-gen_rtx_MEM (mode, addr)
- enum machine_mode mode;
- rtx addr;
+gen_rtx_MEM (enum machine_mode mode, rtx addr)
{
rtx rt = gen_rtx_raw_MEM (mode, addr);
return rt;
}
+/* Generate a memory referring to non-trapping constant memory. */
+
+rtx
+gen_const_mem (enum machine_mode mode, rtx addr)
+{
+ rtx mem = gen_rtx_MEM (mode, addr);
+ MEM_READONLY_P (mem) = 1;
+ MEM_NOTRAP_P (mem) = 1;
+ return mem;
+}
+
rtx
-gen_rtx_SUBREG (mode, reg, offset)
- enum machine_mode mode;
- rtx reg;
- int offset;
+gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
{
/* This is the most common failure type.
Catch it early so we can see who does it. */
is smaller than mode of REG, otherwise paradoxical SUBREG. */
rtx
-gen_lowpart_SUBREG (mode, reg)
- enum machine_mode mode;
- rtx reg;
+gen_lowpart_SUBREG (enum machine_mode mode, rtx reg)
{
enum machine_mode inmode;
subreg_lowpart_offset (mode, inmode));
}
\f
-/* rtx gen_rtx (code, mode, [element1, ..., elementn])
-**
-** This routine generates an RTX of the size specified by
-** <code>, which is an RTX code. The RTX structure is initialized
-** from the arguments <element1> through <elementn>, which are
-** interpreted according to the specific RTX type's format. The
-** special machine mode associated with the rtx (if any) is specified
-** in <mode>.
-**
-** gen_rtx can be invoked in a way which resembles the lisp-like
-** rtx it will generate. For example, the following rtx structure:
-**
-** (plus:QI (mem:QI (reg:SI 1))
-** (mem:QI (plusw:SI (reg:SI 2) (reg:SI 3))))
-**
-** ...would be generated by the following C code:
-**
-** gen_rtx (PLUS, QImode,
-** gen_rtx (MEM, QImode,
-** gen_rtx (REG, SImode, 1)),
-** gen_rtx (MEM, QImode,
-** gen_rtx (PLUS, SImode,
-** gen_rtx (REG, SImode, 2),
-** gen_rtx (REG, SImode, 3)))),
-*/
-
-/*VARARGS2*/
-rtx
-gen_rtx (enum rtx_code code, enum machine_mode mode, ...)
-{
- int i; /* Array indices... */
- const char *fmt; /* Current rtx's format... */
- rtx rt_val; /* RTX to return to caller... */
- va_list p;
-
- va_start (p, mode);
-
- switch (code)
- {
- case CONST_INT:
- rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
- break;
-
- case CONST_DOUBLE:
- {
- HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
- HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT);
-
- rt_val = immed_double_const (arg0, arg1, mode);
- }
- break;
-
- case REG:
- rt_val = gen_rtx_REG (mode, va_arg (p, int));
- break;
-
- case MEM:
- rt_val = gen_rtx_MEM (mode, va_arg (p, rtx));
- break;
-
- default:
- rt_val = rtx_alloc (code); /* Allocate the storage space. */
- rt_val->mode = mode; /* Store the machine mode... */
-
- fmt = GET_RTX_FORMAT (code); /* Find the right format... */
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
- {
- switch (*fmt++)
- {
- case '0': /* Field with unknown use. Zero it. */
- X0EXP (rt_val, i) = NULL_RTX;
- break;
-
- case 'i': /* An integer? */
- XINT (rt_val, i) = va_arg (p, int);
- break;
-
- case 'w': /* A wide integer? */
- XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
- break;
-
- case 's': /* A string? */
- XSTR (rt_val, i) = va_arg (p, char *);
- break;
-
- case 'e': /* An expression? */
- case 'u': /* An insn? Same except when printing. */
- XEXP (rt_val, i) = va_arg (p, rtx);
- break;
-
- case 'E': /* An RTX vector? */
- XVEC (rt_val, i) = va_arg (p, rtvec);
- break;
-
- case 'b': /* A bitmap? */
- XBITMAP (rt_val, i) = va_arg (p, bitmap);
- break;
-
- case 't': /* A tree? */
- XTREE (rt_val, i) = va_arg (p, tree);
- break;
-
- default:
- abort ();
- }
- }
- break;
- }
-
- va_end (p);
- return rt_val;
-}
-
/* gen_rtvec (n, [rt1, ..., rtn])
**
** This routine creates an rtvec and stores within it the
if (n == 0)
return NULL_RTVEC; /* Don't allocate an empty rtvec... */
- vector = (rtx *) alloca (n * sizeof (rtx));
+ vector = alloca (n * sizeof (rtx));
for (i = 0; i < n; i++)
vector[i] = va_arg (p, rtx);
}
rtvec
-gen_rtvec_v (n, argp)
- int n;
- rtx *argp;
+gen_rtvec_v (int n, rtx *argp)
{
int i;
rtvec rt_val;
This pseudo is assigned the next sequential register number. */
rtx
-gen_reg_rtx (mode)
- enum machine_mode mode;
+gen_reg_rtx (enum machine_mode mode)
{
struct function *f = cfun;
rtx val;
memset (new + old_size, 0, old_size);
f->emit->regno_pointer_align = (unsigned char *) new;
- new1 = (rtx *) ggc_realloc (f->emit->x_regno_reg_rtx,
- old_size * 2 * sizeof (rtx));
+ new1 = ggc_realloc (f->emit->x_regno_reg_rtx,
+ old_size * 2 * sizeof (rtx));
memset (new1 + old_size, 0, old_size * sizeof (rtx));
regno_reg_rtx = new1;
return val;
}
-/* Generate an register with same attributes as REG,
- but offsetted by OFFSET. */
+/* Generate a register with same attributes as REG, but offsetted by OFFSET.
+ Do the big endian correction if needed. */
rtx
-gen_rtx_REG_offset (reg, mode, regno, offset)
- enum machine_mode mode;
- unsigned int regno;
- int offset;
- rtx reg;
+gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset)
{
rtx new = gen_rtx_REG (mode, regno);
+ tree decl;
+ HOST_WIDE_INT var_size;
+
+ /* PR middle-end/14084
+ The problem appears when a variable is stored in a larger register
+ and later it is used in the original mode or some mode in between
+ or some part of variable is accessed.
+
+ On little endian machines there is no problem because
+ the REG_OFFSET of the start of the variable is the same when
+ accessed in any mode (it is 0).
+
+ However, this is not true on big endian machines.
+ The offset of the start of the variable is different when accessed
+ in different modes.
+ When we are taking a part of the REG we have to change the OFFSET
+ from offset WRT size of mode of REG to offset WRT size of variable.
+
+ If we would not do the big endian correction the resulting REG_OFFSET
+ would be larger than the size of the DECL.
+
+ Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine:
+
+ REG.mode MODE DECL size old offset new offset description
+ DI SI 4 4 0 int32 in SImode
+ DI SI 1 4 0 char in SImode
+ DI QI 1 7 0 char in QImode
+ DI QI 4 5 1 1st element in QImode
+ of char[4]
+ DI HI 4 6 2 1st element in HImode
+ of int16[2]
+
+ If the size of DECL is equal or greater than the size of REG
+ we can't do this correction because the register holds the
+ whole variable or a part of the variable and thus the REG_OFFSET
+ is already correct. */
+
+ decl = REG_EXPR (reg);
+ if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
+ && decl != NULL
+ && offset > 0
+ && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode)
+ && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0
+ && var_size < GET_MODE_SIZE (GET_MODE (reg))))
+ {
+ int offset_le;
+
+ /* Convert machine endian to little endian WRT size of mode of REG. */
+ if (WORDS_BIG_ENDIAN)
+ offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset)
+ / UNITS_PER_WORD) * UNITS_PER_WORD;
+ else
+ offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
+
+ if (BYTES_BIG_ENDIAN)
+ offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset)
+ % UNITS_PER_WORD);
+ else
+ offset_le += offset % UNITS_PER_WORD;
+
+ if (offset_le >= var_size)
+ {
+ /* MODE is wider than the variable so the new reg will cover
+ the whole variable so the resulting OFFSET should be 0. */
+ offset = 0;
+ }
+ else
+ {
+ /* Convert little endian to machine endian WRT size of variable. */
+ if (WORDS_BIG_ENDIAN)
+ offset = ((var_size - 1 - offset_le)
+ / UNITS_PER_WORD) * UNITS_PER_WORD;
+ else
+ offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD;
+
+ if (BYTES_BIG_ENDIAN)
+ offset += ((var_size - 1 - offset_le)
+ % UNITS_PER_WORD);
+ else
+ offset += offset_le % UNITS_PER_WORD;
+ }
+ }
+
REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg),
- REG_OFFSET (reg) + offset);
+ REG_OFFSET (reg) + offset);
return new;
}
/* Set the decl for MEM to DECL. */
void
-set_reg_attrs_from_mem (reg, mem)
- rtx reg;
- rtx mem;
+set_reg_attrs_from_mem (rtx reg, rtx mem)
{
if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
REG_ATTRS (reg)
Use needed values from memory attributes of MEM. */
void
-set_reg_attrs_for_parm (parm_rtx, mem)
- rtx parm_rtx;
- rtx mem;
+set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
{
- if (GET_CODE (parm_rtx) == REG)
+ if (REG_P (parm_rtx))
set_reg_attrs_from_mem (parm_rtx, mem);
else if (GET_CODE (parm_rtx) == PARALLEL)
{
for (; i < XVECLEN (parm_rtx, 0); i++)
{
rtx x = XVECEXP (parm_rtx, 0, i);
- if (GET_CODE (XEXP (x, 0)) == REG)
+ if (REG_P (XEXP (x, 0)))
REG_ATTRS (XEXP (x, 0))
= get_reg_attrs (MEM_EXPR (mem),
INTVAL (XEXP (x, 1)));
/* Assign the RTX X to declaration T. */
void
-set_decl_rtl (t, x)
- tree t;
- rtx x;
+set_decl_rtl (tree t, rtx x)
{
DECL_CHECK (t)->decl.rtl = x;
if (!x)
return;
- /* For register, we maitain the reverse information too. */
- if (GET_CODE (x) == REG)
+ /* For register, we maintain the reverse information too. */
+ if (REG_P (x))
REG_ATTRS (x) = get_reg_attrs (t, 0);
else if (GET_CODE (x) == SUBREG)
REG_ATTRS (SUBREG_REG (x))
}
}
+/* Assign the RTX X to parameter declaration T. */
+void
+set_decl_incoming_rtl (tree t, rtx x)
+{
+ DECL_INCOMING_RTL (t) = x;
+
+ if (!x)
+ return;
+ /* For register, we maintain the reverse information too. */
+ if (REG_P (x))
+ REG_ATTRS (x) = get_reg_attrs (t, 0);
+ else if (GET_CODE (x) == SUBREG)
+ REG_ATTRS (SUBREG_REG (x))
+ = get_reg_attrs (t, -SUBREG_BYTE (x));
+ if (GET_CODE (x) == CONCAT)
+ {
+ if (REG_P (XEXP (x, 0)))
+ REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0);
+ if (REG_P (XEXP (x, 1)))
+ REG_ATTRS (XEXP (x, 1))
+ = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0))));
+ }
+ if (GET_CODE (x) == PARALLEL)
+ {
+ int i, start;
+
+ /* Check for a NULL entry, used to indicate that the parameter goes
+ both on the stack and in registers. */
+ if (XEXP (XVECEXP (x, 0, 0), 0))
+ start = 0;
+ else
+ start = 1;
+
+ for (i = start; i < XVECLEN (x, 0); i++)
+ {
+ rtx y = XVECEXP (x, 0, i);
+ if (REG_P (XEXP (y, 0)))
+ REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1)));
+ }
+ }
+}
+
/* Identify REG (which may be a CONCAT) as a user register. */
void
-mark_user_reg (reg)
- rtx reg;
+mark_user_reg (rtx reg)
{
if (GET_CODE (reg) == CONCAT)
{
REG_USERVAR_P (XEXP (reg, 0)) = 1;
REG_USERVAR_P (XEXP (reg, 1)) = 1;
}
- else if (GET_CODE (reg) == REG)
+ else if (REG_P (reg))
REG_USERVAR_P (reg) = 1;
else
abort ();
as ALIGN, if nonzero. */
void
-mark_reg_pointer (reg, align)
- rtx reg;
- int align;
+mark_reg_pointer (rtx reg, int align)
{
if (! REG_POINTER (reg))
{
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
else if (align && align < REGNO_POINTER_ALIGN (REGNO (reg)))
- /* We can no-longer be sure just how aligned this pointer is */
+ /* We can no-longer be sure just how aligned this pointer is. */
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
/* Return 1 plus largest pseudo reg number used in the current function. */
int
-max_reg_num ()
+max_reg_num (void)
{
return reg_rtx_no;
}
/* Return 1 + the largest label number used so far in the current function. */
int
-max_label_num ()
+max_label_num (void)
{
if (last_label_num && label_num == base_label_num)
return last_label_num;
/* Return first label number used in this function (if any were used). */
int
-get_first_label_num ()
+get_first_label_num (void)
{
return first_label_num;
}
+
+/* If the rtx for label was created during the expansion of a nested
+ function, then first_label_num won't include this label number.
+ Fix this now so that array indicies work later. */
+
+void
+maybe_set_first_label_num (rtx x)
+{
+ if (CODE_LABEL_NUMBER (x) < first_label_num)
+ first_label_num = CODE_LABEL_NUMBER (x);
+}
\f
/* Return the final regno of X, which is a SUBREG of a hard
register. */
int
-subreg_hard_regno (x, check_mode)
- rtx x;
- int check_mode;
+subreg_hard_regno (rtx x, int check_mode)
{
enum machine_mode mode = GET_MODE (x);
unsigned int byte_offset, base_regno, final_regno;
/* This is where we attempt to catch illegal subregs
created by the compiler. */
if (GET_CODE (x) != SUBREG
- || GET_CODE (reg) != REG)
+ || !REG_P (reg))
abort ();
base_regno = REGNO (reg);
if (base_regno >= FIRST_PSEUDO_REGISTER)
abort ();
#ifdef ENABLE_CHECKING
if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
- SUBREG_BYTE (x), mode))
+ SUBREG_BYTE (x), mode))
abort ();
#endif
/* Catch non-congruent offsets too. */
If this is not a case we can handle, return 0. */
rtx
-gen_lowpart_common (mode, x)
- enum machine_mode mode;
- rtx x;
+gen_lowpart_common (enum machine_mode mode, rtx x)
{
int msize = GET_MODE_SIZE (mode);
- int xsize = GET_MODE_SIZE (GET_MODE (x));
+ int xsize;
int offset = 0;
+ enum machine_mode innermode;
+
+ /* Unfortunately, this routine doesn't take a parameter for the mode of X,
+ so we have to make one up. Yuk. */
+ innermode = GET_MODE (x);
+ if (GET_CODE (x) == CONST_INT && msize <= HOST_BITS_PER_WIDE_INT)
+ innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
+ else if (innermode == VOIDmode)
+ innermode = mode_for_size (HOST_BITS_PER_WIDE_INT * 2, MODE_INT, 0);
+
+ xsize = GET_MODE_SIZE (innermode);
+
+ if (innermode == VOIDmode || innermode == BLKmode)
+ abort ();
- if (GET_MODE (x) == mode)
+ if (innermode == mode)
return x;
/* MODE must occupy no more words than the mode of X. */
- if (GET_MODE (x) != VOIDmode
- && ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
- > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
+ if ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
+ > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
return 0;
/* Don't allow generating paradoxical FLOAT_MODE subregs. */
- if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_MODE (x) != VOIDmode && msize > xsize)
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT && msize > xsize)
return 0;
- offset = subreg_lowpart_offset (mode, GET_MODE (x));
+ offset = subreg_lowpart_offset (mode, innermode);
if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
&& (GET_MODE_CLASS (mode) == MODE_INT
if (GET_MODE (XEXP (x, 0)) == mode)
return XEXP (x, 0);
- else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
+ else if (msize < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
return gen_lowpart_common (mode, XEXP (x, 0));
- else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
+ else if (msize < xsize)
return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0));
}
- else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG
- || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR)
- return simplify_gen_subreg (mode, x, GET_MODE (x), offset);
- else if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT
- || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
- && GET_MODE (x) == VOIDmode)
- return simplify_gen_subreg (mode, x, int_mode_for_mode (mode), offset);
- /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits
- from the low-order part of the constant. */
- else if ((GET_MODE_CLASS (mode) == MODE_INT
- || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
- && GET_MODE (x) == VOIDmode
- && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
- {
- /* If MODE is twice the host word size, X is already the desired
- representation. Otherwise, if MODE is wider than a word, we can't
- do this. If MODE is exactly a word, return just one CONST_INT. */
-
- if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT)
- return x;
- else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
- return 0;
- else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
- return (GET_CODE (x) == CONST_INT ? x
- : GEN_INT (CONST_DOUBLE_LOW (x)));
- else
- {
- /* MODE must be narrower than HOST_BITS_PER_WIDE_INT. */
- HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
- : CONST_DOUBLE_LOW (x));
-
- /* Sign extend to HOST_WIDE_INT. */
- val = trunc_int_for_mode (val, mode);
-
- return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
- : GEN_INT (val));
- }
- }
-
- /* The floating-point emulator can handle all conversions between
- FP and integer operands. This simplifies reload because it
- doesn't have to deal with constructs like (subreg:DI
- (const_double:SF ...)) or (subreg:DF (const_int ...)). */
- /* Single-precision floats are always 32-bits and double-precision
- floats are always 64-bits. */
-
- else if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_MODE_BITSIZE (mode) == 32
- && GET_CODE (x) == CONST_INT)
- {
- REAL_VALUE_TYPE r;
- long i = INTVAL (x);
-
- real_from_target (&r, &i, mode);
- return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
- }
- else if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_MODE_BITSIZE (mode) == 64
- && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
- && GET_MODE (x) == VOIDmode)
- {
- REAL_VALUE_TYPE r;
- HOST_WIDE_INT low, high;
- long i[2];
-
- if (GET_CODE (x) == CONST_INT)
- {
- low = INTVAL (x);
- high = low >> (HOST_BITS_PER_WIDE_INT - 1);
- }
- else
- {
- low = CONST_DOUBLE_LOW (x);
- high = CONST_DOUBLE_HIGH (x);
- }
-
- if (HOST_BITS_PER_WIDE_INT > 32)
- high = low >> 31 >> 1;
-
- /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the
- target machine. */
- if (WORDS_BIG_ENDIAN)
- i[0] = high, i[1] = low;
- else
- i[0] = low, i[1] = high;
-
- real_from_target (&r, i, mode);
- return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
- }
- else if ((GET_MODE_CLASS (mode) == MODE_INT
- || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
- && GET_CODE (x) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
- {
- REAL_VALUE_TYPE r;
- long i[4]; /* Only the low 32 bits of each 'long' are used. */
- int endian = WORDS_BIG_ENDIAN ? 1 : 0;
-
- /* Convert 'r' into an array of four 32-bit words in target word
- order. */
- REAL_VALUE_FROM_CONST_DOUBLE (r, x);
- switch (GET_MODE_BITSIZE (GET_MODE (x)))
- {
- case 32:
- REAL_VALUE_TO_TARGET_SINGLE (r, i[3 * endian]);
- i[1] = 0;
- i[2] = 0;
- i[3 - 3 * endian] = 0;
- break;
- case 64:
- REAL_VALUE_TO_TARGET_DOUBLE (r, i + 2 * endian);
- i[2 - 2 * endian] = 0;
- i[3 - 2 * endian] = 0;
- break;
- case 96:
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i + endian);
- i[3 - 3 * endian] = 0;
- break;
- case 128:
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i);
- break;
- default:
- abort ();
- }
- /* Now, pack the 32-bit elements of the array into a CONST_DOUBLE
- and return it. */
-#if HOST_BITS_PER_WIDE_INT == 32
- return immed_double_const (i[3 * endian], i[1 + endian], mode);
-#else
- if (HOST_BITS_PER_WIDE_INT != 64)
- abort ();
-
- return immed_double_const ((((unsigned long) i[3 * endian])
- | ((HOST_WIDE_INT) i[1 + endian] << 32)),
- (((unsigned long) i[2 - endian])
- | ((HOST_WIDE_INT) i[3 - 3 * endian] << 32)),
- mode);
-#endif
- }
- /* If MODE is a condition code and X is a CONST_INT, the value of X
- must already have been "recognized" by the back-end, and we can
- assume that it is valid for this mode. */
- else if (GET_MODE_CLASS (mode) == MODE_CC
- && GET_CODE (x) == CONST_INT)
- return x;
+ else if (GET_CODE (x) == SUBREG || REG_P (x)
+ || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR
+ || GET_CODE (x) == CONST_DOUBLE || GET_CODE (x) == CONST_INT)
+ return simplify_gen_subreg (mode, x, innermode, offset);
/* Otherwise, we can't do this. */
return 0;
returns NULL_RTX if the component isn't a constant. */
static rtx
-gen_complex_constant_part (mode, x, imagpart_p)
- enum machine_mode mode;
- rtx x;
- int imagpart_p;
+gen_complex_constant_part (enum machine_mode mode, rtx x, int imagpart_p)
{
tree decl, part;
- if (GET_CODE (x) == MEM
+ if (MEM_P (x)
&& GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
{
decl = SYMBOL_REF_DECL (XEXP (x, 0));
This always comes at the low address in memory. */
rtx
-gen_realpart (mode, x)
- enum machine_mode mode;
- rtx x;
+gen_realpart (enum machine_mode mode, rtx x)
{
rtx part;
This always comes at the high address in memory. */
rtx
-gen_imagpart (mode, x)
- enum machine_mode mode;
- rtx x;
+gen_imagpart (enum machine_mode mode, rtx x)
{
rtx part;
else
return gen_highpart (mode, x);
}
-
-/* Return 1 iff X, assumed to be a SUBREG,
- refers to the real part of the complex value in its containing reg.
- Complex values are always stored with the real part in the first word,
- regardless of WORDS_BIG_ENDIAN. */
-
-int
-subreg_realpart_p (x)
- rtx x;
-{
- if (GET_CODE (x) != SUBREG)
- abort ();
-
- return ((unsigned int) SUBREG_BYTE (x)
- < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
-}
\f
-/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value,
- return an rtx (MEM, SUBREG, or CONST_INT) that refers to the
- least-significant part of X.
- MODE specifies how big a part of X to return;
- it usually should not be larger than a word.
- If X is a MEM whose address is a QUEUED, the value may be so also. */
-
rtx
-gen_lowpart (mode, x)
- enum machine_mode mode;
- rtx x;
-{
- rtx result = gen_lowpart_common (mode, x);
-
- if (result)
- return result;
- else if (GET_CODE (x) == REG)
- {
- /* Must be a hard reg that's not valid in MODE. */
- result = gen_lowpart_common (mode, copy_to_reg (x));
- if (result == 0)
- abort ();
- return result;
- }
- else if (GET_CODE (x) == MEM)
- {
- /* The only additional case we can do is MEM. */
- int offset = 0;
-
- /* The following exposes the use of "x" to CSE. */
- if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
- && SCALAR_INT_MODE_P (GET_MODE (x))
- && ! no_new_pseudos)
- return gen_lowpart (mode, force_reg (GET_MODE (x), x));
-
- if (WORDS_BIG_ENDIAN)
- offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
-
- if (BYTES_BIG_ENDIAN)
- /* Adjust the address so that the address-after-the-data
- is unchanged. */
- offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-
- return adjust_address (x, mode, offset);
- }
- else if (GET_CODE (x) == ADDRESSOF)
- return gen_lowpart (mode, force_reg (GET_MODE (x), x));
- else
- abort ();
-}
-
-/* Like `gen_lowpart', but refer to the most significant part.
- This is used to access the imaginary part of a complex number. */
-
-rtx
-gen_highpart (mode, x)
- enum machine_mode mode;
- rtx x;
+gen_highpart (enum machine_mode mode, rtx x)
{
unsigned int msize = GET_MODE_SIZE (mode);
rtx result;
/* This case loses if X is a subreg. To catch bugs early,
complain if an invalid MODE is used even in other cases. */
if (msize > UNITS_PER_WORD
- && msize != GET_MODE_UNIT_SIZE (GET_MODE (x)))
+ && msize != (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x)))
abort ();
result = simplify_gen_subreg (mode, x, GET_MODE (x),
/* simplify_gen_subreg is not guaranteed to return a valid operand for
the target if we have a MEM. gen_highpart must return a valid operand,
emitting code if necessary to do so. */
- if (result != NULL_RTX && GET_CODE (result) == MEM)
+ if (result != NULL_RTX && MEM_P (result))
result = validize_mem (result);
if (!result)
/* Like gen_highpart, but accept mode of EXP operand in case EXP can
be VOIDmode constant. */
rtx
-gen_highpart_mode (outermode, innermode, exp)
- enum machine_mode outermode, innermode;
- rtx exp;
+gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx exp)
{
if (GET_MODE (exp) != VOIDmode)
{
of the value in mode INNERMODE stored in memory in target format. */
unsigned int
-subreg_lowpart_offset (outermode, innermode)
- enum machine_mode outermode, innermode;
+subreg_lowpart_offset (enum machine_mode outermode, enum 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 (outermode, innermode)
- enum machine_mode outermode, innermode;
+subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode)
{
unsigned int offset = 0;
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
If X is not a SUBREG, always return 1 (it is its own low part!). */
int
-subreg_lowpart_p (x)
- rtx x;
+subreg_lowpart_p (rtx x)
{
if (GET_CODE (x) != SUBREG)
return 1;
== SUBREG_BYTE (x));
}
\f
-
-/* Helper routine for all the constant cases of operand_subword.
- Some places invoke this directly. */
-
-rtx
-constant_subword (op, offset, mode)
- rtx op;
- int offset;
- enum machine_mode mode;
-{
- int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
- HOST_WIDE_INT val;
-
- /* If OP is already an integer word, return it. */
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == UNITS_PER_WORD)
- return op;
-
- /* The output is some bits, the width of the target machine's word.
- A wider-word host can surely hold them in a CONST_INT. A narrower-word
- host can't. */
- if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
- && GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_MODE_BITSIZE (mode) == 64
- && GET_CODE (op) == CONST_DOUBLE)
- {
- long k[2];
- REAL_VALUE_TYPE rv;
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
-
- /* We handle 32-bit and >= 64-bit words here. Note that the order in
- which the words are written depends on the word endianness.
- ??? This is a potential portability problem and should
- be fixed at some point.
-
- We must exercise caution with the sign bit. By definition there
- are 32 significant bits in K; there may be more in a HOST_WIDE_INT.
- Consider a host with a 32-bit long and a 64-bit HOST_WIDE_INT.
- So we explicitly mask and sign-extend as necessary. */
- if (BITS_PER_WORD == 32)
- {
- val = k[offset];
- val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
- return GEN_INT (val);
- }
-#if HOST_BITS_PER_WIDE_INT >= 64
- else if (BITS_PER_WORD >= 64 && offset == 0)
- {
- val = k[! WORDS_BIG_ENDIAN];
- val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
- val |= (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN] & 0xffffffff;
- return GEN_INT (val);
- }
-#endif
- else if (BITS_PER_WORD == 16)
- {
- val = k[offset >> 1];
- if ((offset & 1) == ! WORDS_BIG_ENDIAN)
- val >>= 16;
- val = ((val & 0xffff) ^ 0x8000) - 0x8000;
- return GEN_INT (val);
- }
- else
- abort ();
- }
- else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
- && GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_MODE_BITSIZE (mode) > 64
- && GET_CODE (op) == CONST_DOUBLE)
- {
- long k[4];
- REAL_VALUE_TYPE rv;
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
-
- if (BITS_PER_WORD == 32)
- {
- val = k[offset];
- val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
- return GEN_INT (val);
- }
-#if HOST_BITS_PER_WIDE_INT >= 64
- else if (BITS_PER_WORD >= 64 && offset <= 1)
- {
- val = k[offset * 2 + ! WORDS_BIG_ENDIAN];
- val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
- val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff;
- return GEN_INT (val);
- }
-#endif
- else
- abort ();
- }
-
- /* Single word float is a little harder, since single- and double-word
- values often do not have the same high-order bits. We have already
- verified that we want the only defined word of the single-word value. */
- if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_MODE_BITSIZE (mode) == 32
- && GET_CODE (op) == CONST_DOUBLE)
- {
- long l;
- REAL_VALUE_TYPE rv;
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
- REAL_VALUE_TO_TARGET_SINGLE (rv, l);
-
- /* Sign extend from known 32-bit value to HOST_WIDE_INT. */
- val = l;
- val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
-
- if (BITS_PER_WORD == 16)
- {
- if ((offset & 1) == ! WORDS_BIG_ENDIAN)
- val >>= 16;
- val = ((val & 0xffff) ^ 0x8000) - 0x8000;
- }
-
- return GEN_INT (val);
- }
-
- /* The only remaining cases that we can handle are integers.
- Convert to proper endianness now since these cases need it.
- At this point, offset == 0 means the low-order word.
-
- We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT
- in general. However, if OP is (const_int 0), we can just return
- it for any word. */
-
- if (op == const0_rtx)
- return op;
-
- if (GET_MODE_CLASS (mode) != MODE_INT
- || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)
- || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)
- return 0;
-
- if (WORDS_BIG_ENDIAN)
- offset = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - offset;
-
- /* Find out which word on the host machine this value is in and get
- it from the constant. */
- val = (offset / size_ratio == 0
- ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op))
- : (GET_CODE (op) == CONST_INT
- ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
-
- /* Get the value we want into the low bits of val. */
- if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
- val = ((val >> ((offset % size_ratio) * BITS_PER_WORD)));
-
- val = trunc_int_for_mode (val, word_mode);
-
- return GEN_INT (val);
-}
-
/* Return subword OFFSET of operand OP.
The word number, OFFSET, is interpreted as the word number starting
at the low-order address. OFFSET 0 is the low-order word if not
*/
rtx
-operand_subword (op, offset, validate_address, mode)
- rtx op;
- unsigned int offset;
- int validate_address;
- enum machine_mode mode;
+operand_subword (rtx op, unsigned int offset, int validate_address, enum machine_mode mode)
{
if (mode == VOIDmode)
mode = GET_MODE (op);
return const0_rtx;
/* Form a new MEM at the requested address. */
- if (GET_CODE (op) == MEM)
+ if (MEM_P (op))
{
rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
MODE is the mode of OP, in case it is CONST_INT. */
rtx
-operand_subword_force (op, offset, mode)
- rtx op;
- unsigned int offset;
- enum machine_mode mode;
+operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode)
{
rtx result = operand_subword (op, offset, 1, mode);
{
/* If this is a register which can not be accessed by words, copy it
to a pseudo register. */
- if (GET_CODE (op) == REG)
+ if (REG_P (op))
op = copy_to_reg (op);
else
op = force_reg (mode, op);
A test instruction is changed into a compare of 0 against the operand. */
void
-reverse_comparison (insn)
- rtx insn;
+reverse_comparison (rtx insn)
{
rtx body = PATTERN (insn);
rtx comp;
a NULL expression. */
static tree
-component_ref_for_mem_expr (ref)
- tree ref;
+component_ref_for_mem_expr (tree ref)
{
tree inner = TREE_OPERAND (ref, 0);
inner = component_ref_for_mem_expr (inner);
else
{
- tree placeholder_ptr = 0;
-
/* Now remove any conversions: they don't change what the underlying
- object is. Likewise for SAVE_EXPR. Also handle PLACEHOLDER_EXPR. */
+ object is. Likewise for SAVE_EXPR. */
while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR
|| TREE_CODE (inner) == NON_LVALUE_EXPR
|| TREE_CODE (inner) == VIEW_CONVERT_EXPR
- || TREE_CODE (inner) == SAVE_EXPR
- || TREE_CODE (inner) == PLACEHOLDER_EXPR)
- if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
- inner = find_placeholder (inner, &placeholder_ptr);
- else
- inner = TREE_OPERAND (inner, 0);
+ || TREE_CODE (inner) == SAVE_EXPR)
+ inner = TREE_OPERAND (inner, 0);
if (! DECL_P (inner))
inner = NULL_TREE;
if (inner == TREE_OPERAND (ref, 0))
return ref;
else
- return build (COMPONENT_REF, TREE_TYPE (ref), inner,
- TREE_OPERAND (ref, 1));
+ return build3 (COMPONENT_REF, TREE_TYPE (ref), inner,
+ TREE_OPERAND (ref, 1), NULL_TREE);
+}
+
+/* Returns 1 if both MEM_EXPR can be considered equal
+ and 0 otherwise. */
+
+int
+mem_expr_equal_p (tree expr1, tree expr2)
+{
+ if (expr1 == expr2)
+ return 1;
+
+ if (! expr1 || ! expr2)
+ return 0;
+
+ if (TREE_CODE (expr1) != TREE_CODE (expr2))
+ return 0;
+
+ if (TREE_CODE (expr1) == COMPONENT_REF)
+ return
+ mem_expr_equal_p (TREE_OPERAND (expr1, 0),
+ TREE_OPERAND (expr2, 0))
+ && mem_expr_equal_p (TREE_OPERAND (expr1, 1), /* field decl */
+ TREE_OPERAND (expr2, 1));
+
+ if (TREE_CODE (expr1) == INDIRECT_REF)
+ return mem_expr_equal_p (TREE_OPERAND (expr1, 0),
+ TREE_OPERAND (expr2, 0));
+
+ /* Decls with different pointers can't be equal. */
+ if (DECL_P (expr1))
+ return 0;
+
+ abort(); /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already
+ have been resolved here. */
}
/* Given REF, a MEM, and T, either the type of X or the expression
there is an offset outstanding on T that will be applied later. */
void
-set_mem_attributes_minus_bitpos (ref, t, objectp, bitpos)
- rtx ref;
- tree t;
- int objectp;
- HOST_WIDE_INT bitpos;
+set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
+ HOST_WIDE_INT bitpos)
{
HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);
tree expr = MEM_EXPR (ref);
return;
type = TYPE_P (t) ? t : TREE_TYPE (t);
+ if (type == error_mark_node)
+ return;
/* If we have already set DECL_RTL = ref, get_alias_set will get the
wrong answer, as it assumes that DECL_RTL already has the right alias
front-end routine) and use it. */
alias = get_alias_set (t);
- MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
+ MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type);
MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
- RTX_UNCHANGING_P (ref)
- |= ((lang_hooks.honor_readonly
- && (TYPE_READONLY (type) || TREE_READONLY (t)))
- || (! TYPE_P (t) && TREE_CONSTANT (t)));
+ MEM_POINTER (ref) = POINTER_TYPE_P (type);
+ MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (t);
/* If we are making an object of this type, or if this is a DECL, we know
that it is a scalar if the type is not an aggregate. */
the expression. */
if (! TYPE_P (t))
{
- maybe_set_unchanging (ref, t);
+ tree base = get_base_address (t);
+ if (base && DECL_P (base)
+ && TREE_READONLY (base)
+ && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
+ MEM_READONLY_P (ref) = 1;
+
if (TREE_THIS_VOLATILE (t))
MEM_VOLATILE_P (ref) = 1;
else if (TREE_CODE (t) == ARRAY_REF)
{
tree off_tree = size_zero_node;
+ /* We can't modify t, because we use it at the end of the
+ function. */
+ tree t2 = t;
do
{
- tree index = TREE_OPERAND (t, 1);
- tree array = TREE_OPERAND (t, 0);
- tree domain = TYPE_DOMAIN (TREE_TYPE (array));
- tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
- tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+ tree index = TREE_OPERAND (t2, 1);
+ tree low_bound = array_ref_low_bound (t2);
+ tree unit_size = array_ref_element_size (t2);
/* We assume all arrays have sizes that are a multiple of a byte.
First subtract the lower bound, if any, in the type of the
- index, then convert to sizetype and multiply by the size of the
- array element. */
- if (low_bound != 0 && ! integer_zerop (low_bound))
- index = fold (build (MINUS_EXPR, TREE_TYPE (index),
- index, low_bound));
-
- /* If the index has a self-referential type, pass it to a
- WITH_RECORD_EXPR; if the component size is, pass our
- component to one. */
- if (CONTAINS_PLACEHOLDER_P (index))
- index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, t);
- if (CONTAINS_PLACEHOLDER_P (unit_size))
- unit_size = build (WITH_RECORD_EXPR, sizetype,
- unit_size, array);
-
- off_tree
- = fold (build (PLUS_EXPR, sizetype,
- fold (build (MULT_EXPR, sizetype,
- index,
- unit_size)),
- off_tree));
- t = TREE_OPERAND (t, 0);
+ index, then convert to sizetype and multiply by the size of
+ the array element. */
+ if (! integer_zerop (low_bound))
+ index = fold (build2 (MINUS_EXPR, TREE_TYPE (index),
+ index, low_bound));
+
+ off_tree = size_binop (PLUS_EXPR,
+ size_binop (MULT_EXPR, convert (sizetype,
+ index),
+ unit_size),
+ off_tree);
+ t2 = TREE_OPERAND (t2, 0);
}
- while (TREE_CODE (t) == ARRAY_REF);
+ while (TREE_CODE (t2) == ARRAY_REF);
- if (DECL_P (t))
+ if (DECL_P (t2))
{
- expr = t;
+ expr = t2;
offset = NULL;
if (host_integerp (off_tree, 1))
{
HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;
- align = DECL_ALIGN (t);
+ align = DECL_ALIGN (t2);
if (aoff && (unsigned HOST_WIDE_INT) aoff < align)
align = aoff;
offset = GEN_INT (ioff);
apply_bitpos = bitpos;
}
}
- else if (TREE_CODE (t) == COMPONENT_REF)
+ else if (TREE_CODE (t2) == COMPONENT_REF)
{
- expr = component_ref_for_mem_expr (t);
+ expr = component_ref_for_mem_expr (t2);
if (host_integerp (off_tree, 1))
{
offset = GEN_INT (tree_low_cst (off_tree, 1));
the size we got from the type? */
}
else if (flag_argument_noalias > 1
- && TREE_CODE (t) == INDIRECT_REF
- && TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL)
+ && TREE_CODE (t2) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL)
{
- expr = t;
+ expr = t2;
offset = NULL;
}
}
}
void
-set_mem_attributes (ref, t, objectp)
- rtx ref;
- tree t;
- int objectp;
+set_mem_attributes (rtx ref, tree t, int objectp)
{
set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
}
/* Set the decl for MEM to DECL. */
void
-set_mem_attrs_from_reg (mem, reg)
- rtx mem;
- rtx reg;
+set_mem_attrs_from_reg (rtx mem, rtx reg)
{
MEM_ATTRS (mem)
= get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg),
/* Set the alias set of MEM to SET. */
void
-set_mem_alias_set (mem, set)
- rtx mem;
- HOST_WIDE_INT set;
+set_mem_alias_set (rtx mem, HOST_WIDE_INT set)
{
#ifdef ENABLE_CHECKING
/* If the new and old alias sets don't conflict, something is wrong. */
/* Set the alignment of MEM to ALIGN bits. */
void
-set_mem_align (mem, align)
- rtx mem;
- unsigned int align;
+set_mem_align (rtx mem, unsigned int align)
{
MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
MEM_OFFSET (mem), MEM_SIZE (mem), align,
/* Set the expr for MEM to EXPR. */
void
-set_mem_expr (mem, expr)
- rtx mem;
- tree expr;
+set_mem_expr (rtx mem, tree expr)
{
MEM_ATTRS (mem)
= get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem),
/* Set the offset of MEM to OFFSET. */
void
-set_mem_offset (mem, offset)
- rtx mem, offset;
+set_mem_offset (rtx mem, rtx offset)
{
MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
offset, MEM_SIZE (mem), MEM_ALIGN (mem),
/* Set the size of MEM to SIZE. */
void
-set_mem_size (mem, size)
- rtx mem, size;
+set_mem_size (rtx mem, rtx size)
{
MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
MEM_OFFSET (mem), size, MEM_ALIGN (mem),
attributes are not changed. */
static rtx
-change_address_1 (memref, mode, addr, validate)
- rtx memref;
- enum machine_mode mode;
- rtx addr;
- int validate;
+change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
{
rtx new;
- if (GET_CODE (memref) != MEM)
+ if (!MEM_P (memref))
abort ();
if (mode == VOIDmode)
mode = GET_MODE (memref);
if (addr == 0)
addr = XEXP (memref, 0);
+ if (mode == GET_MODE (memref) && addr == XEXP (memref, 0)
+ && (!validate || memory_address_p (mode, addr)))
+ return memref;
if (validate)
{
way we are changing MEMREF, so we only preserve the alias set. */
rtx
-change_address (memref, mode, addr)
- rtx memref;
- enum machine_mode mode;
- rtx addr;
+change_address (rtx memref, enum machine_mode mode, rtx addr)
{
- rtx new = change_address_1 (memref, mode, addr, 1);
+ rtx new = change_address_1 (memref, mode, addr, 1), size;
enum machine_mode mmode = GET_MODE (new);
+ unsigned int align;
+
+ size = mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode));
+ align = mmode == BLKmode ? BITS_PER_UNIT : GET_MODE_ALIGNMENT (mmode);
+
+ /* If there are no changes, just return the original memory reference. */
+ if (new == memref)
+ {
+ if (MEM_ATTRS (memref) == 0
+ || (MEM_EXPR (memref) == NULL
+ && MEM_OFFSET (memref) == NULL
+ && MEM_SIZE (memref) == size
+ && MEM_ALIGN (memref) == align))
+ return new;
+
+ new = gen_rtx_MEM (mmode, XEXP (memref, 0));
+ MEM_COPY_ATTRIBUTES (new, memref);
+ }
MEM_ATTRS (new)
- = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0,
- mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)),
- (mmode == BLKmode ? BITS_PER_UNIT
- : GET_MODE_ALIGNMENT (mmode)),
- mmode);
+ = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode);
return new;
}
and caller is responsible for adjusting MEMREF base register. */
rtx
-adjust_address_1 (memref, mode, offset, validate, adjust)
- rtx memref;
- enum machine_mode mode;
- HOST_WIDE_INT offset;
- int validate, adjust;
+adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
+ int validate, int adjust)
{
rtx addr = XEXP (memref, 0);
rtx new;
rtx size = 0;
unsigned int memalign = MEM_ALIGN (memref);
+ /* If there are no changes, just return the original memory reference. */
+ if (mode == GET_MODE (memref) && !offset
+ && (!validate || memory_address_p (mode, addr)))
+ return memref;
+
/* ??? Prefer to create garbage instead of creating shared rtl.
This may happen even if offset is nonzero -- consider
(plus (plus reg reg) const_int) -- so do this always. */
nonzero, the memory address is forced to be valid. */
rtx
-adjust_automodify_address_1 (memref, mode, addr, offset, validate)
- rtx memref;
- enum machine_mode mode;
- rtx addr;
- HOST_WIDE_INT offset;
- int validate;
+adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr,
+ HOST_WIDE_INT offset, int validate)
{
memref = change_address_1 (memref, VOIDmode, addr, validate);
return adjust_address_1 (memref, mode, offset, validate, 0);
known to be in OFFSET (possibly 1). */
rtx
-offset_address (memref, offset, pow2)
- rtx memref;
- rtx offset;
- unsigned HOST_WIDE_INT pow2;
+offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
{
rtx new, addr = XEXP (memref, 0);
new = simplify_gen_binary (PLUS, Pmode, addr, offset);
/* At this point we don't know _why_ the address is invalid. It
- could have secondary memory refereces, multiplies or anything.
+ could have secondary memory references, multiplies or anything.
However, if we did go and rearrange things, we can wind up not
being able to recognize the magic around pic_offset_table_rtx.
update_temp_slot_address (XEXP (memref, 0), new);
new = change_address_1 (memref, VOIDmode, new, 1);
+ /* If there are no changes, just return the original memory reference. */
+ if (new == memref)
+ return new;
+
/* Update the alignment to reflect the offset. Reset the offset, which
we don't know. */
MEM_ATTRS (new)
by putting something into a register. */
rtx
-replace_equiv_address (memref, addr)
- rtx memref;
- rtx addr;
+replace_equiv_address (rtx memref, rtx addr)
{
/* change_address_1 copies the memory attribute structure without change
and that's exactly what we want here. */
/* Likewise, but the reference is not required to be valid. */
rtx
-replace_equiv_address_nv (memref, addr)
- rtx memref;
- rtx addr;
+replace_equiv_address_nv (rtx memref, rtx addr)
{
return change_address_1 (memref, VOIDmode, addr, 0);
}
operations plus masking logic. */
rtx
-widen_memory_access (memref, mode, offset)
- rtx memref;
- enum machine_mode mode;
- HOST_WIDE_INT offset;
+widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
{
rtx new = adjust_address_1 (memref, mode, offset, 1, 1);
tree expr = MEM_EXPR (new);
rtx memoffset = MEM_OFFSET (new);
unsigned int size = GET_MODE_SIZE (mode);
+ /* If there are no changes, just return the original memory reference. */
+ if (new == memref)
+ return new;
+
/* If we don't know what offset we were at within the expression, then
we can't know if we've overstepped the bounds. */
if (! memoffset)
if (TREE_CODE (expr) == COMPONENT_REF)
{
tree field = TREE_OPERAND (expr, 1);
+ tree offset = component_ref_field_offset (expr);
if (! DECL_SIZE_UNIT (field))
{
&& INTVAL (memoffset) >= 0)
break;
- if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+ if (! host_integerp (offset, 1))
{
expr = NULL_TREE;
break;
}
expr = TREE_OPERAND (expr, 0);
- memoffset = (GEN_INT (INTVAL (memoffset)
- + tree_low_cst (DECL_FIELD_OFFSET (field), 1)
- + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
- / BITS_PER_UNIT)));
+ memoffset
+ = (GEN_INT (INTVAL (memoffset)
+ + tree_low_cst (offset, 1)
+ + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+ / BITS_PER_UNIT)));
}
/* Similarly for the decl. */
else if (DECL_P (expr)
/* Return a newly created CODE_LABEL rtx with a unique label number. */
rtx
-gen_label_rtx ()
+gen_label_rtx (void)
{
return gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, NULL_RTX,
- NULL, label_num++, NULL);
+ 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 (first, last)
- rtx first, last;
+set_new_first_and_last_insn (rtx first, rtx last)
{
rtx insn;
cur_insn_uid++;
}
-/* Set the range of label numbers found in the current function.
+/* Set the last label number found in the current function.
This is used when belatedly compiling an inline function. */
void
-set_new_first_and_last_label_num (first, last)
- int first, last;
+set_new_last_label_num (int last)
{
base_label_num = label_num;
- first_label_num = first;
last_label_num = last;
}
-
-/* Set the last label number found in the current function.
- This is used when belatedly compiling an inline function. */
+\f
+/* Restore all variables describing the current status from the structure *P.
+ This is used after a nested function. */
void
-set_new_last_label_num (last)
- int last;
+restore_emit_status (struct function *p ATTRIBUTE_UNUSED)
{
- base_label_num = label_num;
- last_label_num = last;
+ last_label_num = 0;
}
\f
-/* Restore all variables describing the current status from the structure *P.
- This is used after a nested function. */
+/* Go through all the RTL insn bodies and copy any invalid shared
+ structure. This routine should only be called once. */
+
+static void
+unshare_all_rtl_1 (tree fndecl, rtx insn)
+{
+ tree decl;
+
+ /* Make sure that virtual parameters are not shared. */
+ for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+ SET_DECL_RTL (decl, copy_rtx_if_shared (DECL_RTL (decl)));
+
+ /* Make sure that virtual stack slots are not shared. */
+ unshare_all_decls (DECL_INITIAL (fndecl));
+
+ /* Unshare just about everything else. */
+ unshare_all_rtl_in_chain (insn);
+
+ /* Make sure the addresses of stack slots found outside the insn chain
+ (such as, in DECL_RTL of a variable) are not shared
+ with the insn chain.
+
+ 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);
+}
+
+/* Go through all the RTL insn bodies and copy any invalid shared
+ structure, again. This is a fairly expensive thing to do so it
+ should be done sparingly. */
+
+void
+unshare_all_rtl_again (rtx insn)
+{
+ rtx p;
+ tree decl;
+
+ for (p = insn; p; p = NEXT_INSN (p))
+ if (INSN_P (p))
+ {
+ reset_used_flags (PATTERN (p));
+ reset_used_flags (REG_NOTES (p));
+ reset_used_flags (LOG_LINKS (p));
+ }
+
+ /* Make sure that virtual stack slots are not shared. */
+ reset_used_decls (DECL_INITIAL (cfun->decl));
+
+ /* Make sure that virtual parameters are not shared. */
+ for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = TREE_CHAIN (decl))
+ reset_used_flags (DECL_RTL (decl));
+
+ reset_used_flags (stack_slot_list);
+
+ unshare_all_rtl_1 (cfun->decl, insn);
+}
+
+void
+unshare_all_rtl (void)
+{
+ unshare_all_rtl_1 (current_function_decl, get_insns ());
+}
+
+/* Check that ORIG is not marked when it should not be and mark ORIG as in use,
+ Recursively does the same for subexpressions. */
+
+static void
+verify_rtx_sharing (rtx orig, rtx insn)
+{
+ rtx x = orig;
+ int i;
+ enum rtx_code code;
+ const char *format_ptr;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ /* These types may be freely shared. */
+
+ switch (code)
+ {
+ case REG:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case SCRATCH:
+ return;
+ /* SCRATCH must be shared because they represent distinct values. */
+ case CLOBBER:
+ if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+ return;
+ break;
+
+ case CONST:
+ /* CONST can be shared if it contains a SYMBOL_REF. If it contains
+ a LABEL_REF, it isn't sharable. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+ return;
+ break;
+
+ case MEM:
+ /* A MEM is allowed to be shared if its address is constant. */
+ if (CONSTANT_ADDRESS_P (XEXP (x, 0))
+ || reload_completed || reload_in_progress)
+ return;
+
+ break;
+
+ default:
+ break;
+ }
-void
-restore_emit_status (p)
- struct function *p ATTRIBUTE_UNUSED;
-{
- last_label_num = 0;
-}
-\f
-/* Go through all the RTL insn bodies and copy any invalid shared
- structure. This routine should only be called once. */
+ /* This rtx may not be shared. If it has already been seen,
+ replace it with a copy of itself. */
-void
-unshare_all_rtl (fndecl, insn)
- tree fndecl;
- rtx insn;
-{
- tree decl;
+ if (RTX_FLAG (x, used))
+ {
+ error ("Invalid rtl sharing found in the insn");
+ debug_rtx (insn);
+ error ("Shared rtx");
+ debug_rtx (x);
+ abort ();
+ }
+ RTX_FLAG (x, used) = 1;
- /* Make sure that virtual parameters are not shared. */
- for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
- SET_DECL_RTL (decl, copy_rtx_if_shared (DECL_RTL (decl)));
+ /* Now scan the subexpressions recursively. */
- /* Make sure that virtual stack slots are not shared. */
- unshare_all_decls (DECL_INITIAL (fndecl));
+ format_ptr = GET_RTX_FORMAT (code);
- /* Unshare just about everything else. */
- unshare_all_rtl_1 (insn);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ verify_rtx_sharing (XEXP (x, i), insn);
+ break;
- /* Make sure the addresses of stack slots found outside the insn chain
- (such as, in DECL_RTL of a variable) are not shared
- with the insn chain.
+ case 'E':
+ if (XVEC (x, i) != NULL)
+ {
+ int j;
+ int len = XVECLEN (x, i);
- 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);
+ for (j = 0; j < len; j++)
+ {
+ /* We allow sharing of ASM_OPERANDS inside single instruction. */
+ if (j && GET_CODE (XVECEXP (x, i, j)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (x, i, j))) == ASM_OPERANDS)
+ verify_rtx_sharing (SET_DEST (XVECEXP (x, i, j)), insn);
+ else
+ verify_rtx_sharing (XVECEXP (x, i, j), insn);
+ }
+ }
+ break;
+ }
+ }
+ return;
}
-/* Go through all the RTL insn bodies and copy any invalid shared
- structure, again. This is a fairly expensive thing to do so it
- should be done sparingly. */
+/* Go through all the RTL insn bodies and check that there is no unexpected
+ sharing in between the subexpressions. */
void
-unshare_all_rtl_again (insn)
- rtx insn;
+verify_rtl_sharing (void)
{
rtx p;
- tree decl;
- for (p = insn; p; p = NEXT_INSN (p))
+ for (p = get_insns (); p; p = NEXT_INSN (p))
if (INSN_P (p))
{
reset_used_flags (PATTERN (p));
reset_used_flags (LOG_LINKS (p));
}
- /* Make sure that virtual stack slots are not shared. */
- reset_used_decls (DECL_INITIAL (cfun->decl));
-
- /* Make sure that virtual parameters are not shared. */
- for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = TREE_CHAIN (decl))
- reset_used_flags (DECL_RTL (decl));
-
- reset_used_flags (stack_slot_list);
-
- unshare_all_rtl (cfun->decl, insn);
+ for (p = get_insns (); p; p = NEXT_INSN (p))
+ if (INSN_P (p))
+ {
+ verify_rtx_sharing (PATTERN (p), p);
+ verify_rtx_sharing (REG_NOTES (p), p);
+ verify_rtx_sharing (LOG_LINKS (p), p);
+ }
}
/* Go through all the RTL insn bodies and copy any invalid shared structure.
Assumes the mark bits are cleared at entry. */
-static void
-unshare_all_rtl_1 (insn)
- rtx insn;
+void
+unshare_all_rtl_in_chain (rtx insn)
{
for (; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
/* Go through all virtual stack slots of a function and copy any
shared structure. */
static void
-unshare_all_decls (blk)
- tree blk;
+unshare_all_decls (tree blk)
{
tree t;
/* Go through all virtual stack slots of a function and mark them as
not shared. */
static void
-reset_used_decls (blk)
- tree blk;
+reset_used_decls (tree blk)
{
tree t;
either a MEM of an EXPR_LIST of MEMs. */
rtx
-copy_most_rtx (orig, may_share)
- rtx orig;
- rtx may_share;
+copy_most_rtx (rtx orig, rtx may_share)
{
rtx copy;
int i, j;
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct);
RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil);
RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging);
- RTX_FLAG (copy, integrated) = RTX_FLAG (orig, integrated);
RTX_FLAG (copy, frame_related) = RTX_FLAG (orig, frame_related);
+ RTX_FLAG (copy, return_val) = RTX_FLAG (orig, return_val);
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
break;
case '0':
- /* Copy this through the wide int field; that's safest. */
- X0WINT (copy, i) = X0WINT (orig, i);
+ X0ANY (copy, i) = X0ANY (orig, i);
break;
default:
}
/* Mark ORIG as in use, and return a copy of it if it was already in use.
- Recursively does the same for subexpressions. */
+ Recursively does the same for subexpressions. Uses
+ copy_rtx_if_shared_1 to reduce stack space. */
rtx
-copy_rtx_if_shared (orig)
- rtx orig;
+copy_rtx_if_shared (rtx orig)
{
- rtx x = orig;
+ copy_rtx_if_shared_1 (&orig);
+ return orig;
+}
+
+/* Mark *ORIG1 as in use, and set it to a copy of it if it was already in
+ use. Recursively does the same for subexpressions. */
+
+static void
+copy_rtx_if_shared_1 (rtx *orig1)
+{
+ rtx x;
int i;
enum rtx_code code;
+ rtx *last_ptr;
const char *format_ptr;
int copied = 0;
+ int length;
+
+ /* Repeat is used to turn tail-recursion into iteration. */
+repeat:
+ x = *orig1;
if (x == 0)
- return 0;
+ return;
code = GET_CODE (x);
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
+ case LABEL_REF:
case CODE_LABEL:
case PC:
case CC0:
case SCRATCH:
/* SCRATCH must be shared because they represent distinct values. */
- return x;
+ return;
+ case CLOBBER:
+ if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+ return;
+ break;
case CONST:
/* CONST can be shared if it contains a SYMBOL_REF. If it contains
if (GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
- return x;
+ return;
break;
case INSN:
case NOTE:
case BARRIER:
/* The chain of insns is not being copied. */
- return x;
-
- case MEM:
- /* A MEM is allowed to be shared if its address is constant.
-
- We used to allow sharing of MEMs which referenced
- virtual_stack_vars_rtx or virtual_incoming_args_rtx, but
- that can lose. instantiate_virtual_regs will not unshare
- the MEMs, and combine may change the structure of the address
- because it looks safe and profitable in one context, but
- in some other context it creates unrecognizable RTL. */
- if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
- return x;
-
- break;
+ return;
default:
break;
rtx copy;
copy = rtx_alloc (code);
- memcpy (copy, x,
- (sizeof (*copy) - sizeof (copy->fld)
- + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
+ memcpy (copy, x, RTX_SIZE (code));
x = copy;
copied = 1;
}
must be copied if X was copied. */
format_ptr = GET_RTX_FORMAT (code);
-
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ length = GET_RTX_LENGTH (code);
+ last_ptr = NULL;
+
+ for (i = 0; i < length; i++)
{
switch (*format_ptr++)
{
case 'e':
- XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i));
+ if (last_ptr)
+ copy_rtx_if_shared_1 (last_ptr);
+ last_ptr = &XEXP (x, i);
break;
case 'E':
{
int j;
int len = XVECLEN (x, i);
-
+
+ /* Copy the vector iff I copied the rtx and the length
+ is nonzero. */
if (copied && len > 0)
XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem);
+
+ /* Call recursively on all inside the vector. */
for (j = 0; j < len; j++)
- XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
+ {
+ if (last_ptr)
+ copy_rtx_if_shared_1 (last_ptr);
+ last_ptr = &XVECEXP (x, i, j);
+ }
}
break;
}
}
- return x;
+ *orig1 = x;
+ if (last_ptr)
+ {
+ orig1 = last_ptr;
+ goto repeat;
+ }
+ return;
}
/* Clear all the USED bits in X to allow copy_rtx_if_shared to be used
to look for shared sub-parts. */
void
-reset_used_flags (x)
- rtx x;
+reset_used_flags (rtx x)
{
int i, j;
enum rtx_code code;
const char *format_ptr;
+ int length;
+ /* Repeat is used to turn tail-recursion into iteration. */
+repeat:
if (x == 0)
return;
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
RTX_FLAG (x, used) = 0;
format_ptr = GET_RTX_FORMAT (code);
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ length = GET_RTX_LENGTH (code);
+
+ for (i = 0; i < length; i++)
{
switch (*format_ptr++)
{
case 'e':
+ if (i == length-1)
+ {
+ x = XEXP (x, i);
+ goto repeat;
+ }
reset_used_flags (XEXP (x, i));
break;
}
}
}
+
+/* Set all the USED bits in X to allow copy_rtx_if_shared to be used
+ to look for shared sub-parts. */
+
+void
+set_used_flags (rtx x)
+{
+ int i, j;
+ enum rtx_code code;
+ const char *format_ptr;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ /* These types may be freely shared so we needn't do any resetting
+ for them. */
+
+ switch (code)
+ {
+ case REG:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ return;
+
+ case INSN:
+ case JUMP_INSN:
+ case CALL_INSN:
+ case NOTE:
+ case LABEL_REF:
+ case BARRIER:
+ /* The chain of insns is not being copied. */
+ return;
+
+ default:
+ break;
+ }
+
+ RTX_FLAG (x, used) = 1;
+
+ format_ptr = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ set_used_flags (XEXP (x, i));
+ break;
+
+ case 'E':
+ for (j = 0; j < XVECLEN (x, i); j++)
+ set_used_flags (XVECEXP (x, i, j));
+ break;
+ }
+ }
+}
\f
/* Copy X if necessary so that it won't be altered by changes in OTHER.
Return X or the rtx for the pseudo reg the value of X was copied into.
OTHER must be valid as a SET_DEST. */
rtx
-make_safe_from (x, other)
- rtx x, other;
+make_safe_from (rtx x, rtx other)
{
while (1)
switch (GET_CODE (other))
goto done;
}
done:
- if ((GET_CODE (other) == MEM
+ if ((MEM_P (other)
&& ! CONSTANT_P (x)
- && GET_CODE (x) != REG
+ && !REG_P (x)
&& GET_CODE (x) != SUBREG)
- || (GET_CODE (other) == REG
+ || (REG_P (other)
&& (REGNO (other) < FIRST_PSEUDO_REGISTER
|| reg_mentioned_p (other, x))))
{
/* Return the first insn of the current sequence or current function. */
rtx
-get_insns ()
+get_insns (void)
{
return first_insn;
}
/* Specify a new insn as the first in the chain. */
void
-set_first_insn (insn)
- rtx insn;
+set_first_insn (rtx insn)
{
if (PREV_INSN (insn) != 0)
abort ();
/* Return the last insn emitted in current sequence or current function. */
rtx
-get_last_insn ()
+get_last_insn (void)
{
return last_insn;
}
/* Specify a new insn as the last in the chain. */
void
-set_last_insn (insn)
- rtx insn;
+set_last_insn (rtx insn)
{
if (NEXT_INSN (insn) != 0)
abort ();
/* Return the last insn emitted, even if it is in a sequence now pushed. */
rtx
-get_last_insn_anywhere ()
+get_last_insn_anywhere (void)
{
struct sequence_stack *stack;
if (last_insn)
function. This routine looks inside SEQUENCEs. */
rtx
-get_first_nonnote_insn ()
+get_first_nonnote_insn (void)
{
rtx insn = first_insn;
while (insn)
{
insn = next_insn (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
function. This routine looks inside SEQUENCEs. */
rtx
-get_last_nonnote_insn ()
+get_last_nonnote_insn (void)
{
rtx insn = last_insn;
while (insn)
{
insn = previous_insn (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
/* Return a number larger than any instruction's uid in this function. */
int
-get_max_uid ()
+get_max_uid (void)
{
return cur_insn_uid;
}
/* Renumber instructions so that no instruction UIDs are wasted. */
void
-renumber_insns (stream)
- FILE *stream;
+renumber_insns (FILE *stream)
{
rtx insn;
of the sequence. */
rtx
-next_insn (insn)
- rtx insn;
+next_insn (rtx insn)
{
if (insn)
{
insn = NEXT_INSN (insn);
- if (insn && GET_CODE (insn) == INSN
+ if (insn && NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
}
of the sequence. */
rtx
-previous_insn (insn)
- rtx insn;
+previous_insn (rtx insn)
{
if (insn)
{
insn = PREV_INSN (insn);
- if (insn && GET_CODE (insn) == INSN
+ if (insn && NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1);
}
look inside SEQUENCEs. */
rtx
-next_nonnote_insn (insn)
- rtx insn;
+next_nonnote_insn (rtx insn)
{
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
not look inside SEQUENCEs. */
rtx
-prev_nonnote_insn (insn)
- rtx insn;
+prev_nonnote_insn (rtx insn)
{
while (insn)
{
insn = PREV_INSN (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
SEQUENCEs. */
rtx
-next_real_insn (insn)
- rtx insn;
+next_real_insn (rtx insn)
{
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || GET_CODE (insn) == INSN
- || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+ if (insn == 0 || INSN_P (insn))
break;
}
SEQUENCEs. */
rtx
-prev_real_insn (insn)
- rtx insn;
+prev_real_insn (rtx insn)
{
while (insn)
{
insn = PREV_INSN (insn);
- if (insn == 0 || GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
- || GET_CODE (insn) == JUMP_INSN)
+ if (insn == 0 || INSN_P (insn))
break;
}
This routine does not look inside SEQUENCEs. */
rtx
-last_call_insn ()
+last_call_insn (void)
{
rtx insn;
for (insn = get_last_insn ();
- insn && GET_CODE (insn) != CALL_INSN;
+ insn && !CALL_P (insn);
insn = PREV_INSN (insn))
;
same as next_real_insn. */
int
-active_insn_p (insn)
- rtx insn;
+active_insn_p (rtx insn)
{
- return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
- || (GET_CODE (insn) == INSN
+ return (CALL_P (insn) || JUMP_P (insn)
+ || (NONJUMP_INSN_P (insn)
&& (! reload_completed
|| (GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER))));
}
rtx
-next_active_insn (insn)
- rtx insn;
+next_active_insn (rtx insn)
{
while (insn)
{
same as prev_real_insn. */
rtx
-prev_active_insn (insn)
- rtx insn;
+prev_active_insn (rtx insn)
{
while (insn)
{
/* Return the next CODE_LABEL after the insn INSN, or 0 if there is none. */
rtx
-next_label (insn)
- rtx insn;
+next_label (rtx insn)
{
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
+ if (insn == 0 || LABEL_P (insn))
break;
}
/* Return the last CODE_LABEL before the insn INSN, or 0 if there is none. */
rtx
-prev_label (insn)
- rtx insn;
+prev_label (rtx insn)
{
while (insn)
{
insn = PREV_INSN (insn);
- if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
+ if (insn == 0 || LABEL_P (insn))
break;
}
return insn;
}
+
+/* Return the last label to mark the same position as LABEL. Return null
+ if LABEL itself is null. */
+
+rtx
+skip_consecutive_labels (rtx label)
+{
+ rtx insn;
+
+ for (insn = label; insn != 0 && !INSN_P (insn); insn = NEXT_INSN (insn))
+ if (LABEL_P (insn))
+ label = insn;
+
+ return label;
+}
\f
#ifdef HAVE_cc0
/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER
and REG_CC_USER notes so we can find it. */
void
-link_cc0_insns (insn)
- rtx insn;
+link_cc0_insns (rtx insn)
{
rtx user = next_nonnote_insn (insn);
- if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
+ if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn,
Return 0 if we can't find the insn. */
rtx
-next_cc0_user (insn)
- rtx insn;
+next_cc0_user (rtx insn)
{
rtx note = find_reg_note (insn, REG_CC_USER, NULL_RTX);
return XEXP (note, 0);
insn = next_nonnote_insn (insn);
- if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
note, it is the previous insn. */
rtx
-prev_cc0_setter (insn)
- rtx insn;
+prev_cc0_setter (rtx insn)
{
rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
/* Increment the label uses for all labels present in rtx. */
static void
-mark_label_nuses (x)
- rtx x;
+mark_label_nuses (rtx x)
{
enum rtx_code code;
int i, j;
const char *fmt;
code = GET_CODE (x);
- if (code == LABEL_REF)
+ if (code == LABEL_REF && LABEL_P (XEXP (x, 0)))
LABEL_NUSES (XEXP (x, 0))++;
fmt = GET_RTX_FORMAT (code);
returns TRIAL. If the insn to be returned can be split, it will be. */
rtx
-try_split (pat, trial, last)
- rtx pat, trial;
- int last;
+try_split (rtx pat, rtx trial, int last)
{
rtx before = PREV_INSN (trial);
rtx after = NEXT_INSN (trial);
/* If we are splitting a JUMP_INSN, it might be followed by a BARRIER.
We may need to handle this specially. */
- if (after && GET_CODE (after) == BARRIER)
+ if (after && BARRIER_P (after))
{
has_barrier = 1;
after = NEXT_INSN (after);
/* Mark labels. */
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
{
- if (GET_CODE (insn) == JUMP_INSN)
+ if (JUMP_P (insn))
{
mark_jump_label (PATTERN (insn), insn, 0);
njumps++;
/* If we are splitting a CALL_INSN, look for the CALL_INSN
in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it. */
- if (GET_CODE (trial) == CALL_INSN)
+ if (CALL_P (trial))
{
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
- CALL_INSN_FUNCTION_USAGE (insn)
- = CALL_INSN_FUNCTION_USAGE (trial);
+ rtx *p = &CALL_INSN_FUNCTION_USAGE (insn);
+ while (*p)
+ p = &XEXP (*p, 1);
+ *p = CALL_INSN_FUNCTION_USAGE (trial);
SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial);
}
}
insn = insn_last;
while (insn != NULL_RTX)
{
- if (GET_CODE (insn) == CALL_INSN
- || (flag_non_call_exceptions
+ if (CALL_P (insn)
+ || (flag_non_call_exceptions && INSN_P (insn)
&& may_trap_p (PATTERN (insn))))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_EH_REGION,
insn = insn_last;
while (insn != NULL_RTX)
{
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
insn = insn_last;
while (insn != NULL_RTX)
{
- if (GET_CODE (insn) == JUMP_INSN)
+ if (JUMP_P (insn))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
/* If there are LABELS inside the split insns increment the
usage count so we don't delete the label. */
- if (GET_CODE (trial) == INSN)
+ if (NONJUMP_INSN_P (trial))
{
insn = insn_last;
while (insn != NULL_RTX)
{
- if (GET_CODE (insn) == INSN)
+ if (NONJUMP_INSN_P (insn))
mark_label_nuses (PATTERN (insn));
insn = PREV_INSN (insn);
Store PATTERN in the pattern slots. */
rtx
-make_insn_raw (pattern)
- rtx pattern;
+make_insn_raw (rtx pattern)
{
rtx insn;
/* Like `make_insn_raw' but make a JUMP_INSN instead of an insn. */
static rtx
-make_jump_insn_raw (pattern)
- rtx pattern;
+make_jump_insn_raw (rtx pattern)
{
rtx insn;
/* Like `make_insn_raw' but make a CALL_INSN instead of an insn. */
static rtx
-make_call_insn_raw (pattern)
- rtx pattern;
+make_call_insn_raw (rtx pattern)
{
rtx insn;
INSN may be an INSN, JUMP_INSN, CALL_INSN, CODE_LABEL, BARRIER or NOTE. */
void
-add_insn (insn)
- rtx insn;
+add_insn (rtx insn)
{
PREV_INSN (insn) = last_insn;
NEXT_INSN (insn) = 0;
SEQUENCE. */
void
-add_insn_after (insn, after)
- rtx insn, after;
+add_insn_after (rtx insn, rtx after)
{
rtx next = NEXT_INSN (after);
basic_block bb;
if (next)
{
PREV_INSN (next) = insn;
- if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
+ if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn;
}
else if (last_insn == after)
abort ();
}
- if (GET_CODE (after) != BARRIER
- && GET_CODE (insn) != BARRIER
+ if (!BARRIER_P (after)
+ && !BARRIER_P (insn)
&& (bb = BLOCK_FOR_INSN (after)))
{
set_block_for_insn (insn, bb);
bb->flags |= BB_DIRTY;
/* Should not happen as first in the BB is always
either NOTE or LABEL. */
- if (bb->end == after
+ if (BB_END (bb) == after
/* Avoid clobbering of structure when creating new BB. */
- && GET_CODE (insn) != BARRIER
- && (GET_CODE (insn) != NOTE
+ && !BARRIER_P (insn)
+ && (!NOTE_P (insn)
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
- bb->end = insn;
+ BB_END (bb) = insn;
}
NEXT_INSN (after) = insn;
- if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE)
+ if (NONJUMP_INSN_P (after) && GET_CODE (PATTERN (after)) == SEQUENCE)
{
rtx sequence = PATTERN (after);
NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
SEQUENCE. */
void
-add_insn_before (insn, before)
- rtx insn, before;
+add_insn_before (rtx insn, rtx before)
{
rtx prev = PREV_INSN (before);
basic_block bb;
if (prev)
{
NEXT_INSN (prev) = insn;
- if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+ if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
{
rtx sequence = PATTERN (prev);
NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
abort ();
}
- if (GET_CODE (before) != BARRIER
- && GET_CODE (insn) != BARRIER
+ if (!BARRIER_P (before)
+ && !BARRIER_P (insn)
&& (bb = BLOCK_FOR_INSN (before)))
{
set_block_for_insn (insn, bb);
bb->flags |= BB_DIRTY;
/* Should not happen as first in the BB is always
either NOTE or LABEl. */
- if (bb->head == insn
+ if (BB_HEAD (bb) == insn
/* Avoid clobbering of structure when creating new BB. */
- && GET_CODE (insn) != BARRIER
- && (GET_CODE (insn) != NOTE
+ && !BARRIER_P (insn)
+ && (!NOTE_P (insn)
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
abort ();
}
PREV_INSN (before) = insn;
- if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE)
+ if (NONJUMP_INSN_P (before) && GET_CODE (PATTERN (before)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
}
/* Remove an insn from its doubly-linked list. This function knows how
to handle sequences. */
void
-remove_insn (insn)
- rtx insn;
+remove_insn (rtx insn)
{
rtx next = NEXT_INSN (insn);
rtx prev = PREV_INSN (insn);
if (prev)
{
NEXT_INSN (prev) = next;
- if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+ if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
{
rtx sequence = PATTERN (prev);
NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next;
if (next)
{
PREV_INSN (next) = prev;
- if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
+ if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
}
else if (last_insn == insn)
if (stack == 0)
abort ();
}
- if (GET_CODE (insn) != BARRIER
+ if (!BARRIER_P (insn)
&& (bb = BLOCK_FOR_INSN (insn)))
{
if (INSN_P (insn))
bb->flags |= BB_DIRTY;
- if (bb->head == insn)
+ if (BB_HEAD (bb) == insn)
{
/* Never ever delete the basic block note without deleting whole
basic block. */
- if (GET_CODE (insn) == NOTE)
+ if (NOTE_P (insn))
abort ();
- bb->head = next;
+ BB_HEAD (bb) = next;
}
- if (bb->end == insn)
- bb->end = prev;
+ if (BB_END (bb) == insn)
+ BB_END (bb) = prev;
}
}
/* Append CALL_FUSAGE to the CALL_INSN_FUNCTION_USAGE for CALL_INSN. */
void
-add_function_usage_to (call_insn, call_fusage)
- rtx call_insn, call_fusage;
+add_function_usage_to (rtx call_insn, rtx call_fusage)
{
- if (! call_insn || GET_CODE (call_insn) != CALL_INSN)
+ if (! call_insn || !CALL_P (call_insn))
abort ();
/* Put the register usage information on the CALL. If there is already
FROM becomes the new last instruction. */
void
-delete_insns_since (from)
- rtx from;
+delete_insns_since (rtx from)
{
if (from == 0)
first_insn = 0;
called after delay-slot filling has been done. */
void
-reorder_insns_nobb (from, to, after)
- rtx from, to, after;
+reorder_insns_nobb (rtx from, rtx to, rtx after)
{
/* Splice this bunch out of where it is now. */
if (PREV_INSN (from))
/* Same as function above, but take care to update BB boundaries. */
void
-reorder_insns (from, to, after)
- rtx from, to, after;
+reorder_insns (rtx from, rtx to, rtx after)
{
rtx prev = PREV_INSN (from);
basic_block bb, bb2;
reorder_insns_nobb (from, to, after);
- if (GET_CODE (after) != BARRIER
+ if (!BARRIER_P (after)
&& (bb = BLOCK_FOR_INSN (after)))
{
rtx x;
bb->flags |= BB_DIRTY;
- if (GET_CODE (from) != BARRIER
+ if (!BARRIER_P (from)
&& (bb2 = BLOCK_FOR_INSN (from)))
{
- if (bb2->end == to)
- bb2->end = prev;
+ if (BB_END (bb2) == to)
+ BB_END (bb2) = prev;
bb2->flags |= BB_DIRTY;
}
- if (bb->end == after)
- bb->end = to;
+ if (BB_END (bb) == after)
+ BB_END (bb) = to;
for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x))
- set_block_for_insn (x, bb);
+ if (!BARRIER_P (x))
+ set_block_for_insn (x, bb);
}
}
/* Return the line note insn preceding INSN. */
static rtx
-find_line_note (insn)
- rtx insn;
+find_line_note (rtx insn)
{
if (no_line_numbers)
return 0;
for (; insn; insn = PREV_INSN (insn))
- if (GET_CODE (insn) == NOTE
+ if (NOTE_P (insn)
&& NOTE_LINE_NUMBER (insn) >= 0)
break;
return insn;
}
-/* Like reorder_insns, but inserts line notes to preserve the line numbers
- of the moved insns when debugging. This may insert a note between AFTER
- and FROM, and another one after TO. */
-
-void
-reorder_insns_with_line_notes (from, to, after)
- rtx from, to, after;
-{
- rtx from_line = find_line_note (from);
- rtx after_line = find_line_note (after);
-
- reorder_insns (from, to, after);
-
- if (from_line == after_line)
- return;
-
- if (from_line)
- emit_line_note_after (NOTE_SOURCE_FILE (from_line),
- NOTE_LINE_NUMBER (from_line),
- after);
- if (after_line)
- emit_line_note_after (NOTE_SOURCE_FILE (after_line),
- NOTE_LINE_NUMBER (after_line),
- to);
-}
-
/* Remove unnecessary notes from the instruction stream. */
void
-remove_unnecessary_notes ()
+remove_unnecessary_notes (void)
{
rtx block_stack = NULL_RTX;
rtx eh_stack = NULL_RTX;
next = NEXT_INSN (insn);
/* We're only interested in notes. */
- if (GET_CODE (insn) != NOTE)
+ if (!NOTE_P (insn))
continue;
switch (NOTE_LINE_NUMBER (insn))
{
case NOTE_INSN_DELETED:
- case NOTE_INSN_LOOP_END_TOP_COND:
remove_insn (insn);
break;
break;
/* We're only interested in NOTEs. */
- if (GET_CODE (tmp) != NOTE)
+ if (!NOTE_P (tmp))
continue;
if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG)
/* Make X be output before the instruction BEFORE. */
rtx
-emit_insn_before (x, before)
- rtx x, before;
+emit_insn_before (rtx x, rtx before)
{
rtx last = before;
rtx insn;
and output it before the instruction BEFORE. */
rtx
-emit_jump_insn_before (x, before)
- rtx x, before;
+emit_jump_insn_before (rtx x, rtx before)
{
rtx insn, last = NULL_RTX;
and output it before the instruction BEFORE. */
rtx
-emit_call_insn_before (x, before)
- rtx x, before;
+emit_call_insn_before (rtx x, rtx before)
{
rtx last = NULL_RTX, insn;
and output it before the insn BEFORE. */
rtx
-emit_barrier_before (before)
- rtx before;
+emit_barrier_before (rtx before)
{
rtx insn = rtx_alloc (BARRIER);
/* Emit the label LABEL before the insn BEFORE. */
rtx
-emit_label_before (label, before)
- rtx label, before;
+emit_label_before (rtx label, rtx before)
{
/* This can be called twice for the same label as a result of the
confusion that follows a syntax error! So make it harmless. */
/* Emit a note of subtype SUBTYPE before the insn BEFORE. */
rtx
-emit_note_before (subtype, before)
- int subtype;
- rtx before;
+emit_note_before (int subtype, rtx before)
{
rtx note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
+#ifndef USE_MAPPED_LOCATION
NOTE_SOURCE_FILE (note) = 0;
+#endif
NOTE_LINE_NUMBER (note) = subtype;
BLOCK_FOR_INSN (note) = NULL;
/* Helper for emit_insn_after, handles lists of instructions
efficiently. */
-static rtx emit_insn_after_1 PARAMS ((rtx, rtx));
+static rtx emit_insn_after_1 (rtx, rtx);
static rtx
-emit_insn_after_1 (first, after)
- rtx first, after;
+emit_insn_after_1 (rtx first, rtx after)
{
rtx last;
rtx after_after;
basic_block bb;
- if (GET_CODE (after) != BARRIER
+ if (!BARRIER_P (after)
&& (bb = BLOCK_FOR_INSN (after)))
{
bb->flags |= BB_DIRTY;
for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
- if (GET_CODE (last) != BARRIER)
+ if (!BARRIER_P (last))
set_block_for_insn (last, bb);
- if (GET_CODE (last) != BARRIER)
+ if (!BARRIER_P (last))
set_block_for_insn (last, bb);
- if (bb->end == after)
- bb->end = last;
+ if (BB_END (bb) == after)
+ BB_END (bb) = last;
}
else
for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
/* Make X be output after the insn AFTER. */
rtx
-emit_insn_after (x, after)
- rtx x, after;
+emit_insn_after (rtx x, rtx after)
{
rtx last = after;
as to act as if this insn were at FROM. */
void
-emit_insn_after_with_line_notes (x, after, from)
- rtx x, after, from;
+emit_insn_after_with_line_notes (rtx x, rtx after, rtx from)
{
rtx from_line = find_line_note (from);
rtx after_line = find_line_note (after);
rtx insn = emit_insn_after (x, after);
if (from_line)
- emit_line_note_after (NOTE_SOURCE_FILE (from_line),
- NOTE_LINE_NUMBER (from_line),
- after);
+ emit_note_copy_after (from_line, after);
if (after_line)
- emit_line_note_after (NOTE_SOURCE_FILE (after_line),
- NOTE_LINE_NUMBER (after_line),
- insn);
+ emit_note_copy_after (after_line, insn);
}
/* Make an insn of code JUMP_INSN with body X
and output it after the insn AFTER. */
rtx
-emit_jump_insn_after (x, after)
- rtx x, after;
+emit_jump_insn_after (rtx x, rtx after)
{
rtx last;
and output it after the instruction AFTER. */
rtx
-emit_call_insn_after (x, after)
- rtx x, after;
+emit_call_insn_after (rtx x, rtx after)
{
rtx last;
and output it after the insn AFTER. */
rtx
-emit_barrier_after (after)
- rtx after;
+emit_barrier_after (rtx after)
{
rtx insn = rtx_alloc (BARRIER);
/* Emit the label LABEL after the insn AFTER. */
rtx
-emit_label_after (label, after)
- rtx label, after;
+emit_label_after (rtx label, rtx after)
{
/* This can be called twice for the same label
as a result of the confusion that follows a syntax error!
/* Emit a note of subtype SUBTYPE after the insn AFTER. */
rtx
-emit_note_after (subtype, after)
- int subtype;
- rtx after;
+emit_note_after (int subtype, rtx after)
{
rtx note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
+#ifndef USE_MAPPED_LOCATION
NOTE_SOURCE_FILE (note) = 0;
+#endif
NOTE_LINE_NUMBER (note) = subtype;
BLOCK_FOR_INSN (note) = NULL;
add_insn_after (note, after);
return note;
}
-/* Emit a line note for FILE and LINE after the insn AFTER. */
+/* Emit a copy of note ORIG after the insn AFTER. */
rtx
-emit_line_note_after (file, line, after)
- const char *file;
- int line;
- rtx after;
+emit_note_copy_after (rtx orig, rtx after)
{
rtx note;
- if (no_line_numbers && line > 0)
+ if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers)
{
cur_insn_uid++;
return 0;
note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
- NOTE_SOURCE_FILE (note) = file;
- NOTE_LINE_NUMBER (note) = line;
+ NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig);
+ NOTE_DATA (note) = NOTE_DATA (orig);
BLOCK_FOR_INSN (note) = NULL;
add_insn_after (note, after);
return note;
\f
/* Like emit_insn_after, but set INSN_LOCATOR according to SCOPE. */
rtx
-emit_insn_after_setloc (pattern, after, loc)
- rtx pattern, after;
- int loc;
+emit_insn_after_setloc (rtx pattern, rtx after, int loc)
{
rtx last = emit_insn_after (pattern, after);
+ if (pattern == NULL_RTX)
+ return last;
+
after = NEXT_INSN (after);
while (1)
{
/* Like emit_jump_insn_after, but set INSN_LOCATOR according to SCOPE. */
rtx
-emit_jump_insn_after_setloc (pattern, after, loc)
- rtx pattern, after;
- int loc;
+emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc)
{
rtx last = emit_jump_insn_after (pattern, after);
+ if (pattern == NULL_RTX)
+ return last;
+
after = NEXT_INSN (after);
while (1)
{
/* Like emit_call_insn_after, but set INSN_LOCATOR according to SCOPE. */
rtx
-emit_call_insn_after_setloc (pattern, after, loc)
- rtx pattern, after;
- int loc;
+emit_call_insn_after_setloc (rtx pattern, rtx after, int loc)
{
rtx last = emit_call_insn_after (pattern, after);
+ if (pattern == NULL_RTX)
+ return last;
+
after = NEXT_INSN (after);
while (1)
{
/* Like emit_insn_before, but set INSN_LOCATOR according to SCOPE. */
rtx
-emit_insn_before_setloc (pattern, before, loc)
- rtx pattern, before;
- int loc;
+emit_insn_before_setloc (rtx pattern, rtx before, int loc)
{
rtx first = PREV_INSN (before);
rtx last = emit_insn_before (pattern, before);
+ if (pattern == NULL_RTX)
+ return last;
+
first = NEXT_INSN (first);
while (1)
{
Returns the last insn emitted. */
rtx
-emit_insn (x)
- rtx x;
+emit_insn (rtx x)
{
rtx last = last_insn;
rtx insn;
and add it to the end of the doubly-linked list. */
rtx
-emit_jump_insn (x)
- rtx x;
+emit_jump_insn (rtx x)
{
rtx last = NULL_RTX, insn;
and add it to the end of the doubly-linked list. */
rtx
-emit_call_insn (x)
- rtx x;
+emit_call_insn (rtx x)
{
rtx insn;
/* Add the label LABEL to the end of the doubly-linked list. */
rtx
-emit_label (label)
- rtx label;
+emit_label (rtx label)
{
/* This can be called twice for the same label
as a result of the confusion that follows a syntax error!
and add it to the end of the doubly-linked list. */
rtx
-emit_barrier ()
+emit_barrier (void)
{
rtx barrier = rtx_alloc (BARRIER);
INSN_UID (barrier) = cur_insn_uid++;
return barrier;
}
-/* Make an insn of code NOTE
- with data-fields specified by FILE and LINE
- and add it to the end of the doubly-linked list,
- but only if line-numbers are desired for debugging info. */
+/* Make line numbering NOTE insn for LOCATION add it to the end
+ of the doubly-linked list, but only if line-numbers are desired for
+ debugging info and it doesn't match the previous one. */
rtx
-emit_line_note (file, line)
- const char *file;
- int line;
+emit_line_note (location_t location)
{
- set_file_and_line_for_stmt (file, line);
-
-#if 0
- if (no_line_numbers)
- return 0;
+ rtx note;
+
+#ifdef USE_MAPPED_LOCATION
+ if (location == last_location)
+ return NULL_RTX;
+#else
+ if (location.file && last_location.file
+ && !strcmp (location.file, last_location.file)
+ && location.line == last_location.line)
+ return NULL_RTX;
#endif
+ last_location = location;
+
+ if (no_line_numbers)
+ {
+ cur_insn_uid++;
+ return NULL_RTX;
+ }
- return emit_note (file, line);
+#ifdef USE_MAPPED_LOCATION
+ note = emit_note ((int) location);
+#else
+ note = emit_note (location.line);
+ NOTE_SOURCE_FILE (note) = location.file;
+#endif
+
+ return note;
}
-/* Make an insn of code NOTE
- with data-fields specified by FILE and LINE
- and add it to the end of the doubly-linked list.
- If it is a line-number NOTE, omit it if it matches the previous one. */
+/* Emit a copy of note ORIG. */
rtx
-emit_note (file, line)
- const char *file;
- int line;
+emit_note_copy (rtx orig)
{
rtx note;
-
- if (line > 0)
- {
- if (file && last_filename && !strcmp (file, last_filename)
- && line == last_linenum)
- return 0;
- last_filename = file;
- last_linenum = line;
- }
-
- if (no_line_numbers && line > 0)
+
+ if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers)
{
cur_insn_uid++;
- return 0;
+ return NULL_RTX;
}
-
+
note = rtx_alloc (NOTE);
+
INSN_UID (note) = cur_insn_uid++;
- NOTE_SOURCE_FILE (note) = file;
- NOTE_LINE_NUMBER (note) = line;
+ NOTE_DATA (note) = NOTE_DATA (orig);
+ NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig);
BLOCK_FOR_INSN (note) = NULL;
add_insn (note);
+
return note;
}
-/* Emit a NOTE, and don't omit it even if LINE is the previous note. */
+/* Make an insn of code NOTE or type NOTE_NO
+ and add it to the end of the doubly-linked list. */
rtx
-emit_line_note_force (file, line)
- const char *file;
- int line;
+emit_note (int note_no)
{
- last_linenum = -1;
- return emit_line_note (file, line);
+ rtx note;
+
+ note = rtx_alloc (NOTE);
+ INSN_UID (note) = cur_insn_uid++;
+ NOTE_LINE_NUMBER (note) = note_no;
+ memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
+ BLOCK_FOR_INSN (note) = NULL;
+ add_insn (note);
+ return note;
}
/* Cause next statement to emit a line note even if the line number
- has not changed. This is used at the beginning of a function. */
+ has not changed. */
void
-force_next_line_note ()
+force_next_line_note (void)
{
- last_linenum = -1;
+#ifdef USE_MAPPED_LOCATION
+ last_location = -1;
+#else
+ last_location.line = -1;
+#endif
}
/* Place a note of KIND on insn INSN with DATUM as the datum. If a
note of this type already exists, remove it first. */
rtx
-set_unique_reg_note (insn, kind, datum)
- rtx insn;
- enum reg_note kind;
- rtx datum;
+set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
{
rtx note = find_reg_note (insn, kind, NULL_RTX);
The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */
enum rtx_code
-classify_insn (x)
- rtx x;
+classify_insn (rtx x)
{
- if (GET_CODE (x) == CODE_LABEL)
+ if (LABEL_P (x))
return CODE_LABEL;
if (GET_CODE (x) == CALL)
return CALL_INSN;
If X is a label, it is simply added into the insn chain. */
rtx
-emit (x)
- rtx x;
+emit (rtx x)
{
enum rtx_code code = classify_insn (x);
}
\f
/* Space for free sequence stack entries. */
-static GTY ((deletable (""))) struct sequence_stack *free_sequence_stack;
+static GTY ((deletable)) struct sequence_stack *free_sequence_stack;
-/* Begin emitting insns to a sequence which can be packaged in an
- RTL_EXPR. If this sequence will contain something that might cause
- the compiler to pop arguments to function calls (because those
- pops have previously been deferred; see INHIBIT_DEFER_POP for more
- details), use do_pending_stack_adjust before calling this function.
- That will ensure that the deferred pops are not accidentally
- emitted in the middle of this sequence. */
+/* Begin emitting insns to a sequence. If this sequence will contain
+ something that might cause the compiler to pop arguments to function
+ calls (because those pops have previously been deferred; see
+ INHIBIT_DEFER_POP for more details), use do_pending_stack_adjust
+ before calling this function. That will ensure that the deferred
+ pops are not accidentally emitted in the middle of this sequence. */
void
-start_sequence ()
+start_sequence (void)
{
struct sequence_stack *tem;
free_sequence_stack = tem->next;
}
else
- tem = (struct sequence_stack *) ggc_alloc (sizeof (struct sequence_stack));
+ tem = ggc_alloc (sizeof (struct sequence_stack));
tem->next = seq_stack;
tem->first = first_insn;
tem->last = last_insn;
- tem->sequence_rtl_expr = seq_rtl_expr;
seq_stack = tem;
last_insn = 0;
}
-/* Similarly, but indicate that this sequence will be placed in T, an
- RTL_EXPR. See the documentation for start_sequence for more
- information about how to use this function. */
-
-void
-start_sequence_for_rtl_expr (t)
- tree t;
-{
- start_sequence ();
-
- seq_rtl_expr = t;
-}
-
/* Set up the insn chain starting with FIRST as the current sequence,
saving the previously current one. See the documentation for
start_sequence for more information about how to use this function. */
void
-push_to_sequence (first)
- rtx first;
+push_to_sequence (rtx first)
{
rtx last;
/* Set up the insn chain from a chain stort in FIRST to LAST. */
void
-push_to_full_sequence (first, last)
- rtx first, last;
+push_to_full_sequence (rtx first, rtx last)
{
start_sequence ();
first_insn = first;
as the current sequence, saving the previously current one. */
void
-push_topmost_sequence ()
+push_topmost_sequence (void)
{
struct sequence_stack *stack, *top = NULL;
first_insn = top->first;
last_insn = top->last;
- seq_rtl_expr = top->sequence_rtl_expr;
}
/* After emitting to the outer-level insn chain, update the outer-level
insn chain, and restore the previous saved state. */
void
-pop_topmost_sequence ()
+pop_topmost_sequence (void)
{
struct sequence_stack *stack, *top = NULL;
top->first = first_insn;
top->last = last_insn;
- /* ??? Why don't we save seq_rtl_expr here? */
end_sequence ();
}
information about deferred popping of arguments. */
void
-end_sequence ()
+end_sequence (void)
{
struct sequence_stack *tem = seq_stack;
first_insn = tem->first;
last_insn = tem->last;
- seq_rtl_expr = tem->sequence_rtl_expr;
seq_stack = tem->next;
memset (tem, 0, sizeof (*tem));
free_sequence_stack = tem;
}
-/* This works like end_sequence, but records the old sequence in FIRST
- and LAST. */
-
-void
-end_full_sequence (first, last)
- rtx *first, *last;
-{
- *first = first_insn;
- *last = last_insn;
- end_sequence ();
-}
-
/* Return 1 if currently emitting into a sequence. */
int
-in_sequence_p ()
+in_sequence_p (void)
{
return seq_stack != 0;
}
/* Put the various virtual registers into REGNO_REG_RTX. */
void
-init_virtual_regs (es)
- struct emit_status *es;
+init_virtual_regs (struct emit_status *es)
{
rtx *ptr = es->x_regno_reg_rtx;
ptr[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
SCRATCHes. */
rtx
-copy_insn_1 (orig)
- rtx orig;
+copy_insn_1 (rtx orig)
{
rtx copy;
int i, j;
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case CODE_LABEL:
case PC:
case CC0:
- case ADDRESSOF:
return orig;
+ case CLOBBER:
+ if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER)
+ return orig;
+ break;
case SCRATCH:
for (i = 0; i < copy_insn_n_scratches; i++)
all fields need copying, and then clear the fields that should
not be copied. That is the sensible default behavior, and forces
us to explicitly document why we are *not* copying a flag. */
- memcpy (copy, orig, sizeof (struct rtx_def) - sizeof (rtunion));
+ memcpy (copy, orig, RTX_HDR_SIZE);
/* We do not copy the USED flag, which is used as a mark bit during
walks over the RTL. */
RTX_FLAG (copy, used) = 0;
/* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs. */
- if (GET_RTX_CLASS (code) == 'i')
+ if (INSN_P (orig))
{
RTX_FLAG (copy, jump) = 0;
RTX_FLAG (copy, call) = 0;
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
- copy->fld[i] = orig->fld[i];
+ copy->u.fld[i] = orig->u.fld[i];
switch (*format_ptr++)
{
case 'e':
INSN doesn't really have to be a full INSN; it could be just the
pattern. */
rtx
-copy_insn (insn)
- rtx insn;
+copy_insn (rtx insn)
{
copy_insn_n_scratches = 0;
orig_asm_operands_vector = 0;
before generating rtl for each function. */
void
-init_emit ()
+init_emit (void)
{
struct function *f = cfun;
- f->emit = (struct emit_status *) ggc_alloc (sizeof (struct emit_status));
+ f->emit = ggc_alloc (sizeof (struct emit_status));
first_insn = NULL;
last_insn = NULL;
- seq_rtl_expr = NULL;
cur_insn_uid = 1;
reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
- last_linenum = 0;
- last_filename = 0;
+ last_location = UNKNOWN_LOCATION;
first_label_num = label_num;
last_label_num = 0;
seq_stack = NULL;
f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
f->emit->regno_pointer_align
- = (unsigned char *) ggc_alloc_cleared (f->emit->regno_pointer_align_length
- * sizeof (unsigned char));
+ = ggc_alloc_cleared (f->emit->regno_pointer_align_length
+ * sizeof (unsigned char));
regno_reg_rtx
- = (rtx *) ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx));
+ = ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx));
/* Put copies of all the hard registers into regno_reg_rtx. */
memcpy (regno_reg_rtx,
/* Generate the constant 0. */
static rtx
-gen_const_vector_0 (mode)
- enum machine_mode mode;
+gen_const_vector_0 (enum machine_mode mode)
{
rtx tem;
rtvec v;
/* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when
all elements are zero. */
rtx
-gen_rtx_CONST_VECTOR (mode, v)
- enum machine_mode mode;
- rtvec v;
+gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v)
{
rtx inner_zero = CONST0_RTX (GET_MODE_INNER (mode));
int i;
LINE_NUMBERS is nonzero if line numbers are to be generated. */
void
-init_emit_once (line_numbers)
- int line_numbers;
+init_emit_once (int line_numbers)
{
int i;
enum machine_mode mode;
enum machine_mode double_mode;
+ /* We need reg_raw_mode, so initialize the modes now. */
+ init_reg_modes_once ();
+
/* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash
tables. */
const_int_htab = htab_create_ggc (37, const_int_htab_hash,
This must be done at runtime because the register number field
is in a union and some compilers can't initialize unions. */
- pc_rtx = gen_rtx (PC, VOIDmode);
- cc0_rtx = gen_rtx (CC0, VOIDmode);
+ pc_rtx = gen_rtx_PC (VOIDmode);
+ cc0_rtx = gen_rtx_CC0 (VOIDmode);
stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);
frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
if (hard_frame_pointer_rtx == 0)
/* Create the unique rtx's for certain rtx codes and operand values. */
- /* Don't use gen_rtx here since gen_rtx in this case
+ /* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case
tries to use these variables. */
for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
const_int_rtx[i + MAX_SAVED_CONST_INT] =
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);
+ REAL_VALUE_FROM_INT (dconst3, 3, 0, double_mode);
+ REAL_VALUE_FROM_INT (dconst10, 10, 0, double_mode);
REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode);
REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode);
dconsthalf = dconst1;
- dconsthalf.exp--;
+ SET_REAL_EXP (&dconsthalf, REAL_EXP (&dconsthalf) - 1);
+
+ real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3);
- for (i = 0; i <= 2; i++)
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+ real_from_string (&dconstpi,
+ "3.1415926535897932384626433832795028841971693993751058209749445923078");
+ real_from_string (&dconste,
+ "2.7182818284590452353602874713526624977572470936999595749669676277241");
+
+ for (i = 0; i < (int) ARRAY_SIZE (const_tiny_rtx); i++)
{
REAL_VALUE_TYPE *r =
(i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2);
= gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
#endif
-#ifdef STRUCT_VALUE
- struct_value_rtx = STRUCT_VALUE;
-#else
- struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM);
-#endif
-
-#ifdef STRUCT_VALUE_INCOMING
- struct_value_incoming_rtx = STRUCT_VALUE_INCOMING;
-#else
-#ifdef STRUCT_VALUE_INCOMING_REGNUM
- struct_value_incoming_rtx
- = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM);
-#else
- struct_value_incoming_rtx = struct_value_rtx;
-#endif
-#endif
-
#ifdef STATIC_CHAIN_REGNUM
static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
}
\f
-/* Query and clear/ restore no_line_numbers. This is used by the
- switch / case handling in stmt.c to give proper line numbers in
- warnings about unreachable code. */
-
-int
-force_line_numbers ()
-{
- int old = no_line_numbers;
-
- no_line_numbers = 0;
- if (old)
- force_next_line_note ();
- return old;
-}
-
-void
-restore_line_number_status (old_value)
- int old_value;
-{
- no_line_numbers = old_value;
-}
-
/* Produce exact duplicate of insn INSN after AFTER.
Care updating of libcall regions if present. */
rtx
-emit_copy_of_insn_after (insn, after)
- rtx insn, after;
+emit_copy_of_insn_after (rtx insn, rtx after)
{
rtx new;
rtx note1, note2, link;
return new;
}
+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)
+{
+ if (hard_reg_clobbers[mode][regno])
+ return hard_reg_clobbers[mode][regno];
+ else
+ return (hard_reg_clobbers[mode][regno] =
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno)));
+}
+
#include "gt-emit-rtl.h"