#include "tree-gimple.h"
#include "tree-pass.h"
#include "predict.h"
+#include "vecprim.h"
#ifndef LOCAL_ALIGNMENT
#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
/* The currently compiled function. */
struct function *cfun = 0;
-DEF_VEC_I(int);
-DEF_VEC_ALLOC_I(int,heap);
-
/* These arrays record the INSN_UIDs of the prologue and epilogue insns. */
static VEC(int,heap) *prologue;
static VEC(int,heap) *epilogue;
f->x_return_label = NULL;
f->x_naked_return_label = NULL;
f->x_stack_slot_list = NULL;
- f->x_tail_recursion_reentry = NULL;
+ f->x_stack_check_probe_note = NULL;
f->x_arg_pointer_save_area = NULL;
f->x_parm_birth_insn = NULL;
- f->original_arg_vector = NULL;
- f->original_decl_initial = NULL;
f->epilogue_delay_list = NULL;
}
\f
/* Return size needed for stack frame based on slots so far allocated.
This size counts from zero. It is not rounded to PREFERRED_STACK_BOUNDARY;
the caller may have to do that. */
+
HOST_WIDE_INT
get_frame_size (void)
{
return get_func_frame_size (cfun);
}
+/* Issue an error message and return TRUE if frame OFFSET overflows in
+ the signed target pointer arithmetics for function FUNC. Otherwise
+ return FALSE. */
+
+bool
+frame_offset_overflow (HOST_WIDE_INT offset, tree func)
+{
+ unsigned HOST_WIDE_INT size = FRAME_GROWS_DOWNWARD ? -offset : offset;
+
+ if (size > ((unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (Pmode) - 1))
+ /* Leave room for the fixed part of the frame. */
+ - 64 * UNITS_PER_WORD)
+ {
+ error ("%Jtotal size of local objects too large", func);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* Allocate a stack slot of SIZE bytes and return a MEM rtx for it
with machine mode MODE.
function->x_stack_slot_list
= gen_rtx_EXPR_LIST (VOIDmode, x, function->x_stack_slot_list);
- /* Try to detect frame size overflows on native platforms. */
-#if BITS_PER_WORD >= 32
- if ((FRAME_GROWS_DOWNWARD
- ? (unsigned HOST_WIDE_INT) -function->x_frame_offset
- : (unsigned HOST_WIDE_INT) function->x_frame_offset)
- > ((unsigned HOST_WIDE_INT) 1 << (BITS_PER_WORD - 1))
- /* Leave room for the fixed part of the frame. */
- - 64 * UNITS_PER_WORD)
- {
- error ("%Jtotal size of local objects too large", function->decl);
- /* Avoid duplicate error messages as much as possible. */
- function->x_frame_offset = 0;
- }
-#endif
+ if (frame_offset_overflow (function->x_frame_offset, function->decl))
+ function->x_frame_offset = 0;
return x;
}
static struct temp_slot **
temp_slots_at_level (int level)
{
+ if (level >= (int) VEC_length (temp_slot_p, used_temp_slots))
+ {
+ size_t old_length = VEC_length (temp_slot_p, used_temp_slots);
+ temp_slot_p *p;
- 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);
+ VEC_safe_grow (temp_slot_p, gc, used_temp_slots, level + 1);
+ p = VEC_address (temp_slot_p, used_temp_slots);
+ memset (&p[old_length], 0,
+ sizeof (temp_slot_p) * (level + 1 - old_length));
+ }
- return (struct temp_slot **) &VARRAY_GENERIC_PTR (used_temp_slots, level);
+ return &(VEC_address (temp_slot_p, used_temp_slots)[level]);
}
/* Returns the maximal temporary slot level. */
if (!used_temp_slots)
return -1;
- return VARRAY_ACTIVE_SIZE (used_temp_slots) - 1;
+ return VEC_length (temp_slot_p, used_temp_slots) - 1;
}
/* Moves temporary slot TEMP to LEVEL. */
/* 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 = avail_temp_slots; p; p = p->next)
+ smallest one with the closest alignment.
+
+ If assign_stack_temp is called outside of the tree->rtl expansion,
+ we cannot reuse the stack slots (that may still refer to
+ VIRTUAL_STACK_VARS_REGNUM). */
+ if (!virtuals_instantiated)
{
- 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)))
+ for (p = avail_temp_slots; p; p = p->next)
{
- if (p->align == align && p->size == size)
+ 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)))
{
- selected = p;
- cut_slot_from_list (selected, &avail_temp_slots);
- best_p = 0;
- break;
+ if (p->align == align && p->size == size)
+ {
+ selected = p;
+ cut_slot_from_list (selected, &avail_temp_slots);
+ best_p = 0;
+ break;
+ }
+ best_p = p;
}
- best_p = p;
}
}
if (mode == BLKmode || memory_required)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
- tree size_tree;
rtx tmp;
/* Zero sized arrays are GNU C extension. Set size to 1 to avoid
size = 1;
/* Unfortunately, we don't yet know how to allocate variable-sized
- temporaries. However, sometimes we have a fixed upper limit on
- the size (which is stored in TYPE_ARRAY_MAX_SIZE) and can use that
- instead. This is the case for Chill variable-sized strings. */
- if (size == -1 && TREE_CODE (type) == ARRAY_TYPE
- && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE
- && host_integerp (TYPE_ARRAY_MAX_SIZE (type), 1))
- size = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type), 1);
-
- /* If we still haven't been able to get a size, see if the language
- can compute a maximum size. */
- if (size == -1
- && (size_tree = lang_hooks.types.max_size (type)) != 0
- && host_integerp (size_tree, 1))
- size = tree_low_cst (size_tree, 1);
+ temporaries. However, sometimes we can find a fixed upper limit on
+ the size, so try that instead. */
+ else if (size == -1)
+ size = max_int_size_in_bytes (type);
/* The size of the temporary may be too large to fit into an integer. */
/* ??? Not sure this should happen except for user silliness, so limit
for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL);
}
+/* Helper for instantiate_decls called via walk_tree: Process all decls
+ in the given DECL_VALUE_EXPR. */
+
+static tree
+instantiate_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+ tree t = *tp;
+ if (! EXPR_P (t))
+ {
+ *walk_subtrees = 0;
+ if (DECL_P (t) && DECL_RTL_SET_P (t))
+ instantiate_decl (DECL_RTL (t));
+ }
+ return NULL;
+}
+
/* Subroutine of instantiate_decls: Process all decls in the given
BLOCK node and all its subblocks. */
tree t;
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
- if (DECL_RTL_SET_P (t))
- instantiate_decl (DECL_RTL (t));
+ {
+ if (DECL_RTL_SET_P (t))
+ instantiate_decl (DECL_RTL (t));
+ if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t))
+ {
+ tree v = DECL_VALUE_EXPR (t);
+ walk_tree (&v, instantiate_expr, NULL, NULL);
+ }
+ }
/* Process all subblocks. */
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
{
instantiate_decl (DECL_RTL (decl));
instantiate_decl (DECL_INCOMING_RTL (decl));
+ if (DECL_HAS_VALUE_EXPR_P (decl))
+ {
+ tree v = DECL_VALUE_EXPR (decl);
+ walk_tree (&v, instantiate_expr, NULL, NULL);
+ }
}
/* Now process all variables defined in the function or its subblocks. */
/* Pass through the INSNS of function FNDECL and convert virtual register
references to hard register references. */
-void
+static unsigned int
instantiate_virtual_regs (void)
{
rtx insn;
/* Indicate that, from now on, assign_stack_local should use
frame_pointer_rtx. */
virtuals_instantiated = 1;
+ return 0;
}
struct tree_opt_pass pass_instantiate_virtual_regs =
/* Store the parm in a pseudoregister during the function, but we may
need to do it in a wider mode. */
+ /* This is not really promoting for a call. However we need to be
+ consistent with assign_parm_find_data_types and expand_expr_real_1. */
promoted_nominal_mode
- = promote_mode (data->nominal_type, data->nominal_mode, &unsignedp, 0);
+ = promote_mode (data->nominal_type, data->nominal_mode, &unsignedp, 1);
parmreg = gen_reg_rtx (promoted_nominal_mode);
tree *block_vector;
*n_blocks_p = all_blocks (block, NULL);
- block_vector = xmalloc (*n_blocks_p * sizeof (tree));
+ block_vector = XNEWVEC (tree, *n_blocks_p);
all_blocks (block, block_vector);
return block_vector;
/* Make sure all values used by the optimization passes have sane
defaults. */
-void
+unsigned int
init_function_for_compilation (void)
{
reg_renumber = 0;
gcc_assert (VEC_length (int, prologue) == 0);
gcc_assert (VEC_length (int, epilogue) == 0);
gcc_assert (VEC_length (int, sibcall_epilogue) == 0);
+ return 0;
}
struct tree_opt_pass pass_init_function =
else
#endif
{
- rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 1);
+ rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 2);
/* Expect to be passed the address of a place to store the value.
If it is passed as an argument, assign_parms will take care of
it. */
as opposed to parm setup. */
emit_note (NOTE_INSN_FUNCTION_BEG);
- if (!NOTE_P (get_last_insn ()))
- emit_note (NOTE_INSN_DELETED);
+ gcc_assert (NOTE_P (get_last_insn ()));
+
parm_birth_insn = get_last_insn ();
if (current_function_profile)
#endif
}
- /* After the display initializations is where the tail-recursion label
- should go, if we end up needing one. Ensure we have a NOTE here
- since some things (like trampolines) get placed before this. */
- tail_recursion_reentry = emit_note (NOTE_INSN_DELETED);
+ /* After the display initializations is where the stack checking
+ probe should go. */
+ if(flag_stack_check)
+ stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
/* Make sure there is a line number after the function entry setup code. */
force_next_line_note ();
emit_insn (gen_rtx_USE (VOIDmode, reg));
}
-void
+static void
use_return_register (void)
{
diddle_return_value (do_use_return_reg, NULL);
GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
seq = get_insns ();
end_sequence ();
- emit_insn_before (seq, tail_recursion_reentry);
+ emit_insn_before (seq, stack_check_probe_note);
break;
}
}
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);
+ cfun->ib_boundaries_block = VEC_alloc (tree, gc, 100);
+ VEC_quick_push (tree, cfun->ib_boundaries_block, NULL_TREE);
}
/* Record the boundary for BLOCK. */
if(!cfun->ib_boundaries_block)
return;
- last_block = VARRAY_TOP_TREE (cfun->ib_boundaries_block);
- VARRAY_POP (cfun->ib_boundaries_block);
+ last_block = VEC_pop (tree, 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);
+ for (i = VEC_length (tree, cfun->ib_boundaries_block); i < n; i++)
+ VEC_safe_push (tree, gc, cfun->ib_boundaries_block, last_block);
- VARRAY_PUSH_TREE (cfun->ib_boundaries_block, block);
+ VEC_safe_push (tree, gc, cfun->ib_boundaries_block, block);
}
/* Finishes record of boundaries. */
{
unsigned uid = INSN_UID (insn);
- if (uid >= VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block))
+ if (uid >= VEC_length (tree, cfun->ib_boundaries_block))
return;
- *block = VARRAY_TREE (cfun->ib_boundaries_block, uid);
+ *block = VEC_index (tree, cfun->ib_boundaries_block, uid);
}
/* Releases the ib_boundaries_block records. */
void
free_block_changes (void)
{
- cfun->ib_boundaries_block = NULL;
+ VEC_free (tree, gc, cfun->ib_boundaries_block);
}
/* Returns the name of the current function. */
}
\f
-static void
+static unsigned int
rest_of_handle_check_leaf_regs (void)
{
#ifdef LEAF_REGISTERS
current_function_uses_only_leaf_regs
= optimize > 0 && only_leaf_regs_used () && leaf_function_p ();
#endif
+ return 0;
+}
+
+/* Insert a TYPE into the used types hash table of CFUN. */
+static void
+used_types_insert_helper (tree type, struct function *func)
+{
+ if (type != NULL && func != NULL)
+ {
+ void **slot;
+
+ if (func->used_types_hash == NULL)
+ func->used_types_hash = htab_create_ggc (37, htab_hash_pointer,
+ htab_eq_pointer, NULL);
+ slot = htab_find_slot (func->used_types_hash, type, INSERT);
+ if (*slot == NULL)
+ *slot = type;
+ }
+}
+
+/* Given a type, insert it into the used hash table in cfun. */
+void
+used_types_insert (tree t)
+{
+ while (POINTER_TYPE_P (t) || TREE_CODE (t) == ARRAY_TYPE)
+ t = TREE_TYPE (t);
+ t = TYPE_MAIN_VARIANT (t);
+ if (debug_info_level > DINFO_LEVEL_NONE)
+ used_types_insert_helper (t, cfun);
}
struct tree_opt_pass pass_leaf_regs =