/* Expands front end tree to back end RTL for GCC.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "integrate.h"
#include "langhooks.h"
#include "target.h"
-
-#ifndef TRAMPOLINE_ALIGNMENT
-#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
-#endif
+#include "cfglayout.h"
#ifndef LOCAL_ALIGNMENT
#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
post-instantiation libcalls. */
int virtuals_instantiated;
-/* Nonzero if at least one trampoline has been created. */
-int trampolines_created;
-
/* Assign unique numbers to labels generated for profiling, debugging, etc. */
static GTY(()) int funcdef_no;
target specific, per-function data structures. */
struct machine_function * (*init_machine_status) (void);
-/* The FUNCTION_DECL for an inline function currently being expanded. */
-tree inline_function_decl;
-
/* The currently compiled function. */
struct function *cfun = 0;
{
/* Points to next temporary slot. */
struct temp_slot *next;
+ /* Points to previous temporary slot. */
+ struct temp_slot *prev;
+
/* The rtx to used to reference the slot. */
rtx slot;
/* The rtx used to represent the address if not the address of the
struct function *);
static struct temp_slot *find_temp_slot_from_address (rtx);
static void put_reg_into_stack (struct function *, rtx, tree, enum machine_mode,
- enum machine_mode, int, unsigned int, int, htab_t);
+ unsigned int, bool, bool, bool, htab_t);
static void schedule_fixup_var_refs (struct function *, rtx, tree, enum machine_mode,
htab_t);
static void fixup_var_refs (rtx, enum machine_mode, int, rtx, htab_t);
static void fixup_var_refs_1 (rtx, enum machine_mode, rtx *, rtx,
struct fixup_replacement **, rtx);
static rtx fixup_memory_subreg (rtx, rtx, enum machine_mode, int);
-static rtx walk_fixup_memory_subreg (rtx, rtx, enum machine_mode, int);
+static rtx walk_fixup_memory_subreg (rtx, rtx, rtx, enum machine_mode, int);
static rtx fixup_stack_1 (rtx, rtx);
static void optimize_bit_field (rtx, rtx, rtx *);
static void instantiate_decls (tree, int);
static void instantiate_decl (rtx, HOST_WIDE_INT, int);
static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *);
static int instantiate_virtual_regs_1 (rtx *, rtx, int);
-static void delete_handlers (void);
static void pad_to_arg_alignment (struct args_size *, int, struct args_size *);
static void pad_below (struct args_size *, enum machine_mode, tree);
-static rtx round_trampoline_addr (rtx);
-static rtx adjust_trampoline_addr (rtx);
-static tree *identify_blocks_1 (rtx, tree *, tree *, tree *);
-static void reorder_blocks_0 (tree);
static void reorder_blocks_1 (rtx, tree, varray_type *);
static void reorder_fix_fragments (tree);
-static tree blocks_nreverse (tree);
static int all_blocks (tree, tree *);
static tree *get_block_vector (tree, int *);
extern tree debug_find_var_in_block_tree (tree, tree);
-/* We always define `record_insns' even if its not used so that we
+/* We always define `record_insns' even if it's not used so that we
can always export `prologue_epilogue_contains'. */
static void record_insns (rtx, varray_type *) ATTRIBUTE_UNUSED;
static int contains (rtx, varray_type);
outer_function_chain = p;
p->fixup_var_refs_queue = 0;
- (*lang_hooks.function.enter_nested) (p);
+ lang_hooks.function.enter_nested (p);
cfun = 0;
}
restore_emit_status (p);
- (*lang_hooks.function.leave_nested) (p);
+ lang_hooks.function.leave_nested (p);
/* Finish doing put_var_into_stack for any of our variables which became
addressable during the nested function. If only one entry has to be
/* f->varasm is used by code generation. */
/* f->eh->eh_return_stub_label is used by code generation. */
- (*lang_hooks.function.final) (f);
+ lang_hooks.function.final (f);
f->stmt = NULL;
}
f->varasm = NULL;
f->machine = NULL;
- f->x_temp_slots = NULL;
+ f->x_avail_temp_slots = NULL;
+ f->x_used_temp_slots = NULL;
f->arg_offset_rtx = NULL;
f->return_rtx = NULL;
f->internal_arg_pointer = NULL;
- f->x_nonlocal_labels = NULL;
- f->x_nonlocal_goto_handler_slots = NULL;
f->x_nonlocal_goto_handler_labels = NULL;
- f->x_nonlocal_goto_stack_level = NULL;
- f->x_cleanup_label = NULL;
f->x_return_label = NULL;
f->x_naked_return_label = NULL;
- f->computed_goto_common_label = NULL;
- f->computed_goto_common_reg = NULL;
f->x_save_expr_regs = NULL;
f->x_stack_slot_list = NULL;
f->x_rtl_expr_chain = NULL;
- f->x_tail_recursion_label = NULL;
f->x_tail_recursion_reentry = NULL;
f->x_arg_pointer_save_area = NULL;
- f->x_clobber_return_insn = NULL;
- f->x_context_display = NULL;
- f->x_trampoline_list = NULL;
f->x_parm_birth_insn = NULL;
- f->x_last_parm_insn = NULL;
f->x_parm_reg_stack_loc = NULL;
f->fixup_var_refs_queue = NULL;
f->original_arg_vector = NULL;
f->original_decl_initial = NULL;
- f->inl_last_parm_insn = NULL;
f->epilogue_delay_list = NULL;
}
\f
ALIGN controls the amount of alignment for the address of the slot:
0 means according to MODE,
-1 means use BIGGEST_ALIGNMENT and round size to multiple of that,
+ -2 means use BITS_PER_UNIT,
positive specifies alignment boundary in bits.
We do not round to stack_boundary here.
/* Allow the target to (possibly) increase the alignment of this
stack slot. */
- type = (*lang_hooks.types.type_for_mode) (mode, 0);
+ type = lang_hooks.types.type_for_mode (mode, 0);
if (type)
alignment = LOCAL_ALIGNMENT (type, alignment);
alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
size = CEIL_ROUND (size, alignment);
}
+ else if (align == -2)
+ alignment = 1; /* BITS_PER_UNIT / BITS_PER_UNIT */
else
alignment = align / BITS_PER_UNIT;
{
return assign_stack_local_1 (mode, size, align, cfun);
}
+
+\f
+/* Removes temporary slot TEMP from LIST. */
+
+static void
+cut_slot_from_list (struct temp_slot *temp, struct temp_slot **list)
+{
+ if (temp->next)
+ temp->next->prev = temp->prev;
+ if (temp->prev)
+ temp->prev->next = temp->next;
+ else
+ *list = temp->next;
+
+ temp->prev = temp->next = NULL;
+}
+
+/* Inserts temporary slot TEMP to LIST. */
+
+static void
+insert_slot_to_list (struct temp_slot *temp, struct temp_slot **list)
+{
+ temp->next = *list;
+ if (*list)
+ (*list)->prev = temp;
+ temp->prev = NULL;
+ *list = temp;
+}
+
+/* Returns the list of used temp slots at LEVEL. */
+
+static struct temp_slot **
+temp_slots_at_level (int level)
+{
+ level++;
+
+ if (!used_temp_slots)
+ VARRAY_GENERIC_PTR_INIT (used_temp_slots, 3, "used_temp_slots");
+
+ while (level >= (int) VARRAY_ACTIVE_SIZE (used_temp_slots))
+ VARRAY_PUSH_GENERIC_PTR (used_temp_slots, NULL);
+
+ return (struct temp_slot **) &VARRAY_GENERIC_PTR (used_temp_slots, level);
+}
+
+/* Returns the maximal temporary slot level. */
+
+static int
+max_slot_level (void)
+{
+ if (!used_temp_slots)
+ return -1;
+
+ return VARRAY_ACTIVE_SIZE (used_temp_slots) - 1;
+}
+
+/* Moves temporary slot TEMP to LEVEL. */
+
+static void
+move_slot_to_level (struct temp_slot *temp, int level)
+{
+ cut_slot_from_list (temp, temp_slots_at_level (temp->level));
+ insert_slot_to_list (temp, temp_slots_at_level (level));
+ temp->level = level;
+}
+
+/* Make temporary slot TEMP available. */
+
+static void
+make_slot_available (struct temp_slot *temp)
+{
+ cut_slot_from_list (temp, temp_slots_at_level (temp->level));
+ insert_slot_to_list (temp, &avail_temp_slots);
+ temp->in_use = 0;
+ temp->level = -1;
+}
\f
/* Allocate a temporary stack slot and record it for possible later
reuse.
tree type)
{
unsigned int align;
- struct temp_slot *p, *best_p = 0;
+ struct temp_slot *p, *best_p = 0, *selected = NULL, **pp;
rtx slot;
/* If SIZE is -1 it means that somebody tried to allocate a temporary
align = GET_MODE_ALIGNMENT (mode);
if (! type)
- type = (*lang_hooks.types.type_for_mode) (mode, 0);
+ type = lang_hooks.types.type_for_mode (mode, 0);
if (type)
align = LOCAL_ALIGNMENT (type, align);
/* Try to find an available, already-allocated temporary of the proper
mode which meets the size and alignment requirements. Choose the
smallest one with the closest alignment. */
- for (p = temp_slots; p; p = p->next)
- if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
- && ! p->in_use
- && objects_must_conflict_p (p->type, type)
- && (best_p == 0 || best_p->size > p->size
- || (best_p->size == p->size && best_p->align > p->align)))
- {
- if (p->align == align && p->size == size)
- {
- best_p = 0;
- break;
- }
- best_p = p;
- }
+ for (p = avail_temp_slots; p; p = p->next)
+ {
+ if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
+ && objects_must_conflict_p (p->type, type)
+ && (best_p == 0 || best_p->size > p->size
+ || (best_p->size == p->size && best_p->align > p->align)))
+ {
+ if (p->align == align && p->size == size)
+ {
+ selected = p;
+ cut_slot_from_list (selected, &avail_temp_slots);
+ best_p = 0;
+ break;
+ }
+ best_p = p;
+ }
+ }
/* Make our best, if any, the one to use. */
if (best_p)
{
+ selected = best_p;
+ cut_slot_from_list (selected, &avail_temp_slots);
+
/* If there are enough aligned bytes left over, make them into a new
temp_slot so that the extra bytes don't get wasted. Do this only
for BLKmode slots, so that we can be sure of the alignment. */
p->address = 0;
p->rtl_expr = 0;
p->type = best_p->type;
- p->next = temp_slots;
- temp_slots = p;
+ insert_slot_to_list (p, &avail_temp_slots);
stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot,
stack_slot_list);
best_p->full_size = rounded_size;
}
}
-
- p = best_p;
}
/* If we still didn't find one, make a new temporary. */
- if (p == 0)
+ if (selected == 0)
{
HOST_WIDE_INT frame_offset_old = frame_offset;
p->full_size = frame_offset - frame_offset_old;
#endif
p->address = 0;
- p->next = temp_slots;
- temp_slots = p;
+
+ selected = p;
}
+ p = selected;
p->in_use = 1;
p->addr_taken = 0;
p->rtl_expr = seq_rtl_expr;
if (keep == 2)
{
p->level = target_temp_slot_level;
- p->keep = 0;
+ p->keep = 1;
}
else if (keep == 3)
{
p->keep = keep;
}
+ pp = temp_slots_at_level (p->level);
+ insert_slot_to_list (p, pp);
/* Create a new MEM rtx to avoid clobbering MEM flags of old slots. */
slot = gen_rtx_MEM (mode, XEXP (p->slot, 0));
{
tree type, decl;
enum machine_mode mode;
-#ifndef PROMOTE_FOR_CALL_ONLY
+#ifdef PROMOTE_MODE
int unsignedp;
#endif
decl = NULL, type = type_or_decl;
mode = TYPE_MODE (type);
-#ifndef PROMOTE_FOR_CALL_ONLY
- unsignedp = TREE_UNSIGNED (type);
+#ifdef PROMOTE_MODE
+ unsignedp = TYPE_UNSIGNED (type);
#endif
if (mode == BLKmode || memory_required)
return tmp;
}
-#ifndef PROMOTE_FOR_CALL_ONLY
+#ifdef PROMOTE_MODE
if (! dont_promote)
mode = promote_mode (type, mode, &unsignedp, 0);
#endif
void
combine_temp_slots (void)
{
- struct temp_slot *p, *q;
- struct temp_slot *prev_p, *prev_q;
+ struct temp_slot *p, *q, *next, *next_q;
int num_slots;
/* We can't combine slots, because the information about which slot
/* If there are a lot of temp slots, don't do anything unless
high levels of optimization. */
if (! flag_expensive_optimizations)
- for (p = temp_slots, num_slots = 0; p; p = p->next, num_slots++)
+ for (p = avail_temp_slots, num_slots = 0; p; p = p->next, num_slots++)
if (num_slots > 100 || (num_slots > 10 && optimize == 0))
return;
- for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots)
+ for (p = avail_temp_slots; p; p = next)
{
int delete_p = 0;
- if (! p->in_use && GET_MODE (p->slot) == BLKmode)
- for (q = p->next, prev_q = p; q; q = prev_q->next)
- {
- int delete_q = 0;
- if (! q->in_use && GET_MODE (q->slot) == BLKmode)
- {
- if (p->base_offset + p->full_size == q->base_offset)
- {
- /* Q comes after P; combine Q into P. */
- p->size += q->size;
- p->full_size += q->full_size;
- delete_q = 1;
- }
- else if (q->base_offset + q->full_size == p->base_offset)
- {
- /* P comes after Q; combine P into Q. */
- q->size += p->size;
- q->full_size += p->full_size;
- delete_p = 1;
- break;
- }
- }
- /* Either delete Q or advance past it. */
- if (delete_q)
- prev_q->next = q->next;
- else
- prev_q = q;
- }
- /* Either delete P or advance past it. */
- if (delete_p)
+ next = p->next;
+
+ if (GET_MODE (p->slot) != BLKmode)
+ continue;
+
+ for (q = p->next; q; q = next_q)
{
- if (prev_p)
- prev_p->next = p->next;
- else
- temp_slots = p->next;
+ int delete_q = 0;
+
+ next_q = q->next;
+
+ if (GET_MODE (q->slot) != BLKmode)
+ continue;
+
+ if (p->base_offset + p->full_size == q->base_offset)
+ {
+ /* Q comes after P; combine Q into P. */
+ p->size += q->size;
+ p->full_size += q->full_size;
+ delete_q = 1;
+ }
+ else if (q->base_offset + q->full_size == p->base_offset)
+ {
+ /* P comes after Q; combine P into Q. */
+ q->size += p->size;
+ q->full_size += p->full_size;
+ delete_p = 1;
+ break;
+ }
+ if (delete_q)
+ cut_slot_from_list (q, &avail_temp_slots);
}
- else
- prev_p = p;
+
+ /* Either delete P or advance past it. */
+ if (delete_p)
+ cut_slot_from_list (p, &avail_temp_slots);
}
}
\f
{
struct temp_slot *p;
rtx next;
+ int i;
- for (p = temp_slots; p; p = p->next)
- {
- if (! p->in_use)
- continue;
-
- else if (XEXP (p->slot, 0) == x
- || p->address == x
- || (GET_CODE (x) == PLUS
- && XEXP (x, 0) == virtual_stack_vars_rtx
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) >= p->base_offset
- && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))
- return p;
-
- else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)
- for (next = p->address; next; next = XEXP (next, 1))
- if (XEXP (next, 0) == x)
- return p;
- }
+ for (i = max_slot_level (); i >= 0; i--)
+ for (p = *temp_slots_at_level (i); p; p = p->next)
+ {
+ if (XEXP (p->slot, 0) == x
+ || p->address == x
+ || (GET_CODE (x) == PLUS
+ && XEXP (x, 0) == virtual_stack_vars_rtx
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) >= p->base_offset
+ && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))
+ return p;
+
+ else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)
+ for (next = p->address; next; next = XEXP (next, 1))
+ if (XEXP (next, 0) == x)
+ return p;
+ }
/* If we have a sum involving a register, see if it points to a temp
slot. */
- if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG
+ if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
&& (p = find_temp_slot_from_address (XEXP (x, 0))) != 0)
return p;
- else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG
+ else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 1))
&& (p = find_temp_slot_from_address (XEXP (x, 1))) != 0)
return p;
if (GET_CODE (old) != PLUS)
return;
- if (GET_CODE (new) == REG)
+ if (REG_P (new))
{
update_temp_slot_address (XEXP (old, 0), new);
update_temp_slot_address (XEXP (old, 1), new);
/* If X is not in memory or is at a constant address, it cannot be in
a temporary slot. */
- if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
+ if (!MEM_P (x) || CONSTANT_P (XEXP (x, 0)))
return;
p = find_temp_slot_from_address (XEXP (x, 0));
void
preserve_temp_slots (rtx x)
{
- struct temp_slot *p = 0;
+ struct temp_slot *p = 0, *next;
/* If there is no result, we still might have some objects whose address
were taken, so we need to make sure they stay around. */
if (x == 0)
{
- for (p = temp_slots; p; p = p->next)
- if (p->in_use && p->level == temp_slot_level && p->addr_taken)
- p->level--;
+ for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+ {
+ next = p->next;
+
+ if (p->addr_taken)
+ move_slot_to_level (p, temp_slot_level - 1);
+ }
return;
}
a temporary slot we know it points to. To be consistent with
the code below, we really should preserve all non-kept slots
if we can't find a match, but that seems to be much too costly. */
- if (GET_CODE (x) == REG && REG_POINTER (x))
+ if (REG_P (x) && REG_POINTER (x))
p = find_temp_slot_from_address (x);
/* If X is not in memory or is at a constant address, it cannot be in
a temporary slot, but it can contain something whose address was
taken. */
- if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))))
+ if (p == 0 && (!MEM_P (x) || CONSTANT_P (XEXP (x, 0))))
{
- for (p = temp_slots; p; p = p->next)
- if (p->in_use && p->level == temp_slot_level && p->addr_taken)
- p->level--;
+ for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+ {
+ next = p->next;
+
+ if (p->addr_taken)
+ move_slot_to_level (p, temp_slot_level - 1);
+ }
return;
}
if (p->level == temp_slot_level)
{
- for (q = temp_slots; q; q = q->next)
- if (q != p && q->addr_taken && q->level == p->level)
- q->level--;
+ for (q = *temp_slots_at_level (temp_slot_level); q; q = next)
+ {
+ next = q->next;
+
+ if (p != q && q->addr_taken)
+ move_slot_to_level (q, temp_slot_level - 1);
+ }
- p->level--;
+ move_slot_to_level (p, temp_slot_level - 1);
p->addr_taken = 0;
}
return;
}
/* Otherwise, preserve all non-kept slots at this level. */
- for (p = temp_slots; p; p = p->next)
- if (p->in_use && p->level == temp_slot_level && ! p->keep)
- p->level--;
+ for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+ {
+ next = p->next;
+
+ if (!p->keep)
+ move_slot_to_level (p, temp_slot_level - 1);
+ }
}
/* X is the result of an RTL_EXPR. If it is a temporary slot associated
/* If X is not in memory or is at a constant address, it cannot be in
a temporary slot. */
- if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
+ if (x == 0 || !MEM_P (x) || CONSTANT_P (XEXP (x, 0)))
return;
/* If we can find a match, move it to our level unless it is already at
p = find_temp_slot_from_address (XEXP (x, 0));
if (p != 0)
{
- p->level = MIN (p->level, temp_slot_level);
+ move_slot_to_level (p, MIN (p->level, temp_slot_level));
p->rtl_expr = 0;
}
void
free_temp_slots (void)
{
- struct temp_slot *p;
+ struct temp_slot *p, *next;
+
+ for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+ {
+ next = p->next;
- for (p = temp_slots; p; p = p->next)
- if (p->in_use && p->level == temp_slot_level && ! p->keep
- && p->rtl_expr == 0)
- p->in_use = 0;
+ if (!p->keep && p->rtl_expr == 0)
+ make_slot_available (p);
+ }
combine_temp_slots ();
}
void
free_temps_for_rtl_expr (tree t)
{
- struct temp_slot *p;
-
- for (p = temp_slots; p; p = p->next)
- if (p->rtl_expr == t)
- {
- /* If this slot is below the current TEMP_SLOT_LEVEL, then it
- needs to be preserved. This can happen if a temporary in
- the RTL_EXPR was addressed; preserve_temp_slots will move
- the temporary into a higher level. */
- if (temp_slot_level <= p->level)
- p->in_use = 0;
- else
- p->rtl_expr = NULL_TREE;
- }
-
- combine_temp_slots ();
-}
-
-/* Mark all temporaries ever allocated in this function as not suitable
- for reuse until the current level is exited. */
-
-void
-mark_all_temps_used (void)
-{
- struct temp_slot *p;
+ struct temp_slot *p, *next;
- for (p = temp_slots; p; p = p->next)
+ for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
{
- p->in_use = p->keep = 1;
- p->level = MIN (p->level, temp_slot_level);
+ next = p->next;
+
+ if (p->rtl_expr == t)
+ {
+ /* If this slot is below the current TEMP_SLOT_LEVEL, then it
+ needs to be preserved. This can happen if a temporary in
+ the RTL_EXPR was addressed; preserve_temp_slots will move
+ the temporary into a higher level. */
+ if (temp_slot_level <= p->level)
+ make_slot_available (p);
+ else
+ p->rtl_expr = NULL_TREE;
+ }
}
+
+ combine_temp_slots ();
}
/* Push deeper into the nesting level for stack temporaries. */
void
pop_temp_slots (void)
{
- struct temp_slot *p;
+ struct temp_slot *p, *next;
- for (p = temp_slots; p; p = p->next)
- if (p->in_use && p->level == temp_slot_level && p->rtl_expr == 0)
- p->in_use = 0;
+ for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+ {
+ next = p->next;
+
+ if (p->rtl_expr == 0)
+ make_slot_available (p);
+ }
combine_temp_slots ();
init_temp_slots (void)
{
/* We have not allocated any temporaries yet. */
- temp_slots = 0;
+ avail_temp_slots = 0;
+ used_temp_slots = 0;
temp_slot_level = 0;
var_temp_slot_level = 0;
target_temp_slot_level = 0;
void
put_var_into_stack (tree decl, int rescan)
{
- rtx reg;
+ rtx orig_reg, reg;
enum machine_mode promoted_mode, decl_mode;
struct function *function = 0;
tree context;
- int can_use_addressof;
- int volatilep = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
- int usedp = (TREE_USED (decl)
+ bool can_use_addressof_p;
+ bool volatile_p = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
+ bool used_p = (TREE_USED (decl)
|| (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
context = decl_function_context (decl);
/* Get the current rtl used for this object and its original mode. */
- reg = (TREE_CODE (decl) == SAVE_EXPR
- ? SAVE_EXPR_RTL (decl)
- : DECL_RTL_IF_SET (decl));
+ orig_reg = reg = (TREE_CODE (decl) == SAVE_EXPR
+ ? SAVE_EXPR_RTL (decl)
+ : DECL_RTL_IF_SET (decl));
/* No need to do anything if decl has no rtx yet
since in that case caller is setting TREE_ADDRESSABLE
because it might not be in any active function.
FIXME: Is that really supposed to happen?
It does in ObjC at least. */
- if (context != current_function_decl && context != inline_function_decl)
+ if (context != current_function_decl)
for (function = outer_function_chain; function; function = function->outer)
if (function->decl == context)
break;
reference, with a pseudo to address it, put that pseudo into the stack
if the var is non-local. */
if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)
- && GET_CODE (reg) == MEM
- && GET_CODE (XEXP (reg, 0)) == REG
+ && MEM_P (reg)
+ && REG_P (XEXP (reg, 0))
&& REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
{
- reg = XEXP (reg, 0);
+ orig_reg = reg = XEXP (reg, 0);
decl_mode = promoted_mode = GET_MODE (reg);
}
/* If this variable lives in the current function and we don't need to put it
in the stack for the sake of setjmp or the non-locality, try to keep it in
a register until we know we actually need the address. */
- can_use_addressof
+ can_use_addressof_p
= (function == 0
&& ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl))
&& optimize > 0
/* If we can't use ADDRESSOF, make sure we see through one we already
generated. */
- if (! can_use_addressof && GET_CODE (reg) == MEM
+ if (! can_use_addressof_p
+ && MEM_P (reg)
&& GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
reg = XEXP (XEXP (reg, 0), 0);
/* Now we should have a value that resides in one or more pseudo regs. */
- if (GET_CODE (reg) == REG)
+ if (REG_P (reg))
{
- if (can_use_addressof)
+ if (can_use_addressof_p)
gen_mem_addressof (reg, decl, rescan);
else
- put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
- decl_mode, volatilep, 0, usedp, 0);
+ put_reg_into_stack (function, reg, TREE_TYPE (decl), decl_mode,
+ 0, volatile_p, used_p, false, 0);
+
+ /* If this was previously a MEM but we've removed the ADDRESSOF,
+ set this address into that MEM so we always use the same
+ rtx for this variable. */
+ if (orig_reg != reg && MEM_P (orig_reg))
+ XEXP (orig_reg, 0) = XEXP (reg, 0);
}
else if (GET_CODE (reg) == CONCAT)
{
to the whole CONCAT, lest we do double fixups for the latter
references. */
enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
- tree part_type = (*lang_hooks.types.type_for_mode) (part_mode, 0);
+ tree part_type = lang_hooks.types.type_for_mode (part_mode, 0);
rtx lopart = XEXP (reg, 0);
rtx hipart = XEXP (reg, 1);
#ifdef FRAME_GROWS_DOWNWARD
/* Since part 0 should have a lower address, do it second. */
put_reg_into_stack (function, hipart, part_type, part_mode,
- part_mode, volatilep, 0, 0, 0);
+ 0, volatile_p, false, false, 0);
put_reg_into_stack (function, lopart, part_type, part_mode,
- part_mode, volatilep, 0, 0, 0);
+ 0, volatile_p, false, true, 0);
#else
put_reg_into_stack (function, lopart, part_type, part_mode,
- part_mode, volatilep, 0, 0, 0);
+ 0, volatile_p, false, false, 0);
put_reg_into_stack (function, hipart, part_type, part_mode,
- part_mode, volatilep, 0, 0, 0);
+ 0, volatile_p, false, true, 0);
#endif
/* Change the CONCAT into a combined MEM for both parts. */
/* Prevent sharing of rtl that might lose. */
if (GET_CODE (XEXP (reg, 0)) == PLUS)
XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
- if (usedp && rescan)
+ if (used_p && rescan)
{
schedule_fixup_var_refs (function, reg, TREE_TYPE (decl),
promoted_mode, 0);
/* Subroutine of put_var_into_stack. This puts a single pseudo reg REG
into the stack frame of FUNCTION (0 means the current function).
+ TYPE is the user-level data type of the value hold in the register.
DECL_MODE is the machine mode of the user-level data type.
- PROMOTED_MODE is the machine mode of the register.
- VOLATILE_P is nonzero if this is for a "volatile" decl.
- USED_P is nonzero if this reg might have already been used in an insn. */
+ ORIGINAL_REGNO must be set if the real regno is not visible in REG.
+ VOLATILE_P is true if this is for a "volatile" decl.
+ USED_P is true if this reg might have already been used in an insn.
+ CONSECUTIVE_P is true if the stack slot assigned to reg must be
+ consecutive with the previous stack slot. */
static void
put_reg_into_stack (struct function *function, rtx reg, tree type,
- enum machine_mode promoted_mode, enum machine_mode decl_mode,
- int volatile_p, unsigned int original_regno, int used_p, htab_t ht)
+ enum machine_mode decl_mode, unsigned int original_regno,
+ bool volatile_p, bool used_p, bool consecutive_p,
+ htab_t ht)
{
struct function *func = function ? function : cfun;
- rtx new = 0;
+ enum machine_mode mode = GET_MODE (reg);
unsigned int regno = original_regno;
+ rtx new = 0;
if (regno == 0)
regno = REGNO (reg);
if (regno < func->x_max_parm_reg)
- new = func->x_parm_reg_stack_loc[regno];
+ {
+ if (!func->x_parm_reg_stack_loc)
+ abort ();
+ new = func->x_parm_reg_stack_loc[regno];
+ }
if (new == 0)
- new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func);
+ new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode),
+ consecutive_p ? -2 : 0, func);
PUT_CODE (reg, MEM);
PUT_MODE (reg, decl_mode);
}
if (used_p)
- schedule_fixup_var_refs (function, reg, type, promoted_mode, ht);
+ schedule_fixup_var_refs (function, reg, type, mode, ht);
}
/* Make sure that all refs to the variable, previously made
schedule_fixup_var_refs (struct function *function, rtx reg, tree type,
enum machine_mode promoted_mode, htab_t ht)
{
- int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
+ int unsigned_p = type ? TYPE_UNSIGNED (type) : 0;
if (function != 0)
{
rtx first_insn = get_insns ();
struct sequence_stack *stack = seq_stack;
tree rtl_exps = rtl_expr_chain;
+ int save_volatile_ok = volatile_ok;
/* If there's a hash table, it must record all uses of VAR. */
if (ht)
return;
}
+ /* Volatile is valid in MEMs because all we're doing in changing the
+ address inside. */
+ volatile_ok = 1;
fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp,
stack == 0, may_share);
push_to_full_sequence (stack->first, stack->last);
fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp,
stack->next != 0, may_share);
- /* Update remembered end of sequence
- in case we added an insn at the end. */
+ /* Update bounds of sequence in case we added insns. */
+ stack->first = get_insns ();
stack->last = get_last_insn ();
end_sequence ();
}
end_sequence ();
}
}
+
+ volatile_ok = save_volatile_ok;
}
\f
/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
pointer now. */
rtx next = NEXT_INSN (insn);
- /* CALL_PLACEHOLDERs are special; we have to switch into each of
- the three sequences they (potentially) contain, and process
- them recursively. The CALL_INSN itself is not interesting. */
-
- if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- int i;
-
- /* Look at the Normal call, sibling call and tail recursion
- sequences attached to the CALL_PLACEHOLDER. */
- for (i = 0; i < 3; i++)
- {
- rtx seq = XEXP (PATTERN (insn), i);
- if (seq)
- {
- push_to_sequence (seq);
- fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0,
- may_share);
- XEXP (PATTERN (insn), i) = get_insns ();
- end_sequence ();
- }
- }
- }
-
- else if (INSN_P (insn))
+ if (INSN_P (insn))
fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel,
may_share);
}
/* Look up the insns which reference VAR in HT and fix them up. Other
- arguments are the same as fixup_var_refs_insns.
-
- N.B. No need for special processing of CALL_PLACEHOLDERs here,
- because the hash table will point straight to the interesting insn
- (inside the CALL_PLACEHOLDER). */
+ arguments are the same as fixup_var_refs_insns. */
static void
fixup_var_refs_insns_with_hash (htab_t ht, rtx var, enum machine_mode promoted_mode,
don't delete the insn. */
&& find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0
&& (rtx_equal_p (SET_SRC (set), var)
- || (GET_CODE (SET_SRC (set)) == REG
+ || (REG_P (SET_SRC (set))
&& (prev = prev_nonnote_insn (insn)) != 0
&& (prev_set = single_set (prev)) != 0
&& SET_DEST (prev_set) == SET_SRC (set)
else
{
struct fixup_replacement *replacements = 0;
- rtx next_insn = NEXT_INSN (insn);
if (SMALL_REGISTER_CLASSES)
{
fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
&replacements, no_share);
- /* If this is last_parm_insn, and any instructions were output
- after it to fix it up, then we must set last_parm_insn to
- the last such instruction emitted. */
- if (insn == last_parm_insn)
- last_parm_insn = PREV_INSN (next_insn);
-
while (replacements)
{
struct fixup_replacement *next;
- if (GET_CODE (replacements->new) == REG)
+ if (REG_P (replacements->new))
{
rtx insert_before;
rtx seq;
{
if (GET_CODE (note) != INSN_LIST)
XEXP (note, 0)
- = walk_fixup_memory_subreg (XEXP (note, 0), insn,
+ = walk_fixup_memory_subreg (XEXP (note, 0), insn, var,
promoted_mode, 1);
note = XEXP (note, 1);
}
means that the insn may have become invalid again. We can't
in this case make a new replacement since we already have one
and we must deal with MATCH_DUPs. */
- if (GET_CODE (replacement->new) == MEM)
+ if (MEM_P (replacement->new))
{
INSN_CODE (insn) = -1;
if (recog_memoized (insn) >= 0)
if ((SET_SRC (x) == var
|| (GET_CODE (SET_SRC (x)) == SUBREG
&& SUBREG_REG (SET_SRC (x)) == var))
- && (GET_CODE (SET_DEST (x)) == REG
+ && (REG_P (SET_DEST (x))
|| (GET_CODE (SET_DEST (x)) == SUBREG
- && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
+ && REG_P (SUBREG_REG (SET_DEST (x)))))
&& GET_MODE (var) == promoted_mode
&& x == single_set (insn))
{
if ((SET_DEST (x) == var
|| (GET_CODE (SET_DEST (x)) == SUBREG
&& SUBREG_REG (SET_DEST (x)) == var))
- && (GET_CODE (SET_SRC (x)) == REG
+ && (REG_P (SET_SRC (x))
|| (GET_CODE (SET_SRC (x)) == SUBREG
- && GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
+ && REG_P (SUBREG_REG (SET_SRC (x)))))
&& GET_MODE (var) == promoted_mode
&& x == single_set (insn))
{
return result;
}
-/* Do fixup_memory_subreg on all (SUBREG (MEM ...) ...) contained in X.
+/* Do fixup_memory_subreg on all (SUBREG (VAR) ...) contained in X.
+ VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.
Replace subexpressions of X in place.
- If X itself is a (SUBREG (MEM ...) ...), return the replacement expression.
+ If X itself is a (SUBREG (VAR) ...), return the replacement expression.
Otherwise return X, with its contents possibly altered.
- INSN, PROMOTED_MODE and UNCRITICAL are as for
- fixup_memory_subreg. */
+ INSN and UNCRITICAL are as for fixup_memory_subreg. */
static rtx
-walk_fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode,
- int uncritical)
+walk_fixup_memory_subreg (rtx x, rtx insn, rtx var,
+ enum machine_mode promoted_mode, int uncritical)
{
enum rtx_code code;
const char *fmt;
code = GET_CODE (x);
- if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
+ if (code == SUBREG && SUBREG_REG (x) == var)
return fixup_memory_subreg (x, insn, promoted_mode, uncritical);
/* Nothing special about this RTX; fix its operands. */
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn,
+ XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, var,
promoted_mode, uncritical);
else if (fmt[i] == 'E')
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
XVECEXP (x, i, j)
- = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn,
+ = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, var,
promoted_mode, uncritical);
}
}
/* If we have address of a stack slot but it's not valid
(displacement is too large), compute the sum in a register. */
if (GET_CODE (ad) == PLUS
- && GET_CODE (XEXP (ad, 0)) == REG
+ && REG_P (XEXP (ad, 0))
&& ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER
&& REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER)
|| REGNO (XEXP (ad, 0)) == FRAME_POINTER_REGNUM
/* Now check that the containing word is memory, not a register,
and that it is safe to change the machine mode. */
- if (GET_CODE (XEXP (bitfield, 0)) == MEM)
+ if (MEM_P (XEXP (bitfield, 0)))
memref = XEXP (bitfield, 0);
- else if (GET_CODE (XEXP (bitfield, 0)) == REG
+ else if (REG_P (XEXP (bitfield, 0))
&& equiv_mem != 0)
memref = equiv_mem[REGNO (XEXP (bitfield, 0))];
else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG
- && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == MEM)
+ && MEM_P (SUBREG_REG (XEXP (bitfield, 0))))
memref = SUBREG_REG (XEXP (bitfield, 0));
else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG
&& equiv_mem != 0
- && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == REG)
+ && REG_P (SUBREG_REG (XEXP (bitfield, 0))))
memref = equiv_mem[REGNO (SUBREG_REG (XEXP (bitfield, 0)))];
if (memref
RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
PUT_CODE (reg, MEM);
+ MEM_VOLATILE_P (reg) = 0;
MEM_ATTRS (reg) = 0;
XEXP (reg, 0) = r;
if (rescan
&& (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)))
- fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
+ fixup_var_refs (reg, GET_MODE (reg), TYPE_UNSIGNED (type), reg, 0);
}
else if (rescan)
{
/* This can only happen during reload. Clear the same flag bits as
reload. */
- MEM_VOLATILE_P (reg) = 0;
RTX_UNCHANGING_P (reg) = 0;
MEM_IN_STRUCT_P (reg) = 0;
MEM_SCALAR_P (reg) = 0;
- MEM_ATTRS (reg) = 0;
fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
}
{
if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
&& DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == MEM
+ && MEM_P (DECL_RTL (decl))
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
- && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
+ && REG_P (XEXP (XEXP (DECL_RTL (decl), 0), 0)))
put_addressof_into_stack (XEXP (DECL_RTL (decl), 0), 0);
}
put_addressof_into_stack (rtx r, htab_t ht)
{
tree decl, type;
- int volatile_p, used_p;
+ bool volatile_p, used_p;
rtx reg = XEXP (r, 0);
- if (GET_CODE (reg) != REG)
+ if (!REG_P (reg))
abort ();
decl = ADDRESSOF_DECL (r);
else
{
type = NULL_TREE;
- volatile_p = 0;
- used_p = 1;
+ volatile_p = false;
+ used_p = true;
}
- put_reg_into_stack (0, reg, type, GET_MODE (reg), GET_MODE (reg),
- volatile_p, ADDRESSOF_REGNO (r), used_p, ht);
+ put_reg_into_stack (0, reg, type, GET_MODE (reg), ADDRESSOF_REGNO (r),
+ volatile_p, used_p, false, ht);
}
/* List of replacements made below in purge_addressof_1 when creating
{
rtx sub, insns;
- if (GET_CODE (XEXP (x, 0)) != MEM)
+ if (!MEM_P (XEXP (x, 0)))
put_addressof_into_stack (x, ht);
/* We must create a copy of the rtx because it was created by
/* If SUB is a hard or virtual register, try it as a pseudo-register.
Otherwise, perhaps SUB is an expression, so generate code to compute
it. */
- if (GET_CODE (sub) == REG && REGNO (sub) <= LAST_VIRTUAL_REGISTER)
+ if (REG_P (sub) && REGNO (sub) <= LAST_VIRTUAL_REGISTER)
sub = copy_to_reg (sub);
else
sub = force_operand (sub, NULL_RTX);
{
rtx sub = XEXP (XEXP (x, 0), 0);
- if (GET_CODE (sub) == MEM)
+ if (MEM_P (sub))
sub = adjust_address_nv (sub, GET_MODE (x), 0);
- else if (GET_CODE (sub) == REG
+ else if (REG_P (sub)
&& (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
;
- else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
+ else if (REG_P (sub) && GET_MODE (x) != GET_MODE (sub))
{
int size_x, size_sub;
rtx z = XEXP (XEXP (tem, 1), 0);
if (GET_MODE (x) == GET_MODE (z)
- || (GET_CODE (XEXP (XEXP (tem, 1), 0)) != REG
+ || (!REG_P (XEXP (XEXP (tem, 1), 0))
&& GET_CODE (XEXP (XEXP (tem, 1), 0)) != SUBREG))
abort ();
{
/* Remember the replacement so that the same one can be done
on the REG_NOTES. */
- if (GET_CODE (sub) == REG || GET_CODE (sub) == SUBREG)
+ if (REG_P (sub) || GET_CODE (sub) == SUBREG)
{
rtx tem;
return true;
}
purge_addressof_replacements
- = gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0),
- gen_rtx_EXPR_LIST (VOIDmode, sub,
- purge_addressof_replacements));
+ = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
+ gen_rtx_EXPR_LIST (VOIDmode, sub,
+ purge_addressof_replacements));
return true;
}
goto restart;
tmp.insns = NULL_RTX;
if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
- && GET_CODE (XEXP (*r, 0)) == REG)
+ && REG_P (XEXP (*r, 0)))
{
void **e;
tmp.key = XEXP (*r, 0);
memcpy (*e, &tmp, sizeof (tmp));
}
}
- else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
+ else if (ifmwi->pass == 1 && *r && REG_P (*r))
{
struct insns_for_mem_entry *ifme;
tmp.key = *r;
enum machine_mode mode = GET_MODE (SET_DEST (pattern));
int offset = 0;
- if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
+ if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg))
&& REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
{
offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
}
- if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
+ if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
{
reg = gen_rtx_REG (mode, REGNO (reg) + offset);
SET_DEST (pattern) = reg;
references to hard register references. */
void
-instantiate_virtual_regs (tree fndecl, rtx insns)
+instantiate_virtual_regs (void)
{
rtx insn;
unsigned int i;
/* Compute the offsets to use for this function. */
- in_arg_offset = FIRST_PARM_OFFSET (fndecl);
+ in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
var_offset = STARTING_FRAME_OFFSET;
- dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
+ dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
out_arg_offset = STACK_POINTER_OFFSET;
- cfa_offset = ARG_POINTER_CFA_OFFSET (fndecl);
+ cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
/* Scan all variables and parameters of this function. For each that is
in memory, instantiate all virtual registers if the result is a valid
address. If not, we do it later. That will handle most uses of virtual
regs on many machines. */
- instantiate_decls (fndecl, 1);
+ instantiate_decls (current_function_decl, 1);
/* Initialize recognition, indicating that volatile is OK. */
init_recog ();
/* Scan through all the insns, instantiating every virtual register still
present. */
- for (insn = insns; insn; insn = NEXT_INSN (insn))
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
|| GET_CODE (insn) == CALL_INSN)
{
/* Now instantiate the remaining register equivalences for debugging info.
These will not be valid addresses. */
- instantiate_decls (fndecl, 0);
+ instantiate_decls (current_function_decl, 0);
/* Indicate that, from now on, assign_stack_local should use
frame_pointer_rtx. */
/* If this is not a MEM, no need to do anything. Similarly if the
address is a constant or a register that is not a virtual register. */
- if (x == 0 || GET_CODE (x) != MEM)
+ if (x == 0 || !MEM_P (x))
return;
addr = XEXP (x, 0);
if (CONSTANT_P (addr)
- || (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == REG)
- || (GET_CODE (addr) == REG
+ || (GET_CODE (addr) == ADDRESSOF && REG_P (XEXP (addr, 0)))
+ || (REG_P (addr)
&& (REGNO (addr) < FIRST_VIRTUAL_REGISTER
|| REGNO (addr) > LAST_VIRTUAL_REGISTER)))
return;
/* The only valid sources here are PLUS or REG. Just do
the simplest possible thing to handle them. */
- if (GET_CODE (src) != REG && GET_CODE (src) != PLUS)
+ if (!REG_P (src) && GET_CODE (src) != PLUS)
{
instantiate_virtual_regs_lossage (object);
return 1;
}
start_sequence ();
- if (GET_CODE (src) != REG)
+ if (!REG_P (src))
temp = force_operand (src, NULL_RTX);
else
temp = src;
/* We know the second operand is a constant. Unless the
first operand is a REG (which has been already checked),
it needs to be checked. */
- if (GET_CODE (XEXP (x, 0)) != REG)
+ if (!REG_P (XEXP (x, 0)))
{
loc = &XEXP (x, 0);
goto restart;
go ahead and make the invalid one, but do it to a copy. For a REG,
just make the recursive call, since there's no chance of a problem. */
- if ((GET_CODE (XEXP (x, 0)) == MEM
+ if ((MEM_P (XEXP (x, 0))
&& instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
0))
- || (GET_CODE (XEXP (x, 0)) == REG
+ || (REG_P (XEXP (x, 0))
&& instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
return 1;
return 1;
case ADDRESSOF:
- if (GET_CODE (XEXP (x, 0)) == REG)
+ if (REG_P (XEXP (x, 0)))
return 1;
- else if (GET_CODE (XEXP (x, 0)) == MEM)
+ else if (MEM_P (XEXP (x, 0)))
{
/* If we have a (addressof (mem ..)), do any instantiation inside
since we know we'll be making the inside valid when we finally
return 1;
}
\f
-/* Optimization: assuming this function does not receive nonlocal gotos,
- delete the handlers for such, as well as the insns to establish
- and disestablish them. */
-
-static void
-delete_handlers (void)
-{
- rtx insn;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- /* Delete the handler by turning off the flag that would
- prevent jump_optimize from deleting it.
- Also permit deletion of the nonlocal labels themselves
- if nothing local refers to them. */
- if (GET_CODE (insn) == CODE_LABEL)
- {
- tree t, last_t;
-
- LABEL_PRESERVE_P (insn) = 0;
-
- /* Remove it from the nonlocal_label list, to avoid confusing
- flow. */
- for (t = nonlocal_labels, last_t = 0; t;
- last_t = t, t = TREE_CHAIN (t))
- if (DECL_RTL (TREE_VALUE (t)) == insn)
- break;
- if (t)
- {
- if (! last_t)
- nonlocal_labels = TREE_CHAIN (nonlocal_labels);
- else
- TREE_CHAIN (last_t) = TREE_CHAIN (t);
- }
- }
- if (GET_CODE (insn) == INSN)
- {
- int can_delete = 0;
- rtx t;
- for (t = nonlocal_goto_handler_slots; t != 0; t = XEXP (t, 1))
- if (reg_mentioned_p (t, PATTERN (insn)))
- {
- can_delete = 1;
- break;
- }
- if (can_delete
- || (nonlocal_goto_stack_level != 0
- && reg_mentioned_p (nonlocal_goto_stack_level,
- PATTERN (insn))))
- delete_related_insns (insn);
- }
- }
-}
-\f
-/* Return the first insn following those generated by `assign_parms'. */
-
-rtx
-get_first_nonparm_insn (void)
-{
- if (last_parm_insn)
- return NEXT_INSN (last_parm_insn);
- return get_insns ();
-}
-
/* Return 1 if EXP is an aggregate type (or a value with aggregate type).
This means a type for which function calls must pass an address to the
function or get an address back from the function.
/* If we have something other than a REG (e.g. a PARALLEL), then assume
it is OK. */
- if (GET_CODE (reg) != REG)
+ if (!REG_P (reg))
return 0;
regno = REGNO (reg);
- nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+ nregs = hard_regno_nregs[regno][TYPE_MODE (type)];
for (i = 0; i < nregs; i++)
if (! call_used_regs[regno + i])
return 1;
/* Total space needed so far for args on the stack,
given as a constant and a tree-expression. */
struct args_size stack_args_size;
+ HOST_WIDE_INT extra_pretend_bytes = 0;
tree fntype = TREE_TYPE (fndecl);
tree fnargs = DECL_ARGUMENTS (fndecl), orig_fnargs;
/* This is used for the arg pointer when referring to stack args. */
/* Nonzero if function takes extra anonymous args.
This means the last named arg must be on the stack
right before the anonymous ones. */
- int stdarg
- = (TYPE_ARG_TYPES (fntype) != 0
- && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
- != void_type_node));
-
- current_function_stdarg = stdarg;
+ int stdarg = current_function_stdarg;
/* If the reg that the virtual arg pointer will be translated into is
not a fixed reg or is the stack pointer, make a copy of the virtual
max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
- if (SPLIT_COMPLEX_ARGS)
+ /* If the target wants to split complex arguments into scalars, do so. */
+ if (targetm.calls.split_complex_arg)
fnargs = split_complex_args (fnargs);
#ifdef REG_PARM_STACK_SPACE
-#ifdef MAYBE_REG_PARM_STACK_SPACE
- reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
-#else
reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
#endif
-#endif
#ifdef INIT_CUMULATIVE_INCOMING_ARGS
INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
#else
- INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, fndecl);
+ INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, fndecl, -1);
#endif
/* We haven't yet found an argument that we must push and pretend the
int in_regs;
int partial = 0;
int pretend_bytes = 0;
+ int loaded_in_reg = 0;
/* Set LAST_NAMED if this is last named arg before last
anonymous args. */
/* Set NAMED_ARG if this arg should be treated as a named arg. For
most machines, if this is a varargs/stdarg function, then we treat
the last named arg as if it were anonymous too. */
- named_arg = targetm.calls.strict_argument_naming (&args_so_far) ? 1 : ! last_named;
+ named_arg = (targetm.calls.strict_argument_naming (&args_so_far)
+ ? 1 : !last_named);
if (TREE_TYPE (parm) == error_mark_node
/* This can happen after weird syntax errors
if (targetm.calls.promote_function_args (TREE_TYPE (fndecl)))
{
/* Compute the mode in which the arg is actually extended to. */
- unsignedp = TREE_UNSIGNED (passed_type);
- promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
+ unsignedp = TYPE_UNSIGNED (passed_type);
+ promoted_mode = promote_mode (passed_type, promoted_mode,
+ &unsignedp, 1);
}
/* Let machine desc say which reg (if any) the parm arrives in.
partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
passed_type, named_arg);
if (partial
-#ifndef MAYBE_REG_PARM_STACK_SPACE
/* The caller might already have allocated stack space
for the register parameters. */
- && reg_parm_stack_space == 0
-#endif
- )
+ && reg_parm_stack_space == 0)
{
/* Part of this argument is passed in registers and part
is passed on the stack. Ask the prologue code to extend
bits. We must preserve this invariant by rounding
CURRENT_FUNCTION_PRETEND_ARGS_SIZE up to a stack
boundary. */
+
+ /* We assume at most one partial arg, and it must be the first
+ argument on the stack. */
+ if (extra_pretend_bytes || current_function_pretend_args_size)
+ abort ();
+
pretend_bytes = partial * UNITS_PER_WORD;
current_function_pretend_args_size
= CEIL_ROUND (pretend_bytes, STACK_BYTES);
- /* If PRETEND_BYTES != CURRENT_FUNCTION_PRETEND_ARGS_SIZE,
- insert the padding before the start of the first pretend
- argument. */
- stack_args_size.constant
- = (current_function_pretend_args_size - pretend_bytes);
+ /* We want to align relative to the actual stack pointer, so
+ don't include this in the stack size until later. */
+ extra_pretend_bytes = current_function_pretend_args_size;
}
}
#endif
locate_and_pad_parm (promoted_mode, passed_type, in_regs,
entry_parm ? partial : 0, fndecl,
&stack_args_size, &locate);
+ /* Adjust offsets to include the pretend args. */
+ locate.slot_offset.constant += extra_pretend_bytes - pretend_bytes;
+ locate.offset.constant += extra_pretend_bytes - pretend_bytes;
{
rtx offset_rtx;
+ unsigned int align, boundary;
/* If we're passing this arg using a reg, make its stack home
the aligned stack slot. */
offset_rtx));
set_mem_attributes (stack_parm, parm, 1);
- if (entry_parm && MEM_ATTRS (stack_parm)->align < PARM_BOUNDARY)
- set_mem_align (stack_parm, PARM_BOUNDARY);
- /* Set also REG_ATTRS if parameter was passed in a register. */
+ boundary = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
+ align = 0;
+
+ /* If we're padding upward, we know that the alignment of the slot
+ is FUNCTION_ARG_BOUNDARY. If we're using slot_offset, we're
+ intentionally forcing upward padding. Otherwise we have to come
+ up with a guess at the alignment based on OFFSET_RTX. */
+ if (locate.where_pad == upward || entry_parm)
+ align = boundary;
+ else if (GET_CODE (offset_rtx) == CONST_INT)
+ {
+ align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
+ align = align & -align;
+ }
+ if (align > 0)
+ set_mem_align (stack_parm, align);
+
if (entry_parm)
set_reg_attrs_for_parm (entry_parm, stack_parm);
}
entry_parm = stack_parm;
/* Record permanently how this parm was passed. */
- DECL_INCOMING_RTL (parm) = entry_parm;
+ set_decl_incoming_rtl (parm, entry_parm);
/* If there is actually space on the stack for this parm,
count it in stack_args_size; otherwise set stack_parm to 0
if (entry_parm == stack_parm
|| (GET_CODE (entry_parm) == PARALLEL
&& XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
-#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+#if defined (REG_PARM_STACK_SPACE)
/* On some machines, even if a parm value arrives in a register
- there is still an (uninitialized) stack slot allocated for it.
-
- ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
- whether this parameter already has a stack slot allocated,
- because an arg block exists only if current_function_args_size
- is larger than some threshold, and we haven't calculated that
- yet. So, for now, we just assume that stack slots never exist
- in this case. */
+ there is still an (uninitialized) stack slot allocated
+ for it. */
|| REG_PARM_STACK_SPACE (fndecl) > 0
#endif
)
{
- stack_args_size.constant += pretend_bytes + locate.size.constant;
+ stack_args_size.constant += locate.size.constant;
if (locate.size.var)
ADD_PARM_SIZE (stack_args_size, locate.size.var);
}
/* If we can't trust the parm stack slot to be aligned enough
for its ultimate type, don't use that slot after entry.
We'll make another stack slot, if we need one. */
- {
- unsigned int thisparm_boundary
- = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
-
- if (GET_MODE_ALIGNMENT (nominal_mode) > thisparm_boundary)
- stack_parm = 0;
- }
+ if (STRICT_ALIGNMENT && stack_parm
+ && GET_MODE_ALIGNMENT (nominal_mode) > MEM_ALIGN (stack_parm))
+ stack_parm = 0;
/* If parm was passed in memory, and we need to convert it on entry,
don't store it back in that same slot. */
for (i = 0; i < len; i++)
if (XEXP (XVECEXP (entry_parm, 0, i), 0) != NULL_RTX
- && GET_CODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == REG
+ && REG_P (XEXP (XVECEXP (entry_parm, 0, i), 0))
&& (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0))
== passed_mode)
&& INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0)
{
entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0);
- DECL_INCOMING_RTL (parm) = entry_parm;
+ set_decl_incoming_rtl (parm, entry_parm);
break;
}
}
if (REG_P (parmreg))
{
+ unsigned int regno = REGNO (parmreg);
+
emit_group_store (parmreg, entry_parm, TREE_TYPE (parm),
int_size_in_bytes (TREE_TYPE (parm)));
SET_DECL_RTL (parm, parmreg);
+ loaded_in_reg = 1;
+
+ if (regno >= max_parm_reg)
+ {
+ rtx *new;
+ int old_max_parm_reg = max_parm_reg;
+
+ /* It's slow to expand this one register at a time,
+ but it's also rare and we need max_parm_reg to be
+ precisely correct. */
+ max_parm_reg = regno + 1;
+ new = ggc_realloc (parm_reg_stack_loc,
+ max_parm_reg * sizeof (rtx));
+ memset (new + old_max_parm_reg, 0,
+ (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
+ parm_reg_stack_loc = new;
+ parm_reg_stack_loc[regno] = stack_parm;
+ }
}
}
/* If a BLKmode arrives in registers, copy it to a stack slot.
Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
- if (GET_CODE (entry_parm) == REG
- || GET_CODE (entry_parm) == PARALLEL)
+ if (REG_P (entry_parm)
+ || (GET_CODE (entry_parm) == PARALLEL
+ && (!loaded_in_reg || !optimize)))
{
int size = int_size_in_bytes (TREE_TYPE (parm));
int size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
PUT_MODE (stack_parm, GET_MODE (entry_parm));
set_mem_attributes (stack_parm, parm, 1);
}
- else if (GET_CODE (entry_parm) == PARALLEL
- && GET_MODE(entry_parm) == BLKmode)
+ else if (GET_CODE (entry_parm) == PARALLEL)
;
- else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
+ else if (size != 0 && PARM_BOUNDARY % BITS_PER_WORD != 0)
abort ();
mem = validize_mem (stack_parm);
size_stored / UNITS_PER_WORD);
}
/* If parm is already bound to register pair, don't change
- this binding. */
+ this binding. */
if (! DECL_RTL_SET_P (parm))
SET_DECL_RTL (parm, stack_parm);
}
rtx parmreg;
unsigned int regno, regnoi = 0, regnor = 0;
- unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
+ unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
promoted_nominal_mode
= promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
if (GET_CODE (tempreg) == SUBREG
&& GET_MODE (tempreg) == nominal_mode
- && GET_CODE (SUBREG_REG (tempreg)) == REG
+ && REG_P (SUBREG_REG (tempreg))
&& nominal_mode == passed_mode
&& GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
&& GET_MODE_SIZE (GET_MODE (tempreg))
if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm)))
{
rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm)));
- int unsigned_p = TREE_UNSIGNED (TREE_TYPE (parm));
+ int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (parm));
push_to_sequence (conversion_insns);
emit_move_insn (tempreg, DECL_RTL (parm));
SET_DECL_RTL (parm,
if (nominal_mode == passed_mode
&& ! did_conversion
&& stack_parm != 0
- && GET_CODE (stack_parm) == MEM
+ && MEM_P (stack_parm)
&& locate.offset.var == 0
&& reg_mentioned_p (virtual_incoming_args_rtx,
XEXP (stack_parm, 0)))
push_to_sequence (conversion_insns);
entry_parm = convert_to_mode (nominal_mode, tempreg,
- TREE_UNSIGNED (TREE_TYPE (parm)));
+ TYPE_UNSIGNED (TREE_TYPE (parm)));
if (stack_parm)
/* ??? This may need a big-endian conversion on sparc64. */
stack_parm = adjust_address (stack_parm, nominal_mode, 0);
}
}
- if (SPLIT_COMPLEX_ARGS && fnargs != orig_fnargs)
+ if (targetm.calls.split_complex_arg && fnargs != orig_fnargs)
{
for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm))
{
- if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE)
+ if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
+ && targetm.calls.split_complex_arg (TREE_TYPE (parm)))
{
- SET_DECL_RTL (parm,
- gen_rtx_CONCAT (DECL_MODE (parm),
- DECL_RTL (fnargs),
- DECL_RTL (TREE_CHAIN (fnargs))));
- DECL_INCOMING_RTL (parm)
- = gen_rtx_CONCAT (DECL_MODE (parm),
- DECL_INCOMING_RTL (fnargs),
- DECL_INCOMING_RTL (TREE_CHAIN (fnargs)));
+ rtx tmp, real, imag;
+ enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm));
+
+ real = DECL_RTL (fnargs);
+ imag = DECL_RTL (TREE_CHAIN (fnargs));
+ if (inner != GET_MODE (real))
+ {
+ real = gen_lowpart_SUBREG (inner, real);
+ imag = gen_lowpart_SUBREG (inner, imag);
+ }
+ tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
+ SET_DECL_RTL (parm, tmp);
+
+ real = DECL_INCOMING_RTL (fnargs);
+ imag = DECL_INCOMING_RTL (TREE_CHAIN (fnargs));
+ if (inner != GET_MODE (real))
+ {
+ real = gen_lowpart_SUBREG (inner, real);
+ imag = gen_lowpart_SUBREG (inner, imag);
+ }
+ tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
+ set_decl_incoming_rtl (parm, tmp);
fnargs = TREE_CHAIN (fnargs);
}
else
{
SET_DECL_RTL (parm, DECL_RTL (fnargs));
- DECL_INCOMING_RTL (parm) = DECL_INCOMING_RTL (fnargs);
+ set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs));
+
+ /* Set MEM_EXPR to the original decl, i.e. to PARM,
+ instead of the copy of decl, i.e. FNARGS. */
+ if (DECL_INCOMING_RTL (parm)
+ && MEM_P (DECL_INCOMING_RTL (parm)))
+ set_mem_expr (DECL_INCOMING_RTL (parm), parm);
}
fnargs = TREE_CHAIN (fnargs);
}
SET_DECL_RTL (result, x);
}
- last_parm_insn = get_last_insn ();
-
+ /* We have aligned all the args, so add space for the pretend args. */
+ stack_args_size.constant += extra_pretend_bytes;
current_function_args_size = stack_args_size.constant;
/* Adjust function incoming argument size for alignment and
minimum length. */
#ifdef REG_PARM_STACK_SPACE
-#ifndef MAYBE_REG_PARM_STACK_SPACE
current_function_args_size = MAX (current_function_args_size,
REG_PARM_STACK_SPACE (fndecl));
#endif
-#endif
current_function_args_size
= ((current_function_args_size + STACK_BYTES - 1)
/* Before allocating memory, check for the common case of no complex. */
for (p = args; p; p = TREE_CHAIN (p))
- if (TREE_CODE (TREE_TYPE (p)) == COMPLEX_TYPE)
- goto found;
+ {
+ tree type = TREE_TYPE (p);
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ && targetm.calls.split_complex_arg (type))
+ goto found;
+ }
return args;
found:
for (p = args; p; p = TREE_CHAIN (p))
{
tree type = TREE_TYPE (p);
- if (TREE_CODE (type) == COMPLEX_TYPE)
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ && targetm.calls.split_complex_arg (type))
{
tree decl;
tree subtype = TREE_TYPE (type);
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
- if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG
+ if (REG_P (DECL_INCOMING_RTL (arg))
&& REGNO (DECL_INCOMING_RTL (arg)) == regno
&& TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg));
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (arg));
mode = promote_mode (TREE_TYPE (arg), mode, &unsignedp, 1);
if (mode == GET_MODE (DECL_INCOMING_RTL (arg))
int part_size_in_regs;
#ifdef REG_PARM_STACK_SPACE
-#ifdef MAYBE_REG_PARM_STACK_SPACE
- reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
-#else
reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
-#endif
/* If we have found a stack parm before we reach the end of the
area reserved for registers, skip that area. */
}
\f
/* Walk the tree of blocks describing the binding levels within a function
- and warn about uninitialized variables.
+ and warn about variables the might be killed by setjmp or vfork.
This is done after calling flow_analysis and before global_alloc
clobbers the pseudo-regs to hard regs. */
void
-uninitialized_vars_warning (tree block)
+setjmp_vars_warning (tree block)
{
tree decl, sub;
+
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
{
- if (warn_uninitialized
- && TREE_CODE (decl) == VAR_DECL
- /* These warnings are unreliable for and aggregates
- because assigning the fields one by one can fail to convince
- flow.c that the entire aggregate was initialized.
- Unions are troublesome because members may be shorter. */
- && ! AGGREGATE_TYPE_P (TREE_TYPE (decl))
- && DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == REG
- /* Global optimizations can make it difficult to determine if a
- particular variable has been initialized. However, a VAR_DECL
- with a nonzero DECL_INITIAL had an initializer, so do not
- claim it is potentially uninitialized.
-
- When the DECL_INITIAL is NULL call the language hook to tell us
- if we want to warn. */
- && (DECL_INITIAL (decl) == NULL_TREE || lang_hooks.decl_uninit (decl))
- && regno_uninitialized (REGNO (DECL_RTL (decl))))
- warning ("%J'%D' might be used uninitialized in this function",
- decl, decl);
- if (extra_warnings
- && TREE_CODE (decl) == VAR_DECL
- && DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == REG
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_RTL_SET_P (decl)
+ && REG_P (DECL_RTL (decl))
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
decl, decl);
}
+
for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
- uninitialized_vars_warning (sub);
+ setjmp_vars_warning (sub);
}
-/* Do the appropriate part of uninitialized_vars_warning
+/* Do the appropriate part of setjmp_vars_warning
but for arguments instead of local variables. */
void
for (decl = DECL_ARGUMENTS (current_function_decl);
decl; decl = TREE_CHAIN (decl))
if (DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == REG
+ && REG_P (DECL_RTL (decl))
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'",
decl, decl);
if ((TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL)
&& DECL_RTL (decl) != 0
- && (GET_CODE (DECL_RTL (decl)) == REG
- || (GET_CODE (DECL_RTL (decl)) == MEM
+ && (REG_P (DECL_RTL (decl))
+ || (MEM_P (DECL_RTL (decl))
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
/* If this variable came from an inline function, it must be
that its life doesn't overlap the setjmp. If there was a
if ((TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL)
&& DECL_RTL (decl) != 0
- && (GET_CODE (DECL_RTL (decl)) == REG
- || (GET_CODE (DECL_RTL (decl)) == MEM
+ && (REG_P (DECL_RTL (decl))
+ || (MEM_P (DECL_RTL (decl))
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
&& (
/* If longjmp doesn't restore the registers,
put_var_into_stack (decl, /*rescan=*/true);
}
\f
-/* Return the context-pointer register corresponding to DECL,
- or 0 if it does not need one. */
-
-rtx
-lookup_static_chain (tree decl)
-{
- tree context = decl_function_context (decl);
- tree link;
-
- if (context == 0
- || (TREE_CODE (decl) == FUNCTION_DECL && DECL_NO_STATIC_CHAIN (decl)))
- return 0;
-
- /* We treat inline_function_decl as an alias for the current function
- because that is the inline function whose vars, types, etc.
- are being merged into the current function.
- See expand_inline_function. */
- if (context == current_function_decl || context == inline_function_decl)
- return virtual_stack_vars_rtx;
-
- for (link = context_display; link; link = TREE_CHAIN (link))
- if (TREE_PURPOSE (link) == context)
- return RTL_EXPR_RTL (TREE_VALUE (link));
-
- abort ();
-}
-\f
/* Convert a stack slot address ADDR for variable VAR
(from a containing function)
into an address valid in this function (using a static chain). */
rtx base = 0;
/* If this is the present function, we need not do anything. */
- if (context == current_function_decl || context == inline_function_decl)
+ if (context == current_function_decl)
return addr;
fp = find_function_data (context);
- if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
+ if (GET_CODE (addr) == ADDRESSOF && MEM_P (XEXP (addr, 0)))
addr = XEXP (XEXP (addr, 0), 0);
/* Decode given address as base reg plus displacement. */
- if (GET_CODE (addr) == REG)
+ if (REG_P (addr))
basereg = addr, displacement = 0;
else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
basereg = XEXP (addr, 0), displacement = INTVAL (XEXP (addr, 1));
else
abort ();
- /* We accept vars reached via the containing function's
- incoming arg pointer and via its stack variables pointer. */
- if (basereg == fp->internal_arg_pointer)
- {
- /* If reached via arg pointer, get the arg pointer value
- out of that function's stack frame.
-
- There are two cases: If a separate ap is needed, allocate a
- slot in the outer function for it and dereference it that way.
- This is correct even if the real ap is actually a pseudo.
- Otherwise, just adjust the offset from the frame pointer to
- compensate. */
-
-#ifdef NEED_SEPARATE_AP
- rtx addr;
-
- addr = get_arg_pointer_save_area (fp);
- addr = fix_lexical_addr (XEXP (addr, 0), var);
- addr = memory_address (Pmode, addr);
-
- base = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (base, get_frame_alias_set ());
- base = copy_to_reg (base);
-#else
- displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
- base = lookup_static_chain (var);
-#endif
- }
-
- else if (basereg == virtual_stack_vars_rtx)
- {
- /* This is the same code as lookup_static_chain, duplicated here to
- avoid an extra call to decl_function_context. */
- tree link;
-
- for (link = context_display; link; link = TREE_CHAIN (link))
- if (TREE_PURPOSE (link) == context)
- {
- base = RTL_EXPR_RTL (TREE_VALUE (link));
- break;
- }
- }
-
if (base == 0)
abort ();
return plus_constant (base, displacement);
}
\f
-/* Return the address of the trampoline for entering nested fn FUNCTION.
- If necessary, allocate a trampoline (in the stack frame)
- and emit rtl to initialize its contents (at entry to this function). */
-
-rtx
-trampoline_address (tree function)
-{
- tree link;
- tree rtlexp;
- rtx tramp;
- struct function *fp;
- tree fn_context;
-
- /* Find an existing trampoline and return it. */
- for (link = trampoline_list; link; link = TREE_CHAIN (link))
- if (TREE_PURPOSE (link) == function)
- return
- adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
-
- for (fp = outer_function_chain; fp; fp = fp->outer)
- for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link))
- if (TREE_PURPOSE (link) == function)
- {
- tramp = fix_lexical_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0),
- function);
- return adjust_trampoline_addr (tramp);
- }
-
- /* None exists; we must make one. */
-
- /* Find the `struct function' for the function containing FUNCTION. */
- fp = 0;
- fn_context = decl_function_context (function);
- if (fn_context != current_function_decl
- && fn_context != inline_function_decl)
- fp = find_function_data (fn_context);
-
- /* Allocate run-time space for this trampoline. */
- /* If rounding needed, allocate extra space
- to ensure we have TRAMPOLINE_SIZE bytes left after rounding up. */
-#define TRAMPOLINE_REAL_SIZE \
- (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1)
- tramp = assign_stack_local_1 (BLKmode, TRAMPOLINE_REAL_SIZE, 0,
- fp ? fp : cfun);
- /* Record the trampoline for reuse and note it for later initialization
- by expand_function_end. */
- if (fp != 0)
- {
- rtlexp = make_node (RTL_EXPR);
- RTL_EXPR_RTL (rtlexp) = tramp;
- fp->x_trampoline_list = tree_cons (function, rtlexp,
- fp->x_trampoline_list);
- }
- else
- {
- /* Make the RTL_EXPR node temporary, not momentary, so that the
- trampoline_list doesn't become garbage. */
- rtlexp = make_node (RTL_EXPR);
-
- RTL_EXPR_RTL (rtlexp) = tramp;
- trampoline_list = tree_cons (function, rtlexp, trampoline_list);
- }
-
- tramp = fix_lexical_addr (XEXP (tramp, 0), function);
- return adjust_trampoline_addr (tramp);
-}
-
-/* Given a trampoline address,
- round it to multiple of TRAMPOLINE_ALIGNMENT. */
-
-static rtx
-round_trampoline_addr (rtx tramp)
-{
- /* Round address up to desired boundary. */
- rtx temp = gen_reg_rtx (Pmode);
- rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
- rtx mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
-
- temp = expand_simple_binop (Pmode, PLUS, tramp, addend,
- temp, 0, OPTAB_LIB_WIDEN);
- tramp = expand_simple_binop (Pmode, AND, temp, mask,
- temp, 0, OPTAB_LIB_WIDEN);
-
- return tramp;
-}
-
-/* Given a trampoline address, round it then apply any
- platform-specific adjustments so that the result can be used for a
- function call . */
-
-static rtx
-adjust_trampoline_addr (rtx tramp)
-{
- tramp = round_trampoline_addr (tramp);
-#ifdef TRAMPOLINE_ADJUST_ADDRESS
- TRAMPOLINE_ADJUST_ADDRESS (tramp);
-#endif
- return tramp;
-}
-\f
-/* Put all this function's BLOCK nodes including those that are chained
- onto the first block into a vector, and return it.
- Also store in each NOTE for the beginning or end of a block
- the index of that block in the vector.
- The arguments are BLOCK, the chain of top-level blocks of the function,
- and INSNS, the insn chain of the function. */
-
-void
-identify_blocks (void)
-{
- int n_blocks;
- tree *block_vector, *last_block_vector;
- tree *block_stack;
- tree block = DECL_INITIAL (current_function_decl);
-
- if (block == 0)
- return;
-
- /* Fill the BLOCK_VECTOR with all of the BLOCKs in this function, in
- depth-first order. */
- block_vector = get_block_vector (block, &n_blocks);
- block_stack = xmalloc (n_blocks * sizeof (tree));
-
- last_block_vector = identify_blocks_1 (get_insns (),
- block_vector + 1,
- block_vector + n_blocks,
- block_stack);
-
- /* If we didn't use all of the subblocks, we've misplaced block notes. */
- /* ??? This appears to happen all the time. Latent bugs elsewhere? */
- if (0 && last_block_vector != block_vector + n_blocks)
- abort ();
-
- free (block_vector);
- free (block_stack);
-}
-
-/* Subroutine of identify_blocks. Do the block substitution on the
- insn chain beginning with INSNS. Recurse for CALL_PLACEHOLDER chains.
-
- BLOCK_STACK is pushed and popped for each BLOCK_BEGIN/BLOCK_END pair.
- BLOCK_VECTOR is incremented for each block seen. */
-
-static tree *
-identify_blocks_1 (rtx insns, tree *block_vector, tree *end_block_vector,
- tree *orig_block_stack)
-{
- rtx insn;
- tree *block_stack = orig_block_stack;
-
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == NOTE)
- {
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
- {
- tree b;
-
- /* If there are more block notes than BLOCKs, something
- is badly wrong. */
- if (block_vector == end_block_vector)
- abort ();
-
- b = *block_vector++;
- NOTE_BLOCK (insn) = b;
- *block_stack++ = b;
- }
- else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
- {
- /* If there are more NOTE_INSN_BLOCK_ENDs than
- NOTE_INSN_BLOCK_BEGs, something is badly wrong. */
- if (block_stack == orig_block_stack)
- abort ();
-
- NOTE_BLOCK (insn) = *--block_stack;
- }
- }
- else if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- rtx cp = PATTERN (insn);
-
- block_vector = identify_blocks_1 (XEXP (cp, 0), block_vector,
- end_block_vector, block_stack);
- if (XEXP (cp, 1))
- block_vector = identify_blocks_1 (XEXP (cp, 1), block_vector,
- end_block_vector, block_stack);
- if (XEXP (cp, 2))
- block_vector = identify_blocks_1 (XEXP (cp, 2), block_vector,
- end_block_vector, block_stack);
- }
- }
-
- /* If there are more NOTE_INSN_BLOCK_BEGINs than NOTE_INSN_BLOCK_ENDs,
- something is badly wrong. */
- if (block_stack != orig_block_stack)
- abort ();
-
- return block_vector;
-}
-
/* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END},
and create duplicate blocks. */
/* ??? Need an option to either create block fragments or to create
VARRAY_TREE_INIT (block_stack, 10, "block_stack");
/* Reset the TREE_ASM_WRITTEN bit for all blocks. */
- reorder_blocks_0 (block);
+ clear_block_marks (block);
/* Prune the old trees away, so that they don't get in the way. */
BLOCK_SUBBLOCKS (block) = NULL_TREE;
/* Helper function for reorder_blocks. Reset TREE_ASM_WRITTEN. */
-static void
-reorder_blocks_0 (tree block)
+void
+clear_block_marks (tree block)
{
while (block)
{
TREE_ASM_WRITTEN (block) = 0;
- reorder_blocks_0 (BLOCK_SUBBLOCKS (block));
+ clear_block_marks (BLOCK_SUBBLOCKS (block));
block = BLOCK_CHAIN (block);
}
}
current_block = BLOCK_SUPERCONTEXT (current_block);
}
}
- else if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- rtx cp = PATTERN (insn);
- reorder_blocks_1 (XEXP (cp, 0), current_block, p_block_stack);
- if (XEXP (cp, 1))
- reorder_blocks_1 (XEXP (cp, 1), current_block, p_block_stack);
- if (XEXP (cp, 2))
- reorder_blocks_1 (XEXP (cp, 2), current_block, p_block_stack);
- }
}
}
/* Reverse the order of elements in the chain T of blocks,
and return the new head of the chain (old last element). */
-static tree
+tree
blocks_nreverse (tree t)
{
tree prev = 0, decl, next;
allocate_struct_function (tree fndecl)
{
tree result;
+ tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE;
cfun = ggc_alloc_cleared (sizeof (struct function));
init_stmt_for_function ();
init_eh_for_function ();
- init_emit ();
- init_expr ();
- init_varasm_status (cfun);
- (*lang_hooks.function.init) (cfun);
+ lang_hooks.function.init (cfun);
if (init_machine_status)
cfun->machine = (*init_machine_status) ();
if (fndecl == NULL)
return;
- DECL_SAVED_INSNS (fndecl) = cfun;
+ DECL_STRUCT_FUNCTION (fndecl) = cfun;
cfun->decl = fndecl;
- current_function_name = (*lang_hooks.decl_printable_name) (fndecl, 2);
-
result = DECL_RESULT (fndecl);
if (aggregate_value_p (result, fndecl))
{
current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result));
- current_function_needs_context
- = (decl_function_context (current_function_decl) != 0
- && ! DECL_NO_STATIC_CHAIN (current_function_decl));
+ current_function_stdarg
+ = (fntype
+ && TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node));
}
/* Reset cfun, and other non-struct-function variables to defaults as
static void
prepare_function_start (tree fndecl)
{
- if (fndecl && DECL_SAVED_INSNS (fndecl))
- cfun = DECL_SAVED_INSNS (fndecl);
+ if (fndecl && DECL_STRUCT_FUNCTION (fndecl))
+ cfun = DECL_STRUCT_FUNCTION (fndecl);
else
allocate_struct_function (fndecl);
+ init_emit ();
+ init_varasm_status (cfun);
+ init_expr ();
cse_not_expected = ! optimize;
{
prepare_function_start (subr);
- /* Within function body, compute a type's size as soon it is laid out. */
- immediate_size_expand++;
-
/* Prevent ever trying to delete the first instruction of a
function. Also tell final how to output a linenum before the
function prologue. Note linenums could be missing, e.g. when
compiling a Java .class file. */
- if (DECL_SOURCE_LINE (subr))
+ if (! DECL_IS_BUILTIN (subr))
emit_line_note (DECL_SOURCE_LOCATION (subr));
/* Make sure first insn is a note even if we don't want linenums.
the function's parameters, which must be run at any return statement. */
void
-expand_function_start (tree subr, int parms_have_cleanups)
+expand_function_start (tree subr)
{
- tree tem;
- rtx last_ptr = NULL_RTX;
-
/* Make sure volatile mem refs aren't considered
valid operands of arithmetic insns. */
init_recog_no_volatile ();
- current_function_instrument_entry_exit
- = (flag_instrument_function_entry_exit
- && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
-
current_function_profile
= (profile_flag
&& ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
current_function_limit_stack
= (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
- /* If function gets a static chain arg, store it in the stack frame.
- Do this first, so it gets the first stack slot offset. */
- if (current_function_needs_context)
- {
- last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-
- /* Delay copying static chain if it is not a register to avoid
- conflicts with regs used for parameters. */
- if (! SMALL_REGISTER_CLASSES
- || GET_CODE (static_chain_incoming_rtx) == REG)
- emit_move_insn (last_ptr, static_chain_incoming_rtx);
- }
-
- /* If the parameters of this function need cleaning up, get a label
- for the beginning of the code which executes those cleanups. This must
- be done before doing anything with return_label. */
- if (parms_have_cleanups)
- cleanup_label = gen_label_rtx ();
- else
- cleanup_label = 0;
-
/* Make the label for return statements to jump to. Do not special
case machines with special return instructions -- they will be
handled later during jump, ifcvt, or epilogue creation. */
/* Initialize rtx for parameters and local variables.
In some cases this requires emitting insns. */
-
assign_parms (subr);
- /* Copy the static chain now if it wasn't a register. The delay is to
- avoid conflicts with the parameter passing registers. */
+ /* If function gets a static chain arg, store it. */
+ if (cfun->static_chain_decl)
+ {
+ tree parm = cfun->static_chain_decl;
+ rtx local = gen_reg_rtx (Pmode);
+
+ set_decl_incoming_rtl (parm, static_chain_incoming_rtx);
+ SET_DECL_RTL (parm, local);
+ maybe_set_unchanging (local, parm);
+ mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
+
+ emit_move_insn (local, static_chain_incoming_rtx);
+ }
+
+ /* If the function receives a non-local goto, then store the
+ bits we need to restore the frame pointer. */
+ if (cfun->nonlocal_goto_save_area)
+ {
+ tree t_save;
+ rtx r_save;
- if (SMALL_REGISTER_CLASSES && current_function_needs_context)
- if (GET_CODE (static_chain_incoming_rtx) != REG)
- emit_move_insn (last_ptr, static_chain_incoming_rtx);
+ /* ??? We need to do this save early. Unfortunately here is
+ before the frame variable gets declared. Help out... */
+ expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0));
+
+ t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
+ integer_zero_node, NULL_TREE, NULL_TREE);
+ r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+ emit_move_insn (r_save, virtual_stack_vars_rtx);
+ update_nonlocal_goto_save_area ();
+ }
/* The following was moved from init_function_start.
The move is supposed to make sdb output more accurate. */
emit_note (NOTE_INSN_DELETED);
parm_birth_insn = get_last_insn ();
- context_display = 0;
- if (current_function_needs_context)
- {
- /* Fetch static chain values for containing functions. */
- tem = decl_function_context (current_function_decl);
- /* Copy the static chain pointer into a pseudo. If we have
- small register classes, copy the value from memory if
- static_chain_incoming_rtx is a REG. */
- if (tem)
- {
- /* If the static chain originally came in a register, put it back
- there, then move it out in the next insn. The reason for
- this peculiar code is to satisfy function integration. */
- if (SMALL_REGISTER_CLASSES
- && GET_CODE (static_chain_incoming_rtx) == REG)
- emit_move_insn (static_chain_incoming_rtx, last_ptr);
- last_ptr = copy_to_reg (static_chain_incoming_rtx);
- }
-
- while (tem)
- {
- tree rtlexp = make_node (RTL_EXPR);
-
- RTL_EXPR_RTL (rtlexp) = last_ptr;
- context_display = tree_cons (tem, rtlexp, context_display);
- tem = decl_function_context (tem);
- if (tem == 0)
- break;
- /* Chain thru stack frames, assuming pointer to next lexical frame
- is found at the place we always store it. */
-#ifdef FRAME_GROWS_DOWNWARD
- last_ptr = plus_constant (last_ptr,
- -(HOST_WIDE_INT) GET_MODE_SIZE (Pmode));
-#endif
- last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr));
- set_mem_alias_set (last_ptr, get_frame_alias_set ());
- last_ptr = copy_to_reg (last_ptr);
-
- /* If we are not optimizing, ensure that we know that this
- piece of context is live over the entire function. */
- if (! optimize)
- save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, last_ptr,
- save_expr_regs);
- }
- }
-
- if (current_function_instrument_entry_exit)
- {
- rtx fun = DECL_RTL (current_function_decl);
- if (GET_CODE (fun) == MEM)
- fun = XEXP (fun, 0);
- else
- abort ();
- emit_library_call (profile_function_entry_libfunc, LCT_NORMAL, VOIDmode,
- 2, fun, Pmode,
- expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0,
- hard_frame_pointer_rtx),
- Pmode);
- }
-
if (current_function_profile)
{
#ifdef PROFILE_HOOK
if (! outgoing)
return;
- if (GET_CODE (outgoing) == REG)
+ if (REG_P (outgoing))
(*doit) (outgoing, arg);
else if (GET_CODE (outgoing) == PARALLEL)
{
{
rtx x = XEXP (XVECEXP (outgoing, 0, i), 0);
- if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
(*doit) (x, arg);
}
}
diddle_return_value (do_use_return_reg, NULL);
}
+/* Possibly warn about unused parameters. */
+void
+do_warn_unused_parameter (tree fn)
+{
+ tree decl;
+
+ for (decl = DECL_ARGUMENTS (fn);
+ decl; decl = TREE_CHAIN (decl))
+ if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
+ && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))
+ warning ("%Junused parameter '%D'", decl, decl);
+}
+
static GTY(()) rtx initial_trampoline;
/* Generate RTL for the end of the current function. */
void
expand_function_end (void)
{
- tree link;
rtx clobber_after;
finish_expr_for_function ();
}
#endif
- /* Initialize any trampolines required by this function. */
- for (link = trampoline_list; link; link = TREE_CHAIN (link))
- {
- tree function = TREE_PURPOSE (link);
- rtx context ATTRIBUTE_UNUSED = lookup_static_chain (function);
- rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link));
-#ifdef TRAMPOLINE_TEMPLATE
- rtx blktramp;
-#endif
- rtx seq;
-
-#ifdef TRAMPOLINE_TEMPLATE
- /* First make sure this compilation has a template for
- initializing trampolines. */
- if (initial_trampoline == 0)
- {
- initial_trampoline
- = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
- set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
- }
-#endif
-
- /* Generate insns to initialize the trampoline. */
- start_sequence ();
- tramp = round_trampoline_addr (XEXP (tramp, 0));
-#ifdef TRAMPOLINE_TEMPLATE
- blktramp = replace_equiv_address (initial_trampoline, tramp);
- emit_block_move (blktramp, initial_trampoline,
- GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
-#endif
- trampolines_created = 1;
- INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
- seq = get_insns ();
- end_sequence ();
-
- /* Put those insns at entry to the containing function (this one). */
- emit_insn_before (seq, tail_recursion_reentry);
- }
-
/* If we are doing stack checking and this function makes calls,
do a stack probe at the start of the function to ensure we have enough
space for another stack frame. */
}
}
- /* Possibly warn about unused parameters. */
- if (warn_unused_parameter)
- {
- tree decl;
-
- for (decl = DECL_ARGUMENTS (current_function_decl);
- decl; decl = TREE_CHAIN (decl))
- if (! TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
- && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
- warning ("%Junused parameter '%D'", decl, decl);
- }
-
- /* Delete handlers for nonlocal gotos if nothing uses them. */
- if (nonlocal_goto_handler_slots != 0
- && ! current_function_has_nonlocal_label)
- delete_handlers ();
+ /* Possibly warn about unused parameters.
+ When frontend does unit-at-a-time, the warning is already
+ issued at finalization time. */
+ if (warn_unused_parameter
+ && !lang_hooks.callgraph.expand_function)
+ do_warn_unused_parameter (current_function_decl);
/* End any sequences that failed to be closed due to syntax errors. */
while (in_sequence_p ())
end_sequence ();
- /* Outside function body, can't compute type's actual size
- until next function's body starts. */
- immediate_size_expand--;
-
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
+ /* @@@ This is a kludge. We want to ensure that instructions that
+ may trap are not moved into the epilogue by scheduling, because
+ we don't always emit unwind information for the epilogue.
+ However, not all machine descriptions define a blockage insn, so
+ emit an ASM_INPUT to act as one. */
+ if (flag_non_call_exceptions)
+ emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+
/* Mark the end of the function body.
If control reaches this insn, the function can drop through
without returning a value. */
if (return_label)
emit_label (return_label);
- if (current_function_instrument_entry_exit)
- {
- rtx fun = DECL_RTL (current_function_decl);
- if (GET_CODE (fun) == MEM)
- fun = XEXP (fun, 0);
- else
- abort ();
- emit_library_call (profile_function_exit_libfunc, LCT_NORMAL, VOIDmode,
- 2, fun, Pmode,
- expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0,
- hard_frame_pointer_rtx),
- Pmode);
- }
-
/* Let except.c know where it should emit the call to unregister
the function context for sjlj exceptions. */
if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
/* If we had calls to alloca, and this machine needs
an accurate stack pointer to exit the function,
insert some code to save and restore the stack pointer. */
-#ifdef EXIT_IGNORE_STACK
- if (! EXIT_IGNORE_STACK)
-#endif
- if (current_function_calls_alloca)
- {
- rtx tem = 0;
+ if (! EXIT_IGNORE_STACK
+ && current_function_calls_alloca)
+ {
+ rtx tem = 0;
- emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
- emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
- }
+ emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
+ emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
+ }
/* If scalar return value was computed in a pseudo-reg, or was a named
return value that got dumped to the stack, copy that to the hard
extension. */
if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
{
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result));
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
end_sequence ();
after = emit_insn_after (seq, clobber_after);
-
- if (clobber_after != after)
- cfun->x_clobber_return_insn = after;
}
/* Output the label for the naked return from the function, if one is
}
}
-/* Set the specified locator to the insn chain. */
+/* Set the locator of the insn chain starting at INSN to LOC. */
static void
set_insn_locators (rtx insn, int loc)
{
unchanged. Otherwise, it must be a MEM and we see what the
base register and offset are. In any case, we have to emit any
pending load to the equivalent reg of SP, if any. */
- if (GET_CODE (retaddr) == REG)
+ if (REG_P (retaddr))
{
emit_equiv_load (&info);
add_insn (insn);
insn = next;
continue;
}
- else if (GET_CODE (retaddr) == MEM
- && GET_CODE (XEXP (retaddr, 0)) == REG)
+ else if (MEM_P (retaddr)
+ && REG_P (XEXP (retaddr, 0)))
base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0;
- else if (GET_CODE (retaddr) == MEM
+ else if (MEM_P (retaddr)
&& GET_CODE (XEXP (retaddr, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (retaddr, 0), 0)) == REG
+ && REG_P (XEXP (XEXP (retaddr, 0), 0))
&& GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT)
{
base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0)));
&& !REGNO_REG_SET_P (EXIT_BLOCK_PTR->global_live_at_start,
regno)
&& !refers_to_regno_p (regno,
- regno + HARD_REGNO_NREGS (regno,
- Pmode),
+ regno + hard_regno_nregs[regno]
+ [Pmode],
info.equiv_reg_src, NULL)
&& info.const_equiv[regno] == 0)
break;
p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0);
if (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
- else if (GET_CODE (XEXP (SET_SRC (set), 1)) == REG
+ else if (REG_P (XEXP (SET_SRC (set), 1))
&& REGNO (XEXP (SET_SRC (set), 1)) < FIRST_PSEUDO_REGISTER
&& p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))] != 0)
p->new_sp_offset
p->new_sp_offset += p->sp_offset;
}
- if (p->new_sp_equiv_reg == 0 || GET_CODE (p->new_sp_equiv_reg) != REG)
+ if (p->new_sp_equiv_reg == 0 || !REG_P (p->new_sp_equiv_reg))
abort ();
return;
else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
{
if (p->equiv_reg_src != 0
- || GET_CODE (p->new_sp_equiv_reg) != REG
- || GET_CODE (SET_DEST (set)) != REG
+ || !REG_P (p->new_sp_equiv_reg)
+ || !REG_P (SET_DEST (set))
|| GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) > BITS_PER_WORD
|| REGNO (p->new_sp_equiv_reg) != REGNO (SET_DEST (set)))
abort ();
update_epilogue_consts (rtx dest, rtx x, void *data)
{
struct epi_info *p = (struct epi_info *) data;
+ rtx new;
- if (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
+ if (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
return;
- else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x))
- || GET_CODE (SET_SRC (x)) != CONST_INT)
+
+ /* If we are either clobbering a register or doing a partial set,
+ show we don't know the value. */
+ else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x)))
p->const_equiv[REGNO (dest)] = 0;
- else
+
+ /* If we are setting it to a constant, record that constant. */
+ else if (GET_CODE (SET_SRC (x)) == CONST_INT)
p->const_equiv[REGNO (dest)] = SET_SRC (x);
+
+ /* If this is a binary operation between a register we have been tracking
+ and a constant, see if we can compute a new constant value. */
+ else if (ARITHMETIC_P (SET_SRC (x))
+ && REG_P (XEXP (SET_SRC (x), 0))
+ && REGNO (XEXP (SET_SRC (x), 0)) < FIRST_PSEUDO_REGISTER
+ && p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))] != 0
+ && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+ && 0 != (new = simplify_binary_operation
+ (GET_CODE (SET_SRC (x)), GET_MODE (dest),
+ p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))],
+ XEXP (SET_SRC (x), 1)))
+ && GET_CODE (new) == CONST_INT)
+ p->const_equiv[REGNO (dest)] = new;
+
+ /* Otherwise, we can't do anything with this value. */
+ else
+ p->const_equiv[REGNO (dest)] = 0;
}
/* Emit an insn to do the load shown in p->equiv_reg_src, if needed. */
}
}
#endif
+ /* Find the edge that falls through to EXIT. Other edges may exist
+ due to RETURN instructions, but those don't need epilogues.
+ There really shouldn't be a mixture -- either all should have
+ been converted or none, however... */
+
+ for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ if (e->flags & EDGE_FALLTHRU)
+ break;
+ if (e == NULL)
+ goto epilogue_done;
+
#ifdef HAVE_epilogue
if (HAVE_epilogue)
{
- /* Find the edge that falls through to EXIT. Other edges may exist
- due to RETURN instructions, but those don't need epilogues.
- There really shouldn't be a mixture -- either all should have
- been converted or none, however... */
-
- for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
- if (e->flags & EDGE_FALLTHRU)
- break;
- if (e == NULL)
- goto epilogue_done;
-
start_sequence ();
epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
insert_insn_on_edge (seq, e);
inserted = 1;
}
+ else
#endif
+ {
+ basic_block cur_bb;
+
+ if (! next_active_insn (BB_END (e->src)))
+ goto epilogue_done;
+ /* We have a fall-through edge to the exit block, the source is not
+ at the end of the function, and there will be an assembler epilogue
+ at the end of the function.
+ We can't use force_nonfallthru here, because that would try to
+ use return. Inserting a jump 'by hand' is extremely messy, so
+ we take advantage of cfg_layout_finalize using
+ fixup_fallthru_exit_predecessor. */
+ cfg_layout_initialize ();
+ FOR_EACH_BB (cur_bb)
+ if (cur_bb->index >= 0 && cur_bb->next_bb->index >= 0)
+ cur_bb->rbi->next = cur_bb->next_bb;
+ cfg_layout_finalize ();
+ }
epilogue_done:
if (inserted)
#endif
#ifdef HAVE_prologue
+ /* This is probably all useless now that we use locators. */
if (prologue_end)
{
rtx insn, prev;
/* Similarly, move any line notes that appear after the epilogue.
There is no need, however, to be quite so anal about the existence
- of such a note. */
+ of such a note. Also move the NOTE_INSN_FUNCTION_END and (possibly)
+ NOTE_INSN_FUNCTION_BEG notes, as those can be relevant for debug
+ info generation. */
for (insn = epilogue_end; insn; insn = next)
{
next = NEXT_INSN (insn);
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ if (GET_CODE (insn) == NOTE
+ && (NOTE_LINE_NUMBER (insn) > 0
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END))
reorder_insns (insn, insn, PREV_INSN (epilogue_end));
}
}
VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue");
}
+/* Resets insn_block_boundaries array. */
+
+void
+reset_block_changes (void)
+{
+ VARRAY_TREE_INIT (cfun->ib_boundaries_block, 100, "ib_boundaries_block");
+ VARRAY_PUSH_TREE (cfun->ib_boundaries_block, NULL_TREE);
+}
+
+/* Record the boundary for BLOCK. */
+void
+record_block_change (tree block)
+{
+ int i, n;
+ tree last_block;
+
+ if (!block)
+ return;
+
+ last_block = VARRAY_TOP_TREE (cfun->ib_boundaries_block);
+ VARRAY_POP (cfun->ib_boundaries_block);
+ n = get_max_uid ();
+ for (i = VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block); i < n; i++)
+ VARRAY_PUSH_TREE (cfun->ib_boundaries_block, last_block);
+
+ VARRAY_PUSH_TREE (cfun->ib_boundaries_block, block);
+}
+
+/* Finishes record of boundaries. */
+void finalize_block_changes (void)
+{
+ record_block_change (DECL_INITIAL (current_function_decl));
+}
+
+/* For INSN return the BLOCK it belongs to. */
+void
+check_block_change (rtx insn, tree *block)
+{
+ unsigned uid = INSN_UID (insn);
+
+ if (uid >= VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block))
+ return;
+
+ *block = VARRAY_TREE (cfun->ib_boundaries_block, uid);
+}
+
+/* Releases the ib_boundaries_block records. */
+void
+free_block_changes (void)
+{
+ cfun->ib_boundaries_block = NULL;
+}
+
+/* Returns the name of the current function. */
+const char *
+current_function_name (void)
+{
+ return lang_hooks.decl_printable_name (cfun->decl, 2);
+}
+
#include "gt-function.h"