/* 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.
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 *);
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
mem_attrs *p = (mem_attrs *) x;
mem_attrs *q = (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
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. */
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 (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 =
{
- NULL, /* name */
+ "unshare", /* name */
NULL, /* gate */
unshare_all_rtl, /* execute */
NULL, /* sub */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
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));
+ reset_used_flags (LOG_LINKS (q));
+ }
+ }
}
for (p = get_insns (); p; p = NEXT_INSN (p))
}
}
-/* 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
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;
{
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
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_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;
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;
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;
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;
}
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;
}
}
-/* 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;
- }
- }
-
- /* Too many EH_REGION_BEG notes. */
- gcc_assert (!eh_stack);
-}
-
-struct tree_opt_pass pass_remove_unnecessary_notes =
-{
- NULL, /* name */
- NULL, /* gate */
- remove_unnecessary_notes, /* 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 */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};
-
\f
/* Emit insn(s) of given code and pattern
at a specified place within the doubly-linked list.
/* 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);
return note;
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. */
/* 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;
+ memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
add_insn_after (note, after);
return note;
}
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))
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);
\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;
}
- 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);
{
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. */