/* Emit RTL for the GCC expander.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* Middle-to-low level generation of rtx code and insns.
#include "insn-config.h"
#include "recog.h"
#include "real.h"
+#include "fixed-value.h"
#include "bitmap.h"
#include "basic-block.h"
#include "ggc.h"
#include "debug.h"
#include "langhooks.h"
#include "tree-pass.h"
+#include "df.h"
/* Commonly used modes. */
REAL_VALUE_TYPE dconstsqrt2;
REAL_VALUE_TYPE dconste;
+/* Record fixed-point constant 0 and 1. */
+FIXED_VALUE_TYPE fconst0[MAX_FCONST0];
+FIXED_VALUE_TYPE fconst1[MAX_FCONST1];
+
/* All references to the following fixed hard registers go through
these unique rtl objects. On machines where the frame-pointer and
arg-pointer are the same register, they use the same unique object.
static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
htab_t const_double_htab;
+/* A hash table storing all CONST_FIXEDs. */
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+ htab_t const_fixed_htab;
+
#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)
static rtx make_call_insn_raw (rtx);
static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
-static void reset_used_decls (tree);
+static void set_used_decls (tree);
static void mark_label_nuses (rtx);
static hashval_t const_int_htab_hash (const void *);
static int const_int_htab_eq (const void *, const void *);
static hashval_t const_double_htab_hash (const void *);
static int const_double_htab_eq (const void *, const void *);
static rtx lookup_const_double (rtx);
+static hashval_t const_fixed_htab_hash (const void *);
+static int const_fixed_htab_eq (const void *, const void *);
+static rtx lookup_const_fixed (rtx);
static hashval_t 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,
+static mem_attrs *get_mem_attrs (alias_set_type, 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 hashval_t
const_int_htab_hash (const void *x)
{
- return (hashval_t) INTVAL ((rtx) x);
+ return (hashval_t) INTVAL ((const_rtx) x);
}
/* Returns nonzero if the value represented by X (which is really a
static int
const_int_htab_eq (const void *x, const void *y)
{
- return (INTVAL ((rtx) x) == *((const HOST_WIDE_INT *) y));
+ return (INTVAL ((const_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 (const void *x)
{
- rtx value = (rtx) x;
+ const_rtx const value = (const_rtx) x;
hashval_t h;
if (GET_MODE (value) == VOIDmode)
static int
const_double_htab_eq (const void *x, const void *y)
{
- rtx a = (rtx)x, b = (rtx)y;
+ const_rtx const a = (const_rtx)x, b = (const_rtx)y;
if (GET_MODE (a) != GET_MODE (b))
return 0;
CONST_DOUBLE_REAL_VALUE (b));
}
+/* Returns a hash code for X (which is really a CONST_FIXED). */
+
+static hashval_t
+const_fixed_htab_hash (const void *x)
+{
+ const_rtx const value = (const_rtx) x;
+ hashval_t h;
+
+ h = fixed_hash (CONST_FIXED_VALUE (value));
+ /* MODE is used in the comparison, so it should be in the hash. */
+ h ^= GET_MODE (value);
+ return h;
+}
+
+/* Returns nonzero if the value represented by X (really a ...)
+ is the same as that represented by Y (really a ...). */
+
+static int
+const_fixed_htab_eq (const void *x, const void *y)
+{
+ const_rtx const a = (const_rtx) x, b = (const_rtx) y;
+
+ if (GET_MODE (a) != GET_MODE (b))
+ return 0;
+ return fixed_identical (CONST_FIXED_VALUE (a), CONST_FIXED_VALUE (b));
+}
+
/* Returns a hash code for X (which is a really a mem_attrs *). */
static hashval_t
mem_attrs_htab_hash (const void *x)
{
- mem_attrs *p = (mem_attrs *) x;
+ const mem_attrs *const p = (const mem_attrs *) x;
return (p->alias ^ (p->align * 1000)
^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
static int
mem_attrs_htab_eq (const void *x, const void *y)
{
- mem_attrs *p = (mem_attrs *) x;
- mem_attrs *q = (mem_attrs *) y;
+ const mem_attrs *const p = (const mem_attrs *) x;
+ const mem_attrs *const q = (const mem_attrs *) y;
return (p->alias == q->alias && p->offset == q->offset
&& p->size == q->size && p->align == q->align
MEM of mode MODE. */
static mem_attrs *
-get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size,
+get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size,
unsigned int align, enum machine_mode mode)
{
mem_attrs attrs;
static hashval_t
reg_attrs_htab_hash (const void *x)
{
- reg_attrs *p = (reg_attrs *) x;
+ const reg_attrs *const p = (const reg_attrs *) x;
return ((p->offset * 1000) ^ (long) p->decl);
}
static int
reg_attrs_htab_eq (const void *x, const void *y)
{
- reg_attrs *p = (reg_attrs *) x;
- reg_attrs *q = (reg_attrs *) y;
+ const reg_attrs *const p = (const reg_attrs *) x;
+ const reg_attrs *const q = (const reg_attrs *) y;
return (p->decl == q->decl && p->offset == q->offset);
}
return *slot;
}
+
+#if !HAVE_blockage
+/* Generate an empty ASM_INPUT, which is used to block attempts to schedule
+ across this insn. */
+
+rtx
+gen_blockage (void)
+{
+ rtx x = gen_rtx_ASM_INPUT (VOIDmode, "");
+ MEM_VOLATILE_P (x) = true;
+ return x;
+}
+#endif
+
+
/* Generate a new REG rtx. Make sure ORIGINAL_REGNO is set properly, and
don't attempt to share with the various global pieces of rtl (such as
frame_pointer_rtx). */
return lookup_const_double (real);
}
+/* Determine whether FIXED, a CONST_FIXED, already exists in the
+ hash table. If so, return its counterpart; otherwise add it
+ to the hash table and return it. */
+
+static rtx
+lookup_const_fixed (rtx fixed)
+{
+ void **slot = htab_find_slot (const_fixed_htab, fixed, INSERT);
+ if (*slot == 0)
+ *slot = fixed;
+
+ return (rtx) *slot;
+}
+
+/* Return a CONST_FIXED rtx for a fixed-point value specified by
+ VALUE in mode MODE. */
+
+rtx
+const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
+{
+ rtx fixed = rtx_alloc (CONST_FIXED);
+ PUT_MODE (fixed, mode);
+
+ fixed->u.fv = value;
+
+ return lookup_const_fixed (fixed);
+}
+
/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
of ints: I0 is the low-order word and I1 is the high-order word.
Do not use this routine for non-integer modes; convert to
bool
validate_subreg (enum machine_mode omode, enum machine_mode imode,
- rtx reg, unsigned int offset)
+ const_rtx reg, unsigned int offset)
{
unsigned int isize = GET_MODE_SIZE (imode);
unsigned int osize = GET_MODE_SIZE (omode);
return rt_val;
}
\f
+/* Return the number of bytes between the start of an OUTER_MODE
+ in-memory value and the start of an INNER_MODE in-memory value,
+ given that the former is a lowpart of the latter. It may be a
+ paradoxical lowpart, in which case the offset will be negative
+ on big-endian targets. */
+
+int
+byte_lowpart_offset (enum machine_mode outer_mode,
+ enum machine_mode inner_mode)
+{
+ if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode))
+ return subreg_lowpart_offset (outer_mode, inner_mode);
+ else
+ return -subreg_lowpart_offset (inner_mode, outer_mode);
+}
+\f
/* Generate a REG rtx for a new pseudo register of mode MODE.
This pseudo is assigned the next sequential register number. */
struct function *f = cfun;
rtx val;
- /* Don't let anything called after initial flow analysis create new
- registers. */
- gcc_assert (!no_new_pseudos);
+ gcc_assert (can_create_pseudo_p ());
if (generating_concat_p
&& (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
return val;
}
-/* Update NEW with the same attributes as REG, but offsetted by OFFSET.
- Do the big endian correction if needed. */
+/* Update NEW with the same attributes as REG, but with OFFSET added
+ to the REG_OFFSET. */
static void
update_reg_offset (rtx new, rtx reg, int offset)
{
- 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 (GET_MODE (new))
- && ((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);
}
-/* Generate a register with same attributes as REG, but offsetted by
- OFFSET. */
+/* Generate a register with same attributes as REG, but with OFFSET
+ added to the REG_OFFSET. */
rtx
gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
}
/* Generate a new pseudo-register with the same attributes as REG, but
- offsetted by OFFSET. */
+ with OFFSET added to the REG_OFFSET. */
rtx
gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
return new;
}
-/* Set the decl for MEM to DECL. */
+/* Adjust REG in-place so that it has mode MODE. It is assumed that the
+ new register is a (possibly paradoxical) lowpart of the old one. */
+
+void
+adjust_reg_mode (rtx reg, enum machine_mode mode)
+{
+ update_reg_offset (reg, reg, byte_lowpart_offset (mode, GET_MODE (reg)));
+ PUT_MODE (reg, mode);
+}
+
+/* Copy REG's attributes from X, if X has any attributes. If REG and X
+ have different modes, REG is a (possibly paradoxical) lowpart of X. */
void
-set_reg_attrs_from_mem (rtx reg, rtx mem)
+set_reg_attrs_from_value (rtx reg, rtx x)
{
- if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+ int offset;
+
+ offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
+ if (MEM_P (x) && MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
REG_ATTRS (reg)
- = get_reg_attrs (MEM_EXPR (mem), INTVAL (MEM_OFFSET (mem)));
+ = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+ if (REG_P (x) && REG_ATTRS (x))
+ update_reg_offset (reg, x, offset);
}
/* Set the register attributes for registers contained in PARM_RTX.
set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
{
if (REG_P (parm_rtx))
- set_reg_attrs_from_mem (parm_rtx, mem);
+ set_reg_attrs_from_value (parm_rtx, mem);
else if (GET_CODE (parm_rtx) == PARALLEL)
{
/* Check for a NULL entry in the first slot, used to indicate that the
}
}
-/* Assign the RTX X to declaration T. */
-void
-set_decl_rtl (tree t, rtx x)
-{
- DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x;
+/* Set the REG_ATTRS for registers in value X, given that X represents
+ decl T. */
- 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)
+static void
+set_reg_attrs_for_decl_rtl (tree t, rtx x)
+{
+ if (GET_CODE (x) == SUBREG)
{
- int i;
- for (i = 0; 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)));
- }
+ gcc_assert (subreg_lowpart_p (x));
+ x = 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));
+ REG_ATTRS (x)
+ = get_reg_attrs (t, byte_lowpart_offset (GET_MODE (x),
+ DECL_MODE (t)));
if (GET_CODE (x) == CONCAT)
{
if (REG_P (XEXP (x, 0)))
}
}
+/* Assign the RTX X to declaration T. */
+
+void
+set_decl_rtl (tree t, rtx x)
+{
+ DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x;
+ if (x)
+ set_reg_attrs_for_decl_rtl (t, x);
+}
+
+/* Assign the RTX X to parameter declaration T. BY_REFERENCE_P is true
+ if the ABI requires the parameter to be passed by reference. */
+
+void
+set_decl_incoming_rtl (tree t, rtx x, bool by_reference_p)
+{
+ DECL_INCOMING_RTL (t) = x;
+ if (x && !by_reference_p)
+ set_reg_attrs_for_decl_rtl (t, x);
+}
+
/* Identify REG (which may be a CONCAT) as a user register. */
void
subreg_highpart_offset (outermode, innermode));
}
-/* Return offset in bytes to get OUTERMODE low part
- of the value in mode INNERMODE stored in memory in target format. */
+/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value. */
unsigned int
subreg_lowpart_offset (enum machine_mode outermode, enum machine_mode innermode)
If X is not a SUBREG, always return 1 (it is its own low part!). */
int
-subreg_lowpart_p (rtx x)
+subreg_lowpart_p (const_rtx x)
{
if (GET_CODE (x) != SUBREG)
return 1;
and 0 otherwise. */
int
-mem_expr_equal_p (tree expr1, tree expr2)
+mem_expr_equal_p (const_tree expr1, const_tree expr2)
{
if (expr1 == expr2)
return 1;
set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
HOST_WIDE_INT bitpos)
{
- HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);
+ alias_set_type alias = MEM_ALIAS_SET (ref);
tree expr = MEM_EXPR (ref);
rtx offset = MEM_OFFSET (ref);
rtx size = MEM_SIZE (ref);
set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
}
-/* Set the decl for MEM to DECL. */
+/* Set MEM to the decl that REG refers to. */
void
set_mem_attrs_from_reg (rtx mem, rtx reg)
/* Set the alias set of MEM to SET. */
void
-set_mem_alias_set (rtx mem, HOST_WIDE_INT set)
+set_mem_alias_set (rtx mem, alias_set_type set)
{
#ifdef ENABLE_CHECKING
/* If the new and old alias sets don't conflict, something is wrong. */
{
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));
+ set_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));
+ set_used_flags (DECL_RTL (decl));
reset_used_flags (stack_slot_list);
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
+ TODO_dump_func | TODO_verify_rtl_sharing, /* todo_flags_finish */
0 /* letter */
};
case REG:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case LABEL_REF:
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)
+ if (shared_const_p (orig))
return;
break;
{
reset_used_flags (PATTERN (p));
reset_used_flags (REG_NOTES (p));
- reset_used_flags (LOG_LINKS (p));
if (GET_CODE (PATTERN (p)) == SEQUENCE)
{
int i;
gcc_assert (INSN_P (q));
reset_used_flags (PATTERN (q));
reset_used_flags (REG_NOTES (q));
- reset_used_flags (LOG_LINKS (q));
}
}
}
{
verify_rtx_sharing (PATTERN (p), p);
verify_rtx_sharing (REG_NOTES (p), p);
- verify_rtx_sharing (LOG_LINKS (p), p);
}
}
{
PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
- LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
}
}
/* Go through all virtual stack slots of a function and mark them as
- not shared. */
+ shared. We never replace the DECL_RTLs themselves with a copy,
+ but expressions mentioned into a DECL_RTL cannot be shared with
+ expressions in the instruction stream.
+
+ Note that reload may convert pseudo registers into memories in-place.
+ Pseudo registers are always shared, but MEMs never are. Thus if we
+ reset the used flags on MEMs in the instruction stream, we must set
+ them again on MEMs that appear in DECL_RTLs. */
+
static void
-reset_used_decls (tree blk)
+set_used_decls (tree blk)
{
tree t;
/* Mark decls. */
for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
if (DECL_RTL_SET_P (t))
- reset_used_flags (DECL_RTL (t));
+ set_used_flags (DECL_RTL (t));
/* Now process sub-blocks. */
- for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
- reset_used_decls (t);
+ for (t = BLOCK_SUBBLOCKS (blk); t; t = BLOCK_CHAIN (t))
+ set_used_decls (t);
}
/* Mark ORIG as in use, and return a copy of it if it was already in use.
case REG:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case LABEL_REF:
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)
+ if (shared_const_p (x))
return;
break;
case REG:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case REG:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
same as next_real_insn. */
int
-active_insn_p (rtx insn)
+active_insn_p (const_rtx insn)
{
return (CALL_P (insn) || JUMP_P (insn)
|| (NONJUMP_INSN_P (insn)
rtx before = PREV_INSN (trial);
rtx after = NEXT_INSN (trial);
int has_barrier = 0;
- rtx tem;
+ rtx tem, note_retval, note_libcall;
rtx note, seq;
int probability;
rtx insn_last, insn;
insn_last = NEXT_INSN (insn_last);
}
+ /* We will be adding the new sequence to the function. The splitters
+ may have introduced invalid RTL sharing, so unshare the sequence now. */
+ unshare_all_rtl_in_chain (seq);
+
/* Mark labels. */
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
{
break;
#endif
+ case REG_LIBCALL:
+ /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note
+ after split. */
+ REG_NOTES (insn_last)
+ = gen_rtx_INSN_LIST (REG_LIBCALL,
+ XEXP (note, 0),
+ REG_NOTES (insn_last));
+
+ note_retval = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL);
+ XEXP (note_retval, 0) = insn_last;
+ break;
+
+ case REG_RETVAL:
+ /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note
+ after split. */
+ REG_NOTES (insn_last)
+ = gen_rtx_INSN_LIST (REG_RETVAL,
+ XEXP (note, 0),
+ REG_NOTES (insn_last));
+
+ note_libcall = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL);
+ XEXP (note_libcall, 0) = insn_last;
+ break;
+
default:
break;
}
/* If there are LABELS inside the split insns increment the
usage count so we don't delete the label. */
- if (NONJUMP_INSN_P (trial))
+ if (INSN_P (trial))
{
insn = insn_last;
while (insn != NULL_RTX)
{
+ /* JUMP_P insns have already been "marked" above. */
if (NONJUMP_INSN_P (insn))
mark_label_nuses (PATTERN (insn));
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
INSN_LOCATOR (insn) = curr_insn_locator ();
BLOCK_FOR_INSN (insn) = NULL;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
JUMP_LABEL (insn) = NULL;
INSN_LOCATOR (insn) = curr_insn_locator ();
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
CALL_INSN_FUNCTION_USAGE (insn) = NULL;
INSN_LOCATOR (insn) = curr_insn_locator ();
SEQUENCE. */
void
-add_insn_after (rtx insn, rtx after)
+add_insn_after (rtx insn, rtx after, basic_block bb)
{
rtx next = NEXT_INSN (after);
- basic_block bb;
gcc_assert (!optimize || !INSN_DELETED_P (after));
{
set_block_for_insn (insn, bb);
if (INSN_P (insn))
- bb->flags |= BB_DIRTY;
+ df_insn_rescan (insn);
/* Should not happen as first in the BB is always
either NOTE or LABEL. */
if (BB_END (bb) == after
/* Avoid clobbering of structure when creating new BB. */
&& !BARRIER_P (insn)
- && (!NOTE_P (insn)
- || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
+ && !NOTE_INSN_BASIC_BLOCK_P (insn))
BB_END (bb) = insn;
}
}
/* Add INSN into the doubly-linked list before insn BEFORE. This and
- the previous should be the only functions called to insert an insn once
- delay slots have been filled since only they know how to update a
- SEQUENCE. */
+ the previous should be the only functions called to insert an insn
+ once delay slots have been filled since only they know how to
+ update a SEQUENCE. If BB is NULL, an attempt is made to infer the
+ bb from before. */
void
-add_insn_before (rtx insn, rtx before)
+add_insn_before (rtx insn, rtx before, basic_block bb)
{
rtx prev = PREV_INSN (before);
- basic_block bb;
gcc_assert (!optimize || !INSN_DELETED_P (before));
gcc_assert (stack);
}
- if (!BARRIER_P (before)
- && !BARRIER_P (insn)
- && (bb = BLOCK_FOR_INSN (before)))
+ if (!bb
+ && !BARRIER_P (before)
+ && !BARRIER_P (insn))
+ bb = BLOCK_FOR_INSN (before);
+
+ if (bb)
{
set_block_for_insn (insn, bb);
if (INSN_P (insn))
- bb->flags |= BB_DIRTY;
+ df_insn_rescan (insn);
/* Should not happen as first in the BB is always either NOTE or
LABEL. */
gcc_assert (BB_HEAD (bb) != insn
/* Avoid clobbering of structure when creating new BB. */
|| BARRIER_P (insn)
- || (NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK));
+ || NOTE_INSN_BASIC_BLOCK_P (insn));
}
PREV_INSN (before) = insn;
PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
}
+
+/* Replace insn with an deleted instruction note. */
+
+void set_insn_deleted (rtx insn)
+{
+ df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn));
+ PUT_CODE (insn, NOTE);
+ NOTE_KIND (insn) = NOTE_INSN_DELETED;
+}
+
+
/* Remove an insn from its doubly-linked list. This function knows how
to handle sequences. */
void
rtx prev = PREV_INSN (insn);
basic_block bb;
+ /* Later in the code, the block will be marked dirty. */
+ df_insn_delete (NULL, INSN_UID (insn));
+
if (prev)
{
NEXT_INSN (prev) = next;
&& (bb = BLOCK_FOR_INSN (insn)))
{
if (INSN_P (insn))
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
if (BB_HEAD (bb) == insn)
{
/* Never ever delete the basic block note without deleting whole
&& (bb = BLOCK_FOR_INSN (after)))
{
rtx x;
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
if (!BARRIER_P (from)
&& (bb2 = BLOCK_FOR_INSN (from)))
{
if (BB_END (bb2) == to)
BB_END (bb2) = prev;
- bb2->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb2);
}
if (BB_END (bb) == after)
for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x))
if (!BARRIER_P (x))
- set_block_for_insn (x, bb);
+ df_insn_change_bb (x, bb);
}
}
/* Make X be output before the instruction BEFORE. */
rtx
-emit_insn_before_noloc (rtx x, rtx before)
+emit_insn_before_noloc (rtx x, rtx before, basic_block bb)
{
rtx last = before;
rtx insn;
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_before (insn, before);
+ add_insn_before (insn, before, bb);
last = insn;
insn = next;
}
default:
last = make_insn_raw (x);
- add_insn_before (last, before);
+ add_insn_before (last, before, bb);
break;
}
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_before (insn, before);
+ add_insn_before (insn, before, NULL);
last = insn;
insn = next;
}
default:
last = make_jump_insn_raw (x);
- add_insn_before (last, before);
+ add_insn_before (last, before, NULL);
break;
}
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_before (insn, before);
+ add_insn_before (insn, before, NULL);
last = insn;
insn = next;
}
default:
last = make_call_insn_raw (x);
- add_insn_before (last, before);
+ add_insn_before (last, before, NULL);
break;
}
INSN_UID (insn) = cur_insn_uid++;
- add_insn_before (insn, before);
+ add_insn_before (insn, before, NULL);
return insn;
}
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
- add_insn_before (label, before);
+ add_insn_before (label, before, NULL);
}
return label;
/* Emit a note of subtype SUBTYPE before the insn BEFORE. */
rtx
-emit_note_before (int subtype, rtx before)
+emit_note_before (enum insn_note 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;
+ NOTE_KIND (note) = subtype;
BLOCK_FOR_INSN (note) = NULL;
+ memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
- add_insn_before (note, before);
+ add_insn_before (note, before, NULL);
return note;
}
\f
/* Helper for emit_insn_after, handles lists of instructions
efficiently. */
-static rtx emit_insn_after_1 (rtx, rtx);
-
static rtx
-emit_insn_after_1 (rtx first, rtx after)
+emit_insn_after_1 (rtx first, rtx after, basic_block bb)
{
rtx last;
rtx after_after;
- basic_block bb;
+ if (!bb && !BARRIER_P (after))
+ bb = BLOCK_FOR_INSN (after);
- if (!BARRIER_P (after)
- && (bb = BLOCK_FOR_INSN (after)))
+ if (bb)
{
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
if (!BARRIER_P (last))
- set_block_for_insn (last, bb);
+ {
+ set_block_for_insn (last, bb);
+ df_insn_rescan (last);
+ }
if (!BARRIER_P (last))
- set_block_for_insn (last, bb);
+ {
+ set_block_for_insn (last, bb);
+ df_insn_rescan (last);
+ }
if (BB_END (bb) == after)
BB_END (bb) = last;
}
return last;
}
-/* Make X be output after the insn AFTER. */
+/* Make X be output after the insn AFTER and set the BB of insn. If
+ BB is NULL, an attempt is made to infer the BB from AFTER. */
rtx
-emit_insn_after_noloc (rtx x, rtx after)
+emit_insn_after_noloc (rtx x, rtx after, basic_block bb)
{
rtx last = after;
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after);
+ last = emit_insn_after_1 (x, after, bb);
break;
#ifdef ENABLE_RTL_CHECKING
default:
last = make_insn_raw (x);
- add_insn_after (last, after);
+ add_insn_after (last, after, bb);
break;
}
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after);
+ last = emit_insn_after_1 (x, after, NULL);
break;
#ifdef ENABLE_RTL_CHECKING
default:
last = make_jump_insn_raw (x);
- add_insn_after (last, after);
+ add_insn_after (last, after, NULL);
break;
}
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after);
+ last = emit_insn_after_1 (x, after, NULL);
break;
#ifdef ENABLE_RTL_CHECKING
default:
last = make_call_insn_raw (x);
- add_insn_after (last, after);
+ add_insn_after (last, after, NULL);
break;
}
INSN_UID (insn) = cur_insn_uid++;
- add_insn_after (insn, after);
+ add_insn_after (insn, after, NULL);
return insn;
}
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
- add_insn_after (label, after);
+ add_insn_after (label, after, NULL);
}
return label;
/* Emit a note of subtype SUBTYPE after the insn AFTER. */
rtx
-emit_note_after (int subtype, rtx after)
+emit_note_after (enum insn_note 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;
+ NOTE_KIND (note) = subtype;
BLOCK_FOR_INSN (note) = NULL;
- add_insn_after (note, after);
+ memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
+ add_insn_after (note, after, NULL);
return note;
}
\f
rtx
emit_insn_after_setloc (rtx pattern, rtx after, int loc)
{
- rtx last = emit_insn_after_noloc (pattern, after);
+ rtx last = emit_insn_after_noloc (pattern, after, NULL);
if (pattern == NULL_RTX || !loc)
return last;
if (INSN_P (after))
return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
else
- return emit_insn_after_noloc (pattern, after);
+ return emit_insn_after_noloc (pattern, after, NULL);
}
/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */
emit_insn_before_setloc (rtx pattern, rtx before, int loc)
{
rtx first = PREV_INSN (before);
- rtx last = emit_insn_before_noloc (pattern, before);
+ rtx last = emit_insn_before_noloc (pattern, before, NULL);
if (pattern == NULL_RTX || !loc)
return last;
if (INSN_P (before))
return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
else
- return emit_insn_before_noloc (pattern, before);
+ return emit_insn_before_noloc (pattern, before, NULL);
}
/* like emit_insn_before_noloc, but set insn_locator according to scope. */
INSN_UID (note) = cur_insn_uid++;
NOTE_DATA (note) = NOTE_DATA (orig);
- NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig);
+ NOTE_KIND (note) = NOTE_KIND (orig);
BLOCK_FOR_INSN (note) = NULL;
add_insn (note);
and add it to the end of the doubly-linked list. */
rtx
-emit_note (int note_no)
+emit_note (enum insn_note kind)
{
rtx note;
note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
- NOTE_LINE_NUMBER (note) = note_no;
+ NOTE_KIND (note) = kind;
memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
BLOCK_FOR_INSN (note) = NULL;
add_insn (note);
void
force_next_line_note (void)
{
-#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
set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
{
rtx note = find_reg_note (insn, kind, NULL_RTX);
+ rtx new_note = NULL;
switch (kind)
{
It serves no useful purpose and breaks eliminate_regs. */
if (GET_CODE (datum) == ASM_OPERANDS)
return NULL_RTX;
+
+ if (note)
+ {
+ XEXP (note, 0) = datum;
+ df_notes_rescan (insn);
+ return note;
+ }
break;
default:
+ if (note)
+ {
+ XEXP (note, 0) = datum;
+ return note;
+ }
break;
}
- if (note)
+ new_note = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
+ REG_NOTES (insn) = new_note;
+
+ switch (kind)
{
- XEXP (note, 0) = datum;
- return note;
+ case REG_EQUAL:
+ case REG_EQUIV:
+ df_notes_rescan (insn);
+ break;
+ default:
+ break;
}
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
return REG_NOTES (insn);
}
\f
last_insn = last;
}
+/* Like push_to_sequence, but take the last insn as an argument to avoid
+ looping through the list. */
+
+void
+push_to_sequence2 (rtx first, rtx last)
+{
+ start_sequence ();
+
+ first_insn = first;
+ last_insn = last;
+}
+
/* Set up the outer-level insn chain
as the current sequence, saving the previously current one. */
case REG:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
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 (orig, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+ if (shared_const_p (orig))
return orig;
break;
return gen_rtx_raw_CONST_VECTOR (mode, v);
}
+/* Initialise global register information required by all functions. */
+
+void
+init_emit_regs (void)
+{
+ int i;
+
+ /* Reset register attributes */
+ htab_empty (reg_attrs_htab);
+
+ /* We need reg_raw_mode, so initialize the modes now. */
+ init_reg_modes_target ();
+
+ /* Assign register numbers to the globally defined register rtx. */
+ 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);
+ hard_frame_pointer_rtx = gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);
+ arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
+ virtual_incoming_args_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
+ virtual_stack_vars_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
+ virtual_stack_dynamic_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
+ virtual_outgoing_args_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
+ virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+
+ /* Initialize RTL for commonly used hard registers. These are
+ copied into regno_reg_rtx as we begin to compile each function. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
+
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+ return_address_pointer_rtx
+ = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
+#endif
+
+#ifdef STATIC_CHAIN_REGNUM
+ static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+
+#ifdef STATIC_CHAIN_INCOMING_REGNUM
+ if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
+ static_chain_incoming_rtx
+ = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
+ else
+#endif
+ static_chain_incoming_rtx = static_chain_rtx;
+#endif
+
+#ifdef STATIC_CHAIN
+ static_chain_rtx = STATIC_CHAIN;
+
+#ifdef STATIC_CHAIN_INCOMING
+ static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
+#else
+ static_chain_incoming_rtx = static_chain_rtx;
+#endif
+#endif
+
+ if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+ pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
+ else
+ pic_offset_table_rtx = NULL_RTX;
+}
+
/* Create some permanent unique rtl objects shared between all functions.
LINE_NUMBERS is nonzero if line numbers are to be generated. */
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. */
+ /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
+ hash tables. */
const_int_htab = htab_create_ggc (37, const_int_htab_hash,
const_int_htab_eq, NULL);
const_double_htab = htab_create_ggc (37, const_double_htab_hash,
const_double_htab_eq, NULL);
+ const_fixed_htab = htab_create_ggc (37, const_fixed_htab_hash,
+ const_fixed_htab_eq, NULL);
+
mem_attrs_htab = htab_create_ggc (37, mem_attrs_htab_hash,
mem_attrs_htab_eq, NULL);
reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash,
ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
- /* Assign register numbers to the globally defined register rtx.
- 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);
- 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)
- hard_frame_pointer_rtx = gen_raw_REG (Pmode,
- HARD_FRAME_POINTER_REGNUM);
- if (arg_pointer_rtx == 0)
- arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
- virtual_incoming_args_rtx =
- gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
- virtual_stack_vars_rtx =
- gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
- virtual_stack_dynamic_rtx =
- gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
- virtual_outgoing_args_rtx =
- gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
- virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
-
- /* Initialize RTL for commonly used hard registers. These are
- copied into regno_reg_rtx as we begin to compile each function. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
-
#ifdef INIT_EXPANDERS
/* This is to initialize {init|mark|free}_machine_status before the first
call to push_function_context_to. This is needed by the Chill front
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
}
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_INT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
+ const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+ }
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
+ const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+ }
+
for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
}
- for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
- if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
- const_tiny_rtx[0][i] = const0_rtx;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FRACT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ FCONST0(mode).data.high = 0;
+ FCONST0(mode).data.low = 0;
+ FCONST0(mode).mode = mode;
+ const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+ FCONST0 (mode), mode);
+ }
- const_tiny_rtx[0][(int) BImode] = const0_rtx;
- if (STORE_FLAG_VALUE == 1)
- const_tiny_rtx[1][(int) BImode] = const1_rtx;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_UFRACT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ FCONST0(mode).data.high = 0;
+ FCONST0(mode).data.low = 0;
+ FCONST0(mode).mode = mode;
+ const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+ FCONST0 (mode), mode);
+ }
-#ifdef RETURN_ADDRESS_POINTER_REGNUM
- return_address_pointer_rtx
- = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
-#endif
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_ACCUM);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ FCONST0(mode).data.high = 0;
+ FCONST0(mode).data.low = 0;
+ FCONST0(mode).mode = mode;
+ const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+ FCONST0 (mode), mode);
+
+ /* We store the value 1. */
+ FCONST1(mode).data.high = 0;
+ FCONST1(mode).data.low = 0;
+ FCONST1(mode).mode = mode;
+ lshift_double (1, 0, GET_MODE_FBIT (mode),
+ 2 * HOST_BITS_PER_WIDE_INT,
+ &FCONST1(mode).data.low,
+ &FCONST1(mode).data.high,
+ SIGNED_FIXED_POINT_MODE_P (mode));
+ const_tiny_rtx[1][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+ FCONST1 (mode), mode);
+ }
-#ifdef STATIC_CHAIN_REGNUM
- static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_UACCUM);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ FCONST0(mode).data.high = 0;
+ FCONST0(mode).data.low = 0;
+ FCONST0(mode).mode = mode;
+ const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+ FCONST0 (mode), mode);
+
+ /* We store the value 1. */
+ FCONST1(mode).data.high = 0;
+ FCONST1(mode).data.low = 0;
+ FCONST1(mode).mode = mode;
+ lshift_double (1, 0, GET_MODE_FBIT (mode),
+ 2 * HOST_BITS_PER_WIDE_INT,
+ &FCONST1(mode).data.low,
+ &FCONST1(mode).data.high,
+ SIGNED_FIXED_POINT_MODE_P (mode));
+ const_tiny_rtx[1][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+ FCONST1 (mode), mode);
+ }
-#ifdef STATIC_CHAIN_INCOMING_REGNUM
- if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
- static_chain_incoming_rtx
- = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
- else
-#endif
- static_chain_incoming_rtx = static_chain_rtx;
-#endif
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FRACT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+ }
-#ifdef STATIC_CHAIN
- static_chain_rtx = STATIC_CHAIN;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UFRACT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+ }
-#ifdef STATIC_CHAIN_INCOMING
- static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
-#else
- static_chain_incoming_rtx = static_chain_rtx;
-#endif
-#endif
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_ACCUM);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+ const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+ }
- if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
- pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UACCUM);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+ const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+ }
+
+ for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
+ if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
+ const_tiny_rtx[0][i] = const0_rtx;
+
+ const_tiny_rtx[0][(int) BImode] = const0_rtx;
+ if (STORE_FLAG_VALUE == 1)
+ const_tiny_rtx[1][(int) BImode] = const1_rtx;
}
\f
/* Produce exact duplicate of insn INSN after AFTER.
which may be duplicated by the basic block reordering code. */
RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
- /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
- make them. */
+ /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
+ will make them. REG_LABEL_TARGETs are created there too, but are
+ supposed to be sticky, so we copy them. */
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
- if (REG_NOTE_KIND (link) != REG_LABEL)
+ if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
{
if (GET_CODE (link) == EXPR_LIST)
REG_NOTES (new)