#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "except.h"
#include "function.h"
#include "expr.h"
#include "libfuncs.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#include "recog.h"
#include "output.h"
#include "basic-block.h"
#include "toplev.h"
#include "hashtab.h"
#include "ggc.h"
#include "tm_p.h"
#include "integrate.h"
#include "langhooks.h"
#ifndef FRAME_ALIGN_MOD
#define FRAME_ALIGN_MOD(A,O,S) 0
#endif
#ifndef FUNCTION_ARG_MOD_BOUNDARY
#define FUNCTION_ARG_MOD_BOUNDARY(MODE,TYPE) 0
#endif
#ifndef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
#endif
#ifndef LOCAL_ALIGNMENT
#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
#endif
#ifndef NAME__MAIN
#define NAME__MAIN "__main"
#endif
#define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1))
#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
#define NEED_SEPARATE_AP
#endif
int current_function_is_leaf;
int current_function_nothrow;
int current_function_sp_is_unchanging;
int current_function_uses_only_leaf_regs;
int virtuals_instantiated;
static GTY(()) int funcdef_no;
struct machine_function * (*init_machine_status) PARAMS ((void));
tree inline_function_decl;
struct function *cfun = 0;
static GTY(()) varray_type prologue;
static GTY(()) varray_type epilogue;
static GTY(()) varray_type sibcall_epilogue;
struct temp_slot GTY(())
{
struct temp_slot *next;
rtx slot;
rtx address;
unsigned int align;
HOST_WIDE_INT size;
tree type;
tree rtl_expr;
char in_use;
char addr_taken;
int level;
int keep;
HOST_WIDE_INT base_offset;
HOST_WIDE_INT full_size;
};
struct fixup_replacement GTY(())
{
rtx old;
rtx new;
struct fixup_replacement *next;
};
struct insns_for_mem_entry
{
rtx key;
rtx insns;
};
static rtx assign_stack_local_1 PARAMS ((enum machine_mode, HOST_WIDE_INT,
int, struct function *));
static struct temp_slot *find_temp_slot_from_address PARAMS ((rtx));
static void put_reg_into_stack PARAMS ((struct function *, rtx, tree,
enum machine_mode, enum machine_mode,
int, unsigned int, int,
htab_t));
static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree,
enum machine_mode,
htab_t));
static void fixup_var_refs PARAMS ((rtx, enum machine_mode, int, rtx,
htab_t));
static struct fixup_replacement
*find_fixup_replacement PARAMS ((struct fixup_replacement **, rtx));
static void fixup_var_refs_insns PARAMS ((rtx, rtx, enum machine_mode,
int, int, rtx));
static void fixup_var_refs_insns_with_hash
PARAMS ((htab_t, rtx,
enum machine_mode, int, rtx));
static void fixup_var_refs_insn PARAMS ((rtx, rtx, enum machine_mode,
int, int, rtx));
static void fixup_var_refs_1 PARAMS ((rtx, enum machine_mode, rtx *, rtx,
struct fixup_replacement **, rtx));
static rtx fixup_memory_subreg PARAMS ((rtx, rtx, enum machine_mode, int));
static rtx walk_fixup_memory_subreg PARAMS ((rtx, rtx, enum machine_mode,
int));
static rtx fixup_stack_1 PARAMS ((rtx, rtx));
static void optimize_bit_field PARAMS ((rtx, rtx, rtx *));
static void instantiate_decls PARAMS ((tree, int));
static void instantiate_decls_1 PARAMS ((tree, int));
static void instantiate_decl PARAMS ((rtx, HOST_WIDE_INT, int));
static rtx instantiate_new_reg PARAMS ((rtx, HOST_WIDE_INT *));
static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int));
static void delete_handlers PARAMS ((void));
static void pad_to_arg_alignment PARAMS ((struct args_size *, int, int,
struct args_size *));
static void pad_below PARAMS ((struct args_size *, enum machine_mode,
tree));
static rtx round_trampoline_addr PARAMS ((rtx));
static rtx adjust_trampoline_addr PARAMS ((rtx));
static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
static void reorder_blocks_0 PARAMS ((tree));
static void reorder_blocks_1 PARAMS ((rtx, tree, varray_type *));
static void reorder_fix_fragments PARAMS ((tree));
static tree blocks_nreverse PARAMS ((tree));
static int all_blocks PARAMS ((tree, tree *));
static tree *get_block_vector PARAMS ((tree, int *));
extern tree debug_find_var_in_block_tree PARAMS ((tree, tree));
static void record_insns PARAMS ((rtx, varray_type *)) ATTRIBUTE_UNUSED;
static int contains PARAMS ((rtx, varray_type));
#ifdef HAVE_return
static void emit_return_into_block PARAMS ((basic_block, rtx));
#endif
static void put_addressof_into_stack PARAMS ((rtx, htab_t));
static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
htab_t));
static void purge_single_hard_subreg_set PARAMS ((rtx));
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
static rtx keep_stack_depressed PARAMS ((rtx));
#endif
static int is_addressof PARAMS ((rtx *, void *));
static hashval_t insns_for_mem_hash PARAMS ((const void *));
static int insns_for_mem_comp PARAMS ((const void *, const void *));
static int insns_for_mem_walk PARAMS ((rtx *, void *));
static void compute_insns_for_mem PARAMS ((rtx, rtx, htab_t));
static void prepare_function_start PARAMS ((void));
static void do_clobber_return_reg PARAMS ((rtx, void *));
static void do_use_return_reg PARAMS ((rtx, void *));
static GTY(()) struct function *outer_function_chain;
struct function *
find_function_data (decl)
tree decl;
{
struct function *p;
for (p = outer_function_chain; p; p = p->outer)
if (p->decl == decl)
return p;
abort ();
}
void
push_function_context_to (context)
tree context;
{
struct function *p;
if (context)
{
if (context == current_function_decl)
cfun->contains_functions = 1;
else
{
struct function *containing = find_function_data (context);
containing->contains_functions = 1;
}
}
if (cfun == 0)
init_dummy_function_start ();
p = cfun;
p->outer = outer_function_chain;
outer_function_chain = p;
p->fixup_var_refs_queue = 0;
(*lang_hooks.function.enter_nested) (p);
cfun = 0;
}
void
push_function_context ()
{
push_function_context_to (current_function_decl);
}
void
pop_function_context_from (context)
tree context ATTRIBUTE_UNUSED;
{
struct function *p = outer_function_chain;
struct var_refs_queue *queue;
cfun = p;
outer_function_chain = p->outer;
current_function_decl = p->decl;
reg_renumber = 0;
restore_emit_status (p);
(*lang_hooks.function.leave_nested) (p);
if (p->fixup_var_refs_queue == 0)
;
else if (p->fixup_var_refs_queue->next == 0)
fixup_var_refs (p->fixup_var_refs_queue->modified,
p->fixup_var_refs_queue->promoted_mode,
p->fixup_var_refs_queue->unsignedp,
p->fixup_var_refs_queue->modified, 0);
else
{
rtx list = 0;
for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
list = gen_rtx_EXPR_LIST (VOIDmode, queue->modified, list);
for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
fixup_var_refs (queue->modified, queue->promoted_mode,
queue->unsignedp, list, 0);
}
p->fixup_var_refs_queue = 0;
rtx_equal_function_value_matters = 1;
virtuals_instantiated = 0;
generating_concat_p = 1;
}
void
pop_function_context ()
{
pop_function_context_from (current_function_decl);
}
void
free_after_parsing (f)
struct function *f;
{
(*lang_hooks.function.final) (f);
f->stmt = NULL;
}
void
free_after_compilation (f)
struct function *f;
{
f->eh = NULL;
f->expr = NULL;
f->emit = NULL;
f->varasm = NULL;
f->machine = NULL;
f->x_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_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;
}
HOST_WIDE_INT
get_func_frame_size (f)
struct function *f;
{
#ifdef FRAME_GROWS_DOWNWARD
return -f->x_frame_offset;
#else
return f->x_frame_offset;
#endif
}
HOST_WIDE_INT
get_frame_size ()
{
return get_func_frame_size (cfun);
}
static rtx
assign_stack_local_1 (mode, size, align, function)
enum machine_mode mode;
HOST_WIDE_INT size;
int align;
struct function *function;
{
rtx x, addr;
int bigend_correction = 0;
int alignment;
int frame_off, frame_alignment, frame_phase;
if (align == 0)
{
tree type;
if (mode == BLKmode)
alignment = BIGGEST_ALIGNMENT;
else
alignment = GET_MODE_ALIGNMENT (mode);
type = (*lang_hooks.types.type_for_mode) (mode, 0);
if (type)
alignment = LOCAL_ALIGNMENT (type, alignment);
alignment /= BITS_PER_UNIT;
}
else if (align == -1)
{
alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
size = CEIL_ROUND (size, alignment);
}
else
alignment = align / BITS_PER_UNIT;
#ifdef FRAME_GROWS_DOWNWARD
function->x_frame_offset -= size;
#endif
if (alignment * BITS_PER_UNIT > PREFERRED_STACK_BOUNDARY)
alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
if (function->stack_alignment_needed < alignment * BITS_PER_UNIT)
function->stack_alignment_needed = alignment * BITS_PER_UNIT;
frame_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
frame_off = STARTING_FRAME_OFFSET % frame_alignment;
frame_phase = frame_off ? frame_alignment - frame_off : 0;
#ifdef FRAME_GROWS_DOWNWARD
function->x_frame_offset = FLOOR_ROUND (function->x_frame_offset - frame_phase, alignment) + frame_phase;
#else
function->x_frame_offset = CEIL_ROUND (function->x_frame_offset - frame_phase, alignment) + frame_phase;
#endif
if (BYTES_BIG_ENDIAN && mode != BLKmode)
bigend_correction = size - GET_MODE_SIZE (mode);
if (function == cfun && virtuals_instantiated)
addr = plus_constant (frame_pointer_rtx,
(frame_offset + bigend_correction
+ STARTING_FRAME_OFFSET));
else
addr = plus_constant (virtual_stack_vars_rtx,
function->x_frame_offset + bigend_correction);
#ifndef FRAME_GROWS_DOWNWARD
function->x_frame_offset += size;
#endif
x = gen_rtx_MEM (mode, addr);
function->x_stack_slot_list
= gen_rtx_EXPR_LIST (VOIDmode, x, function->x_stack_slot_list);
return x;
}
rtx
assign_stack_local (mode, size, align)
enum machine_mode mode;
HOST_WIDE_INT size;
int align;
{
return assign_stack_local_1 (mode, size, align, cfun);
}
rtx
assign_stack_temp_for_type (mode, size, keep, type)
enum machine_mode mode;
HOST_WIDE_INT size;
int keep;
tree type;
{
unsigned int align;
struct temp_slot *p, *best_p = 0;
rtx slot;
if (size == -1)
abort ();
if (mode == BLKmode)
align = BIGGEST_ALIGNMENT;
else
align = GET_MODE_ALIGNMENT (mode);
if (! type)
type = (*lang_hooks.types.type_for_mode) (mode, 0);
if (type)
align = LOCAL_ALIGNMENT (type, align);
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;
}
if (best_p)
{
if (GET_MODE (best_p->slot) == BLKmode)
{
int alignment = best_p->align / BITS_PER_UNIT;
HOST_WIDE_INT rounded_size = CEIL_ROUND (size, alignment);
if (best_p->size - rounded_size >= alignment)
{
p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
p->in_use = p->addr_taken = 0;
p->size = best_p->size - rounded_size;
p->base_offset = best_p->base_offset + rounded_size;
p->full_size = best_p->full_size - rounded_size;
p->slot = gen_rtx_MEM (BLKmode,
plus_constant (XEXP (best_p->slot, 0),
rounded_size));
p->align = best_p->align;
p->address = 0;
p->rtl_expr = 0;
p->type = best_p->type;
p->next = temp_slots;
temp_slots = p;
stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot,
stack_slot_list);
best_p->size = rounded_size;
best_p->full_size = rounded_size;
}
}
p = best_p;
}
if (p == 0)
{
HOST_WIDE_INT frame_offset_old = frame_offset;
p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
if (mode == BLKmode && align < BIGGEST_ALIGNMENT)
abort ();
p->slot = assign_stack_local (mode,
(mode == BLKmode
? CEIL_ROUND (size, align / BITS_PER_UNIT)
: size),
align);
p->align = align;
#ifdef FRAME_GROWS_DOWNWARD
p->size = frame_offset_old - frame_offset;
#else
p->size = size;
#endif
#ifdef FRAME_GROWS_DOWNWARD
p->base_offset = frame_offset;
p->full_size = frame_offset_old - frame_offset;
#else
p->base_offset = frame_offset_old;
p->full_size = frame_offset - frame_offset_old;
#endif
p->address = 0;
p->next = temp_slots;
temp_slots = p;
}
p->in_use = 1;
p->addr_taken = 0;
p->rtl_expr = seq_rtl_expr;
p->type = type;
if (keep == 2)
{
p->level = target_temp_slot_level;
p->keep = 0;
}
else if (keep == 3)
{
p->level = var_temp_slot_level;
p->keep = 0;
}
else
{
p->level = temp_slot_level;
p->keep = keep;
}
slot = gen_rtx_MEM (mode, XEXP (p->slot, 0));
stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, slot, stack_slot_list);
set_mem_alias_set (slot, type ? get_alias_set (type) : 0);
set_mem_align (slot, align);
if (type != 0)
{
RTX_UNCHANGING_P (slot) = (lang_hooks.honor_readonly
&& TYPE_READONLY (type));
MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type);
MEM_SET_IN_STRUCT_P (slot, AGGREGATE_TYPE_P (type));
}
return slot;
}
rtx
assign_stack_temp (mode, size, keep)
enum machine_mode mode;
HOST_WIDE_INT size;
int keep;
{
return assign_stack_temp_for_type (mode, size, keep, NULL_TREE);
}
rtx
assign_temp (type_or_decl, keep, memory_required, dont_promote)
tree type_or_decl;
int keep;
int memory_required;
int dont_promote ATTRIBUTE_UNUSED;
{
tree type, decl;
enum machine_mode mode;
#ifndef PROMOTE_FOR_CALL_ONLY
int unsignedp;
#endif
if (DECL_P (type_or_decl))
decl = type_or_decl, type = TREE_TYPE (decl);
else
decl = NULL, type = type_or_decl;
mode = TYPE_MODE (type);
#ifndef PROMOTE_FOR_CALL_ONLY
unsignedp = TREE_UNSIGNED (type);
#endif
if (mode == BLKmode || memory_required)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
rtx tmp;
if (size == 0)
size = 1;
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 (decl && size == -1
&& TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
{
error_with_decl (decl, "size of variable `%s' is too large");
size = 1;
}
tmp = assign_stack_temp_for_type (mode, size, keep, type);
return tmp;
}
#ifndef PROMOTE_FOR_CALL_ONLY
if (! dont_promote)
mode = promote_mode (type, mode, &unsignedp, 0);
#endif
return gen_reg_rtx (mode);
}
void
combine_temp_slots ()
{
struct temp_slot *p, *q;
struct temp_slot *prev_p, *prev_q;
int num_slots;
if (flag_strict_aliasing)
return;
if (! flag_expensive_optimizations)
for (p = 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)
{
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)
{
p->size += q->size;
p->full_size += q->full_size;
delete_q = 1;
}
else if (q->base_offset + q->full_size == p->base_offset)
{
q->size += p->size;
q->full_size += p->full_size;
delete_p = 1;
break;
}
}
if (delete_q)
prev_q->next = q->next;
else
prev_q = q;
}
if (delete_p)
{
if (prev_p)
prev_p->next = p->next;
else
temp_slots = p->next;
}
else
prev_p = p;
}
}
static struct temp_slot *
find_temp_slot_from_address (x)
rtx x;
{
struct temp_slot *p;
rtx next;
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;
}
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG
&& (p = find_temp_slot_from_address (XEXP (x, 0))) != 0)
return p;
else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG
&& (p = find_temp_slot_from_address (XEXP (x, 1))) != 0)
return p;
return 0;
}
void
update_temp_slot_address (old, new)
rtx old, new;
{
struct temp_slot *p;
if (rtx_equal_p (old, new))
return;
p = find_temp_slot_from_address (old);
if (p == 0)
{
if (GET_CODE (old) != PLUS)
return;
if (GET_CODE (new) == REG)
{
update_temp_slot_address (XEXP (old, 0), new);
update_temp_slot_address (XEXP (old, 1), new);
return;
}
else if (GET_CODE (new) != PLUS)
return;
if (rtx_equal_p (XEXP (old, 0), XEXP (new, 0)))
update_temp_slot_address (XEXP (old, 1), XEXP (new, 1));
else if (rtx_equal_p (XEXP (old, 1), XEXP (new, 0)))
update_temp_slot_address (XEXP (old, 0), XEXP (new, 1));
else if (rtx_equal_p (XEXP (old, 0), XEXP (new, 1)))
update_temp_slot_address (XEXP (old, 1), XEXP (new, 0));
else if (rtx_equal_p (XEXP (old, 1), XEXP (new, 1)))
update_temp_slot_address (XEXP (old, 0), XEXP (new, 0));
return;
}
else if (p->address == 0)
p->address = new;
else
{
if (GET_CODE (p->address) != EXPR_LIST)
p->address = gen_rtx_EXPR_LIST (VOIDmode, p->address, NULL_RTX);
p->address = gen_rtx_EXPR_LIST (VOIDmode, new, p->address);
}
}
void
mark_temp_addr_taken (x)
rtx x;
{
struct temp_slot *p;
if (x == 0)
return;
if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
return;
p = find_temp_slot_from_address (XEXP (x, 0));
if (p != 0)
p->addr_taken = 1;
}
void
preserve_temp_slots (x)
rtx x;
{
struct temp_slot *p = 0;
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--;
return;
}
if (GET_CODE (x) == REG && REG_POINTER (x))
p = find_temp_slot_from_address (x);
if (p == 0 && (GET_CODE (x) != MEM || 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--;
return;
}
if (p == 0)
p = find_temp_slot_from_address (XEXP (x, 0));
if (p != 0)
{
struct temp_slot *q;
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--;
p->level--;
p->addr_taken = 0;
}
return;
}
for (p = temp_slots; p; p = p->next)
if (p->in_use && p->level == temp_slot_level && ! p->keep)
p->level--;
}
void
preserve_rtl_expr_result (x)
rtx x;
{
struct temp_slot *p;
if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
return;
p = find_temp_slot_from_address (XEXP (x, 0));
if (p != 0)
{
p->level = MIN (p->level, temp_slot_level);
p->rtl_expr = 0;
}
return;
}
void
free_temp_slots ()
{
struct temp_slot *p;
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;
combine_temp_slots ();
}
void
free_temps_for_rtl_expr (t)
tree t;
{
struct temp_slot *p;
for (p = temp_slots; p; p = p->next)
if (p->rtl_expr == t)
{
if (temp_slot_level <= p->level)
p->in_use = 0;
else
p->rtl_expr = NULL_TREE;
}
combine_temp_slots ();
}
void
mark_all_temps_used ()
{
struct temp_slot *p;
for (p = temp_slots; p; p = p->next)
{
p->in_use = p->keep = 1;
p->level = MIN (p->level, temp_slot_level);
}
}
void
push_temp_slots ()
{
temp_slot_level++;
}
#if 0
void
push_temp_slots_for_block ()
{
push_temp_slots ();
var_temp_slot_level = temp_slot_level;
}
void
push_temp_slots_for_target ()
{
push_temp_slots ();
target_temp_slot_level = temp_slot_level;
}
int
get_target_temp_slot_level ()
{
return target_temp_slot_level;
}
void
set_target_temp_slot_level (level)
int level;
{
target_temp_slot_level = level;
}
#endif
void
pop_temp_slots ()
{
struct temp_slot *p;
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;
combine_temp_slots ();
temp_slot_level--;
}
void
init_temp_slots ()
{
temp_slots = 0;
temp_slot_level = 0;
var_temp_slot_level = 0;
target_temp_slot_level = 0;
}
void
put_var_into_stack (decl)
tree decl;
{
rtx 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)
|| (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
context = decl_function_context (decl);
reg = (TREE_CODE (decl) == SAVE_EXPR
? SAVE_EXPR_RTL (decl)
: DECL_RTL_IF_SET (decl));
if (reg == 0)
return;
decl_mode = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl))
: DECL_MODE (decl));
promoted_mode = GET_MODE (reg);
if (context != current_function_decl && context != inline_function_decl)
for (function = outer_function_chain; function; function = function->outer)
if (function->decl == context)
break;
if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)
&& GET_CODE (reg) == MEM
&& GET_CODE (XEXP (reg, 0)) == REG
&& REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
{
reg = XEXP (reg, 0);
decl_mode = promoted_mode = GET_MODE (reg);
}
can_use_addressof
= (function == 0
&& optimize > 0
&& decl_mode == promoted_mode
#ifdef NON_SAVING_SETJMP
&& ! (NON_SAVING_SETJMP && current_function_calls_setjmp)
#endif
);
if (! can_use_addressof && GET_CODE (reg) == MEM
&& GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
reg = XEXP (XEXP (reg, 0), 0);
if (GET_CODE (reg) == REG)
{
if (can_use_addressof)
gen_mem_addressof (reg, decl);
else
put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
decl_mode, volatilep, 0, usedp, 0);
}
else if (GET_CODE (reg) == CONCAT)
{
enum machine_mode part_mode = GET_MODE (XEXP (reg, 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
put_reg_into_stack (function, hipart, part_type, part_mode,
part_mode, volatilep, 0, 0, 0);
put_reg_into_stack (function, lopart, part_type, part_mode,
part_mode, volatilep, 0, 0, 0);
#else
put_reg_into_stack (function, lopart, part_type, part_mode,
part_mode, volatilep, 0, 0, 0);
put_reg_into_stack (function, hipart, part_type, part_mode,
part_mode, volatilep, 0, 0, 0);
#endif
PUT_CODE (reg, MEM);
MEM_ATTRS (reg) = 0;
if (DECL_P (decl))
SET_DECL_RTL (decl, NULL);
set_mem_attributes (reg, decl, 1);
if (DECL_P (decl))
SET_DECL_RTL (decl, reg);
XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);
if (GET_CODE (XEXP (reg, 0)) == PLUS)
XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
if (usedp)
{
schedule_fixup_var_refs (function, reg, TREE_TYPE (decl),
promoted_mode, 0);
schedule_fixup_var_refs (function, lopart, part_type, part_mode, 0);
schedule_fixup_var_refs (function, hipart, part_type, part_mode, 0);
}
}
else
return;
}
static void
put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
original_regno, used_p, ht)
struct function *function;
rtx reg;
tree type;
enum machine_mode promoted_mode, decl_mode;
int volatile_p;
unsigned int original_regno;
int used_p;
htab_t ht;
{
struct function *func = function ? function : cfun;
rtx new = 0;
unsigned int regno = original_regno;
if (regno == 0)
regno = REGNO (reg);
if (regno < func->x_max_parm_reg)
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);
PUT_CODE (reg, MEM);
PUT_MODE (reg, decl_mode);
XEXP (reg, 0) = XEXP (new, 0);
MEM_ATTRS (reg) = 0;
MEM_VOLATILE_P (reg) = volatile_p;
if (type)
{
MEM_SET_IN_STRUCT_P (reg,
AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
set_mem_alias_set (reg, get_alias_set (type));
}
if (used_p)
schedule_fixup_var_refs (function, reg, type, promoted_mode, ht);
}
static void
schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
struct function *function;
rtx reg;
tree type;
enum machine_mode promoted_mode;
htab_t ht;
{
int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
if (function != 0)
{
struct var_refs_queue *temp;
temp
= (struct var_refs_queue *) ggc_alloc (sizeof (struct var_refs_queue));
temp->modified = reg;
temp->promoted_mode = promoted_mode;
temp->unsignedp = unsigned_p;
temp->next = function->fixup_var_refs_queue;
function->fixup_var_refs_queue = temp;
}
else
fixup_var_refs (reg, promoted_mode, unsigned_p, reg, ht);
}
static void
fixup_var_refs (var, promoted_mode, unsignedp, may_share, ht)
rtx var;
enum machine_mode promoted_mode;
int unsignedp;
htab_t ht;
rtx may_share;
{
tree pending;
rtx first_insn = get_insns ();
struct sequence_stack *stack = seq_stack;
tree rtl_exps = rtl_expr_chain;
if (ht)
{
if (stack != 0)
abort ();
fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp,
may_share);
return;
}
fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp,
stack == 0, may_share);
for (; stack; stack = stack->next)
{
push_to_full_sequence (stack->first, stack->last);
fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp,
stack->next != 0, may_share);
stack->last = get_last_insn ();
end_sequence ();
}
for (pending = rtl_exps; pending; pending = TREE_CHAIN (pending))
{
rtx seq = RTL_EXPR_SEQUENCE (TREE_VALUE (pending));
if (seq != const0_rtx && seq != 0)
{
push_to_sequence (seq);
fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0,
may_share);
end_sequence ();
}
}
}
static struct fixup_replacement *
find_fixup_replacement (replacements, x)
struct fixup_replacement **replacements;
rtx x;
{
struct fixup_replacement *p;
for (p = *replacements; p != 0 && ! rtx_equal_p (p->old, x); p = p->next)
;
if (p == 0)
{
p = (struct fixup_replacement *) xmalloc (sizeof (struct fixup_replacement));
p->old = x;
p->new = 0;
p->next = *replacements;
*replacements = p;
}
return p;
}
static void
fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel, may_share)
rtx insn;
rtx var;
enum machine_mode promoted_mode;
int unsignedp;
int toplevel;
rtx may_share;
{
while (insn)
{
rtx next = NEXT_INSN (insn);
if (GET_CODE (insn) == CALL_INSN
&& GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
{
int i;
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))
fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel,
may_share);
insn = next;
}
}
static void
fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp, may_share)
htab_t ht;
rtx var;
enum machine_mode promoted_mode;
int unsignedp;
rtx may_share;
{
struct insns_for_mem_entry tmp;
struct insns_for_mem_entry *ime;
rtx insn_list;
tmp.key = var;
ime = (struct insns_for_mem_entry *) htab_find (ht, &tmp);
for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1))
if (INSN_P (XEXP (insn_list, 0)))
fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode,
unsignedp, 1, may_share);
}
static void
fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel, no_share)
rtx insn;
rtx var;
enum machine_mode promoted_mode;
int unsignedp;
int toplevel;
rtx no_share;
{
rtx call_dest = 0;
rtx set, prev, prev_set;
rtx note;
note = REG_NOTES (insn);
if (GET_CODE (PATTERN (insn)) == CLOBBER
&& (XEXP (PATTERN (insn), 0) == var
|| (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
&& (XEXP (XEXP (PATTERN (insn), 0), 0) == var
|| XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
{
if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
remove_note (XEXP (note, 0),
find_reg_note (XEXP (note, 0), REG_RETVAL,
NULL_RTX));
delete_insn (insn);
}
else if (toplevel
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == var
&& find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0
&& (rtx_equal_p (SET_SRC (set), var)
|| (GET_CODE (SET_SRC (set)) == REG
&& (prev = prev_nonnote_insn (insn)) != 0
&& (prev_set = single_set (prev)) != 0
&& SET_DEST (prev_set) == SET_SRC (set)
&& rtx_equal_p (SET_SRC (prev_set), var))))
{
delete_insn (insn);
}
else
{
struct fixup_replacement *replacements = 0;
rtx next_insn = NEXT_INSN (insn);
if (SMALL_REGISTER_CLASSES)
{
if (call_dest != 0 && GET_CODE (insn) == INSN
&& reg_mentioned_p (var, PATTERN (insn))
&& reg_mentioned_p (call_dest, PATTERN (insn)))
{
rtx temp = gen_reg_rtx (GET_MODE (call_dest));
emit_insn_before (gen_move_insn (temp, call_dest), insn);
PATTERN (insn) = replace_rtx (PATTERN (insn),
call_dest, temp);
}
if (GET_CODE (insn) == CALL_INSN
&& GET_CODE (PATTERN (insn)) == SET)
call_dest = SET_DEST (PATTERN (insn));
else if (GET_CODE (insn) == CALL_INSN
&& GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
else
call_dest = 0;
}
fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
&replacements, no_share);
if (insn == last_parm_insn)
last_parm_insn = PREV_INSN (next_insn);
while (replacements)
{
struct fixup_replacement *next;
if (GET_CODE (replacements->new) == REG)
{
rtx insert_before;
rtx seq;
if (GET_CODE (replacements->old) == SUBREG)
replacements->old
= fixup_memory_subreg (replacements->old, insn,
promoted_mode, 0);
else
replacements->old
= fixup_stack_1 (replacements->old, insn);
insert_before = insn;
if (GET_MODE (replacements->new)
!= GET_MODE (replacements->old))
{
start_sequence ();
convert_move (replacements->new,
replacements->old, unsignedp);
seq = get_insns ();
end_sequence ();
}
else
seq = gen_move_insn (replacements->new,
replacements->old);
emit_insn_before (seq, insert_before);
}
next = replacements->next;
free (replacements);
replacements = next;
}
}
while (note)
{
if (GET_CODE (note) != INSN_LIST)
XEXP (note, 0)
= walk_fixup_memory_subreg (XEXP (note, 0), insn,
promoted_mode, 1);
note = XEXP (note, 1);
}
}
static void
fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
rtx var;
enum machine_mode promoted_mode;
rtx *loc;
rtx insn;
struct fixup_replacement **replacements;
rtx no_share;
{
int i;
rtx x = *loc;
RTX_CODE code = GET_CODE (x);
const char *fmt;
rtx tem, tem1;
struct fixup_replacement *replacement;
switch (code)
{
case ADDRESSOF:
if (XEXP (x, 0) == var)
{
rtx sub = copy_rtx (XEXP (var, 0));
if (! validate_change (insn, loc, sub, 0))
{
rtx y = gen_reg_rtx (GET_MODE (sub));
rtx seq, new_insn;
if (! validate_replace_rtx (*loc, y, insn))
abort ();
start_sequence ();
new_insn = emit_insn (gen_rtx_SET (VOIDmode, y, sub));
seq = get_insns ();
end_sequence ();
if (recog_memoized (new_insn) < 0)
{
start_sequence ();
sub = force_operand (sub, y);
if (sub != y)
emit_insn (gen_move_insn (y, sub));
seq = get_insns ();
end_sequence ();
}
#ifdef HAVE_cc0
if (PREV_INSN (insn) && sets_cc0_p (PREV_INSN (insn)))
insn = PREV_INSN (insn);
#endif
emit_insn_before (seq, insn);
}
}
return;
case MEM:
if (var == x)
{
replacement = find_fixup_replacement (replacements, var);
if (replacement->new)
{
*loc = replacement->new;
return;
}
*loc = replacement->new = x = fixup_stack_1 (x, insn);
INSN_CODE (insn) = -1;
if (! flag_force_mem && GET_MODE (x) == promoted_mode
&& recog_memoized (insn) >= 0)
return;
*loc = replacement->new = gen_reg_rtx (promoted_mode);
return;
}
if (reg_mentioned_p (var, x))
{
replacement = find_fixup_replacement (replacements, x);
if (replacement->new == 0)
replacement->new = copy_most_rtx (x, no_share);
*loc = x = replacement->new;
code = GET_CODE (x);
}
break;
case REG:
case CC0:
case PC:
case CONST_INT:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
case CONST_DOUBLE:
case CONST_VECTOR:
return;
case SIGN_EXTRACT:
case ZERO_EXTRACT:
if (XEXP (x, 0) == var
|| (GET_CODE (XEXP (x, 0)) == SUBREG
&& SUBREG_REG (XEXP (x, 0)) == var))
{
tem = XEXP (x, 0);
if (GET_CODE (tem) == SUBREG)
{
if (GET_MODE_BITSIZE (GET_MODE (tem))
> GET_MODE_BITSIZE (GET_MODE (var)))
{
replacement = find_fixup_replacement (replacements, var);
if (replacement->new == 0)
replacement->new = gen_reg_rtx (GET_MODE (var));
SUBREG_REG (tem) = replacement->new;
XEXP (x, 0) = tem;
return;
}
else
tem = fixup_memory_subreg (tem, insn, promoted_mode, 0);
}
else
tem = fixup_stack_1 (tem, insn);
if (! flag_force_mem && GET_CODE (XEXP (x, 1)) == CONST_INT
&& GET_CODE (XEXP (x, 2)) == CONST_INT
&& ! mode_dependent_address_p (XEXP (tem, 0))
&& ! MEM_VOLATILE_P (tem))
{
enum machine_mode wanted_mode = VOIDmode;
enum machine_mode is_mode = GET_MODE (tem);
HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
if (GET_CODE (x) == ZERO_EXTRACT)
{
enum machine_mode new_mode
= mode_for_extraction (EP_extzv, 1);
if (new_mode != MAX_MACHINE_MODE)
wanted_mode = new_mode;
}
else if (GET_CODE (x) == SIGN_EXTRACT)
{
enum machine_mode new_mode
= mode_for_extraction (EP_extv, 1);
if (new_mode != MAX_MACHINE_MODE)
wanted_mode = new_mode;
}
if (wanted_mode != VOIDmode
&& GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
{
HOST_WIDE_INT offset = pos / BITS_PER_UNIT;
rtx old_pos = XEXP (x, 2);
rtx newmem;
if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
offset = (GET_MODE_SIZE (is_mode)
- GET_MODE_SIZE (wanted_mode) - offset);
pos %= GET_MODE_BITSIZE (wanted_mode);
newmem = adjust_address_nv (tem, wanted_mode, offset);
INSN_CODE (insn) = -1;
XEXP (x, 0) = newmem;
XEXP (x, 2) = GEN_INT (pos);
if (recog_memoized (insn) >= 0)
return;
XEXP (x, 2) = old_pos;
}
}
tem1 = gen_reg_rtx (GET_MODE (tem));
emit_insn_before (gen_move_insn (tem1, tem), insn);
XEXP (x, 0) = tem1;
return;
}
break;
case SUBREG:
if (SUBREG_REG (x) == var)
{
if (SUBREG_PROMOTED_VAR_P (x))
{
*loc = var;
fixup_var_refs_1 (var, GET_MODE (var), loc, insn, replacements,
no_share);
return;
}
if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (var)))
{
replacement = find_fixup_replacement (replacements, var);
if (replacement->new == 0)
replacement->new = gen_reg_rtx (promoted_mode);
SUBREG_REG (x) = replacement->new;
return;
}
replacement = find_fixup_replacement (replacements, x);
if (replacement->new)
{
*loc = replacement->new;
return;
}
replacement->new = *loc = fixup_memory_subreg (x, insn,
promoted_mode, 0);
INSN_CODE (insn) = -1;
if (! flag_force_mem && recog_memoized (insn) >= 0)
return;
*loc = replacement->new = gen_reg_rtx (GET_MODE (x));
return;
}
break;
case SET:
if (GET_CODE (SET_DEST (x)) == SIGN_EXTRACT
|| GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
optimize_bit_field (x, insn, 0);
if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT
|| GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
optimize_bit_field (x, insn, 0);
if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG
&& SUBREG_REG (XEXP (SET_DEST (x), 0)) == var
&& (GET_MODE_SIZE (GET_MODE (XEXP (SET_DEST (x), 0)))
> GET_MODE_SIZE (GET_MODE (var))))
{
replacement = find_fixup_replacement (replacements, var);
if (replacement->new == 0)
replacement->new = gen_reg_rtx (GET_MODE (var));
SUBREG_REG (XEXP (SET_DEST (x), 0)) = replacement->new;
emit_insn_after (gen_move_insn (var, replacement->new), insn);
}
if (GET_CODE (SET_DEST (x)) == SUBREG
&& SUBREG_REG (SET_DEST (x)) == var
&& (GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
> GET_MODE_SIZE (GET_MODE (var))))
{
SET_DEST (x) = tem = gen_reg_rtx (GET_MODE (SET_DEST (x)));
emit_insn_after (gen_move_insn (var, gen_lowpart (GET_MODE (var),
tem)),
insn);
break;
}
{
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
rtx outerdest = dest;
while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == ZERO_EXTRACT)
dest = XEXP (dest, 0);
if (GET_CODE (src) == SUBREG)
src = SUBREG_REG (src);
if (src != var && dest != var)
break;
INSN_CODE (insn) = -1;
if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var
&& mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE)
{
fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 1),
insn, replacements, no_share);
fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 2),
insn, replacements, no_share);
fixup_var_refs_1 (var, promoted_mode, &SET_SRC (x),
insn, replacements, no_share);
tem = XEXP (outerdest, 0);
if (GET_CODE (tem) == SUBREG
&& SUBREG_REG (tem) == var)
tem = fixup_memory_subreg (tem, insn, promoted_mode, 0);
else
tem = fixup_stack_1 (tem, insn);
if (GET_CODE (XEXP (outerdest, 1)) == CONST_INT
&& GET_CODE (XEXP (outerdest, 2)) == CONST_INT
&& ! mode_dependent_address_p (XEXP (tem, 0))
&& ! MEM_VOLATILE_P (tem))
{
enum machine_mode wanted_mode;
enum machine_mode is_mode = GET_MODE (tem);
HOST_WIDE_INT pos = INTVAL (XEXP (outerdest, 2));
wanted_mode = mode_for_extraction (EP_insv, 0);
if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
{
HOST_WIDE_INT offset = pos / BITS_PER_UNIT;
rtx old_pos = XEXP (outerdest, 2);
rtx newmem;
if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
offset = (GET_MODE_SIZE (is_mode)
- GET_MODE_SIZE (wanted_mode) - offset);
pos %= GET_MODE_BITSIZE (wanted_mode);
newmem = adjust_address_nv (tem, wanted_mode, offset);
INSN_CODE (insn) = -1;
XEXP (outerdest, 0) = newmem;
XEXP (outerdest, 2) = GEN_INT (pos);
if (recog_memoized (insn) >= 0)
return;
XEXP (outerdest, 2) = old_pos;
}
}
tem1 = gen_reg_rtx (GET_MODE (tem));
emit_insn_before (gen_move_insn (tem1, tem), insn);
emit_insn_after (gen_move_insn (tem, tem1), insn);
XEXP (outerdest, 0) = tem1;
return;
}
if (dest == var && GET_CODE (SET_DEST (x)) == STRICT_LOW_PART)
SET_DEST (x) = XEXP (SET_DEST (x), 0);
if ((SET_SRC (x) == var
|| (GET_CODE (SET_SRC (x)) == SUBREG
&& SUBREG_REG (SET_SRC (x)) == var))
&& (GET_CODE (SET_DEST (x)) == REG
|| (GET_CODE (SET_DEST (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
&& GET_MODE (var) == promoted_mode
&& x == single_set (insn))
{
rtx pat, last;
if (GET_CODE (SET_SRC (x)) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (SET_SRC (x)))
> GET_MODE_SIZE (GET_MODE (var))))
{
replacement = find_fixup_replacement (replacements, var);
if (replacement->new == NULL_RTX)
replacement->new = gen_reg_rtx (GET_MODE (var));
SUBREG_REG (SET_SRC (x)) = replacement->new;
}
else
{
replacement = find_fixup_replacement (replacements, SET_SRC (x));
if (replacement->new)
SET_SRC (x) = replacement->new;
else if (GET_CODE (SET_SRC (x)) == SUBREG)
SET_SRC (x) = replacement->new
= fixup_memory_subreg (SET_SRC (x), insn, promoted_mode,
0);
else
SET_SRC (x) = replacement->new
= fixup_stack_1 (SET_SRC (x), insn);
}
if (recog_memoized (insn) >= 0)
return;
pat = gen_move_insn (SET_DEST (x), SET_SRC (x));
if (NEXT_INSN (pat) != NULL_RTX)
{
last = emit_insn_before (pat, insn);
if (REG_NOTES (last) && REG_NOTES (insn))
abort ();
if (REG_NOTES (last))
REG_NOTES (insn) = REG_NOTES (last);
PATTERN (insn) = PATTERN (last);
delete_insn (last);
}
else
PATTERN (insn) = PATTERN (pat);
return;
}
if ((SET_DEST (x) == var
|| (GET_CODE (SET_DEST (x)) == SUBREG
&& SUBREG_REG (SET_DEST (x)) == var))
&& (GET_CODE (SET_SRC (x)) == REG
|| (GET_CODE (SET_SRC (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
&& GET_MODE (var) == promoted_mode
&& x == single_set (insn))
{
rtx pat, last;
if (GET_CODE (SET_DEST (x)) == SUBREG)
SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn,
promoted_mode, 0);
else
SET_DEST (x) = fixup_stack_1 (SET_DEST (x), insn);
if (recog_memoized (insn) >= 0)
return;
pat = gen_move_insn (SET_DEST (x), SET_SRC (x));
if (NEXT_INSN (pat) != NULL_RTX)
{
last = emit_insn_before (pat, insn);
if (REG_NOTES (last) && REG_NOTES (insn))
abort ();
if (REG_NOTES (last))
REG_NOTES (insn) = REG_NOTES (last);
PATTERN (insn) = PATTERN (last);
delete_insn (last);
}
else
PATTERN (insn) = PATTERN (pat);
return;
}
if (dest == var)
{
rtx temp;
rtx fixeddest = SET_DEST (x);
enum machine_mode temp_mode;
if (GET_CODE (fixeddest) == STRICT_LOW_PART)
fixeddest = XEXP (fixeddest, 0);
if (GET_CODE (fixeddest) == SUBREG)
{
fixeddest = fixup_memory_subreg (fixeddest, insn,
promoted_mode, 0);
temp_mode = GET_MODE (fixeddest);
}
else
{
fixeddest = fixup_stack_1 (fixeddest, insn);
temp_mode = promoted_mode;
}
temp = gen_reg_rtx (temp_mode);
emit_insn_after (gen_move_insn (fixeddest,
gen_lowpart (GET_MODE (fixeddest),
temp)),
insn);
SET_DEST (x) = temp;
}
}
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements,
no_share);
else if (fmt[i] == 'E')
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j),
insn, replacements, no_share);
}
}
}
static rtx
fixup_memory_subreg (x, insn, promoted_mode, uncritical)
rtx x;
rtx insn;
enum machine_mode promoted_mode;
int uncritical;
{
int offset;
rtx mem = SUBREG_REG (x);
rtx addr = XEXP (mem, 0);
enum machine_mode mode = GET_MODE (x);
rtx result, seq;
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (mem)) && ! uncritical)
abort ();
offset = SUBREG_BYTE (x);
if (BYTES_BIG_ENDIAN)
offset -= (GET_MODE_SIZE (promoted_mode) - GET_MODE_SIZE (GET_MODE (mem)));
if (!flag_force_addr
&& memory_address_p (mode, plus_constant (addr, offset)))
return adjust_address (mem, mode, offset);
start_sequence ();
result = adjust_address (mem, mode, offset);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
return result;
}
static rtx
walk_fixup_memory_subreg (x, insn, promoted_mode, uncritical)
rtx x;
rtx insn;
enum machine_mode promoted_mode;
int uncritical;
{
enum rtx_code code;
const char *fmt;
int i;
if (x == 0)
return 0;
code = GET_CODE (x);
if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
return fixup_memory_subreg (x, insn, promoted_mode, uncritical);
fmt = GET_RTX_FORMAT (code);
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,
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,
promoted_mode, uncritical);
}
}
return x;
}
static rtx
fixup_stack_1 (x, insn)
rtx x;
rtx insn;
{
int i;
RTX_CODE code = GET_CODE (x);
const char *fmt;
if (code == MEM)
{
rtx ad = XEXP (x, 0);
if (GET_CODE (ad) == PLUS
&& GET_CODE (XEXP (ad, 0)) == REG
&& ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER
&& REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER)
|| REGNO (XEXP (ad, 0)) == FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
|| REGNO (XEXP (ad, 0)) == HARD_FRAME_POINTER_REGNUM
#endif
|| REGNO (XEXP (ad, 0)) == STACK_POINTER_REGNUM
|| REGNO (XEXP (ad, 0)) == ARG_POINTER_REGNUM
|| XEXP (ad, 0) == current_function_internal_arg_pointer)
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
{
rtx temp, seq;
if (memory_address_p (GET_MODE (x), ad))
return x;
start_sequence ();
temp = copy_to_reg (ad);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
return replace_equiv_address (x, temp);
}
return x;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
XEXP (x, i) = fixup_stack_1 (XEXP (x, i), insn);
else if (fmt[i] == 'E')
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
XVECEXP (x, i, j) = fixup_stack_1 (XVECEXP (x, i, j), insn);
}
}
return x;
}
static void
optimize_bit_field (body, insn, equiv_mem)
rtx body;
rtx insn;
rtx *equiv_mem;
{
rtx bitfield;
int destflag;
rtx seq = 0;
enum machine_mode mode;
if (GET_CODE (SET_DEST (body)) == SIGN_EXTRACT
|| GET_CODE (SET_DEST (body)) == ZERO_EXTRACT)
bitfield = SET_DEST (body), destflag = 1;
else
bitfield = SET_SRC (body), destflag = 0;
if (GET_CODE (XEXP (bitfield, 1)) == CONST_INT
&& GET_CODE (XEXP (bitfield, 2)) == CONST_INT
&& ((mode = mode_for_size (INTVAL (XEXP (bitfield, 1)), MODE_INT, 1))
!= BLKmode)
&& INTVAL (XEXP (bitfield, 2)) % INTVAL (XEXP (bitfield, 1)) == 0)
{
rtx memref = 0;
if (GET_CODE (XEXP (bitfield, 0)) == MEM)
memref = XEXP (bitfield, 0);
else if (GET_CODE (XEXP (bitfield, 0)) == REG
&& 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)
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)
memref = equiv_mem[REGNO (SUBREG_REG (XEXP (bitfield, 0)))];
if (memref
&& ! mode_dependent_address_p (XEXP (memref, 0))
&& ! MEM_VOLATILE_P (memref))
{
HOST_WIDE_INT offset = INTVAL (XEXP (bitfield, 2));
rtx insns;
if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
offset = (GET_MODE_BITSIZE (GET_MODE (XEXP (bitfield, 0)))
- offset - INTVAL (XEXP (bitfield, 1)));
offset /= BITS_PER_UNIT;
if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
{
offset += (SUBREG_BYTE (XEXP (bitfield, 0))
/ UNITS_PER_WORD) * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
offset -= (MIN (UNITS_PER_WORD,
GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
- MIN (UNITS_PER_WORD,
GET_MODE_SIZE (GET_MODE (memref))));
}
start_sequence ();
memref = adjust_address (memref, mode, offset);
insns = get_insns ();
end_sequence ();
emit_insn_before (insns, insn);
if (destflag)
{
validate_change (insn, &SET_DEST (body), memref, 1);
if (! CONSTANT_ADDRESS_P (SET_SRC (body)))
{
rtx src = SET_SRC (body);
while (GET_CODE (src) == SUBREG
&& SUBREG_BYTE (src) == 0)
src = SUBREG_REG (src);
if (GET_MODE (src) != GET_MODE (memref))
src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
validate_change (insn, &SET_SRC (body), src, 1);
}
else if (GET_MODE (SET_SRC (body)) != VOIDmode
&& GET_MODE (SET_SRC (body)) != GET_MODE (memref))
abort ();
}
else
{
rtx dest = SET_DEST (body);
while (GET_CODE (dest) == SUBREG
&& SUBREG_BYTE (dest) == 0
&& (GET_MODE_CLASS (GET_MODE (dest))
== GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest))))
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
<= UNITS_PER_WORD))
dest = SUBREG_REG (dest);
validate_change (insn, &SET_DEST (body), dest, 1);
if (GET_MODE (dest) == GET_MODE (memref))
validate_change (insn, &SET_SRC (body), memref, 1);
else
{
rtx newreg = gen_reg_rtx (GET_MODE (dest));
start_sequence ();
convert_move (newreg, memref,
GET_CODE (SET_SRC (body)) == ZERO_EXTRACT);
seq = get_insns ();
end_sequence ();
validate_change (insn, &SET_SRC (body), newreg, 1);
}
}
if (apply_change_group () && seq)
emit_insn_before (seq, insn);
}
}
}
static int in_arg_offset;
static int var_offset;
static int dynamic_offset;
static int out_arg_offset;
static int cfa_offset;
#ifndef STACK_POINTER_OFFSET
#define STACK_POINTER_OFFSET 0
#endif
#ifndef STACK_DYNAMIC_OFFSET
#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
#define STACK_DYNAMIC_OFFSET(FNDECL) \
((ACCUMULATE_OUTGOING_ARGS \
? (current_function_outgoing_args_size + REG_PARM_STACK_SPACE (FNDECL)) : 0)\
+ (STACK_POINTER_OFFSET)) \
#else
#define STACK_DYNAMIC_OFFSET(FNDECL) \
((ACCUMULATE_OUTGOING_ARGS ? current_function_outgoing_args_size : 0) \
+ (STACK_POINTER_OFFSET))
#endif
#endif
#ifndef ARG_POINTER_CFA_OFFSET
#define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL)
#endif
rtx
gen_mem_addressof (reg, decl)
rtx reg;
tree decl;
{
rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
REGNO (reg), decl);
HOST_WIDE_INT set = decl ? get_alias_set (decl) : 0;
REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
PUT_CODE (reg, MEM);
MEM_ATTRS (reg) = 0;
XEXP (reg, 0) = r;
if (decl)
{
tree type = TREE_TYPE (decl);
enum machine_mode decl_mode
= (DECL_P (decl) ? DECL_MODE (decl) : TYPE_MODE (TREE_TYPE (decl)));
rtx decl_rtl = (TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl)
: DECL_RTL_IF_SET (decl));
PUT_MODE (reg, decl_mode);
if (DECL_P (decl) && decl_rtl == reg)
SET_DECL_RTL (decl, 0);
set_mem_attributes (reg, decl, 1);
set_mem_alias_set (reg, set);
if (DECL_P (decl) && decl_rtl == reg)
SET_DECL_RTL (decl, reg);
if (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0))
fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
}
else
fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
return reg;
}
void
flush_addressof (decl)
tree decl;
{
if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
&& DECL_RTL (decl) != 0
&& GET_CODE (DECL_RTL (decl)) == MEM
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
&& GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
put_addressof_into_stack (XEXP (DECL_RTL (decl), 0), 0);
}
static void
put_addressof_into_stack (r, ht)
rtx r;
htab_t ht;
{
tree decl, type;
int volatile_p, used_p;
rtx reg = XEXP (r, 0);
if (GET_CODE (reg) != REG)
abort ();
decl = ADDRESSOF_DECL (r);
if (decl)
{
type = TREE_TYPE (decl);
volatile_p = (TREE_CODE (decl) != SAVE_EXPR
&& TREE_THIS_VOLATILE (decl));
used_p = (TREE_USED (decl)
|| (DECL_P (decl) && DECL_INITIAL (decl) != 0));
}
else
{
type = NULL_TREE;
volatile_p = 0;
used_p = 1;
}
put_reg_into_stack (0, reg, type, GET_MODE (reg), GET_MODE (reg),
volatile_p, ADDRESSOF_REGNO (r), used_p, ht);
}
static rtx purge_bitfield_addressof_replacements;
static rtx purge_addressof_replacements;
static bool
purge_addressof_1 (loc, insn, force, store, ht)
rtx *loc;
rtx insn;
int force, store;
htab_t ht;
{
rtx x;
RTX_CODE code;
int i, j;
const char *fmt;
bool result = true;
restart:
x = *loc;
if (x == 0)
return true;
code = GET_CODE (x);
if (code == SET)
{
result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
return result;
}
else if (code == ADDRESSOF)
{
rtx sub, insns;
if (GET_CODE (XEXP (x, 0)) != MEM)
put_addressof_into_stack (x, ht);
sub = copy_rtx (XEXP (XEXP (x, 0), 0));
if (validate_change (insn, loc, sub, 0)
|| validate_replace_rtx (x, sub, insn))
return true;
start_sequence ();
sub = force_operand (sub, NULL_RTX);
if (! validate_change (insn, loc, sub, 0)
&& ! validate_replace_rtx (x, sub, insn))
abort ();
insns = get_insns ();
end_sequence ();
emit_insn_before (insns, insn);
return true;
}
else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
{
rtx sub = XEXP (XEXP (x, 0), 0);
if (GET_CODE (sub) == MEM)
sub = adjust_address_nv (sub, GET_MODE (x), 0);
else if (GET_CODE (sub) == REG
&& (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
;
else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
{
int size_x, size_sub;
if (!insn)
{
rtx tem;
for (tem = purge_bitfield_addressof_replacements;
tem != NULL_RTX;
tem = XEXP (XEXP (tem, 1), 1))
if (rtx_equal_p (x, XEXP (tem, 0)))
{
*loc = XEXP (XEXP (tem, 1), 0);
return true;
}
for (tem = purge_addressof_replacements;
tem != NULL_RTX;
tem = XEXP (XEXP (tem, 1), 1))
if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
{
rtx z = XEXP (XEXP (tem, 1), 0);
if (GET_MODE (x) == GET_MODE (z)
|| (GET_CODE (XEXP (XEXP (tem, 1), 0)) != REG
&& GET_CODE (XEXP (XEXP (tem, 1), 0)) != SUBREG))
abort ();
if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
z = SUBREG_REG (z);
if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (x))
> GET_MODE_SIZE (GET_MODE (z))))
{
z = gen_rtx_SUBREG (GET_MODE (x), z, 0);
}
else
z = gen_lowpart (GET_MODE (x), z);
*loc = z;
return true;
}
return false;
}
size_x = GET_MODE_BITSIZE (GET_MODE (x));
size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
if (size_x <= size_sub
&& GET_MODE_CLASS (GET_MODE (sub)) != MODE_VECTOR_INT
&& GET_MODE_CLASS (GET_MODE (sub)) != MODE_VECTOR_FLOAT
&& int_mode_for_mode (GET_MODE (sub)) != BLKmode)
{
rtx val, seq;
if (store)
{
rtx p = PREV_INSN (insn);
start_sequence ();
val = gen_reg_rtx (GET_MODE (x));
if (! validate_change (insn, loc, val, 0))
{
end_sequence ();
goto give_up;
}
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
insn, ht);
start_sequence ();
store_bit_field (sub, size_x, 0, GET_MODE (x),
val, GET_MODE_SIZE (GET_MODE (sub)));
unshare_all_rtl_again (get_insns ());
seq = get_insns ();
end_sequence ();
p = emit_insn_after (seq, insn);
if (NEXT_INSN (insn))
compute_insns_for_mem (NEXT_INSN (insn),
p ? NEXT_INSN (p) : NULL_RTX,
ht);
}
else
{
rtx p = PREV_INSN (insn);
start_sequence ();
val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
GET_MODE (x), GET_MODE (x),
GET_MODE_SIZE (GET_MODE (sub)));
if (! validate_change (insn, loc, val, 0))
{
end_sequence ();
goto give_up;
}
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
insn, ht);
}
purge_bitfield_addressof_replacements
= gen_rtx_EXPR_LIST (VOIDmode, x,
gen_rtx_EXPR_LIST
(VOIDmode, val,
purge_bitfield_addressof_replacements));
return true;
}
}
else if (validate_change (insn, loc, sub, 0))
{
if (GET_CODE (sub) == REG || GET_CODE (sub) == SUBREG)
{
rtx tem;
for (tem = purge_addressof_replacements;
tem != NULL_RTX;
tem = XEXP (XEXP (tem, 1), 1))
if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
{
XEXP (XEXP (tem, 1), 0) = sub;
return true;
}
purge_addressof_replacements
= gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0),
gen_rtx_EXPR_LIST (VOIDmode, sub,
purge_addressof_replacements));
return true;
}
goto restart;
}
}
give_up:
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
{
if (*fmt == 'e')
result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht);
else if (*fmt == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht);
}
return result;
}
static hashval_t
insns_for_mem_hash (k)
const void * k;
{
struct insns_for_mem_entry *m = (struct insns_for_mem_entry *) k;
return htab_hash_pointer (m->key);
}
static int
insns_for_mem_comp (k1, k2)
const void * k1;
const void * k2;
{
struct insns_for_mem_entry *m1 = (struct insns_for_mem_entry *) k1;
struct insns_for_mem_entry *m2 = (struct insns_for_mem_entry *) k2;
return m1->key == m2->key;
}
struct insns_for_mem_walk_info
{
htab_t ht;
rtx insn;
int pass;
};
static int
insns_for_mem_walk (r, data)
rtx *r;
void *data;
{
struct insns_for_mem_walk_info *ifmwi
= (struct insns_for_mem_walk_info *) data;
struct insns_for_mem_entry tmp;
tmp.insns = NULL_RTX;
if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
&& GET_CODE (XEXP (*r, 0)) == REG)
{
PTR *e;
tmp.key = XEXP (*r, 0);
e = htab_find_slot (ifmwi->ht, &tmp, INSERT);
if (*e == NULL)
{
*e = ggc_alloc (sizeof (tmp));
memcpy (*e, &tmp, sizeof (tmp));
}
}
else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
{
struct insns_for_mem_entry *ifme;
tmp.key = *r;
ifme = (struct insns_for_mem_entry *) htab_find (ifmwi->ht, &tmp);
if (ifme && (!ifme->insns || XEXP (ifme->insns, 0) != ifmwi->insn))
ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn,
ifme->insns);
}
return 0;
}
static void
compute_insns_for_mem (insns, last_insn, ht)
rtx insns;
rtx last_insn;
htab_t ht;
{
rtx insn;
struct insns_for_mem_walk_info ifmwi;
ifmwi.ht = ht;
for (ifmwi.pass = 0; ifmwi.pass < 2; ++ifmwi.pass)
for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
ifmwi.insn = insn;
for_each_rtx (&insn, insns_for_mem_walk, &ifmwi);
}
}
static int
is_addressof (rtl, data)
rtx *rtl;
void *data ATTRIBUTE_UNUSED;
{
return GET_CODE (*rtl) == ADDRESSOF;
}
void
purge_addressof (insns)
rtx insns;
{
rtx insn;
htab_t ht;
ht = htab_create_ggc (1000, insns_for_mem_hash, insns_for_mem_comp, NULL);
compute_insns_for_mem (insns, NULL_RTX, ht);
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
|| GET_CODE (insn) == CALL_INSN)
{
if (! purge_addressof_1 (&PATTERN (insn), insn,
asm_noperands (PATTERN (insn)) > 0, 0, ht))
abort ();
if (! purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0, ht))
{
rtx note;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_RETVAL)
abort ();
if (for_each_rtx (¬e, is_addressof, NULL))
remove_note (insn, note);
}
}
}
purge_bitfield_addressof_replacements = 0;
purge_addressof_replacements = 0;
unshare_all_rtl_again (get_insns ());
}
static void
purge_single_hard_subreg_set (pattern)
rtx pattern;
{
rtx reg = SET_DEST (pattern);
enum machine_mode mode = GET_MODE (SET_DEST (pattern));
int offset = 0;
if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
&& REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
{
offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
GET_MODE (SUBREG_REG (reg)),
SUBREG_BYTE (reg),
GET_MODE (reg));
reg = SUBREG_REG (reg);
}
if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
{
reg = gen_rtx_REG (mode, REGNO (reg) + offset);
SET_DEST (pattern) = reg;
}
}
void
purge_hard_subreg_sets (insn)
rtx insn;
{
for (; insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
{
rtx pattern = PATTERN (insn);
switch (GET_CODE (pattern))
{
case SET:
if (GET_CODE (SET_DEST (pattern)) == SUBREG)
purge_single_hard_subreg_set (pattern);
break;
case PARALLEL:
{
int j;
for (j = XVECLEN (pattern, 0) - 1; j >= 0; j--)
{
rtx inner_pattern = XVECEXP (pattern, 0, j);
if (GET_CODE (inner_pattern) == SET
&& GET_CODE (SET_DEST (inner_pattern)) == SUBREG)
purge_single_hard_subreg_set (inner_pattern);
}
}
break;
default:
break;
}
}
}
}
void
instantiate_virtual_regs (fndecl, insns)
tree fndecl;
rtx insns;
{
rtx insn;
unsigned int i;
in_arg_offset = FIRST_PARM_OFFSET (fndecl);
var_offset = STARTING_FRAME_OFFSET;
dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
out_arg_offset = STACK_POINTER_OFFSET;
cfa_offset = ARG_POINTER_CFA_OFFSET (fndecl);
instantiate_decls (fndecl, 1);
init_recog ();
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
|| GET_CODE (insn) == CALL_INSN)
{
instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1);
instantiate_virtual_regs_1 (®_NOTES (insn), NULL_RTX, 0);
if (GET_CODE (insn) == CALL_INSN)
instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn),
NULL_RTX, 0);
}
for (i = 0; i < max_parm_reg; ++i)
if (parm_reg_stack_loc[i])
instantiate_virtual_regs_1 (&parm_reg_stack_loc[i], NULL_RTX, 0);
instantiate_decls (fndecl, 0);
virtuals_instantiated = 1;
}
static void
instantiate_decls (fndecl, valid_only)
tree fndecl;
int valid_only;
{
tree decl;
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
HOST_WIDE_INT size_rtl;
instantiate_decl (DECL_RTL (decl), size, valid_only);
size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl)));
size = MAX (size_rtl, size);
instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
}
instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
}
static void
instantiate_decls_1 (let, valid_only)
tree let;
int valid_only;
{
tree t;
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
if (DECL_RTL_SET_P (t))
instantiate_decl (DECL_RTL (t),
int_size_in_bytes (TREE_TYPE (t)),
valid_only);
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
instantiate_decls_1 (t, valid_only);
}
static void
instantiate_decl (x, size, valid_only)
rtx x;
HOST_WIDE_INT size;
int valid_only;
{
enum machine_mode mode;
rtx addr;
if (x == 0 || GET_CODE (x) != MEM)
return;
addr = XEXP (x, 0);
if (CONSTANT_P (addr)
|| (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == REG)
|| (GET_CODE (addr) == REG
&& (REGNO (addr) < FIRST_VIRTUAL_REGISTER
|| REGNO (addr) > LAST_VIRTUAL_REGISTER)))
return;
if (valid_only)
addr = copy_rtx (addr);
instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
if (valid_only && size >= 0)
{
unsigned HOST_WIDE_INT decl_size = size;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
return;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
return;
if (VECTOR_MODE_P (GET_MODE (x))
&& ! memory_address_p (GET_MODE (x), addr))
return;
}
XEXP (x, 0) = addr;
}
static rtx
instantiate_new_reg (x, poffset)
rtx x;
HOST_WIDE_INT *poffset;
{
rtx new;
HOST_WIDE_INT offset;
if (x == virtual_incoming_args_rtx)
new = arg_pointer_rtx, offset = in_arg_offset;
else if (x == virtual_stack_vars_rtx)
new = frame_pointer_rtx, offset = var_offset;
else if (x == virtual_stack_dynamic_rtx)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (x == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
else if (x == virtual_cfa_rtx)
new = arg_pointer_rtx, offset = cfa_offset;
else
return 0;
*poffset = offset;
return new;
}
static int
instantiate_virtual_regs_1 (loc, object, extra_insns)
rtx *loc;
rtx object;
int extra_insns;
{
rtx x;
RTX_CODE code;
rtx new = 0;
HOST_WIDE_INT offset = 0;
rtx temp;
rtx seq;
int i, j;
const char *fmt;
restart:
x = *loc;
if (x == 0)
return 1;
code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case CONST:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
case RETURN:
return 1;
case SET:
if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0)
{
rtx src = SET_SRC (x);
offset = - offset;
instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
if (GET_CODE (src) != REG && GET_CODE (src) != PLUS)
abort ();
start_sequence ();
if (GET_CODE (src) != REG)
temp = force_operand (src, NULL_RTX);
else
temp = src;
temp = force_operand (plus_constant (temp, offset), NULL_RTX);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, object);
SET_DEST (x) = new;
if (! validate_change (object, &SET_SRC (x), temp, 0)
|| ! extra_insns)
abort ();
return 1;
}
instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns);
loc = &SET_SRC (x);
goto restart;
case PLUS:
if (CONSTANT_P (XEXP (x, 1)))
{
rtx old, new_offset;
if (GET_CODE (XEXP (x, 0)) == PLUS)
{
if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset)))
{
instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
extra_insns);
new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
}
else
{
loc = &XEXP (x, 0);
goto restart;
}
}
#ifdef POINTERS_EXTEND_UNSIGNED
else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& 0 != (new
= instantiate_new_reg (SUBREG_REG (XEXP (x, 0)),
&offset))
&& validate_change (object, loc,
plus_constant (gen_lowpart (ptr_mode,
new),
offset
+ INTVAL (XEXP (x, 1))),
0))
return 1;
#endif
else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0)
{
if (GET_CODE (XEXP (x, 0)) != REG)
{
loc = &XEXP (x, 0);
goto restart;
}
return 1;
}
new_offset = plus_constant (XEXP (x, 1), offset);
if (new_offset == const0_rtx
&& validate_change (object, loc, new, 0))
return 1;
old = XEXP (x, 0);
if (offset == 0
? ! validate_change (object, &XEXP (x, 0), new, 0)
: (XEXP (x, 0) = new,
! validate_change (object, &XEXP (x, 1), new_offset, 0)))
{
if (! extra_insns)
{
XEXP (x, 0) = old;
return 0;
}
temp = gen_reg_rtx (Pmode);
XEXP (x, 0) = new;
if (validate_change (object, &XEXP (x, 1), temp, 0))
emit_insn_before (gen_move_insn (temp, new_offset), object);
else
{
XEXP (x, 0) = old;
new = gen_rtx_PLUS (Pmode, new, new_offset);
start_sequence ();
temp = force_operand (new, NULL_RTX);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, object);
if (! validate_change (object, loc, temp, 0)
&& ! validate_replace_rtx (x, temp, object))
abort ();
}
}
return 1;
}
case EXPR_LIST:
case CALL:
case COMPARE:
case MINUS:
case MULT:
case DIV: case UDIV:
case MOD: case UMOD:
case AND: case IOR: case XOR:
case ROTATERT: case ROTATE:
case ASHIFTRT: case LSHIFTRT: case ASHIFT:
case NE: case EQ:
case GE: case GT: case GEU: case GTU:
case LE: case LT: case LEU: case LTU:
if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1)))
instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns);
loc = &XEXP (x, 0);
goto restart;
case MEM:
temp = XEXP (x, 0);
if (CONSTANT_ADDRESS_P (temp)
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| temp == arg_pointer_rtx
#endif
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
|| temp == hard_frame_pointer_rtx
#endif
|| temp == frame_pointer_rtx)
return 1;
if (GET_CODE (temp) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (temp, 1))
&& (XEXP (temp, 0) == frame_pointer_rtx
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
|| XEXP (temp, 0) == hard_frame_pointer_rtx
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| XEXP (temp, 0) == arg_pointer_rtx
#endif
))
return 1;
if (temp == virtual_stack_vars_rtx
|| temp == virtual_incoming_args_rtx
|| (GET_CODE (temp) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (temp, 1))
&& (XEXP (temp, 0) == virtual_stack_vars_rtx
|| XEXP (temp, 0) == virtual_incoming_args_rtx)))
{
if (instantiate_virtual_regs_1 (&XEXP (x, 0),
object ? object : x, 0))
return 1;
*loc = x = copy_rtx (x);
}
case PREFETCH:
case SUBREG:
case STRICT_LOW_PART:
case NEG: case NOT:
case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC:
case SIGN_EXTEND: case ZERO_EXTEND:
case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE:
case FLOAT: case FIX:
case UNSIGNED_FIX: case UNSIGNED_FLOAT:
case ABS:
case SQRT:
case FFS:
loc = &XEXP (x, 0);
goto restart;
case USE:
case CLOBBER:
if ((GET_CODE (XEXP (x, 0)) == MEM
&& instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
0))
|| (GET_CODE (XEXP (x, 0)) == REG
&& instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
return 1;
XEXP (x, 0) = copy_rtx (XEXP (x, 0));
loc = &XEXP (x, 0);
goto restart;
case REG:
if ((new = instantiate_new_reg (x, &offset)) != 0)
{
temp = plus_constant (new, offset);
if (!validate_change (object, loc, temp, 0))
{
if (! extra_insns)
return 0;
start_sequence ();
temp = force_operand (temp, NULL_RTX);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, object);
if (! validate_change (object, loc, temp, 0)
&& ! validate_replace_rtx (x, temp, object))
abort ();
}
}
return 1;
case ADDRESSOF:
if (GET_CODE (XEXP (x, 0)) == REG)
return 1;
else if (GET_CODE (XEXP (x, 0)) == MEM)
{
instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), NULL_RTX, 0);
return 1;
}
break;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
if (*fmt == 'e')
{
if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns))
return 0;
}
else if (*fmt == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object,
extra_insns))
return 0;
return 1;
}
static void
delete_handlers ()
{
rtx insn;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
tree t, last_t;
LABEL_PRESERVE_P (insn) = 0;
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);
}
}
}
int
max_parm_reg_num ()
{
return max_parm_reg;
}
rtx
get_first_nonparm_insn ()
{
if (last_parm_insn)
return NEXT_INSN (last_parm_insn);
return get_insns ();
}
rtx
get_first_block_beg ()
{
rtx searcher;
rtx insn = get_first_nonparm_insn ();
for (searcher = insn; searcher; searcher = NEXT_INSN (searcher))
if (GET_CODE (searcher) == NOTE
&& NOTE_LINE_NUMBER (searcher) == NOTE_INSN_BLOCK_BEG)
return searcher;
abort ();
return NULL_RTX;
}
int
aggregate_value_p (exp)
tree exp;
{
int i, regno, nregs;
rtx reg;
tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
if (TREE_CODE (type) == VOID_TYPE)
return 0;
if (RETURN_IN_MEMORY (type))
return 1;
if (TREE_ADDRESSABLE (type))
return 1;
if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
return 1;
reg = hard_function_value (type, 0, 0);
if (GET_CODE (reg) != REG)
return 0;
regno = REGNO (reg);
nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
for (i = 0; i < nregs; i++)
if (! call_used_regs[regno + i])
return 1;
return 0;
}
void
assign_parms (fndecl)
tree fndecl;
{
tree parm;
rtx entry_parm = 0;
rtx stack_parm = 0;
CUMULATIVE_ARGS args_so_far;
enum machine_mode promoted_mode, passed_mode;
enum machine_mode nominal_mode, promoted_nominal_mode;
int unsignedp;
struct args_size stack_args_size;
tree fntype = TREE_TYPE (fndecl);
tree fnargs = DECL_ARGUMENTS (fndecl);
rtx internal_arg_pointer;
tree function_result_decl = 0;
#ifdef SETUP_INCOMING_VARARGS
int varargs_setup = 0;
#endif
rtx conversion_insns = 0;
struct args_size alignment_pad;
int stdarg
= (TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node));
current_function_stdarg = stdarg;
if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
|| ! (fixed_regs[ARG_POINTER_REGNUM]
|| ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM)))
internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx);
else
internal_arg_pointer = virtual_incoming_args_rtx;
current_function_internal_arg_pointer = internal_arg_pointer;
stack_args_size.constant = 0;
stack_args_size.var = 0;
#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, 0);
#endif
#ifdef REARRANGE_ARG_LIST
DECL_ARGUMENTS (fndecl) = fnargs = REARRANGE_ARG_LIST (args_so_far, fnargs);
#endif
if (aggregate_value_p (DECL_RESULT (fndecl))
&& ! current_function_returns_pcc_struct
&& struct_value_incoming_rtx == 0)
{
tree type = build_pointer_type (TREE_TYPE (fntype));
function_result_decl = build_decl (PARM_DECL, NULL_TREE, type);
DECL_ARG_TYPE (function_result_decl) = type;
TREE_CHAIN (function_result_decl) = fnargs;
fnargs = function_result_decl;
}
max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
current_function_pretend_args_size = 0;
for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
{
struct args_size stack_offset;
struct args_size arg_size;
int passed_pointer = 0;
int did_conversion = 0;
tree passed_type = DECL_ARG_TYPE (parm);
tree nominal_type = TREE_TYPE (parm);
int pretend_named;
int last_named = 0, named_arg;
if (stdarg)
{
tree tem;
for (tem = TREE_CHAIN (parm); tem; tem = TREE_CHAIN (tem))
if (DECL_NAME (tem))
break;
if (tem == 0)
last_named = 1;
}
named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
if (TREE_TYPE (parm) == error_mark_node
|| TREE_CODE (parm) != PARM_DECL
|| passed_type == NULL)
{
SET_DECL_RTL (parm, gen_rtx_MEM (BLKmode, const0_rtx));
DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
TREE_USED (parm) = 1;
continue;
}
passed_mode = TYPE_MODE (passed_type);
nominal_mode = TYPE_MODE (nominal_type);
if (nominal_mode == VOIDmode)
{
SET_DECL_RTL (parm, const0_rtx);
DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
continue;
}
if (DECL_TRANSPARENT_UNION (parm)
|| (TREE_CODE (passed_type) == UNION_TYPE
&& TYPE_TRANSPARENT_UNION (passed_type)))
passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
&& contains_placeholder_p (TYPE_SIZE (passed_type)))
|| TREE_ADDRESSABLE (passed_type)
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
|| FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
passed_type, named_arg)
#endif
)
{
passed_type = nominal_type = build_pointer_type (passed_type);
passed_pointer = 1;
passed_mode = nominal_mode = Pmode;
}
else if (passed_type != nominal_type
&& POINTER_TYPE_P (passed_type)
&& TREE_TYPE (passed_type) == nominal_type)
{
nominal_type = passed_type;
passed_pointer = 1;
passed_mode = nominal_mode = Pmode;
}
promoted_mode = passed_mode;
#ifdef PROMOTE_FUNCTION_ARGS
unsignedp = TREE_UNSIGNED (passed_type);
promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
#endif
#ifdef FUNCTION_INCOMING_ARG
entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
passed_type, named_arg);
#else
entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
passed_type, named_arg);
#endif
if (entry_parm == 0)
promoted_mode = passed_mode;
#ifdef SETUP_INCOMING_VARARGS
if (last_named && !varargs_setup)
{
SETUP_INCOMING_VARARGS (args_so_far, promoted_mode, passed_type,
current_function_pretend_args_size, 0);
varargs_setup = 1;
}
#endif
pretend_named = named_arg || PRETEND_OUTGOING_VARARGS_NAMED;
#ifdef NO_REG_PARM_STACK_SPACE
if (NO_REG_PARM_STACK_SPACE(args_so_far, entry_parm))
stack_offset = stack_args_size;
else
#endif
locate_and_pad_parm (promoted_mode, passed_type,
#ifdef STACK_PARMS_IN_REG_PARM_AREA
1,
#else
#ifdef FUNCTION_INCOMING_ARG
FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
passed_type,
pretend_named) != 0,
#else
FUNCTION_ARG (args_so_far, promoted_mode,
passed_type,
pretend_named) != 0,
#endif
#endif
fndecl, &stack_args_size, &stack_offset, &arg_size,
&alignment_pad);
{
rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
if (offset_rtx == const0_rtx)
stack_parm = gen_rtx_MEM (promoted_mode, internal_arg_pointer);
else
stack_parm = gen_rtx_MEM (promoted_mode,
gen_rtx_PLUS (Pmode,
internal_arg_pointer,
offset_rtx));
set_mem_attributes (stack_parm, parm, 1);
}
if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
entry_parm = 0;
#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (entry_parm)
{
int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
passed_type, named_arg);
if (nregs > 0)
{
#if defined (REG_PARM_STACK_SPACE) && !defined (MAYBE_REG_PARM_STACK_SPACE)
if (REG_PARM_STACK_SPACE (fndecl) == 0)
#endif
current_function_pretend_args_size
= (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
/ (PARM_BOUNDARY / BITS_PER_UNIT)
* (PARM_BOUNDARY / BITS_PER_UNIT));
if (GET_CODE (entry_parm) == PARALLEL)
emit_group_store (validize_mem (stack_parm), entry_parm,
int_size_in_bytes (TREE_TYPE (parm)));
else
move_block_from_reg (REGNO (entry_parm),
validize_mem (stack_parm), nregs,
int_size_in_bytes (TREE_TYPE (parm)));
entry_parm = stack_parm;
}
}
#endif
if (entry_parm == 0)
entry_parm = stack_parm;
DECL_INCOMING_RTL (parm) = entry_parm;
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)
|| REG_PARM_STACK_SPACE (fndecl) > 0
#endif
)
#ifdef NO_REG_PARM_STACK_SPACE
&& !NO_REG_PARM_STACK_SPACE (args_so_far, entry_parm)
#endif
)
{
stack_args_size.constant += arg_size.constant;
if (arg_size.var)
ADD_PARM_SIZE (stack_args_size, arg_size.var);
}
else
stack_parm = 0;
FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
passed_type, named_arg);
{
unsigned int thisparm_boundary
= FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
if (GET_MODE_ALIGNMENT (nominal_mode) > thisparm_boundary)
stack_parm = 0;
}
if (entry_parm != 0
&& nominal_mode != BLKmode && nominal_mode != passed_mode)
stack_parm = 0;
if (GET_CODE (entry_parm) == PARALLEL
&& nominal_mode != BLKmode && passed_mode != BLKmode)
{
int i, len = XVECLEN (entry_parm, 0);
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
&& (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;
break;
}
}
if (GET_CODE (entry_parm) == PARALLEL && nominal_mode != BLKmode)
{
rtx parmreg = gen_reg_rtx (nominal_mode);
emit_group_store (parmreg, entry_parm, int_size_in_bytes (TREE_TYPE (parm)));
SET_DECL_RTL (parm, parmreg);
}
if (nominal_mode == BLKmode || GET_CODE (entry_parm) == PARALLEL)
{
if (GET_CODE (entry_parm) == REG
|| GET_CODE (entry_parm) == PARALLEL)
{
int size_stored
= CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
ABI_UNITS_PER_WORD);
if (stack_parm == 0)
{
stack_parm
= assign_stack_local (GET_MODE (entry_parm),
size_stored, 0);
set_mem_attributes (stack_parm, parm, 1);
}
else if (PARM_BOUNDARY % ABI_BITS_PER_WORD != 0)
abort ();
if (GET_CODE (entry_parm) == PARALLEL)
emit_group_store (validize_mem (stack_parm), entry_parm,
int_size_in_bytes (TREE_TYPE (parm)));
else
move_block_from_reg (REGNO (entry_parm),
validize_mem (stack_parm),
size_stored / ABI_UNITS_PER_WORD,
int_size_in_bytes (TREE_TYPE (parm)));
}
SET_DECL_RTL (parm, stack_parm);
}
else if (! ((! optimize
&& ! DECL_REGISTER (parm))
|| TREE_SIDE_EFFECTS (parm)
|| (flag_float_store
&& TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE))
|| passed_pointer || parm == function_result_decl)
{
rtx parmreg;
unsigned int regno, regnoi = 0, regnor = 0;
unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
promoted_nominal_mode
= promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
parmreg = gen_reg_rtx (promoted_nominal_mode);
mark_user_reg (parmreg);
if (passed_pointer)
{
rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)),
parmreg);
set_mem_attributes (x, parm, 1);
SET_DECL_RTL (parm, x);
}
else
{
SET_DECL_RTL (parm, parmreg);
maybe_set_unchanging (DECL_RTL (parm), parm);
}
if (nominal_mode != passed_mode
|| promoted_nominal_mode != promoted_mode)
{
int save_tree_used;
rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
emit_move_insn (tempreg, validize_mem (entry_parm));
push_to_sequence (conversion_insns);
tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
if (GET_CODE (tempreg) == SUBREG
&& GET_MODE (tempreg) == nominal_mode
&& GET_CODE (SUBREG_REG (tempreg)) == REG
&& nominal_mode == passed_mode
&& GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
&& GET_MODE_SIZE (GET_MODE (tempreg))
< GET_MODE_SIZE (GET_MODE (entry_parm)))
{
SUBREG_PROMOTED_VAR_P (tempreg) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (tempreg, unsignedp);
}
save_tree_used = TREE_USED (parm);
expand_assignment (parm,
make_tree (nominal_type, tempreg), 0, 0);
TREE_USED (parm) = save_tree_used;
conversion_insns = get_insns ();
did_conversion = 1;
end_sequence ();
}
else
emit_move_insn (parmreg, validize_mem (entry_parm));
if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode
&& (TYPE_MODE (TREE_TYPE (parm)) != GET_MODE (DECL_RTL (parm))
|| ! ((! optimize
&& ! DECL_REGISTER (parm))
|| TREE_SIDE_EFFECTS (parm)
|| (flag_float_store
&& TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE))))
{
parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
mark_user_reg (parmreg);
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));
push_to_sequence (conversion_insns);
emit_move_insn (tempreg, DECL_RTL (parm));
SET_DECL_RTL (parm,
convert_to_mode (GET_MODE (parmreg),
tempreg,
unsigned_p));
emit_move_insn (parmreg, DECL_RTL (parm));
conversion_insns = get_insns();
did_conversion = 1;
end_sequence ();
}
else
emit_move_insn (parmreg, DECL_RTL (parm));
SET_DECL_RTL (parm, parmreg);
stack_parm = 0;
}
#ifdef FUNCTION_ARG_CALLEE_COPIES
else if (passed_pointer
&& FUNCTION_ARG_CALLEE_COPIES (args_so_far,
TYPE_MODE (DECL_ARG_TYPE (parm)),
DECL_ARG_TYPE (parm),
named_arg)
&& ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
{
rtx copy;
tree type = DECL_ARG_TYPE (parm);
push_to_sequence (conversion_insns);
if (!COMPLETE_TYPE_P (type)
|| TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
copy = gen_rtx_MEM (BLKmode,
allocate_dynamic_stack_space
(expr_size (parm), NULL_RTX,
TYPE_ALIGN (type)));
else
copy = assign_stack_temp (TYPE_MODE (type),
int_size_in_bytes (type), 1);
set_mem_attributes (copy, parm, 1);
store_expr (parm, copy, 0);
emit_move_insn (parmreg, XEXP (copy, 0));
conversion_insns = get_insns ();
did_conversion = 1;
end_sequence ();
}
#endif
if (GET_CODE (parmreg) == CONCAT)
regno = MAX (REGNO (XEXP (parmreg, 0)), REGNO (XEXP (parmreg, 1)));
else
regno = REGNO (parmreg);
if (regno >= max_parm_reg)
{
rtx *new;
int old_max_parm_reg = max_parm_reg;
max_parm_reg = regno + 1;
new = (rtx *) ggc_realloc (parm_reg_stack_loc,
max_parm_reg * sizeof (rtx));
memset ((char *) (new + old_max_parm_reg), 0,
(max_parm_reg - old_max_parm_reg) * sizeof (rtx));
parm_reg_stack_loc = new;
}
if (GET_CODE (parmreg) == CONCAT)
{
enum machine_mode submode = GET_MODE (XEXP (parmreg, 0));
regnor = REGNO (gen_realpart (submode, parmreg));
regnoi = REGNO (gen_imagpart (submode, parmreg));
if (stack_parm != 0)
{
parm_reg_stack_loc[regnor]
= gen_realpart (submode, stack_parm);
parm_reg_stack_loc[regnoi]
= gen_imagpart (submode, stack_parm);
}
else
{
parm_reg_stack_loc[regnor] = 0;
parm_reg_stack_loc[regnoi] = 0;
}
}
else
parm_reg_stack_loc[REGNO (parmreg)] = stack_parm;
if (nominal_mode == passed_mode
&& ! did_conversion
&& stack_parm != 0
&& GET_CODE (stack_parm) == MEM
&& stack_offset.var == 0
&& reg_mentioned_p (virtual_incoming_args_rtx,
XEXP (stack_parm, 0)))
{
rtx linsn = get_last_insn ();
rtx sinsn, set;
if (GET_CODE (parmreg) == CONCAT)
for (sinsn = linsn; sinsn != 0;
sinsn = prev_nonnote_insn (sinsn))
{
set = single_set (sinsn);
if (set != 0
&& SET_DEST (set) == regno_reg_rtx [regnoi])
REG_NOTES (sinsn)
= gen_rtx_EXPR_LIST (REG_EQUIV,
parm_reg_stack_loc[regnoi],
REG_NOTES (sinsn));
else if (set != 0
&& SET_DEST (set) == regno_reg_rtx [regnor])
REG_NOTES (sinsn)
= gen_rtx_EXPR_LIST (REG_EQUIV,
parm_reg_stack_loc[regnor],
REG_NOTES (sinsn));
}
else if ((set = single_set (linsn)) != 0
&& SET_DEST (set) == parmreg)
REG_NOTES (linsn)
= gen_rtx_EXPR_LIST (REG_EQUIV,
stack_parm, REG_NOTES (linsn));
}
if (POINTER_TYPE_P (TREE_TYPE (parm)))
mark_reg_pointer (parmreg,
TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
if (TREE_ADDRESSABLE (parm))
{
push_to_sequence (conversion_insns);
put_var_into_stack (parm);
conversion_insns = get_insns ();
end_sequence ();
}
}
else
{
if (promoted_mode != nominal_mode)
{
rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
emit_move_insn (tempreg, validize_mem (entry_parm));
push_to_sequence (conversion_insns);
entry_parm = convert_to_mode (nominal_mode, tempreg,
TREE_UNSIGNED (TREE_TYPE (parm)));
if (stack_parm)
stack_parm = adjust_address (stack_parm, nominal_mode, 0);
conversion_insns = get_insns ();
did_conversion = 1;
end_sequence ();
}
if (entry_parm != stack_parm)
{
if (stack_parm == 0)
{
stack_parm
= assign_stack_local (GET_MODE (entry_parm),
GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
set_mem_attributes (stack_parm, parm, 1);
}
if (promoted_mode != nominal_mode)
{
push_to_sequence (conversion_insns);
emit_move_insn (validize_mem (stack_parm),
validize_mem (entry_parm));
conversion_insns = get_insns ();
end_sequence ();
}
else
emit_move_insn (validize_mem (stack_parm),
validize_mem (entry_parm));
}
SET_DECL_RTL (parm, stack_parm);
}
if (parm == function_result_decl)
{
tree result = DECL_RESULT (fndecl);
rtx addr = DECL_RTL (parm);
rtx x;
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (addr) != Pmode)
addr = convert_memory_address (Pmode, addr);
#endif
x = gen_rtx_MEM (DECL_MODE (result), addr);
set_mem_attributes (x, result, 1);
SET_DECL_RTL (result, x);
}
if (GET_CODE (DECL_RTL (parm)) == REG)
REGNO_DECL (REGNO (DECL_RTL (parm))) = parm;
else if (GET_CODE (DECL_RTL (parm)) == CONCAT)
{
REGNO_DECL (REGNO (XEXP (DECL_RTL (parm), 0))) = parm;
REGNO_DECL (REGNO (XEXP (DECL_RTL (parm), 1))) = parm;
}
}
emit_insn (conversion_insns);
last_parm_insn = get_last_insn ();
current_function_args_size = stack_args_size.constant;
cfun->unrounded_args_size = stack_args_size.constant;
#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
#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
current_function_args_size
= ((current_function_args_size + STACK_BYTES - 1)
/ STACK_BYTES) * STACK_BYTES;
#ifdef ARGS_GROW_DOWNWARD
current_function_arg_offset_rtx
= (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
: expand_expr (size_diffop (stack_args_size.var,
size_int (-stack_args_size.constant)),
NULL_RTX, VOIDmode, 0));
#else
current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
#endif
current_function_pops_args = RETURN_POPS_ARGS (fndecl, TREE_TYPE (fndecl),
current_function_args_size);
current_function_args_info = args_so_far;
if (!cfun->cw_asm_function) {
current_function_return_rtx
= (DECL_RTL_SET_P (DECL_RESULT (fndecl))
? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
if (DECL_RTL_SET_P (DECL_RESULT (fndecl)))
{
tree decl_result = DECL_RESULT (fndecl);
rtx decl_rtl = DECL_RTL (decl_result);
if (REG_P (decl_rtl)
? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER
: DECL_REGISTER (decl_result))
{
rtx real_decl_rtl;
#ifdef FUNCTION_OUTGOING_VALUE
real_decl_rtl = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl_result),
fndecl);
#else
real_decl_rtl = FUNCTION_VALUE (TREE_TYPE (decl_result),
fndecl);
#endif
REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
current_function_return_rtx = real_decl_rtl;
}
}
}
}
#ifdef PROMOTE_FUNCTION_ARGS
rtx
promoted_input_arg (regno, pmode, punsignedp)
unsigned int regno;
enum machine_mode *pmode;
int *punsignedp;
{
tree arg;
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG
&& 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));
mode = promote_mode (TREE_TYPE (arg), mode, &unsignedp, 1);
if (mode == GET_MODE (DECL_INCOMING_RTL (arg))
&& mode != DECL_MODE (arg))
{
*pmode = DECL_MODE (arg);
*punsignedp = unsignedp;
return DECL_INCOMING_RTL (arg);
}
}
return 0;
}
#endif
void
locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
initial_offset_ptr, offset_ptr, arg_size_ptr,
alignment_pad)
enum machine_mode passed_mode;
tree type;
int in_regs ATTRIBUTE_UNUSED;
tree fndecl ATTRIBUTE_UNUSED;
struct args_size *initial_offset_ptr;
struct args_size *offset_ptr;
struct args_size *arg_size_ptr;
struct args_size *alignment_pad;
{
tree sizetree
= type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
int mod_boundary = FUNCTION_ARG_MOD_BOUNDARY (passed_mode, type);
#ifdef ARGS_GROW_DOWNWARD
tree s2 = sizetree;
#endif
#ifdef REG_PARM_STACK_SPACE
if (! in_regs)
{
int reg_parm_stack_space = 0;
#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 (reg_parm_stack_space > 0 && TREE_CODE (type) != VECTOR_TYPE)
{
if (initial_offset_ptr->var)
{
initial_offset_ptr->var
= size_binop (MAX_EXPR, ARGS_SIZE_TREE (*initial_offset_ptr),
ssize_int (reg_parm_stack_space));
initial_offset_ptr->constant = 0;
}
else if (initial_offset_ptr->constant < reg_parm_stack_space)
initial_offset_ptr->constant = reg_parm_stack_space;
}
}
#endif
arg_size_ptr->var = 0;
arg_size_ptr->constant = 0;
alignment_pad->var = 0;
alignment_pad->constant = 0;
#ifdef ARGS_GROW_DOWNWARD
if (initial_offset_ptr->var)
{
offset_ptr->constant = 0;
offset_ptr->var = size_binop (MINUS_EXPR, ssize_int (0),
initial_offset_ptr->var);
}
else
{
offset_ptr->constant = -initial_offset_ptr->constant;
offset_ptr->var = 0;
}
if (where_pad != none
&& (!host_integerp (sizetree, 1)
|| (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
SUB_PARM_SIZE (*offset_ptr, s2);
if (!in_regs
#ifdef REG_PARM_STACK_SPACE
|| REG_PARM_STACK_SPACE (fndecl) > 0
#endif
)
pad_to_arg_alignment (offset_ptr, mod_boundary, boundary, alignment_pad);
if (initial_offset_ptr->var)
arg_size_ptr->var = size_binop (MINUS_EXPR,
size_binop (MINUS_EXPR,
ssize_int (0),
initial_offset_ptr->var),
offset_ptr->var);
else
arg_size_ptr->constant = (-initial_offset_ptr->constant
- offset_ptr->constant);
if (where_pad == downward
&& !in_regs)
pad_below (offset_ptr, passed_mode, sizetree);
#else
if (!in_regs
#ifdef REG_PARM_STACK_SPACE
|| REG_PARM_STACK_SPACE (fndecl) > 0
#endif
)
pad_to_arg_alignment (initial_offset_ptr, mod_boundary, boundary,
alignment_pad);
*offset_ptr = *initial_offset_ptr;
#ifdef PUSH_ROUNDING
if (passed_mode != BLKmode)
sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
#endif
if (where_pad == downward
&& !(in_regs && passed_mode == BLKmode))
pad_below (offset_ptr, passed_mode, sizetree);
if (where_pad != none
&& (!host_integerp (sizetree, 1)
|| (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
ADD_PARM_SIZE (*arg_size_ptr, sizetree);
#endif
}
static void
pad_to_arg_alignment (offset_ptr, mod_boundary, boundary, alignment_pad)
struct args_size *offset_ptr;
int mod_boundary;
int boundary;
struct args_size *alignment_pad;
{
tree save_var = NULL_TREE;
HOST_WIDE_INT save_constant = 0;
int boundary_in_bytes = boundary / BITS_PER_UNIT;
int mod_boundary_in_bytes = mod_boundary / BITS_PER_UNIT;
if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
{
save_var = offset_ptr->var;
save_constant = offset_ptr->constant;
}
alignment_pad->var = NULL_TREE;
alignment_pad->constant = 0;
if (boundary > BITS_PER_UNIT)
{
if (offset_ptr->var)
{
offset_ptr->constant -= mod_boundary_in_bytes;
offset_ptr->var =
#ifdef ARGS_GROW_DOWNWARD
round_down
#else
round_up
#endif
(ARGS_SIZE_TREE (*offset_ptr),
boundary / BITS_PER_UNIT);
offset_ptr->constant = mod_boundary_in_bytes;
if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
alignment_pad->var = size_binop (MINUS_EXPR, offset_ptr->var,
save_var);
}
else
{
offset_ptr->constant = mod_boundary_in_bytes +
#ifdef ARGS_GROW_DOWNWARD
FLOOR_ROUND (offset_ptr->constant - mod_boundary_in_bytes,
boundary_in_bytes);
#else
CEIL_ROUND (offset_ptr->constant - mod_boundary_in_bytes,
boundary_in_bytes);
#endif
if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
alignment_pad->constant = offset_ptr->constant - save_constant;
}
}
}
static void
pad_below (offset_ptr, passed_mode, sizetree)
struct args_size *offset_ptr;
enum machine_mode passed_mode;
tree sizetree;
{
if (passed_mode != BLKmode)
{
if (GET_MODE_BITSIZE (passed_mode) % PARM_BOUNDARY)
offset_ptr->constant
+= (((GET_MODE_BITSIZE (passed_mode) + PARM_BOUNDARY - 1)
/ PARM_BOUNDARY * PARM_BOUNDARY / BITS_PER_UNIT)
- GET_MODE_SIZE (passed_mode));
}
else
{
if (TREE_CODE (sizetree) != INTEGER_CST
|| (TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)
{
tree s2 = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
ADD_PARM_SIZE (*offset_ptr, s2);
SUB_PARM_SIZE (*offset_ptr, sizetree);
}
}
}
void
uninitialized_vars_warning (block)
tree block;
{
tree decl, sub;
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
{
if (warn_uninitialized
&& TREE_CODE (decl) == VAR_DECL
&& ! AGGREGATE_TYPE_P (TREE_TYPE (decl))
&& DECL_RTL (decl) != 0
&& GET_CODE (DECL_RTL (decl)) == REG
&& DECL_INITIAL (decl) == NULL_TREE
&& regno_uninitialized (REGNO (DECL_RTL (decl))))
warning_with_decl (decl,
"`%s' might be used uninitialized in this function");
if (extra_warnings
&& TREE_CODE (decl) == VAR_DECL
&& DECL_RTL (decl) != 0
&& GET_CODE (DECL_RTL (decl)) == REG
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
warning_with_decl (decl,
"variable `%s' might be clobbered by `longjmp' or `vfork'");
}
for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
uninitialized_vars_warning (sub);
}
void
setjmp_args_warning ()
{
tree decl;
for (decl = DECL_ARGUMENTS (current_function_decl);
decl; decl = TREE_CHAIN (decl))
if (DECL_RTL (decl) != 0
&& GET_CODE (DECL_RTL (decl)) == REG
&& regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
warning_with_decl (decl,
"argument `%s' might be clobbered by `longjmp' or `vfork'");
}
void
setjmp_protect (block)
tree block;
{
tree decl, sub;
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (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
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
&& ! DECL_FROM_INLINE (decl)
&& (
#ifdef NON_SAVING_SETJMP
NON_SAVING_SETJMP
||
#endif
! DECL_REGISTER (decl)))
put_var_into_stack (decl);
for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
setjmp_protect (sub);
}
void
setjmp_protect_args ()
{
tree decl;
for (decl = DECL_ARGUMENTS (current_function_decl);
decl; decl = TREE_CHAIN (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
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
&& (
#ifdef NON_SAVING_SETJMP
NON_SAVING_SETJMP
||
#endif
! DECL_REGISTER (decl)))
put_var_into_stack (decl);
}
rtx
lookup_static_chain (decl)
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;
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 ();
}
rtx
fix_lexical_addr (addr, var)
rtx addr;
tree var;
{
rtx basereg;
HOST_WIDE_INT displacement;
tree context = decl_function_context (var);
struct function *fp;
rtx base = 0;
if (context == current_function_decl || context == inline_function_decl)
return addr;
fp = find_function_data (context);
if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
addr = XEXP (XEXP (addr, 0), 0);
if (GET_CODE (addr) == REG)
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 ();
if (basereg == fp->internal_arg_pointer)
{
#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)
{
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);
}
rtx
trampoline_address (function)
tree function;
{
tree link;
tree rtlexp;
rtx tramp;
struct function *fp;
tree fn_context;
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);
}
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);
#ifdef ALLOCATE_TRAMPOLINE
tramp = ALLOCATE_TRAMPOLINE (fp);
#else
#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);
#endif
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
{
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);
}
static rtx
round_trampoline_addr (tramp)
rtx tramp;
{
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;
}
static rtx
adjust_trampoline_addr (tramp)
rtx tramp;
{
tramp = round_trampoline_addr (tramp);
#ifdef TRAMPOLINE_ADJUST_ADDRESS
TRAMPOLINE_ADJUST_ADDRESS (tramp);
#endif
return tramp;
}
void
identify_blocks ()
{
int n_blocks;
tree *block_vector, *last_block_vector;
tree *block_stack;
tree block = DECL_INITIAL (current_function_decl);
if (block == 0)
return;
block_vector = get_block_vector (block, &n_blocks);
block_stack = (tree *) xmalloc (n_blocks * sizeof (tree));
last_block_vector = identify_blocks_1 (get_insns (),
block_vector + 1,
block_vector + n_blocks,
block_stack);
if (0 && last_block_vector != block_vector + n_blocks)
abort ();
free (block_vector);
free (block_stack);
}
static tree *
identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
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 (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 (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 (block_stack != orig_block_stack)
abort ();
return block_vector;
}
void
reorder_blocks ()
{
tree block = DECL_INITIAL (current_function_decl);
varray_type block_stack;
if (block == NULL_TREE)
return;
VARRAY_TREE_INIT (block_stack, 10, "block_stack");
reorder_blocks_0 (block);
BLOCK_SUBBLOCKS (block) = NULL_TREE;
BLOCK_CHAIN (block) = NULL_TREE;
reorder_blocks_1 (get_insns (), block, &block_stack);
BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
reorder_fix_fragments (block);
}
static void
reorder_blocks_0 (block)
tree block;
{
while (block)
{
TREE_ASM_WRITTEN (block) = 0;
reorder_blocks_0 (BLOCK_SUBBLOCKS (block));
block = BLOCK_CHAIN (block);
}
}
static void
reorder_blocks_1 (insns, current_block, p_block_stack)
rtx insns;
tree current_block;
varray_type *p_block_stack;
{
rtx insn;
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
tree block = NOTE_BLOCK (insn);
if (TREE_ASM_WRITTEN (block))
{
tree new_block = copy_node (block);
tree origin;
origin = (BLOCK_FRAGMENT_ORIGIN (block)
? BLOCK_FRAGMENT_ORIGIN (block)
: block);
BLOCK_FRAGMENT_ORIGIN (new_block) = origin;
BLOCK_FRAGMENT_CHAIN (new_block)
= BLOCK_FRAGMENT_CHAIN (origin);
BLOCK_FRAGMENT_CHAIN (origin) = new_block;
NOTE_BLOCK (insn) = new_block;
block = new_block;
}
BLOCK_SUBBLOCKS (block) = 0;
TREE_ASM_WRITTEN (block) = 1;
BLOCK_SUPERCONTEXT (block) = current_block;
BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
BLOCK_SUBBLOCKS (current_block) = block;
current_block = block;
VARRAY_PUSH_TREE (*p_block_stack, block);
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
{
NOTE_BLOCK (insn) = VARRAY_TOP_TREE (*p_block_stack);
VARRAY_POP (*p_block_stack);
BLOCK_SUBBLOCKS (current_block)
= blocks_nreverse (BLOCK_SUBBLOCKS (current_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);
}
}
}
static void
reorder_fix_fragments (block)
tree block;
{
while (block)
{
tree dup_origin = BLOCK_FRAGMENT_ORIGIN (block);
tree new_origin = NULL_TREE;
if (dup_origin)
{
if (! TREE_ASM_WRITTEN (dup_origin))
{
new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin);
while (! TREE_ASM_WRITTEN (new_origin))
new_origin = BLOCK_FRAGMENT_CHAIN (new_origin);
BLOCK_FRAGMENT_ORIGIN (new_origin) = NULL_TREE;
}
}
else if (! dup_origin)
new_origin = block;
if (new_origin)
{
tree *pp = &BLOCK_FRAGMENT_CHAIN (new_origin);
tree chain = *pp;
while (chain)
{
if (TREE_ASM_WRITTEN (chain))
{
BLOCK_FRAGMENT_ORIGIN (chain) = new_origin;
*pp = chain;
pp = &BLOCK_FRAGMENT_CHAIN (chain);
}
chain = BLOCK_FRAGMENT_CHAIN (chain);
}
*pp = NULL_TREE;
}
reorder_fix_fragments (BLOCK_SUBBLOCKS (block));
block = BLOCK_CHAIN (block);
}
}
static tree
blocks_nreverse (t)
tree t;
{
tree prev = 0, decl, next;
for (decl = t; decl; decl = next)
{
next = BLOCK_CHAIN (decl);
BLOCK_CHAIN (decl) = prev;
prev = decl;
}
return prev;
}
static int
all_blocks (block, vector)
tree block;
tree *vector;
{
int n_blocks = 0;
while (block)
{
TREE_ASM_WRITTEN (block) = 0;
if (vector)
vector[n_blocks] = block;
++n_blocks;
n_blocks += all_blocks (BLOCK_SUBBLOCKS (block),
vector ? vector + n_blocks : 0);
block = BLOCK_CHAIN (block);
}
return n_blocks;
}
static tree *
get_block_vector (block, n_blocks_p)
tree block;
int *n_blocks_p;
{
tree *block_vector;
*n_blocks_p = all_blocks (block, NULL);
block_vector = (tree *) xmalloc (*n_blocks_p * sizeof (tree));
all_blocks (block, block_vector);
return block_vector;
}
static GTY(()) int next_block_index = 2;
void
number_blocks (fn)
tree fn;
{
int i;
int n_blocks;
tree *block_vector;
#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
next_block_index = 1;
#endif
block_vector = get_block_vector (DECL_INITIAL (fn), &n_blocks);
for (i = 1; i < n_blocks; ++i)
BLOCK_NUMBER (block_vector[i]) = next_block_index++;
free (block_vector);
return;
}
tree
debug_find_var_in_block_tree (var, block)
tree var;
tree block;
{
tree t;
for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t))
if (t == var)
return block;
for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t))
{
tree ret = debug_find_var_in_block_tree (var, t);
if (ret)
return ret;
}
return NULL_TREE;
}
static void
prepare_function_start ()
{
cfun = (struct function *) ggc_alloc_cleared (sizeof (struct function));
init_stmt_for_function ();
init_eh_for_function ();
cse_not_expected = ! optimize;
caller_save_needed = 0;
stack_slot_list = 0;
current_function_has_nonlocal_label = 0;
current_function_has_nonlocal_goto = 0;
nonlocal_goto_handler_slots = 0;
nonlocal_goto_stack_level = 0;
nonlocal_labels = 0;
nonlocal_goto_handler_labels = 0;
function_call_count = 0;
max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
init_emit ();
init_expr ();
reg_renumber = 0;
init_varasm_status (cfun);
cfun->inlinable = 0;
cfun->original_decl_initial = 0;
cfun->original_arg_vector = 0;
cfun->stack_alignment_needed = STACK_BOUNDARY;
cfun->preferred_stack_boundary = STACK_BOUNDARY;
current_function_calls_setjmp = 0;
current_function_calls_longjmp = 0;
current_function_calls_alloca = 0;
current_function_contains_functions = 0;
current_function_is_leaf = 0;
current_function_nothrow = 0;
current_function_sp_is_unchanging = 0;
current_function_uses_only_leaf_regs = 0;
current_function_has_computed_jump = 0;
current_function_is_thunk = 0;
current_function_returns_pcc_struct = 0;
current_function_returns_struct = 0;
current_function_epilogue_delay_list = 0;
current_function_uses_const_pool = 0;
current_function_uses_pic_offset_table = 0;
current_function_cannot_inline = 0;
tail_recursion_label = 0;
arg_pointer_save_area = 0;
frame_offset = 0;
save_expr_regs = 0;
rtl_expr_chain = 0;
init_temp_slots ();
rtx_equal_function_value_matters = 1;
virtuals_instantiated = 0;
generating_concat_p = 1;
frame_pointer_needed = 0;
current_function_stdarg = 0;
trampoline_list = 0;
init_pending_stack_adjust ();
inhibit_defer_pop = 0;
current_function_outgoing_args_size = 0;
current_function_funcdef_no = funcdef_no++;
cfun->arc_profile = profile_arc_flag || flag_test_coverage;
cfun->arc_profile = profile_arc_flag || flag_test_coverage;
cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
cfun->max_jumptable_ents = 0;
(*lang_hooks.function.init) (cfun);
if (init_machine_status)
cfun->machine = (*init_machine_status) ();
}
void
init_dummy_function_start ()
{
prepare_function_start ();
}
void
init_function_start (subr, filename, line)
tree subr;
const char *filename;
int line;
{
prepare_function_start ();
current_function_name = (*lang_hooks.decl_printable_name) (subr, 2);
cfun->decl = subr;
current_function_needs_context
= (decl_function_context (current_function_decl) != 0
&& ! DECL_NO_STATIC_CHAIN (current_function_decl));
if (DECL_CW_ASM_FUNCTION (current_function_decl))
{
cfun->cw_asm_function = 1;
cfun->cw_asm_noreturn = DECL_CW_ASM_NORETURN (current_function_decl);
cfun->cw_asm_frame_size = DECL_CW_ASM_FRAME_SIZE (current_function_decl);
}
immediate_size_expand++;
if (line > 0)
emit_line_note (filename, line);
emit_note (NULL, NOTE_INSN_DELETED);
if (aggregate_value_p (DECL_RESULT (subr)))
{
#ifdef PCC_STATIC_STRUCT_RETURN
current_function_returns_pcc_struct = 1;
#endif
current_function_returns_struct = 1;
}
if (warn_aggregate_return
&& AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr))))
warning ("function returns an aggregate");
current_function_returns_pointer
= POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
}
void
init_function_for_compilation ()
{
reg_renumber = 0;
VARRAY_GROW (prologue, 0);
VARRAY_GROW (epilogue, 0);
VARRAY_GROW (sibcall_epilogue, 0);
}
#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
#undef HAS_INIT_SECTION
#define HAS_INIT_SECTION
#endif
void
expand_main_function ()
{
#ifdef FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
if (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN)
{
int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
rtx tmp, seq;
start_sequence ();
#ifdef STACK_GROWS_DOWNWARD
tmp = expand_simple_binop (Pmode, AND, stack_pointer_rtx, GEN_INT(-align),
stack_pointer_rtx, 1, OPTAB_WIDEN);
#else
tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
GEN_INT (align - 1), NULL_RTX, 1, OPTAB_WIDEN);
tmp = expand_simple_binop (Pmode, AND, tmp, GEN_INT (-align),
stack_pointer_rtx, 1, OPTAB_WIDEN);
#endif
if (tmp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, tmp);
tmp = force_reg (Pmode, const0_rtx);
allocate_dynamic_stack_space (tmp, NULL_RTX, BIGGEST_ALIGNMENT);
seq = get_insns ();
end_sequence ();
for (tmp = get_last_insn (); tmp; tmp = PREV_INSN (tmp))
if (NOTE_P (tmp) && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_FUNCTION_BEG)
break;
if (tmp)
emit_insn_before (seq, tmp);
else
emit_insn (seq);
}
#endif
#ifndef HAS_INIT_SECTION
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), LCT_NORMAL,
VOIDmode, 0);
#endif
}
void
expand_pending_sizes (pending_sizes)
tree pending_sizes;
{
tree tem;
for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem))
{
expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
emit_queue ();
}
}
void
expand_function_start (subr, parms_have_cleanups)
tree subr;
int parms_have_cleanups;
{
tree tem;
rtx last_ptr = NULL_RTX;
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 (current_function_needs_context)
{
last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
if (! SMALL_REGISTER_CLASSES
|| GET_CODE (static_chain_incoming_rtx) == REG)
emit_move_insn (last_ptr, static_chain_incoming_rtx);
}
if (parms_have_cleanups)
cleanup_label = gen_label_rtx ();
else
cleanup_label = 0;
return_label = gen_label_rtx ();
if (aggregate_value_p (DECL_RESULT (subr)))
{
rtx value_address = 0;
#ifdef PCC_STATIC_STRUCT_RETURN
if (current_function_returns_pcc_struct)
{
int size = int_size_in_bytes (TREE_TYPE (DECL_RESULT (subr)));
value_address = assemble_static_space (size);
}
else
#endif
{
if (struct_value_incoming_rtx)
{
value_address = gen_reg_rtx (Pmode);
emit_move_insn (value_address, struct_value_incoming_rtx);
}
}
if (value_address)
{
rtx x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
set_mem_attributes (x, DECL_RESULT (subr), 1);
SET_DECL_RTL (DECL_RESULT (subr), x);
}
}
else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
else
{
rtx hard_reg
= hard_function_value (TREE_TYPE (DECL_RESULT (subr)),
subr, 1);
if (REG_P (hard_reg))
SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
else if (GET_CODE (hard_reg) == PARALLEL)
SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
else
abort ();
DECL_REGISTER (DECL_RESULT (subr)) = 1;
}
assign_parms (subr);
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);
emit_note (NULL, NOTE_INSN_FUNCTION_BEG);
if (GET_CODE (get_last_insn ()) != NOTE)
emit_note (NULL, NOTE_INSN_DELETED);
parm_birth_insn = get_last_insn ();
context_display = 0;
if (current_function_needs_context)
{
tem = decl_function_context (current_function_decl);
if (tem)
{
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;
#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 (! 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
PROFILE_HOOK (current_function_funcdef_no);
#endif
}
tail_recursion_reentry = emit_note (NULL, NOTE_INSN_DELETED);
expand_pending_sizes (nreverse (get_pending_sizes ()));
force_next_line_note ();
}
void
expand_dummy_function_end ()
{
while (in_sequence_p ())
end_sequence ();
free_after_parsing (cfun);
free_after_compilation (cfun);
cfun = 0;
}
void
diddle_return_value (doit, arg)
void (*doit) PARAMS ((rtx, void *));
void *arg;
{
rtx outgoing = current_function_return_rtx;
if (! outgoing)
return;
if (GET_CODE (outgoing) == REG)
(*doit) (outgoing, arg);
else if (GET_CODE (outgoing) == PARALLEL)
{
int i;
for (i = 0; i < XVECLEN (outgoing, 0); i++)
{
rtx x = XEXP (XVECEXP (outgoing, 0, i), 0);
if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
(*doit) (x, arg);
}
}
}
static void
do_clobber_return_reg (reg, arg)
rtx reg;
void *arg ATTRIBUTE_UNUSED;
{
emit_insn (gen_rtx_CLOBBER (VOIDmode, reg));
}
void
clobber_return_register ()
{
diddle_return_value (do_clobber_return_reg, NULL);
if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
{
tree decl_result = DECL_RESULT (current_function_decl);
rtx decl_rtl = DECL_RTL (decl_result);
if (REG_P (decl_rtl) && REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER)
{
do_clobber_return_reg (decl_rtl, NULL);
}
}
}
static void
do_use_return_reg (reg, arg)
rtx reg;
void *arg ATTRIBUTE_UNUSED;
{
emit_insn (gen_rtx_USE (VOIDmode, reg));
}
void
use_return_register ()
{
diddle_return_value (do_use_return_reg, NULL);
}
static GTY(()) rtx initial_trampoline;
void
expand_function_end (filename, line, end_bindings)
const char *filename;
int line;
int end_bindings;
{
tree link;
rtx clobber_after;
finish_expr_for_function ();
if (arg_pointer_save_area && ! cfun->arg_pointer_save_area_init)
get_arg_pointer_save_area (cfun);
#ifdef NON_SAVING_SETJMP
if (NON_SAVING_SETJMP && current_function_calls_setjmp)
{
if (DECL_INITIAL (current_function_decl) != error_mark_node)
setjmp_protect (DECL_INITIAL (current_function_decl));
setjmp_protect_args ();
}
#endif
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
if (initial_trampoline == 0)
{
initial_trampoline
= gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
}
#endif
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
INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, tail_recursion_reentry);
}
if (flag_stack_check && ! STACK_CHECK_BUILTIN)
{
rtx insn, seq;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
start_sequence ();
probe_stack_range (STACK_CHECK_PROTECT,
GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, tail_recursion_reentry);
break;
}
}
if (warn_unused_parameter > 0
|| (warn_unused_parameter < 0 && extra_warnings))
{
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_with_decl (decl, "unused parameter `%s'");
}
if (nonlocal_goto_handler_slots != 0
&& ! current_function_has_nonlocal_label)
delete_handlers ();
while (in_sequence_p ())
end_sequence ();
immediate_size_expand--;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
emit_note (NULL, NOTE_INSN_FUNCTION_END);
if (flag_test_coverage)
emit_note (NULL, NOTE_INSN_REPEATED_LINE_NUMBER);
emit_line_note_force (filename, line);
clobber_after = get_last_insn ();
if (return_label)
emit_label (return_label);
if (end_bindings)
expand_end_bindings (0, 0, 0);
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);
}
if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
sjlj_emit_function_exit_after (get_last_insn ());
#ifdef EXIT_IGNORE_STACK
if (! EXIT_IGNORE_STACK)
#endif
if (current_function_calls_alloca)
{
rtx tem = 0;
emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
}
if (!cfun->cw_asm_function) {
if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
{
tree decl_result = DECL_RESULT (current_function_decl);
rtx decl_rtl = DECL_RTL (decl_result);
if (REG_P (decl_rtl)
? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER
: DECL_REGISTER (decl_result))
{
rtx real_decl_rtl = current_function_return_rtx;
if (! REG_FUNCTION_VALUE_P (real_decl_rtl))
abort ();
if (GET_MODE (real_decl_rtl) == BLKmode)
PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl));
if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
{
int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result));
#ifdef PROMOTE_FUNCTION_RETURN
promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
&unsignedp, 1);
#endif
convert_move (real_decl_rtl, decl_rtl, unsignedp);
}
else if (GET_CODE (real_decl_rtl) == PARALLEL)
{
if (GET_CODE (decl_rtl) == PARALLEL)
emit_group_move (real_decl_rtl, decl_rtl);
else
emit_group_load (real_decl_rtl, decl_rtl,
int_size_in_bytes (TREE_TYPE (decl_result)));
}
else
emit_move_insn (real_decl_rtl, decl_rtl);
}
}
if (current_function_returns_struct
|| current_function_returns_pcc_struct)
{
rtx value_address
= XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
#ifdef FUNCTION_OUTGOING_VALUE
rtx outgoing
= FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
current_function_decl);
#else
rtx outgoing
= FUNCTION_VALUE (build_pointer_type (type), current_function_decl);
#endif
REG_FUNCTION_VALUE_P (outgoing) = 1;
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (outgoing) != GET_MODE (value_address))
value_address = convert_memory_address (GET_MODE (outgoing),
value_address);
#endif
emit_move_insn (outgoing, value_address);
current_function_return_rtx = outgoing;
}
expand_eh_return ();
{
rtx seq, after;
start_sequence ();
clobber_return_register ();
seq = get_insns ();
end_sequence ();
after = emit_insn_after (seq, clobber_after);
if (clobber_after != after)
cfun->x_clobber_return_insn = after;
}
use_return_register ();
}
expand_fixups (get_insns ());
}
rtx
get_arg_pointer_save_area (f)
struct function *f;
{
rtx ret = f->x_arg_pointer_save_area;
if (! ret)
{
ret = assign_stack_local_1 (Pmode, GET_MODE_SIZE (Pmode), 0, f);
f->x_arg_pointer_save_area = ret;
}
if (f == cfun && ! f->arg_pointer_save_area_init)
{
rtx seq;
start_sequence ();
emit_move_insn (validize_mem (ret), virtual_incoming_args_rtx);
seq = get_insns ();
end_sequence ();
push_topmost_sequence ();
emit_insn_after (seq, get_insns ());
pop_topmost_sequence ();
}
return ret;
}
static void
record_insns (insns, vecp)
rtx insns;
varray_type *vecp;
{
int i, len;
rtx tmp;
tmp = insns;
len = 0;
while (tmp != NULL_RTX)
{
len++;
tmp = NEXT_INSN (tmp);
}
i = VARRAY_SIZE (*vecp);
VARRAY_GROW (*vecp, i + len);
tmp = insns;
while (tmp != NULL_RTX)
{
VARRAY_INT (*vecp, i) = INSN_UID (tmp);
i++;
tmp = NEXT_INSN (tmp);
}
}
static int
contains (insn, vec)
rtx insn;
varray_type vec;
{
int i, j;
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int count = 0;
for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
for (j = VARRAY_SIZE (vec) - 1; j >= 0; --j)
if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) == VARRAY_INT (vec, j))
count++;
return count;
}
else
{
for (j = VARRAY_SIZE (vec) - 1; j >= 0; --j)
if (INSN_UID (insn) == VARRAY_INT (vec, j))
return 1;
}
return 0;
}
int
prologue_epilogue_contains (insn)
rtx insn;
{
if (contains (insn, prologue))
return 1;
if (contains (insn, epilogue))
return 1;
return 0;
}
int
sibcall_epilogue_contains (insn)
rtx insn;
{
if (sibcall_epilogue)
return contains (insn, sibcall_epilogue);
return 0;
}
#ifdef HAVE_return
static void
emit_return_into_block (bb, line_note)
basic_block bb;
rtx line_note;
{
rtx p, end;
p = NEXT_INSN (bb->end);
end = emit_jump_insn_after (gen_return (), bb->end);
if (line_note)
emit_line_note_after (NOTE_SOURCE_FILE (line_note),
NOTE_LINE_NUMBER (line_note), PREV_INSN (bb->end));
}
#endif
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
struct epi_info
{
rtx sp_equiv_reg;
HOST_WIDE_INT sp_offset;
rtx new_sp_equiv_reg;
HOST_WIDE_INT new_sp_offset;
rtx equiv_reg_src;
};
static void handle_epilogue_set PARAMS ((rtx, struct epi_info *));
static void emit_equiv_load PARAMS ((struct epi_info *));
static rtx
keep_stack_depressed (insns)
rtx insns;
{
int j;
struct epi_info info;
rtx insn, next;
if (NEXT_INSN (insns) == NULL_RTX)
return insns;
start_sequence ();
info.sp_equiv_reg = stack_pointer_rtx;
info.sp_offset = 0;
info.equiv_reg_src = 0;
insn = insns;
next = NULL_RTX;
while (insn != NULL_RTX)
{
next = NEXT_INSN (insn);
if (!INSN_P (insn))
{
add_insn (insn);
insn = next;
continue;
}
if (info.equiv_reg_src != 0
&& reg_referenced_p (info.sp_equiv_reg, PATTERN (insn)))
{
emit_equiv_load (&info);
info.sp_equiv_reg = 0;
}
info.new_sp_equiv_reg = info.sp_equiv_reg;
info.new_sp_offset = info.sp_offset;
if (GET_CODE (PATTERN (insn)) == RETURN
|| (GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
{
rtx retaddr = INCOMING_RETURN_ADDR_RTX;
rtx base = 0;
HOST_WIDE_INT offset = 0;
rtx jump_insn, jump_set;
if (GET_CODE (retaddr) == REG)
{
emit_equiv_load (&info);
add_insn (insn);
insn = next;
continue;
}
else if (GET_CODE (retaddr) == MEM
&& GET_CODE (XEXP (retaddr, 0)) == REG)
base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0;
else if (GET_CODE (retaddr) == MEM
&& GET_CODE (XEXP (retaddr, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (retaddr, 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT)
{
base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0)));
offset = INTVAL (XEXP (XEXP (retaddr, 0), 1));
}
else
abort ();
retaddr = plus_constant (base, offset);
if (base == stack_pointer_rtx)
retaddr = simplify_replace_rtx (retaddr, stack_pointer_rtx,
plus_constant (info.sp_equiv_reg,
info.sp_offset));
retaddr = gen_rtx_MEM (Pmode, retaddr);
if (info.equiv_reg_src
&& reg_overlap_mentioned_p (info.equiv_reg_src, retaddr))
{
unsigned int regno;
rtx reg;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (HARD_REGNO_MODE_OK (regno, Pmode)
&& !fixed_regs[regno]
&& TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)
&& !REGNO_REG_SET_P (EXIT_BLOCK_PTR->global_live_at_start,
regno)
&& !refers_to_regno_p (regno,
regno + HARD_REGNO_NREGS (regno,
Pmode),
info.equiv_reg_src, NULL))
break;
if (regno == FIRST_PSEUDO_REGISTER)
abort ();
reg = gen_rtx_REG (Pmode, regno);
emit_move_insn (reg, retaddr);
retaddr = reg;
}
emit_equiv_load (&info);
jump_insn = emit_jump_insn (gen_indirect_jump (retaddr));
jump_set = single_set (jump_insn);
if (jump_set == 0)
abort ();
else
SET_IS_RETURN_P (jump_set) = 1;
}
else if (!reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))
&& (info.sp_equiv_reg == stack_pointer_rtx
|| !reg_set_p (info.sp_equiv_reg, insn)))
add_insn (insn);
else if (! reg_set_p (stack_pointer_rtx, insn)
&& (info.sp_equiv_reg == stack_pointer_rtx
|| !reg_set_p (info.sp_equiv_reg, insn)))
{
if (! validate_replace_rtx (stack_pointer_rtx,
plus_constant (info.sp_equiv_reg,
info.sp_offset),
insn))
abort ();
add_insn (insn);
}
else if (GET_CODE (PATTERN (insn)) == SET)
handle_epilogue_set (PATTERN (insn), &info);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
for (j = 0; j < XVECLEN (PATTERN (insn), 0); j++)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET)
handle_epilogue_set (XVECEXP (PATTERN (insn), 0, j), &info);
}
else
add_insn (insn);
info.sp_equiv_reg = info.new_sp_equiv_reg;
info.sp_offset = info.new_sp_offset;
insn = next;
}
insns = get_insns ();
end_sequence ();
return insns;
}
static void
handle_epilogue_set (set, p)
rtx set;
struct epi_info *p;
{
if (reg_set_p (stack_pointer_rtx, set))
{
if (SET_DEST (set) != stack_pointer_rtx)
abort ();
if (GET_CODE (SET_SRC (set)) == PLUS
&& GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
{
p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0);
p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
}
else
p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0;
if (p->new_sp_equiv_reg == stack_pointer_rtx)
{
p->new_sp_equiv_reg = p->sp_equiv_reg;
p->new_sp_offset += p->sp_offset;
}
if (p->new_sp_equiv_reg == 0 || GET_CODE (p->new_sp_equiv_reg) != REG)
abort ();
return;
}
else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
{
if (!rtx_equal_p (p->new_sp_equiv_reg, SET_DEST (set))
|| p->equiv_reg_src != 0)
abort ();
else
p->equiv_reg_src
= simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
plus_constant (p->sp_equiv_reg,
p->sp_offset));
}
else
{
SET_SRC (set) = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
plus_constant (p->sp_equiv_reg,
p->sp_offset));
SET_DEST (set) = simplify_replace_rtx (SET_DEST (set), stack_pointer_rtx,
plus_constant (p->sp_equiv_reg,
p->sp_offset));
emit_insn (set);
}
}
static void
emit_equiv_load (p)
struct epi_info *p;
{
if (p->equiv_reg_src != 0)
emit_move_insn (p->sp_equiv_reg, p->equiv_reg_src);
p->equiv_reg_src = 0;
}
#endif
void
thread_prologue_and_epilogue_insns (f)
rtx f ATTRIBUTE_UNUSED;
{
int inserted = 0;
edge e;
#if defined (HAVE_sibcall_epilogue) || defined (HAVE_epilogue) || defined (HAVE_return) || defined (HAVE_prologue)
rtx seq;
#endif
#ifdef HAVE_prologue
rtx prologue_end = NULL_RTX;
#endif
#if defined (HAVE_epilogue) || defined(HAVE_return)
rtx epilogue_end = NULL_RTX;
#endif
#ifdef HAVE_prologue
if (HAVE_prologue)
{
start_sequence ();
seq = gen_prologue ();
emit_insn (seq);
record_insns (seq, &prologue);
prologue_end = emit_note (NULL, NOTE_INSN_PROLOGUE_END);
seq = get_insns ();
end_sequence ();
if (!ENTRY_BLOCK_PTR->succ || ENTRY_BLOCK_PTR->succ->succ_next)
abort ();
insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
inserted = 1;
}
#endif
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
if ((e->flags & EDGE_FAKE) == 0)
break;
if (e == NULL)
goto epilogue_done;
#ifdef HAVE_return
if (optimize && HAVE_return)
{
basic_block last;
edge e_next;
rtx label;
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
if (e->flags & EDGE_FALLTHRU)
break;
if (e == NULL)
goto epilogue_done;
last = e->src;
label = last->end;
while (label && GET_CODE (label) != CODE_LABEL)
{
if (active_insn_p (label))
break;
label = PREV_INSN (label);
}
if (last->head == label && GET_CODE (label) == CODE_LABEL)
{
rtx epilogue_line_note = NULL_RTX;
for (seq = get_last_insn ();
seq && ! active_insn_p (seq);
seq = PREV_INSN (seq))
if (GET_CODE (seq) == NOTE && NOTE_LINE_NUMBER (seq) > 0)
{
epilogue_line_note = seq;
break;
}
for (e = last->pred; e; e = e_next)
{
basic_block bb = e->src;
rtx jump;
e_next = e->pred_next;
if (bb == ENTRY_BLOCK_PTR)
continue;
jump = bb->end;
if ((GET_CODE (jump) != JUMP_INSN) || JUMP_LABEL (jump) != label)
continue;
if (simplejump_p (jump))
{
emit_return_into_block (bb, epilogue_line_note);
delete_insn (jump);
}
else if (condjump_p (jump))
{
rtx ret, *loc;
ret = SET_SRC (PATTERN (jump));
if (GET_CODE (XEXP (ret, 1)) == LABEL_REF)
loc = &XEXP (ret, 1);
else
loc = &XEXP (ret, 2);
ret = gen_rtx_RETURN (VOIDmode);
if (! validate_change (jump, loc, ret, 0))
continue;
if (JUMP_LABEL (jump))
LABEL_NUSES (JUMP_LABEL (jump))--;
if (bb->succ->succ_next == NULL)
continue;
}
else
continue;
redirect_edge_succ (e, EXIT_BLOCK_PTR);
}
emit_barrier_after (last->end);
emit_return_into_block (last, epilogue_line_note);
epilogue_end = last->end;
last->succ->flags &= ~EDGE_FALLTHRU;
goto epilogue_done;
}
}
#endif
#ifdef HAVE_epilogue
if (HAVE_epilogue)
{
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 (NULL, NOTE_INSN_EPILOGUE_BEG);
seq = gen_epilogue ();
#ifdef INCOMING_RETURN_ADDR_RTX
if (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
&& TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))
seq = keep_stack_depressed (seq);
#endif
emit_jump_insn (seq);
record_insns (seq, &epilogue);
seq = get_insns ();
end_sequence ();
insert_insn_on_edge (seq, e);
inserted = 1;
}
#endif
epilogue_done:
if (inserted)
commit_edge_insertions ();
#ifdef HAVE_sibcall_epilogue
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
{
basic_block bb = e->src;
rtx insn = bb->end;
rtx i;
rtx newinsn;
if (GET_CODE (insn) != CALL_INSN
|| ! SIBLING_CALL_P (insn))
continue;
start_sequence ();
emit_insn (gen_sibcall_epilogue ());
seq = get_insns ();
end_sequence ();
record_insns (seq, &sibcall_epilogue);
i = PREV_INSN (insn);
newinsn = emit_insn_before (seq, insn);
}
#endif
#ifdef HAVE_prologue
if (prologue_end)
{
rtx insn, prev;
for (insn = prologue_end; insn; insn = prev)
{
prev = PREV_INSN (insn);
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
{
if (prev == NULL)
break;
reorder_insns (insn, insn, prologue_end);
}
}
for (insn = ENTRY_BLOCK_PTR->next_bb->end;
insn != prologue_end && insn;
insn = PREV_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
break;
if (! insn)
{
for (insn = next_active_insn (prologue_end);
insn;
insn = PREV_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
{
emit_line_note_after (NOTE_SOURCE_FILE (insn),
NOTE_LINE_NUMBER (insn),
prologue_end);
break;
}
}
}
#endif
#ifdef HAVE_epilogue
if (epilogue_end)
{
rtx insn, next;
for (insn = epilogue_end; insn; insn = next)
{
next = NEXT_INSN (insn);
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
reorder_insns (insn, insn, PREV_INSN (epilogue_end));
}
}
#endif
}
void
reposition_prologue_and_epilogue_notes (f)
rtx f ATTRIBUTE_UNUSED;
{
#if defined (HAVE_prologue) || defined (HAVE_epilogue)
rtx insn, last, note;
int len;
if ((len = VARRAY_SIZE (prologue)) > 0)
{
last = 0, note = 0;
for (insn = f; insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
note = insn;
}
else if (contains (insn, prologue))
{
last = insn;
if (--len == 0)
break;
}
}
if (last)
{
rtx next;
if (note == 0)
{
for (note = last; (note = NEXT_INSN (note));)
if (GET_CODE (note) == NOTE
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
break;
}
next = NEXT_INSN (note);
if (GET_CODE (last) == CODE_LABEL)
last = NEXT_INSN (last);
reorder_insns (note, note, last);
}
}
if ((len = VARRAY_SIZE (epilogue)) > 0)
{
last = 0, note = 0;
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
note = insn;
}
else if (contains (insn, epilogue))
{
last = insn;
if (--len == 0)
break;
}
}
if (last)
{
if (note == 0)
{
for (note = insn; (note = PREV_INSN (note));)
if (GET_CODE (note) == NOTE
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
break;
}
if (PREV_INSN (last) != note)
reorder_insns (note, note, PREV_INSN (last));
}
}
#endif
}
void
init_function_once ()
{
VARRAY_INT_INIT (prologue, 0, "prologue");
VARRAY_INT_INIT (epilogue, 0, "epilogue");
VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue");
}
#include "gt-function.h"