enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */
enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */
+/* Datastructures maintained for currently processed function in RTL form. */
+
+struct rtl_data x_rtl;
+
+/* Indexed by pseudo register number, gives the rtx for that pseudo.
+ Allocated in parallel with regno_pointer_align.
+ FIXME: We could put it into emit_status struct, but gengtype is not able to deal
+ with length attribute nested in top level structures. */
+
+rtx * regno_reg_rtx;
/* This is *not* reset after each function. It gives each CODE_LABEL
in the entire compilation a unique label number. */
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)
-#define last_location (cfun->emit->x_last_location)
-#define first_label_num (cfun->emit->x_first_label_num)
+#define first_insn (crtl->emit.x_first_insn)
+#define last_insn (crtl->emit.x_last_insn)
+#define cur_insn_uid (crtl->emit.x_cur_insn_uid)
+#define last_location (crtl->emit.x_last_location)
+#define first_label_num (crtl->emit.x_first_label_num)
static rtx make_call_insn_raw (rtx);
static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
memcpy (*slot, &attrs, sizeof (mem_attrs));
}
- return *slot;
+ return (mem_attrs *) *slot;
}
/* Returns a hash code for X (which is a really a reg_attrs *). */
memcpy (*slot, &attrs, sizeof (reg_attrs));
}
- return *slot;
+ return (reg_attrs *) *slot;
}
{
rtx mem = gen_rtx_MEM (mode, addr);
MEM_NOTRAP_P (mem) = 1;
- if (!current_function_calls_alloca)
+ if (!cfun->calls_alloca)
set_mem_alias_set (mem, get_frame_alias_set ());
return mem;
}
if (n == 0)
return NULL_RTVEC; /* Don't allocate an empty rtvec... */
- vector = alloca (n * sizeof (rtx));
+ vector = XALLOCAVEC (rtx, n);
for (i = 0; i < n; i++)
vector[i] = va_arg (p, rtx);
rtx
gen_reg_rtx (enum machine_mode mode)
{
- struct function *f = cfun;
rtx val;
gcc_assert (can_create_pseudo_p ());
/* Make sure regno_pointer_align, and regno_reg_rtx are large
enough to have an element for this pseudo reg number. */
- if (reg_rtx_no == f->emit->regno_pointer_align_length)
+ if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
{
- int old_size = f->emit->regno_pointer_align_length;
+ int old_size = crtl->emit.regno_pointer_align_length;
char *new;
rtx *new1;
- new = ggc_realloc (f->emit->regno_pointer_align, old_size * 2);
+ new = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
memset (new + old_size, 0, old_size);
- f->emit->regno_pointer_align = (unsigned char *) new;
+ crtl->emit.regno_pointer_align = (unsigned char *) new;
- new1 = ggc_realloc (f->emit->x_regno_reg_rtx,
- old_size * 2 * sizeof (rtx));
+ new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
memset (new1 + old_size, 0, old_size * sizeof (rtx));
regno_reg_rtx = new1;
- f->emit->regno_pointer_align_length = old_size * 2;
+ crtl->emit.regno_pointer_align_length = old_size * 2;
}
val = gen_raw_REG (mode, reg_rtx_no);
{
int offset;
+ /* Hard registers can be reused for multiple purposes within the same
+ function, so setting REG_ATTRS, REG_POINTER and REG_POINTER_ALIGN
+ on them is wrong. */
+ if (HARD_REGISTER_P (reg))
+ return;
+
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 (x), INTVAL (MEM_OFFSET (x)) + offset);
- if (REG_P (x) && REG_ATTRS (x))
- update_reg_offset (reg, x, offset);
+ if (MEM_P (x))
+ {
+ if (MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
+ REG_ATTRS (reg)
+ = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+ if (MEM_POINTER (x))
+ mark_reg_pointer (reg, MEM_ALIGN (x));
+ }
+ else if (REG_P (x))
+ {
+ if (REG_ATTRS (x))
+ update_reg_offset (reg, x, offset);
+ if (REG_POINTER (x))
+ mark_reg_pointer (reg, REGNO_POINTER_ALIGN (REGNO (x)));
+ }
+}
+
+/* Generate a REG rtx for a new pseudo register, copying the mode
+ and attributes from X. */
+
+rtx
+gen_reg_rtx_and_attrs (rtx x)
+{
+ rtx reg = gen_reg_rtx (GET_MODE (x));
+ set_reg_attrs_from_value (reg, x);
+ return reg;
}
/* Set the register attributes for registers contained in PARM_RTX.
/* If the rtx for label was created during the expansion of a nested
function, then first_label_num won't include this label number.
- Fix this now so that array indicies work later. */
+ Fix this now so that array indices work later. */
void
maybe_set_first_label_num (rtx x)
{
/* Now remove any conversions: they don't change what the underlying
object is. Likewise for SAVE_EXPR. */
- while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR
- || TREE_CODE (inner) == NON_LVALUE_EXPR
+ while (CONVERT_EXPR_P (inner)
|| TREE_CODE (inner) == VIEW_CONVERT_EXPR
|| TREE_CODE (inner) == SAVE_EXPR)
inner = TREE_OPERAND (inner, 0);
/* Now remove any conversions: they don't change what the underlying
object is. Likewise for SAVE_EXPR. */
- while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
- || TREE_CODE (t) == NON_LVALUE_EXPR
+ while (CONVERT_EXPR_P (t)
|| TREE_CODE (t) == VIEW_CONVERT_EXPR
|| TREE_CODE (t) == SAVE_EXPR)
t = TREE_OPERAND (t, 0);
}
/* If this is a field reference and not a bit-field, record it. */
- /* ??? There is some information that can be gleened from bit-fields,
+ /* ??? There is some information that can be gleaned from bit-fields,
such as the word offset in the structure that might be modified.
But skip it for now. */
else if (TREE_CODE (t) == COMPONENT_REF
if (TREE_CODE (t) == ALIGN_INDIRECT_REF)
{
- /* Force EXPR and OFFSE to NULL, since we don't know exactly what
+ /* Force EXPR and OFFSET to NULL, since we don't know exactly what
we're overlapping. */
offset = NULL;
expr = NULL;
/* Return a memory reference like MEMREF, but with its mode changed
to MODE and its address changed to ADDR, which is assumed to be
- MEMREF offseted by OFFSET bytes. If VALIDATE is
+ MEMREF offset by OFFSET bytes. If VALIDATE is
nonzero, the memory address is forced to be valid. */
rtx
if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
- REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn,
- REG_NOTES (user));
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
+ add_reg_note (user, REG_CC_SETTER, insn);
+ add_reg_note (insn, REG_CC_USER, user);
}
/* Return the next insn that uses CC0 after INSN, which is assumed to
find_auto_inc (rtx *xp, void *data)
{
rtx x = *xp;
- rtx reg = data;
+ rtx reg = (rtx) data;
if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC)
return 0;
rtx before = PREV_INSN (trial);
rtx after = NEXT_INSN (trial);
int has_barrier = 0;
- rtx tem, note_retval, note_libcall;
- rtx note, seq;
+ rtx note, seq, tem;
int probability;
rtx insn_last, insn;
int njumps = 0;
is responsible for this step using
split_branch_probability variable. */
gcc_assert (njumps == 1);
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_BR_PROB,
- GEN_INT (probability),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_BR_PROB, GEN_INT (probability));
}
}
}
if (CALL_P (insn)
|| (flag_non_call_exceptions && INSN_P (insn)
&& may_trap_p (PATTERN (insn))))
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_EH_REGION,
- XEXP (note, 0),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_EH_REGION, XEXP (note, 0));
}
break;
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));
+ add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
}
break;
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));
+ add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
}
break;
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));
+ add_reg_note (insn, REG_INC, reg);
}
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;
}
return note;
}
+/* Emit a clobber of lvalue X. */
+
+rtx
+emit_clobber (rtx x)
+{
+ /* CONCATs should not appear in the insn stream. */
+ if (GET_CODE (x) == CONCAT)
+ {
+ emit_clobber (XEXP (x, 0));
+ return emit_clobber (XEXP (x, 1));
+ }
+ return emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+}
+
+/* Return a sequence of insns to clobber lvalue X. */
+
+rtx
+gen_clobber (rtx x)
+{
+ rtx seq;
+
+ start_sequence ();
+ emit_clobber (x);
+ seq = get_insns ();
+ end_sequence ();
+ return seq;
+}
+
+/* Emit a use of rvalue X. */
+
+rtx
+emit_use (rtx x)
+{
+ /* CONCATs should not appear in the insn stream. */
+ if (GET_CODE (x) == CONCAT)
+ {
+ emit_use (XEXP (x, 0));
+ return emit_use (XEXP (x, 1));
+ }
+ return emit_insn (gen_rtx_USE (VOIDmode, x));
+}
+
+/* Return a sequence of insns to use rvalue X. */
+
+rtx
+gen_use (rtx x)
+{
+ rtx seq;
+
+ start_sequence ();
+ emit_use (x);
+ seq = get_insns ();
+ end_sequence ();
+ return seq;
+}
+
/* Cause next statement to emit a line note even if the line number
has not changed. */
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)
{
break;
}
- new_note = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
- REG_NOTES (insn) = new_note;
+ add_reg_note (insn, kind, datum);
switch (kind)
{
free_sequence_stack = tem->next;
}
else
- tem = ggc_alloc (sizeof (struct sequence_stack));
+ tem = GGC_NEW (struct sequence_stack);
tem->next = seq_stack;
tem->first = first_insn;
/* Put the various virtual registers into REGNO_REG_RTX. */
static void
-init_virtual_regs (struct emit_status *es)
+init_virtual_regs (void)
{
- rtx *ptr = es->x_regno_reg_rtx;
- ptr[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
- ptr[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
- ptr[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
- ptr[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
- ptr[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
+ regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
+ regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
+ regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
+ regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
+ regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
}
\f
void
init_emit (void)
{
- struct function *f = cfun;
-
- f->emit = ggc_alloc (sizeof (struct emit_status));
first_insn = NULL;
last_insn = NULL;
cur_insn_uid = 1;
/* Init the tables that describe all the pseudo regs. */
- f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
+ crtl->emit.regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
- f->emit->regno_pointer_align
- = ggc_alloc_cleared (f->emit->regno_pointer_align_length
- * sizeof (unsigned char));
+ crtl->emit.regno_pointer_align
+ = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
regno_reg_rtx
- = ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx));
+ = GGC_NEWVEC (rtx, crtl->emit.regno_pointer_align_length);
/* Put copies of all the hard registers into regno_reg_rtx. */
memcpy (regno_reg_rtx,
FIRST_PSEUDO_REGISTER * sizeof (rtx));
/* Put copies of all the virtual register rtx into regno_reg_rtx. */
- init_virtual_regs (f->emit);
+ init_virtual_regs ();
/* Indicate that the virtual registers and stack locations are
all pointers. */
rtx
emit_copy_of_insn_after (rtx insn, rtx after)
{
- rtx new;
- rtx note1, note2, link;
+ rtx new, link;
switch (GET_CODE (insn))
{
CALL_INSN_FUNCTION_USAGE (new)
= copy_insn (CALL_INSN_FUNCTION_USAGE (insn));
SIBLING_CALL_P (new) = SIBLING_CALL_P (insn);
- CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn);
+ RTL_CONST_CALL_P (new) = RTL_CONST_CALL_P (insn);
+ RTL_PURE_CALL_P (new) = RTL_PURE_CALL_P (insn);
+ RTL_LOOPING_CONST_OR_PURE_CALL_P (new)
+ = RTL_LOOPING_CONST_OR_PURE_CALL_P (insn);
break;
default:
if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
{
if (GET_CODE (link) == EXPR_LIST)
- REG_NOTES (new)
- = gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
- copy_insn_1 (XEXP (link, 0)), REG_NOTES (new));
+ add_reg_note (new, REG_NOTE_KIND (link),
+ copy_insn_1 (XEXP (link, 0)));
else
- REG_NOTES (new)
- = gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
- XEXP (link, 0), REG_NOTES (new));
+ add_reg_note (new, REG_NOTE_KIND (link), XEXP (link, 0));
}
- /* Fix the libcall sequences. */
- if ((note1 = find_reg_note (new, REG_RETVAL, NULL_RTX)) != NULL)
- {
- rtx p = new;
- while ((note2 = find_reg_note (p, REG_LIBCALL, NULL_RTX)) == NULL)
- p = PREV_INSN (p);
- XEXP (note1, 0) = p;
- XEXP (note2, 0) = new;
- }
INSN_CODE (new) = INSN_CODE (insn);
return new;
}