/* Emit RTL for the GCC expander.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, 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 "ggc.h"
#include "debug.h"
#include "langhooks.h"
+#include "tree-pass.h"
+#include "df.h"
/* Commonly used modes. */
REAL_VALUE_TYPE dconstm2;
REAL_VALUE_TYPE dconsthalf;
REAL_VALUE_TYPE dconstthird;
-REAL_VALUE_TYPE dconstpi;
+REAL_VALUE_TYPE dconstsqrt2;
REAL_VALUE_TYPE dconste;
/* All references to the following fixed hard registers go through
#define last_location (cfun->emit->x_last_location)
#define first_label_num (cfun->emit->x_first_label_num)
-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 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;
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)
^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
- ^ (size_t) p->expr);
+ ^ (size_t) iterative_hash_expr (p->expr, 0));
}
/* Returns nonzero if the value represented by X (which is really a
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->expr == q->expr && p->offset == q->offset
- && p->size == q->size && p->align == q->align);
+ return (p->alias == q->alias && p->offset == q->offset
+ && p->size == q->size && p->align == q->align
+ && (p->expr == q->expr
+ || (p->expr != NULL_TREE && q->expr != NULL_TREE
+ && operand_equal_p (p->expr, q->expr, 0))));
}
/* Allocate a new mem_attrs structure and insert it into the hash table if
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). */
rtx real = rtx_alloc (CONST_DOUBLE);
PUT_MODE (real, mode);
- memcpy (&CONST_DOUBLE_LOW (real), &value, sizeof (REAL_VALUE_TYPE));
+ real->u.rv = value;
return lookup_const_double (real);
}
rtx value;
unsigned int i;
+ /* There are the following cases (note that there are no modes with
+ HOST_BITS_PER_WIDE_INT < GET_MODE_BITSIZE (mode) < 2 * HOST_BITS_PER_WIDE_INT):
+
+ 1) If GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT, then we use
+ gen_int_mode.
+ 2) GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT, but the value of
+ the integer fits into HOST_WIDE_INT anyway (i.e., i1 consists only
+ from copies of the sign bit, and sign of i0 and i1 are the same), then
+ we return a CONST_INT for i0.
+ 3) Otherwise, we create a CONST_DOUBLE for i0 and i1. */
if (mode != VOIDmode)
{
- int width;
-
gcc_assert (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
/* We can get a 0 for an error mark. */
|| GET_MODE_CLASS (mode) == MODE_VECTOR_INT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT);
- /* We clear out all bits that don't belong in MODE, unless they and
- our sign bit are all one. So we get either a reasonable negative
- value or a reasonable unsigned value for this mode. */
- width = GET_MODE_BITSIZE (mode);
- if (width < HOST_BITS_PER_WIDE_INT
- && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1)))
- != ((HOST_WIDE_INT) (-1) << (width - 1))))
- i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0;
- else if (width == HOST_BITS_PER_WIDE_INT
- && ! (i1 == ~0 && i0 < 0))
- i1 = 0;
- else
- /* We should be able to represent this value as a constant. */
- gcc_assert (width <= 2 * HOST_BITS_PER_WIDE_INT);
-
- /* If this would be an entire word for the target, but is not for
- the host, then sign-extend on the host so that the number will
- look the same way on the host that it would on the target.
-
- For example, when building a 64 bit alpha hosted 32 bit sparc
- targeted compiler, then we want the 32 bit unsigned value -1 to be
- represented as a 64 bit value -1, and not as 0x00000000ffffffff.
- The latter confuses the sparc backend. */
-
- if (width < HOST_BITS_PER_WIDE_INT
- && (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
- i0 |= ((HOST_WIDE_INT) (-1) << width);
-
- /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a
- CONST_INT.
-
- ??? Strictly speaking, this is wrong if we create a CONST_INT for
- a large unsigned constant with the size of MODE being
- HOST_BITS_PER_WIDE_INT and later try to interpret that constant
- in a wider mode. In that case we will mis-interpret it as a
- negative number.
-
- Unfortunately, the only alternative is to make a CONST_DOUBLE for
- any constant in any mode if it is an unsigned constant larger
- than the maximum signed integer in an int on the host. However,
- doing this will break everyone that always expects to see a
- CONST_INT for SImode and smaller.
-
- We have always been making CONST_INTs in this case, so nothing
- new is being broken. */
-
- if (width <= HOST_BITS_PER_WIDE_INT)
- i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0;
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ return gen_int_mode (i0, mode);
+
+ gcc_assert (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT);
}
/* If this integer fits in one word, return a CONST_INT. */
return mem;
}
+/* Generate a MEM referring to fixed portions of the frame, e.g., register
+ save areas. */
+
+rtx
+gen_frame_mem (enum machine_mode mode, rtx addr)
+{
+ rtx mem = gen_rtx_MEM (mode, addr);
+ MEM_NOTRAP_P (mem) = 1;
+ set_mem_alias_set (mem, get_frame_alias_set ());
+ return mem;
+}
+
+/* Generate a MEM referring to a temporary use of the stack, not part
+ of the fixed stack frame. For example, something which is pushed
+ by a target splitter. */
+rtx
+gen_tmp_stack_mem (enum machine_mode mode, rtx addr)
+{
+ rtx mem = gen_rtx_MEM (mode, addr);
+ MEM_NOTRAP_P (mem) = 1;
+ if (!current_function_calls_alloca)
+ set_mem_alias_set (mem, get_frame_alias_set ());
+ return mem;
+}
+
/* We want to create (subreg:OMODE (obj:IMODE) OFFSET). Return true if
this construct would be valid, and false otherwise. */
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;
}
-/* Generate a register with same attributes as REG, but offsetted by OFFSET.
+/* Update NEW with the same attributes as REG, but offsetted by OFFSET.
Do the big endian correction if needed. */
-rtx
-gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset)
+static void
+update_reg_offset (rtx new, rtx reg, int offset)
{
- rtx new = gen_rtx_REG (mode, regno);
tree decl;
HOST_WIDE_INT var_size;
if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
&& decl != NULL
&& offset > 0
- && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode)
+ && 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))))
{
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. */
+
+rtx
+gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
+ int offset)
+{
+ rtx new = gen_rtx_REG (mode, regno);
+
+ update_reg_offset (new, reg, offset);
+ return new;
+}
+
+/* Generate a new pseudo-register with the same attributes as REG, but
+ offsetted by OFFSET. */
+
+rtx
+gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
+{
+ rtx new = gen_reg_rtx (mode);
+
+ update_reg_offset (new, reg, offset);
return new;
}
void
set_decl_rtl (tree t, rtx x)
{
- DECL_CHECK (t)->decl.rtl = x;
+ DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x;
if (!x)
return;
/* 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)
+ if (GET_CODE (x) == CONST_INT
+ && msize * BITS_PER_UNIT <= 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);
return 0;
/* Don't allow generating paradoxical FLOAT_MODE subregs. */
- if (GET_MODE_CLASS (mode) == MODE_FLOAT && msize > xsize)
+ if (SCALAR_FLOAT_MODE_P (mode) && msize > xsize)
return 0;
offset = subreg_lowpart_offset (mode, innermode);
alias = get_alias_set (t);
MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type);
- MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
+ MEM_IN_STRUCT_P (ref)
+ = AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE;
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. */
- if ((objectp || DECL_P (t)) && ! AGGREGATE_TYPE_P (type))
+ if ((objectp || DECL_P (t))
+ && ! AGGREGATE_TYPE_P (type)
+ && TREE_CODE (type) != COMPLEX_TYPE)
MEM_SCALAR_P (ref) = 1;
/* We can set the alignment from the type if we are making an object,
the expression. */
if (! TYPE_P (t))
{
- tree base = get_base_address (t);
- if (base && DECL_P (base)
- && TREE_READONLY (base)
- && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
- {
- tree base_type = TREE_TYPE (base);
- gcc_assert (!(base_type && TYPE_NEEDS_CONSTRUCTING (base_type))
- || DECL_ARTIFICIAL (base));
- MEM_READONLY_P (ref) = 1;
- }
+ tree base;
if (TREE_THIS_VOLATILE (t))
MEM_VOLATILE_P (ref) = 1;
|| TREE_CODE (t) == SAVE_EXPR)
t = TREE_OPERAND (t, 0);
+ /* We may look through structure-like accesses for the purposes of
+ examining TREE_THIS_NOTRAP, but not array-like accesses. */
+ base = t;
+ while (TREE_CODE (base) == COMPONENT_REF
+ || TREE_CODE (base) == REALPART_EXPR
+ || TREE_CODE (base) == IMAGPART_EXPR
+ || TREE_CODE (base) == BIT_FIELD_REF)
+ base = TREE_OPERAND (base, 0);
+
+ if (DECL_P (base))
+ {
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (base), TS_DECL_WITH_VIS))
+ MEM_NOTRAP_P (ref) = !DECL_WEAK (base);
+ else
+ MEM_NOTRAP_P (ref) = 1;
+ }
+ else
+ MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (base);
+
+ base = get_base_address (base);
+ if (base && DECL_P (base)
+ && TREE_READONLY (base)
+ && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
+ {
+ tree base_type = TREE_TYPE (base);
+ gcc_assert (!(base_type && TYPE_NEEDS_CONSTRUCTING (base_type))
+ || DECL_ARTIFICIAL (base));
+ MEM_READONLY_P (ref) = 1;
+ }
+
/* If this expression uses it's parent's alias set, mark it such
that we won't change it. */
if (component_uses_parent_alias_set (t))
index, low_bound);
off_tree = size_binop (PLUS_EXPR,
- size_binop (MULT_EXPR, convert (sizetype,
- index),
+ size_binop (MULT_EXPR,
+ fold_convert (sizetype,
+ index),
unit_size),
off_tree);
t2 = TREE_OPERAND (t2, 0);
structure. This routine should only be called once. */
static void
-unshare_all_rtl_1 (tree fndecl, rtx insn)
+unshare_all_rtl_1 (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);
{
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_flags (stack_slot_list);
- unshare_all_rtl_1 (cfun->decl, insn);
+ unshare_all_rtl_1 (insn);
}
-void
+unsigned int
unshare_all_rtl (void)
{
- unshare_all_rtl_1 (current_function_decl, get_insns ());
+ unshare_all_rtl_1 (get_insns ());
+ return 0;
}
+struct tree_opt_pass pass_unshare_all_rtl =
+{
+ "unshare", /* name */
+ NULL, /* gate */
+ unshare_all_rtl, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+
/* Check that ORIG is not marked when it should not be and mark ORIG as in use,
Recursively does the same for subexpressions. */
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;
#ifdef ENABLE_CHECKING
if (RTX_FLAG (x, used))
{
- error ("Invalid rtl sharing found in the insn");
+ error ("invalid rtl sharing found in the insn");
debug_rtx (insn);
- error ("Shared rtx");
+ error ("shared rtx");
debug_rtx (x);
- internal_error ("Internal consistency failure");
+ internal_error ("internal consistency failure");
}
#endif
gcc_assert (!RTX_FLAG (x, used));
{
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;
+ rtx q, sequence = PATTERN (p);
+
+ for (i = 0; i < XVECLEN (sequence, 0); i++)
+ {
+ q = XVECEXP (sequence, 0, i);
+ gcc_assert (INSN_P (q));
+ reset_used_flags (PATTERN (q));
+ reset_used_flags (REG_NOTES (q));
+ }
+ }
}
for (p = get_insns (); p; p = NEXT_INSN (p))
{
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 copy any
- shared structure. */
-static void
-unshare_all_decls (tree blk)
-{
- tree t;
-
- /* Copy shared decls. */
- for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
- if (DECL_RTL_SET_P (t))
- SET_DECL_RTL (t, copy_rtx_if_shared (DECL_RTL (t)));
-
- /* Now process sub-blocks. */
- for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
- unshare_all_decls (t);
-}
-
/* Go through all virtual stack slots of a function and mark them as
not shared. */
static void
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;
if (RTX_FLAG (x, used))
{
- rtx copy;
-
- copy = rtx_alloc (code);
- memcpy (copy, x, RTX_SIZE (code));
- x = copy;
+ x = shallow_copy_rtx (x);
copied = 1;
}
RTX_FLAG (x, used) = 1;
continue;
else
{
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
}
continue;
else
{
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0,
XVECLEN (PATTERN (insn), 0) - 1);
{
return cur_insn_uid;
}
-
-/* Renumber instructions so that no instruction UIDs are wasted. */
-
-void
-renumber_insns (FILE *stream)
-{
- rtx insn;
-
- /* If we're not supposed to renumber instructions, don't. */
- if (!flag_renumber_insns)
- return;
-
- /* If there aren't that many instructions, then it's not really
- worth renumbering them. */
- if (flag_renumber_insns == 1 && get_max_uid () < 25000)
- return;
-
- cur_insn_uid = 1;
-
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (stream)
- fprintf (stream, "Renumbering insn %d to %d\n",
- INSN_UID (insn), cur_insn_uid);
- INSN_UID (insn) = cur_insn_uid++;
- }
-}
\f
/* Return the next insn. If it is a SEQUENCE, return the first insn
of the sequence. */
}
#endif
+#ifdef AUTO_INC_DEC
+/* Find a RTX_AUTOINC class rtx which matches DATA. */
+
+static int
+find_auto_inc (rtx *xp, void *data)
+{
+ rtx x = *xp;
+ rtx reg = data;
+
+ if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC)
+ return 0;
+
+ switch (GET_CODE (x))
+ {
+ case PRE_DEC:
+ case PRE_INC:
+ case POST_DEC:
+ case POST_INC:
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ if (rtx_equal_p (reg, XEXP (x, 0)))
+ return 1;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return -1;
+}
+#endif
+
/* Increment the label uses for all labels present in rtx. */
static void
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))
{
switch (REG_NOTE_KIND (note))
{
case REG_EH_REGION:
- insn = insn_last;
- while (insn != NULL_RTX)
+ for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (CALL_P (insn)
|| (flag_non_call_exceptions && INSN_P (insn)
= gen_rtx_EXPR_LIST (REG_EH_REGION,
XEXP (note, 0),
REG_NOTES (insn));
- insn = PREV_INSN (insn);
}
break;
case REG_NORETURN:
case REG_SETJMP:
- insn = insn_last;
- while (insn != NULL_RTX)
+ for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (CALL_P (insn))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (insn));
- insn = PREV_INSN (insn);
}
break;
case REG_NON_LOCAL_GOTO:
- insn = insn_last;
- while (insn != NULL_RTX)
+ for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (JUMP_P (insn))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (insn));
- insn = PREV_INSN (insn);
}
break;
+#ifdef AUTO_INC_DEC
+ case REG_INC:
+ for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
+ {
+ rtx reg = XEXP (note, 0);
+ if (!FIND_REG_INC_NOTE (insn, reg)
+ && for_each_rtx (&PATTERN (insn), find_auto_inc, reg) > 0)
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, reg,
+ REG_NOTES (insn));
+ }
+ break;
+#endif
+
default:
break;
}
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
- INSN_LOCATOR (insn) = 0;
+ INSN_LOCATOR (insn) = curr_insn_locator ();
BLOCK_FOR_INSN (insn) = NULL;
#ifdef ENABLE_RTL_CHECKING
/* Like `make_insn_raw' but make a JUMP_INSN instead of an insn. */
-static rtx
+rtx
make_jump_insn_raw (rtx pattern)
{
rtx insn;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
JUMP_LABEL (insn) = NULL;
- INSN_LOCATOR (insn) = 0;
+ INSN_LOCATOR (insn) = curr_insn_locator ();
BLOCK_FOR_INSN (insn) = NULL;
return insn;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
CALL_INSN_FUNCTION_USAGE (insn) = NULL;
- INSN_LOCATOR (insn) = 0;
+ INSN_LOCATOR (insn) = curr_insn_locator ();
BLOCK_FOR_INSN (insn) = NULL;
return insn;
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);
- }
-}
-
-/* Return the line note insn preceding INSN. */
-
-static rtx
-find_line_note (rtx insn)
-{
- if (no_line_numbers)
- return 0;
-
- for (; insn; insn = PREV_INSN (insn))
- if (NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) >= 0)
- break;
-
- return insn;
-}
-
-/* Remove unnecessary notes from the instruction stream. */
-
-void
-remove_unnecessary_notes (void)
-{
- rtx eh_stack = NULL_RTX;
- rtx insn;
- rtx next;
- rtx tmp;
-
- /* We must not remove the first instruction in the function because
- the compiler depends on the first instruction being a note. */
- for (insn = NEXT_INSN (get_insns ()); insn; insn = next)
- {
- /* Remember what's next. */
- next = NEXT_INSN (insn);
-
- /* We're only interested in notes. */
- if (!NOTE_P (insn))
- continue;
-
- switch (NOTE_LINE_NUMBER (insn))
- {
- case NOTE_INSN_DELETED:
- remove_insn (insn);
- break;
-
- case NOTE_INSN_EH_REGION_BEG:
- eh_stack = alloc_INSN_LIST (insn, eh_stack);
- break;
-
- case NOTE_INSN_EH_REGION_END:
- /* Too many end notes. */
- gcc_assert (eh_stack);
- /* Mismatched nesting. */
- gcc_assert (NOTE_EH_HANDLER (XEXP (eh_stack, 0))
- == NOTE_EH_HANDLER (insn));
- tmp = eh_stack;
- eh_stack = XEXP (eh_stack, 1);
- free_INSN_LIST_node (tmp);
- break;
-
- case NOTE_INSN_BLOCK_BEG:
- case NOTE_INSN_BLOCK_END:
- /* BLOCK_END and BLOCK_BEG notes only exist in the `final' pass. */
- gcc_unreachable ();
-
- default:
- break;
- }
+ {
+ set_block_for_insn (x, bb);
+ df_insn_change_bb (x);
+ }
}
-
- /* Too many EH_REGION_BEG notes. */
- gcc_assert (!eh_stack);
}
\f
/* 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;
}
return last;
}
-/* Similar to emit_insn_after, except that line notes are to be inserted so
- as to act as if this insn were at FROM. */
-
-void
-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_note_copy_after (from_line, after);
-
- if (after_line)
- emit_note_copy_after (after_line, insn);
-}
/* Make an insn of code JUMP_INSN with body X
and output it after the insn AFTER. */
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;
- BLOCK_FOR_INSN (note) = NULL;
- add_insn_after (note, after);
- return note;
-}
-
-/* Emit a copy of note ORIG after the insn AFTER. */
-
-rtx
-emit_note_copy_after (rtx orig, rtx after)
-{
- rtx note;
-
- 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_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig);
- NOTE_DATA (note) = NOTE_DATA (orig);
+ 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;
- first = NEXT_INSN (first);
+ if (!first)
+ first = get_insns ();
+ else
+ first = NEXT_INSN (first);
while (1)
{
if (active_insn_p (first) && !INSN_LOCATOR (first))
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. */
return barrier;
}
-/* 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 (location_t location)
-{
- 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;
- }
-
-#ifdef USE_MAPPED_LOCATION
- note = emit_note ((int) location);
-#else
- note = emit_note (location.line);
- NOTE_SOURCE_FILE (note) = location.file;
-#endif
-
- return note;
-}
-
/* Emit a copy of note ORIG. */
rtx
{
rtx note;
- if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers)
- {
- cur_insn_uid++;
- return NULL_RTX;
- }
-
note = rtx_alloc (NOTE);
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);
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. */
\f
/* Put the various virtual registers into REGNO_REG_RTX. */
-void
+static void
init_virtual_regs (struct emit_status *es)
{
rtx *ptr = es->x_regno_reg_rtx;
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;
break;
}
- copy = rtx_alloc (code);
-
- /* Copy the various flags, and other information. We assume that
- all fields need copying, and then clear the fields that should
+ /* Copy the various flags, fields, and other information. We assume
+ that 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, RTX_HDR_SIZE);
+ copy = shallow_copy_rtx (orig);
/* We do not copy the USED flag, which is used as a mark bit during
walks over the RTL. */
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
- {
- copy->u.fld[i] = orig->u.fld[i];
- switch (*format_ptr++)
- {
- case 'e':
- if (XEXP (orig, i) != NULL)
- XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
- break;
+ switch (*format_ptr++)
+ {
+ case 'e':
+ if (XEXP (orig, i) != NULL)
+ XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
+ break;
- case 'E':
- case 'V':
- if (XVEC (orig, i) == orig_asm_constraints_vector)
- XVEC (copy, i) = copy_asm_constraints_vector;
- else if (XVEC (orig, i) == orig_asm_operands_vector)
- XVEC (copy, i) = copy_asm_operands_vector;
- else if (XVEC (orig, i) != NULL)
- {
- XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
- for (j = 0; j < XVECLEN (copy, i); j++)
- XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
- }
- break;
+ case 'E':
+ case 'V':
+ if (XVEC (orig, i) == orig_asm_constraints_vector)
+ XVEC (copy, i) = copy_asm_constraints_vector;
+ else if (XVEC (orig, i) == orig_asm_operands_vector)
+ XVEC (copy, i) = copy_asm_operands_vector;
+ else if (XVEC (orig, i) != NULL)
+ {
+ XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
+ for (j = 0; j < XVECLEN (copy, i); j++)
+ XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
+ }
+ break;
- case 't':
- case 'w':
- case 'i':
- case 's':
- case 'S':
- case 'u':
- case '0':
- /* These are left unchanged. */
- break;
+ case 't':
+ case 'w':
+ case 'i':
+ case 's':
+ case 'S':
+ case 'u':
+ case '0':
+ /* These are left unchanged. */
+ break;
- default:
- gcc_unreachable ();
- }
- }
+ default:
+ gcc_unreachable ();
+ }
if (code == SCRATCH)
{
units = GET_MODE_NUNITS (mode);
inner = GET_MODE_INNER (mode);
+ gcc_assert (!DECIMAL_FLOAT_MODE_P (inner));
+
v = rtvec_alloc (units);
/* We need to call this function after we set the scalar const_tiny_rtx
word_mode = VOIDmode;
double_mode = VOIDmode;
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT
word_mode = mode;
}
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+ mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
/* 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 (&dconstsqrt2,
+ "1.4142135623730950488016887242096980785696718753769480731766797379907");
real_from_string (&dconste,
"2.7182818284590452353602874713526624977572470936999595749669676277241");
REAL_VALUE_TYPE *r =
(i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2);
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ const_tiny_rtx[i][(int) mode] =
+ CONST_DOUBLE_FROM_REAL_VALUE (*r, mode);
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_DECIMAL_FLOAT);
+ mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[i][(int) mode] =
CONST_DOUBLE_FROM_REAL_VALUE (*r, mode);
const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i);
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
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))
{
if (GET_CODE (link) == EXPR_LIST)
REG_NOTES (new)
- = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
- XEXP (link, 0),
- REG_NOTES (new)));
+ = gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
+ copy_insn_1 (XEXP (link, 0)), REG_NOTES (new));
else
REG_NOTES (new)
- = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
- XEXP (link, 0),
- REG_NOTES (new)));
+ = gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
+ XEXP (link, 0), REG_NOTES (new));
}
/* Fix the libcall sequences. */