#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "except.h"
#include "function.h"
#include "insn-flags.h"
#include "expr.h"
#include "insn-codes.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#include "recog.h"
#include "output.h"
#include "basic-block.h"
#include "obstack.h"
#include "toplev.h"
#include "hash.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
#if defined (_WIN32) && defined (NEXT_PDO)
extern char *exportNamesForDLL;
#endif
#ifndef LOCAL_ALIGNMENT
#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
#endif
#ifndef NAME__MAIN
#define NAME__MAIN "__main"
#define SYMBOL__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_pops_args;
int current_function_returns_struct;
int current_function_returns_pcc_struct;
int current_function_needs_context;
int current_function_calls_setjmp;
int current_function_calls_longjmp;
int current_function_has_nonlocal_label;
int current_function_has_nonlocal_goto;
int current_function_contains_functions;
int current_function_is_leaf;
int current_function_sp_is_unchanging;
int current_function_uses_only_leaf_regs;
int current_function_has_computed_jump;
int current_function_is_thunk;
int current_function_calls_alloca;
int current_function_returns_pointer;
rtx current_function_epilogue_delay_list;
int current_function_args_size;
int current_function_pretend_args_size;
int current_function_outgoing_args_size;
rtx current_function_arg_offset_rtx;
int current_function_varargs;
int current_function_stdarg;
CUMULATIVE_ARGS current_function_args_info;
char *current_function_name;
rtx current_function_return_rtx;
int current_function_uses_const_pool;
int current_function_uses_pic_offset_table;
rtx current_function_internal_arg_pointer;
char *current_function_cannot_inline;
int current_function_instrument_entry_exit;
int current_function_check_memory_usage;
tree inline_function_decl;
int function_call_count;
tree nonlocal_labels;
rtx nonlocal_goto_handler_slots;
rtx nonlocal_goto_handler_labels;
rtx nonlocal_goto_stack_level;
rtx cleanup_label;
rtx return_label;
rtx save_expr_regs;
rtx stack_slot_list;
tree rtl_expr_chain;
rtx tail_recursion_label;
rtx tail_recursion_reentry;
rtx arg_pointer_save_area;
HOST_WIDE_INT frame_offset;
static tree context_display;
static tree trampoline_list;
static rtx parm_birth_insn;
#if 0
static int invalid_stack_slot;
#endif
static rtx last_parm_insn;
int max_parm_reg;
rtx *parm_reg_stack_loc;
static int virtuals_instantiated;
void (*save_machine_status) PROTO((struct function *));
void (*restore_machine_status) PROTO((struct function *));
extern int rtx_equal_function_value_matters;
extern tree sequence_rtl_expr;
struct temp_slot
{
struct temp_slot *next;
rtx slot;
rtx address;
int align;
HOST_WIDE_INT size;
int alias_set;
tree rtl_expr;
char in_use;
char addr_taken;
int level;
int keep;
HOST_WIDE_INT base_offset;
HOST_WIDE_INT full_size;
};
struct temp_slot *temp_slots;
int temp_slot_level;
int var_temp_slot_level;
int target_temp_slot_level;
struct fixup_replacement
{
rtx old;
rtx new;
struct fixup_replacement *next;
};
struct insns_for_mem_entry {
struct hash_entry he;
rtx insns;
};
static rtx assign_outer_stack_local PROTO ((enum machine_mode, HOST_WIDE_INT,
int, struct function *));
static rtx assign_stack_temp_for_type PROTO ((enum machine_mode, HOST_WIDE_INT,
int, tree));
static struct temp_slot *find_temp_slot_from_address PROTO((rtx));
static void put_reg_into_stack PROTO((struct function *, rtx, tree,
enum machine_mode, enum machine_mode,
int, int, int,
struct hash_table *));
static void fixup_var_refs PROTO((rtx, enum machine_mode, int,
struct hash_table *));
static struct fixup_replacement
*find_fixup_replacement PROTO((struct fixup_replacement **, rtx));
static void fixup_var_refs_insns PROTO((rtx, enum machine_mode, int,
rtx, int, struct hash_table *));
static void fixup_var_refs_1 PROTO((rtx, enum machine_mode, rtx *, rtx,
struct fixup_replacement **));
static rtx fixup_memory_subreg PROTO((rtx, rtx, int));
static rtx walk_fixup_memory_subreg PROTO((rtx, rtx, int));
static rtx fixup_stack_1 PROTO((rtx, rtx));
static void optimize_bit_field PROTO((rtx, rtx, rtx *));
static void instantiate_decls PROTO((tree, int));
static void instantiate_decls_1 PROTO((tree, int));
static void instantiate_decl PROTO((rtx, int, int));
static int instantiate_virtual_regs_1 PROTO((rtx *, rtx, int));
static void delete_handlers PROTO((void));
static void pad_to_arg_alignment PROTO((struct args_size *, int, int));
#ifndef ARGS_GROW_DOWNWARD
static void pad_below PROTO((struct args_size *, enum machine_mode,
tree));
#endif
#ifdef ARGS_GROW_DOWNWARD
static tree round_down PROTO((tree, int));
#endif
static rtx round_trampoline_addr PROTO((rtx));
static tree blocks_nreverse PROTO((tree));
static int all_blocks PROTO((tree, tree *));
#if defined (HAVE_prologue) || defined (HAVE_epilogue)
static int *record_insns PROTO((rtx));
static int contains PROTO((rtx, int *));
#endif
static void put_addressof_into_stack PROTO((rtx, struct hash_table *));
static void purge_addressof_1 PROTO((rtx *, rtx, int, int,
struct hash_table *));
static struct hash_entry *insns_for_mem_newfunc PROTO((struct hash_entry *,
struct hash_table *,
hash_table_key));
static unsigned long insns_for_mem_hash PROTO ((hash_table_key));
static boolean insns_for_mem_comp PROTO ((hash_table_key, hash_table_key));
static int insns_for_mem_walk PROTO ((rtx *, void *));
static void compute_insns_for_mem PROTO ((rtx, rtx, struct hash_table *));
struct function *outer_function_chain;
struct function *
find_function_data (decl)
tree decl;
{
struct function *p;
for (p = outer_function_chain; p; p = p->next)
if (p->decl == decl)
return p;
abort ();
}
void
push_function_context_to (context)
tree context;
{
struct function *p = (struct function *) xmalloc (sizeof (struct function));
p->next = outer_function_chain;
outer_function_chain = p;
p->name = current_function_name;
p->decl = current_function_decl;
p->pops_args = current_function_pops_args;
p->returns_struct = current_function_returns_struct;
p->returns_pcc_struct = current_function_returns_pcc_struct;
p->returns_pointer = current_function_returns_pointer;
p->needs_context = current_function_needs_context;
p->calls_setjmp = current_function_calls_setjmp;
p->calls_longjmp = current_function_calls_longjmp;
p->calls_alloca = current_function_calls_alloca;
p->has_nonlocal_label = current_function_has_nonlocal_label;
p->has_nonlocal_goto = current_function_has_nonlocal_goto;
p->contains_functions = current_function_contains_functions;
p->has_computed_jump = current_function_has_computed_jump;
p->is_thunk = current_function_is_thunk;
p->args_size = current_function_args_size;
p->pretend_args_size = current_function_pretend_args_size;
p->arg_offset_rtx = current_function_arg_offset_rtx;
p->varargs = current_function_varargs;
p->stdarg = current_function_stdarg;
p->uses_const_pool = current_function_uses_const_pool;
p->uses_pic_offset_table = current_function_uses_pic_offset_table;
p->internal_arg_pointer = current_function_internal_arg_pointer;
p->cannot_inline = current_function_cannot_inline;
p->max_parm_reg = max_parm_reg;
p->parm_reg_stack_loc = parm_reg_stack_loc;
p->outgoing_args_size = current_function_outgoing_args_size;
p->return_rtx = current_function_return_rtx;
p->nonlocal_goto_handler_slots = nonlocal_goto_handler_slots;
p->nonlocal_goto_handler_labels = nonlocal_goto_handler_labels;
p->nonlocal_goto_stack_level = nonlocal_goto_stack_level;
p->nonlocal_labels = nonlocal_labels;
p->cleanup_label = cleanup_label;
p->return_label = return_label;
p->save_expr_regs = save_expr_regs;
p->stack_slot_list = stack_slot_list;
p->parm_birth_insn = parm_birth_insn;
p->frame_offset = frame_offset;
p->tail_recursion_label = tail_recursion_label;
p->tail_recursion_reentry = tail_recursion_reentry;
p->arg_pointer_save_area = arg_pointer_save_area;
p->rtl_expr_chain = rtl_expr_chain;
p->last_parm_insn = last_parm_insn;
p->context_display = context_display;
p->trampoline_list = trampoline_list;
p->function_call_count = function_call_count;
p->temp_slots = temp_slots;
p->temp_slot_level = temp_slot_level;
p->target_temp_slot_level = target_temp_slot_level;
p->var_temp_slot_level = var_temp_slot_level;
p->fixup_var_refs_queue = 0;
p->epilogue_delay_list = current_function_epilogue_delay_list;
p->args_info = current_function_args_info;
p->check_memory_usage = current_function_check_memory_usage;
p->instrument_entry_exit = current_function_instrument_entry_exit;
save_tree_status (p, context);
save_storage_status (p);
save_emit_status (p);
save_expr_status (p);
save_stmt_status (p);
save_varasm_status (p, context);
if (save_machine_status)
(*save_machine_status) (p);
}
void
push_function_context ()
{
push_function_context_to (current_function_decl);
}
void
pop_function_context_from (context)
tree context;
{
struct function *p = outer_function_chain;
struct var_refs_queue *queue;
outer_function_chain = p->next;
current_function_contains_functions
= p->contains_functions || p->inline_obstacks
|| context == current_function_decl;
current_function_has_computed_jump = p->has_computed_jump;
current_function_name = p->name;
current_function_decl = p->decl;
current_function_pops_args = p->pops_args;
current_function_returns_struct = p->returns_struct;
current_function_returns_pcc_struct = p->returns_pcc_struct;
current_function_returns_pointer = p->returns_pointer;
current_function_needs_context = p->needs_context;
current_function_calls_setjmp = p->calls_setjmp;
current_function_calls_longjmp = p->calls_longjmp;
current_function_calls_alloca = p->calls_alloca;
current_function_has_nonlocal_label = p->has_nonlocal_label;
current_function_has_nonlocal_goto = p->has_nonlocal_goto;
current_function_is_thunk = p->is_thunk;
current_function_args_size = p->args_size;
current_function_pretend_args_size = p->pretend_args_size;
current_function_arg_offset_rtx = p->arg_offset_rtx;
current_function_varargs = p->varargs;
current_function_stdarg = p->stdarg;
current_function_uses_const_pool = p->uses_const_pool;
current_function_uses_pic_offset_table = p->uses_pic_offset_table;
current_function_internal_arg_pointer = p->internal_arg_pointer;
current_function_cannot_inline = p->cannot_inline;
max_parm_reg = p->max_parm_reg;
parm_reg_stack_loc = p->parm_reg_stack_loc;
current_function_outgoing_args_size = p->outgoing_args_size;
current_function_return_rtx = p->return_rtx;
nonlocal_goto_handler_slots = p->nonlocal_goto_handler_slots;
nonlocal_goto_handler_labels = p->nonlocal_goto_handler_labels;
nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;
nonlocal_labels = p->nonlocal_labels;
cleanup_label = p->cleanup_label;
return_label = p->return_label;
save_expr_regs = p->save_expr_regs;
stack_slot_list = p->stack_slot_list;
parm_birth_insn = p->parm_birth_insn;
frame_offset = p->frame_offset;
tail_recursion_label = p->tail_recursion_label;
tail_recursion_reentry = p->tail_recursion_reentry;
arg_pointer_save_area = p->arg_pointer_save_area;
rtl_expr_chain = p->rtl_expr_chain;
last_parm_insn = p->last_parm_insn;
context_display = p->context_display;
trampoline_list = p->trampoline_list;
function_call_count = p->function_call_count;
temp_slots = p->temp_slots;
temp_slot_level = p->temp_slot_level;
target_temp_slot_level = p->target_temp_slot_level;
var_temp_slot_level = p->var_temp_slot_level;
current_function_epilogue_delay_list = p->epilogue_delay_list;
reg_renumber = 0;
current_function_args_info = p->args_info;
current_function_check_memory_usage = p->check_memory_usage;
current_function_instrument_entry_exit = p->instrument_entry_exit;
restore_tree_status (p, context);
restore_storage_status (p);
restore_expr_status (p);
restore_emit_status (p);
restore_stmt_status (p);
restore_varasm_status (p);
if (restore_machine_status)
(*restore_machine_status) (p);
for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
fixup_var_refs (queue->modified, queue->promoted_mode,
queue->unsignedp, 0);
free (p);
rtx_equal_function_value_matters = 1;
virtuals_instantiated = 0;
}
void pop_function_context ()
{
pop_function_context_from (current_function_decl);
}
HOST_WIDE_INT
get_frame_size ()
{
#ifdef FRAME_GROWS_DOWNWARD
return -frame_offset;
#else
return frame_offset;
#endif
}
rtx
assign_stack_local (mode, size, align)
enum machine_mode mode;
HOST_WIDE_INT size;
int align;
{
register rtx x, addr;
int bigend_correction = 0;
int alignment, alignment_mod;
if (align == 0)
{
tree type;
alignment = GET_MODE_ALIGNMENT (mode);
if (mode == BLKmode)
alignment = BIGGEST_ALIGNMENT;
type = 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
frame_offset -= size;
#endif
alignment_mod = FRAME_ALIGN_MOD(alignment, frame_offset, size);
#ifdef FRAME_GROWS_DOWNWARD
frame_offset = alignment_mod + FLOOR_ROUND (frame_offset - alignment_mod,
alignment);
#else
frame_offset = alignment_mod + CEIL_ROUND (frame_offset - alignment_mod,
alignment);
#endif
if (BYTES_BIG_ENDIAN && mode != BLKmode)
bigend_correction = size - GET_MODE_SIZE (mode);
if (virtuals_instantiated)
addr = plus_constant (frame_pointer_rtx,
(frame_offset + bigend_correction
+ STARTING_FRAME_OFFSET));
else
addr = plus_constant (virtual_stack_vars_rtx,
frame_offset + bigend_correction);
#ifndef FRAME_GROWS_DOWNWARD
frame_offset += size;
#endif
x = gen_rtx_MEM (mode, addr);
stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, x, stack_slot_list);
return x;
}
static rtx
assign_outer_stack_local (mode, size, align, function)
enum machine_mode mode;
HOST_WIDE_INT size;
int align;
struct function *function;
{
register rtx x, addr;
int bigend_correction = 0;
int alignment;
int alignment_mod;
push_obstacks (function->function_obstack,
function->function_maybepermanent_obstack);
if (align == 0)
{
tree type;
alignment = GET_MODE_ALIGNMENT (mode);
if (mode == BLKmode)
alignment = BIGGEST_ALIGNMENT;
type = 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->frame_offset -= size;
#endif
alignment_mod = FRAME_ALIGN_MOD(alignment, function->frame_offset, size);
#ifdef FRAME_GROWS_DOWNWARD
function->frame_offset
= alignment_mod + FLOOR_ROUND (function->frame_offset - alignment_mod,
alignment);
#else
function->frame_offset
= alignment_mod + CEIL_ROUND (function->frame_offset - alignment_mod,
alignment);
#endif
if (BYTES_BIG_ENDIAN && mode != BLKmode)
bigend_correction = size - GET_MODE_SIZE (mode);
addr = plus_constant (virtual_stack_vars_rtx,
function->frame_offset + bigend_correction);
#ifndef FRAME_GROWS_DOWNWARD
function->frame_offset += size;
#endif
x = gen_rtx_MEM (mode, addr);
function->stack_slot_list
= gen_rtx_EXPR_LIST (VOIDmode, x, function->stack_slot_list);
pop_obstacks ();
return x;
}
static rtx
assign_stack_temp_for_type (mode, size, keep, type)
enum machine_mode mode;
HOST_WIDE_INT size;
int keep;
tree type;
{
int align;
int alias_set;
struct temp_slot *p, *best_p = 0;
if (size == -1)
abort ();
if (type)
alias_set = get_alias_set (type);
else
alias_set = 0;
align = GET_MODE_ALIGNMENT (mode);
if (mode == BLKmode)
align = BIGGEST_ALIGNMENT;
if (! type)
type = 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
&& (!flag_strict_aliasing
|| (alias_set && p->alias_set == alias_set))
&& (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
&& !flag_strict_aliasing)
{
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 *) oballoc (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->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 *) oballoc (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;
p->alias_set = alias_set;
#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 = sequence_rtl_expr;
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;
}
RTX_UNCHANGING_P (p->slot) = 0;
MEM_IN_STRUCT_P (p->slot) = 0;
MEM_SCALAR_P (p->slot) = 0;
MEM_ALIAS_SET (p->slot) = 0;
return p->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, keep, memory_required, dont_promote)
tree type;
int keep;
int memory_required;
int dont_promote;
{
enum machine_mode mode = TYPE_MODE (type);
int unsignedp = TREE_UNSIGNED (type);
if (mode == BLKmode || memory_required)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
rtx tmp;
if (size == -1 && TREE_CODE (type) == ARRAY_TYPE
&& TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE
&& TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST)
size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));
tmp = assign_stack_temp_for_type (mode, size, keep, type);
MEM_SET_IN_STRUCT_P (tmp, AGGREGATE_TYPE_P (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;
}
return 0;
}
void
update_temp_slot_address (old, new)
rtx old, new;
{
struct temp_slot *p = find_temp_slot_from_address (old);
if (p == 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 && REGNO_POINTER_FLAG (REGNO (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--;
}
#ifndef NEXT_SEMANTICS
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;
}
#endif
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)
p->in_use = 0;
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++;
}
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;
}
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;
{
register rtx reg;
enum machine_mode promoted_mode, decl_mode;
struct function *function = 0;
tree context;
int can_use_addressof;
context = decl_function_context (decl);
reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (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->next)
if (function->decl == context)
break;
if (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,
TREE_SIDE_EFFECTS (decl), 0,
TREE_USED (decl) || DECL_INITIAL (decl) != 0,
0);
}
else if (GET_CODE (reg) == CONCAT)
{
enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
tree part_type = TREE_TYPE (TREE_TYPE (decl));
#ifdef FRAME_GROWS_DOWNWARD
put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
part_mode, TREE_SIDE_EFFECTS (decl), 0,
TREE_USED (decl) || DECL_INITIAL (decl) != 0,
0);
put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
part_mode, TREE_SIDE_EFFECTS (decl), 0,
TREE_USED (decl) || DECL_INITIAL (decl) != 0,
0);
#else
put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
part_mode, TREE_SIDE_EFFECTS (decl), 0,
TREE_USED (decl) || DECL_INITIAL (decl) != 0,
0);
put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
part_mode, TREE_SIDE_EFFECTS (decl), 0,
TREE_USED (decl) || DECL_INITIAL (decl) != 0,
0);
#endif
PUT_CODE (reg, MEM);
MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
MEM_ALIAS_SET (reg) = get_alias_set (decl);
XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);
if (GET_CODE (XEXP (reg, 0)) == PLUS)
XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
}
else
return;
if (current_function_check_memory_usage)
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
XEXP (reg, 0), Pmode,
GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
}
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;
int original_regno;
int used_p;
struct hash_table *ht;
{
rtx new = 0;
int regno = original_regno;
if (regno == 0)
regno = REGNO (reg);
if (function)
{
if (regno < function->max_parm_reg)
new = function->parm_reg_stack_loc[regno];
if (new == 0)
new = assign_outer_stack_local (decl_mode, GET_MODE_SIZE (decl_mode),
0, function);
}
else
{
if (regno < max_parm_reg)
new = parm_reg_stack_loc[regno];
if (new == 0)
new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
}
PUT_MODE (reg, decl_mode);
XEXP (reg, 0) = XEXP (new, 0);
MEM_VOLATILE_P (reg) = volatile_p;
PUT_CODE (reg, MEM);
MEM_SET_IN_STRUCT_P (reg,
AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
MEM_ALIAS_SET (reg) = get_alias_set (type);
if (used_p && function != 0)
{
struct var_refs_queue *temp;
push_obstacks (function->function_obstack,
function->function_maybepermanent_obstack);
temp
= (struct var_refs_queue *) savealloc (sizeof (struct var_refs_queue));
temp->modified = reg;
temp->promoted_mode = promoted_mode;
temp->unsignedp = TREE_UNSIGNED (type);
temp->next = function->fixup_var_refs_queue;
function->fixup_var_refs_queue = temp;
pop_obstacks ();
}
else if (used_p)
fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type), ht);
}
static void
fixup_var_refs (var, promoted_mode, unsignedp, ht)
rtx var;
enum machine_mode promoted_mode;
int unsignedp;
struct hash_table *ht;
{
tree pending;
rtx first_insn = get_insns ();
struct sequence_stack *stack = sequence_stack;
tree rtl_exps = rtl_expr_chain;
fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn,
stack == 0, ht);
if (ht)
return;
for (; stack; stack = stack->next)
{
push_to_sequence (stack->first);
fixup_var_refs_insns (var, promoted_mode, unsignedp,
stack->first, stack->next != 0, 0);
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 (var, promoted_mode, unsignedp, seq, 0,
0);
end_sequence ();
}
}
push_to_sequence (catch_clauses);
fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses,
0, 0);
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 && p->old != x; p = p->next)
;
if (p == 0)
{
p = (struct fixup_replacement *) oballoc (sizeof (struct fixup_replacement));
p->old = x;
p->new = 0;
p->next = *replacements;
*replacements = p;
}
return p;
}
static void
fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
rtx var;
enum machine_mode promoted_mode;
int unsignedp;
rtx insn;
int toplevel;
struct hash_table *ht;
{
rtx call_dest = 0;
rtx insn_list = NULL_RTX;
if (ht)
{
insn_list = ((struct insns_for_mem_entry *)
hash_lookup (ht, var, 0, 0))->insns;
insn = insn_list ? XEXP (insn_list, 0) : NULL_RTX;
insn_list = XEXP (insn_list, 1);
}
while (insn)
{
rtx next = NEXT_INSN (insn);
rtx set, prev, prev_set;
rtx note;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
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));
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
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))))
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
if (insn == last_parm_insn)
last_parm_insn = PREV_INSN (next);
}
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);
if (insn == last_parm_insn)
last_parm_insn = PREV_INSN (next_insn);
while (replacements)
{
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, 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 = gen_sequence ();
end_sequence ();
}
else
seq = gen_move_insn (replacements->new,
replacements->old);
emit_insn_before (seq, insert_before);
}
replacements = replacements->next;
}
}
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (GET_CODE (note) != INSN_LIST)
XEXP (note, 0)
= walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
}
if (!ht)
insn = next;
else if (insn_list)
{
insn = XEXP (insn_list, 0);
insn_list = XEXP (insn_list, 1);
}
else
insn = NULL_RTX;
}
}
static void
fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
register rtx var;
enum machine_mode promoted_mode;
register rtx *loc;
rtx insn;
struct fixup_replacement **replacements;
{
register int i;
register rtx x = *loc;
RTX_CODE code = GET_CODE (x);
register char *fmt;
register 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 = gen_sequence ();
end_sequence ();
if (recog_memoized (new_insn) < 0)
{
start_sequence ();
force_operand (sub, y);
seq = gen_sequence ();
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, var);
*loc = x = replacement->new;
}
break;
case REG:
case CC0:
case PC:
case CONST_INT:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
case CONST_DOUBLE:
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;
}
else
tem = fixup_memory_subreg (tem, insn, 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));
#ifdef HAVE_extzv
if (GET_CODE (x) == ZERO_EXTRACT)
{
wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
if (wanted_mode == VOIDmode)
wanted_mode = word_mode;
}
#endif
#ifdef HAVE_extv
if (GET_CODE (x) == SIGN_EXTRACT)
{
wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
if (wanted_mode == VOIDmode)
wanted_mode = word_mode;
}
#endif
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 = gen_rtx_MEM (wanted_mode,
plus_constant (XEXP (tem, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
MEM_COPY_ATTRIBUTES (newmem, tem);
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);
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 (GET_MODE (var));
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, 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, NULL_PTR);
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);
#ifdef HAVE_insv
rtx outerdest = dest;
#endif
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 = XEXP (src, 0);
if (src != var && dest != var)
break;
INSN_CODE (insn) = -1;
#ifdef HAVE_insv
if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var)
{
fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 1),
insn, replacements);
fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 2),
insn, replacements);
fixup_var_refs_1 (var, promoted_mode, &SET_SRC (x),
insn, replacements);
tem = XEXP (outerdest, 0);
if (GET_CODE (tem) == SUBREG
&& SUBREG_REG (tem) == var)
tem = fixup_memory_subreg (tem, insn, 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 = insn_operand_mode[(int) CODE_FOR_insv][0];
if (wanted_mode == VOIDmode)
wanted_mode = word_mode;
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 = gen_rtx_MEM (wanted_mode,
plus_constant (XEXP (tem, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
MEM_COPY_ATTRIBUTES (newmem, tem);
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;
}
#endif
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;
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, 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 (GET_CODE (pat) == SEQUENCE)
{
emit_insn_after (pat, insn);
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
else
PATTERN (insn) = 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;
if (GET_CODE (SET_DEST (x)) == SUBREG)
SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, 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 (GET_CODE (pat) == SEQUENCE)
{
emit_insn_after (pat, insn);
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
else
PATTERN (insn) = pat;
return;
}
if (dest == var)
{
rtx temp;
rtx fixeddest = SET_DEST (x);
if (GET_CODE (fixeddest) == STRICT_LOW_PART)
fixeddest = XEXP (fixeddest, 0);
if (GET_CODE (fixeddest) == SUBREG)
{
fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
promoted_mode = GET_MODE (fixeddest);
}
else
fixeddest = fixup_stack_1 (fixeddest, insn);
temp = gen_reg_rtx (promoted_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);
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j),
insn, replacements);
}
}
}
static rtx
fixup_memory_subreg (x, insn, uncritical)
rtx x;
rtx insn;
int uncritical;
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
rtx addr = XEXP (SUBREG_REG (x), 0);
enum machine_mode mode = GET_MODE (x);
rtx result;
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
&& ! uncritical)
abort ();
if (BYTES_BIG_ENDIAN)
offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
addr = plus_constant (addr, offset);
if (!flag_force_addr && memory_address_p (mode, addr))
return change_address (SUBREG_REG (x), mode, addr);
start_sequence ();
result = change_address (SUBREG_REG (x), mode, addr);
emit_insn_before (gen_sequence (), insn);
end_sequence ();
return result;
}
static rtx
walk_fixup_memory_subreg (x, insn, uncritical)
register rtx x;
rtx insn;
int uncritical;
{
register enum rtx_code code;
register char *fmt;
register 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, 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, uncritical);
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
XVECEXP (x, i, j)
= walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, uncritical);
}
}
return x;
}
static rtx
fixup_stack_1 (x, insn)
rtx x;
rtx insn;
{
register int i;
register RTX_CODE code = GET_CODE (x);
register char *fmt;
if (code == MEM)
{
register 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 = gen_sequence ();
end_sequence ();
emit_insn_before (seq, insn);
return change_address (x, VOIDmode, 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);
if (fmt[i] == 'E')
{
register 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;
{
register 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)
{
register 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_WORD (XEXP (bitfield, 0)) * 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 = change_address (memref, mode,
plus_constant (XEXP (memref, 0), offset));
insns = get_insns ();
end_sequence ();
emit_insns_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_WORD (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_WORD (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_insns_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
#ifdef ACCUMULATE_OUTGOING_ARGS
#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
#define STACK_DYNAMIC_OFFSET(FNDECL) \
(current_function_outgoing_args_size \
+ REG_PARM_STACK_SPACE (FNDECL) + (STACK_POINTER_OFFSET))
#else
#define STACK_DYNAMIC_OFFSET(FNDECL) \
(current_function_outgoing_args_size + (STACK_POINTER_OFFSET))
#endif
#else
#define STACK_DYNAMIC_OFFSET(FNDECL) STACK_POINTER_OFFSET
#endif
#endif
#ifndef ARG_POINTER_CFA_OFFSET
#define ARG_POINTER_CFA_OFFSET 0
#endif
rtx
gen_mem_addressof (reg, decl)
rtx reg;
tree decl;
{
tree type = TREE_TYPE (decl);
rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg));
SET_ADDRESSOF_DECL (r, decl);
REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
XEXP (reg, 0) = r;
PUT_CODE (reg, MEM);
PUT_MODE (reg, DECL_MODE (decl));
MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (type));
MEM_ALIAS_SET (reg) = get_alias_set (decl);
if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), 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;
struct hash_table *ht;
{
tree decl = ADDRESSOF_DECL (r);
rtx reg = XEXP (r, 0);
if (GET_CODE (reg) != REG)
abort ();
put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
ADDRESSOF_REGNO (r),
TREE_USED (decl) || DECL_INITIAL (decl) != 0, ht);
}
static rtx purge_bitfield_addressof_replacements;
static rtx purge_addressof_replacements;
static void
purge_addressof_1 (loc, insn, force, store, ht)
rtx *loc;
rtx insn;
int force, store;
struct hash_table *ht;
{
rtx x;
RTX_CODE code;
int i, j;
char *fmt;
restart:
x = *loc;
if (x == 0)
return;
code = GET_CODE (x);
if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
{
rtx insns;
rtx sub = copy_rtx (XEXP (XEXP (x, 0), 0));
if (validate_change (insn, loc, sub, 0)
|| validate_replace_rtx (x, sub, insn))
return;
start_sequence ();
sub = force_operand (sub, NULL_RTX);
if (! validate_change (insn, loc, sub, 0)
&& ! validate_replace_rtx (x, sub, insn))
abort ();
insns = gen_sequence ();
end_sequence ();
emit_insn_before (insns, insn);
return;
}
else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
{
rtx sub = XEXP (XEXP (x, 0), 0);
rtx sub2;
if (GET_CODE (sub) == MEM)
{
sub2 = gen_rtx_MEM (GET_MODE (x), copy_rtx (XEXP (sub, 0)));
MEM_COPY_ATTRIBUTES (sub2, sub);
RTX_UNCHANGING_P (sub2) = RTX_UNCHANGING_P (sub);
sub = sub2;
}
if (GET_CODE (sub) == REG
&& (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
{
put_addressof_into_stack (XEXP (x, 0), ht);
return;
}
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;
}
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_WORD (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;
}
abort ();
}
size_x = GET_MODE_BITSIZE (GET_MODE (x));
size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
if (size_x <= size_sub
&& 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 = gen_sequence ();
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)),
GET_MODE_SIZE (GET_MODE (sub)));
for (p = get_insns(); p; p = NEXT_INSN (p))
{
reset_used_flags (PATTERN (p));
reset_used_flags (REG_NOTES (p));
reset_used_flags (LOG_LINKS (p));
}
unshare_all_rtl (get_insns ());
seq = gen_sequence ();
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)),
GET_MODE_SIZE (GET_MODE (sub)));
if (! validate_change (insn, loc, val, 0))
{
end_sequence ();
goto give_up;
}
seq = gen_sequence ();
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;
}
}
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;
}
purge_addressof_replacements
= gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0),
gen_rtx_EXPR_LIST (VOIDmode, sub,
purge_addressof_replacements));
return;
}
goto restart;
}
give_up:;
}
else if (code == ADDRESSOF)
{
put_addressof_into_stack (x, ht);
return;
}
else if (code == SET)
{
purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
return;
}
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
{
if (*fmt == 'e')
purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht);
else if (*fmt == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht);
}
}
static struct hash_entry *
insns_for_mem_newfunc (he, ht, k)
struct hash_entry *he;
struct hash_table *ht;
hash_table_key k ATTRIBUTE_UNUSED;
{
struct insns_for_mem_entry *ifmhe;
if (he)
return he;
ifmhe = ((struct insns_for_mem_entry *)
hash_allocate (ht, sizeof (struct insns_for_mem_entry)));
ifmhe->insns = NULL_RTX;
return &ifmhe->he;
}
static unsigned long
insns_for_mem_hash (k)
hash_table_key k;
{
return (unsigned long) k;
}
static boolean
insns_for_mem_comp (k1, k2)
hash_table_key k1;
hash_table_key k2;
{
return k1 == k2;
}
struct insns_for_mem_walk_info {
struct hash_table *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;
if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
&& GET_CODE (XEXP (*r, 0)) == REG)
hash_lookup (ifmwi->ht, XEXP (*r, 0), 1, 0);
else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
{
struct insns_for_mem_entry *ifme
= (struct insns_for_mem_entry *) hash_lookup (ifmwi->ht,
*r,
0,
0);
if (ifme && (!ifme->insns || XEXP (ifme->insns, 0) != ifmwi->insn))
{
push_obstacks (&ifmwi->ht->memory, &ifmwi->ht->memory);
ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn,
ifme->insns);
pop_obstacks ();
}
}
return 0;
}
static void
compute_insns_for_mem (insns, last_insn, ht)
rtx insns;
rtx last_insn;
struct hash_table *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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
ifmwi.insn = insn;
for_each_rtx (&insn, insns_for_mem_walk, &ifmwi);
}
}
void
purge_addressof (insns)
rtx insns;
{
rtx insn;
struct hash_table ht;
hash_table_init (&ht,
insns_for_mem_newfunc,
insns_for_mem_hash,
insns_for_mem_comp);
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)
{
purge_addressof_1 (&PATTERN (insn), insn,
asm_noperands (PATTERN (insn)) > 0, 0, &ht);
purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0, &ht);
}
hash_table_free (&ht);
purge_bitfield_addressof_replacements = 0;
purge_addressof_replacements = 0;
}
void
instantiate_virtual_regs (fndecl, insns)
tree fndecl;
rtx insns;
{
rtx insn;
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;
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);
}
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;
if (DECL_SAVED_INSNS (fndecl))
resume_temporary_allocation ();
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
instantiate_decl (DECL_RTL (decl), size, valid_only);
size = MAX (GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl))), size);
instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
}
instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
if (DECL_INLINE (fndecl) || DECL_DEFER_OUTPUT (fndecl))
{
preserve_data ();
rtl_in_current_obstack ();
}
}
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))
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;
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)
{
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode && GET_MODE_SIZE (mode) <= 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) <= size;
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
return;
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR
&& ! memory_address_p (GET_MODE (x), addr))
return;
}
XEXP (x, 0) = addr;
}
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;
char *fmt;
restart:
x = *loc;
if (x == 0)
return 1;
code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
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 (SET_DEST (x) == virtual_incoming_args_rtx)
new = arg_pointer_rtx, offset = - in_arg_offset;
else if (SET_DEST (x) == virtual_stack_vars_rtx)
new = frame_pointer_rtx, offset = - var_offset;
else if (SET_DEST (x) == virtual_stack_dynamic_rtx)
new = stack_pointer_rtx, offset = - dynamic_offset;
else if (SET_DEST (x) == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = - out_arg_offset;
else if (SET_DEST (x) == virtual_cfa_rtx)
new = arg_pointer_rtx, offset = - cfa_offset;
if (new)
{
if (GET_CODE (SET_SRC (x)) != REG
&& GET_CODE (SET_SRC (x)) != PLUS)
abort ();
start_sequence ();
if (GET_CODE (SET_SRC (x)) != REG)
temp = force_operand (SET_SRC (x), NULL_RTX);
else
temp = SET_SRC (x);
temp = force_operand (plus_constant (temp, offset), NULL_RTX);
seq = get_insns ();
end_sequence ();
emit_insns_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)
{
rtx inner = XEXP (XEXP (x, 0), 0);
if (inner == virtual_incoming_args_rtx)
new = arg_pointer_rtx, offset = in_arg_offset;
else if (inner == virtual_stack_vars_rtx)
new = frame_pointer_rtx, offset = var_offset;
else if (inner == virtual_stack_dynamic_rtx)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (inner == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
else if (inner == virtual_cfa_rtx)
new = arg_pointer_rtx, offset = cfa_offset;
else
{
loc = &XEXP (x, 0);
goto restart;
}
instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
extra_insns);
new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
}
else if (XEXP (x, 0) == virtual_incoming_args_rtx)
new = arg_pointer_rtx, offset = in_arg_offset;
else if (XEXP (x, 0) == virtual_stack_vars_rtx)
new = frame_pointer_rtx, offset = var_offset;
else if (XEXP (x, 0) == virtual_stack_dynamic_rtx)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
else if (XEXP (x, 0) == virtual_cfa_rtx)
new = arg_pointer_rtx, offset = cfa_offset;
else
{
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_insns_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 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 (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;
if (new)
{
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_insns_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_insn (insn);
}
}
}
void
use_variable (rtl)
rtx rtl;
{
if (GET_CODE (rtl) == REG)
emit_insn (gen_rtx_USE (VOIDmode, rtl));
else if (GET_CODE (rtl) == MEM
&& GET_CODE (XEXP (rtl, 0)) == REG
&& (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
|| REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
&& XEXP (rtl, 0) != current_function_internal_arg_pointer)
emit_insn (gen_rtx_USE (VOIDmode, XEXP (rtl, 0)));
}
void
use_variable_after (rtl, insn)
rtx rtl, insn;
{
if (GET_CODE (rtl) == REG)
emit_insn_after (gen_rtx_USE (VOIDmode, rtl), insn);
else if (GET_CODE (rtl) == MEM
&& GET_CODE (XEXP (rtl, 0)) == REG
&& (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
|| REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
&& XEXP (rtl, 0) != current_function_internal_arg_pointer)
emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (rtl, 0)), 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 ()
{
register rtx searcher;
register 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;
if (TREE_CODE_CLASS (TREE_CODE (exp)) == 't')
type = exp;
else
type = TREE_TYPE (exp);
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);
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, second_time)
tree fndecl;
int second_time;
{
register tree parm;
register rtx entry_parm = 0;
register 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;
int hide_last_arg
= (current_function_varargs
&& fnargs
&& (parm = tree_last (fnargs)) != 0
&& DECL_NAME (parm)
&& (! strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
"__builtin_va_alist")));
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))
&& ! second_time)
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
if (! second_time)
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 *) savealloc (max_parm_reg * sizeof (rtx));
bzero ((char *) parm_reg_stack_loc, max_parm_reg * sizeof (rtx));
current_function_pretend_args_size = 0;
for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
{
int aggregate = AGGREGATE_TYPE_P (TREE_TYPE (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 = ((TREE_CHAIN (parm) == 0
|| DECL_NAME (TREE_CHAIN (parm)) == 0)
&& (stdarg || current_function_varargs));
int named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
if (TREE_TYPE (parm) == error_mark_node
|| TREE_CODE (parm) != PARM_DECL
|| passed_type == NULL)
{
DECL_INCOMING_RTL (parm) = DECL_RTL (parm)
= gen_rtx_MEM (BLKmode, const0_rtx);
TREE_USED (parm) = 1;
continue;
}
if (hide_last_arg && last_named)
current_function_args_info = args_so_far;
passed_mode = TYPE_MODE (passed_type);
nominal_mode = TYPE_MODE (nominal_type);
if (nominal_mode == VOIDmode)
{
DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = const0_rtx;
continue;
}
if (DECL_TRANSPARENT_UNION (parm)
|| 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;
}
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,
second_time);
varargs_setup = 1;
}
#endif
pretend_named = named_arg || PRETEND_OUTGOING_VARARGS_NAMED;
#if defined (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);
if (! second_time)
{
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));
MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
}
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)
{
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 (! second_time)
{
if (GET_CODE (entry_parm) == PARALLEL)
emit_group_store (validize_mem (stack_parm), entry_parm,
int_size_in_bytes (TREE_TYPE (parm)),
(TYPE_ALIGN (TREE_TYPE (parm))
/ BITS_PER_UNIT));
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;
if (! second_time)
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
)
#if defined (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);
if (second_time)
continue;
{
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 0
if (nominal_mode != BLKmode && nominal_mode != passed_mode
&& stack_parm != 0)
{
rtx offset_rtx;
if (BYTES_BIG_ENDIAN
&& GET_MODE_SIZE (nominal_mode) < UNITS_PER_WORD)
stack_offset.constant += (GET_MODE_SIZE (passed_mode)
- GET_MODE_SIZE (nominal_mode));
offset_rtx = ARGS_SIZE_RTX (stack_offset);
if (offset_rtx == const0_rtx)
stack_parm = gen_rtx_MEM (nominal_mode, internal_arg_pointer);
else
stack_parm = gen_rtx_MEM (nominal_mode,
gen_rtx_PLUS (Pmode,
internal_arg_pointer,
offset_rtx));
MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
}
#endif
#ifdef STACK_REGS
if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
emit_insn (gen_rtx_USE (GET_MODE (entry_parm), entry_parm));
#endif
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)),
UNITS_PER_WORD);
if (stack_parm == 0)
{
stack_parm
= assign_stack_local (GET_MODE (entry_parm),
size_stored, 0);
MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
}
else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
abort ();
if (TREE_READONLY (parm))
RTX_UNCHANGING_P (stack_parm) = 1;
if (GET_CODE (entry_parm) == PARALLEL)
emit_group_store (validize_mem (stack_parm), entry_parm,
int_size_in_bytes (TREE_TYPE (parm)),
(TYPE_ALIGN (TREE_TYPE (parm))
/ BITS_PER_UNIT));
else
move_block_from_reg (REGNO (entry_parm),
validize_mem (stack_parm),
size_stored / UNITS_PER_WORD,
int_size_in_bytes (TREE_TYPE (parm)));
}
DECL_RTL (parm) = stack_parm;
}
else if (! ((obey_regdecls && ! DECL_REGISTER (parm)
&& ! DECL_INLINE (fndecl))
|| TREE_ADDRESSABLE (parm)
|| TREE_SIDE_EFFECTS (parm)
|| (flag_float_store
&& TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE))
|| passed_pointer || parm == function_result_decl)
{
register rtx parmreg;
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)
{
DECL_RTL (parm)
= gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
MEM_SET_IN_STRUCT_P (DECL_RTL (parm), aggregate);
}
else
DECL_RTL (parm) = parmreg;
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);
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
&& ! ((obey_regdecls && ! DECL_REGISTER (parm)
&& ! DECL_INLINE (fndecl))
|| TREE_ADDRESSABLE (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);
emit_move_insn (parmreg, DECL_RTL (parm));
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 (TYPE_SIZE (type) == 0
|| 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);
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
RTX_UNCHANGING_P (copy) = TREE_READONLY (parm);
store_expr (parm, copy, 0);
emit_move_insn (parmreg, XEXP (copy, 0));
if (current_function_check_memory_usage)
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
XEXP (copy, 0), Pmode,
GEN_INT (int_size_in_bytes (type)),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
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 *) savealloc (max_parm_reg * sizeof (rtx));
bcopy ((char *) parm_reg_stack_loc, (char *) new,
old_max_parm_reg * sizeof (rtx));
bzero ((char *) (new + old_max_parm_reg),
(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)))
/ BITS_PER_UNIT));
}
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 = change_address (stack_parm, nominal_mode,
NULL_RTX);
}
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);
MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
}
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));
}
if (current_function_check_memory_usage)
{
push_to_sequence (conversion_insns);
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
XEXP (stack_parm, 0), Pmode,
GEN_INT (GET_MODE_SIZE (GET_MODE
(entry_parm))),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
conversion_insns = get_insns ();
end_sequence ();
}
DECL_RTL (parm) = stack_parm;
}
if (parm == function_result_decl)
{
tree result = DECL_RESULT (fndecl);
tree restype = TREE_TYPE (result);
DECL_RTL (result)
= gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
MEM_SET_IN_STRUCT_P (DECL_RTL (result),
AGGREGATE_TYPE_P (restype));
}
if (TREE_THIS_VOLATILE (parm))
MEM_VOLATILE_P (DECL_RTL (parm)) = 1;
if (TREE_READONLY (parm))
RTX_UNCHANGING_P (DECL_RTL (parm)) = 1;
}
emit_insns (conversion_insns);
last_parm_insn = get_last_insn ();
current_function_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
#ifdef STACK_BOUNDARY
#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
current_function_args_size
= ((current_function_args_size + STACK_BYTES - 1)
/ STACK_BYTES) * STACK_BYTES;
#endif
#ifdef ARGS_GROW_DOWNWARD
current_function_arg_offset_rtx
= (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
: expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,
size_int (-stack_args_size.constant)),
NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD));
#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);
if (!hide_last_arg)
current_function_args_info = args_so_far;
current_function_return_rtx = DECL_RTL (DECL_RESULT (fndecl));
}
#ifdef PROMOTE_FUNCTION_ARGS
rtx
promoted_input_arg (regno, pmode, punsignedp)
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)
enum machine_mode passed_mode;
tree type;
int in_regs;
tree fndecl ATTRIBUTE_UNUSED;
struct args_size *initial_offset_ptr;
struct args_size *offset_ptr;
struct args_size *arg_size_ptr;
{
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 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),
size_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;
#ifdef ARGS_GROW_DOWNWARD
if (initial_offset_ptr->var)
{
offset_ptr->constant = 0;
offset_ptr->var = size_binop (MINUS_EXPR, integer_zero_node,
initial_offset_ptr->var);
}
else
{
offset_ptr->constant = - initial_offset_ptr->constant;
offset_ptr->var = 0;
}
if (where_pad != none
&& (TREE_CODE (sizetree) != INTEGER_CST
|| ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
SUB_PARM_SIZE (*offset_ptr, sizetree);
if (where_pad != downward)
pad_to_arg_alignment (offset_ptr, mod_boundary, boundary);
if (initial_offset_ptr->var)
{
arg_size_ptr->var = size_binop (MINUS_EXPR,
size_binop (MINUS_EXPR,
integer_zero_node,
initial_offset_ptr->var),
offset_ptr->var);
}
else
{
arg_size_ptr->constant = (- initial_offset_ptr->constant
- offset_ptr->constant);
}
#else
pad_to_arg_alignment (initial_offset_ptr, mod_boundary, boundary);
*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
&& (TREE_CODE (sizetree) != INTEGER_CST
|| ((TREE_INT_CST_LOW (sizetree) * 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)
struct args_size *offset_ptr;
int mod_boundary;
int boundary;
{
int boundary_in_bytes = boundary / BITS_PER_UNIT;
int mod_boundary_in_bytes = mod_boundary / BITS_PER_UNIT;
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;
}
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
}
}
#ifndef ARGS_GROW_DOWNWARD
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);
}
}
}
#endif
#ifdef ARGS_GROW_DOWNWARD
static tree
round_down (value, divisor)
tree value;
int divisor;
{
return size_binop (MULT_EXPR,
size_binop (FLOOR_DIV_EXPR, value, size_int (divisor)),
size_int (divisor));
}
#endif
void
uninitialized_vars_warning (block)
tree block;
{
register tree decl, sub;
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
{
if (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 (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 ()
{
register 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;
{
register 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 ()
{
register 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;
for (fp = outer_function_chain; fp; fp = fp->next)
if (fp->decl == context)
break;
if (fp == 0)
abort ();
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;
if (fp->arg_pointer_save_area == 0)
fp->arg_pointer_save_area
= assign_outer_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0, fp);
addr = fix_lexical_addr (XEXP (fp->arg_pointer_save_area, 0), var);
addr = memory_address (Pmode, addr);
base = copy_to_reg (gen_rtx_MEM (Pmode, addr));
#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
round_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
for (fp = outer_function_chain; fp; fp = fp->next)
for (link = fp->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 round_trampoline_addr (tramp);
}
fp = 0;
fn_context = decl_function_context (function);
if (fn_context != current_function_decl
&& fn_context != inline_function_decl)
for (fp = outer_function_chain; fp; fp = fp->next)
if (fp->decl == fn_context)
break;
#ifdef ALLOCATE_TRAMPOLINE
tramp = ALLOCATE_TRAMPOLINE (fp);
#else
#ifdef TRAMPOLINE_ALIGNMENT
#define TRAMPOLINE_REAL_SIZE \
(TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1)
#else
#define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE)
#endif
if (fp != 0)
tramp = assign_outer_stack_local (BLKmode, TRAMPOLINE_REAL_SIZE, 0, fp);
else
tramp = assign_stack_local (BLKmode, TRAMPOLINE_REAL_SIZE, 0);
#endif
if (fp != 0)
{
push_obstacks (fp->function_maybepermanent_obstack,
fp->function_maybepermanent_obstack);
rtlexp = make_node (RTL_EXPR);
RTL_EXPR_RTL (rtlexp) = tramp;
fp->trampoline_list = tree_cons (function, rtlexp, fp->trampoline_list);
pop_obstacks ();
}
else
{
int momentary = suspend_momentary ();
rtlexp = make_node (RTL_EXPR);
resume_momentary (momentary);
RTL_EXPR_RTL (rtlexp) = tramp;
trampoline_list = tree_cons (function, rtlexp, trampoline_list);
}
tramp = fix_lexical_addr (XEXP (tramp, 0), function);
return round_trampoline_addr (tramp);
}
static rtx
round_trampoline_addr (tramp)
rtx tramp;
{
#ifdef TRAMPOLINE_ALIGNMENT
rtx temp = gen_reg_rtx (Pmode);
temp = expand_binop (Pmode, add_optab, tramp,
GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1),
temp, 0, OPTAB_LIB_WIDEN);
tramp = expand_binop (Pmode, and_optab, temp,
GEN_INT (- TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT),
temp, 0, OPTAB_LIB_WIDEN);
#endif
return tramp;
}
tree *
identify_blocks (block, insns)
tree block;
rtx insns;
{
int n_blocks;
tree *block_vector;
int *block_stack;
int depth = 0;
int next_block_number = 1;
int current_block_number = 1;
rtx insn;
if (block == 0)
return 0;
n_blocks = all_blocks (block, 0);
block_vector = (tree *) xmalloc (n_blocks * sizeof (tree));
block_stack = (int *) alloca (n_blocks * sizeof (int));
all_blocks (block, block_vector);
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
block_stack[depth++] = current_block_number;
current_block_number = next_block_number;
NOTE_BLOCK_NUMBER (insn) = next_block_number++;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
{
NOTE_BLOCK_NUMBER (insn) = current_block_number;
current_block_number = block_stack[--depth];
}
}
if (n_blocks != next_block_number)
abort ();
return block_vector;
}
tree
reorder_blocks (block_vector, block, insns)
tree *block_vector;
tree block;
rtx insns;
{
tree current_block = block;
rtx insn;
if (block_vector == 0)
return block;
BLOCK_SUBBLOCKS (current_block) = 0;
BLOCK_CHAIN (current_block) = 0;
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
tree block = block_vector[NOTE_BLOCK_NUMBER (insn)];
if (TREE_ASM_WRITTEN (block))
block = copy_node (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;
NOTE_SOURCE_FILE (insn) = 0;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
{
BLOCK_SUBBLOCKS (current_block)
= blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
current_block = BLOCK_SUPERCONTEXT (current_block);
NOTE_SOURCE_FILE (insn) = 0;
}
}
BLOCK_SUBBLOCKS (current_block)
= blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
return current_block;
}
static tree
blocks_nreverse (t)
tree t;
{
register 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;
}
void
init_function_start (subr, filename, line)
tree subr;
char *filename;
int line;
{
init_stmt_for_function ();
cse_not_expected = ! optimize;
caller_save_needed = 0;
stack_slot_list = 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_const_rtx_hash_table ();
current_function_name = (*decl_printable_name) (subr, 2);
current_function_needs_context
= (decl_function_context (current_function_decl) != 0
&& ! DECL_NO_STATIC_CHAIN (current_function_decl));
current_function_calls_setjmp = 0;
current_function_calls_longjmp = 0;
current_function_calls_alloca = 0;
current_function_has_nonlocal_label = 0;
current_function_has_nonlocal_goto = 0;
current_function_contains_functions = 0;
current_function_is_leaf = 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 ();
immediate_size_expand++;
trampoline_list = 0;
init_pending_stack_adjust ();
inhibit_defer_pop = 0;
current_function_outgoing_args_size = 0;
if (line > 0)
emit_line_note (filename, line);
emit_note (NULL_PTR, 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)));
rtx_equal_function_value_matters = 1;
virtuals_instantiated = 0;
frame_pointer_needed = 0;
current_function_varargs = 0;
current_function_stdarg = 0;
}
void
mark_varargs ()
{
current_function_varargs = 1;
}
#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
#undef HAS_INIT_SECTION
#define HAS_INIT_SECTION
#endif
void
expand_main_function ()
{
#if !defined (HAS_INIT_SECTION)
#ifdef NEXT_EXTENSION
rtx _argv, _argc;
tree __main_type
= build_function_type (void_type,
tree_cons (0, int_type,
tree_cons (0, pointer_type, 0)));
#endif
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0,
VOIDmode, 0);
#endif
}
extern struct obstack permanent_obstack;
void
expand_function_start (subr, parms_have_cleanups)
tree subr;
int parms_have_cleanups;
{
register int i;
tree tem;
rtx last_ptr = NULL_RTX;
init_recog_no_volatile ();
current_function_check_memory_usage
= (flag_check_memory_usage
&& ! DECL_NO_CHECK_MEMORY_USAGE (current_function_decl));
current_function_instrument_entry_exit
= (flag_instrument_function_entry_exit
&& ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (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;
#ifdef HAVE_return
if (cleanup_label == 0 && HAVE_return
&& ! current_function_instrument_entry_exit
&& ! current_function_returns_pcc_struct
&& ! (current_function_returns_struct && ! optimize))
return_label = 0;
else
return_label = gen_label_rtx ();
#else
return_label = gen_label_rtx ();
#endif
if (aggregate_value_p (DECL_RESULT (subr)))
{
register 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)
{
DECL_RTL (DECL_RESULT (subr))
= gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
MEM_SET_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)),
AGGREGATE_TYPE_P (TREE_TYPE
(DECL_RESULT
(subr))));
}
}
else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
DECL_RTL (DECL_RESULT (subr)) = 0;
else if (parms_have_cleanups || current_function_instrument_entry_exit)
{
enum machine_mode mode = DECL_MODE (DECL_RESULT (subr));
#ifdef PROMOTE_FUNCTION_RETURN
tree type = TREE_TYPE (DECL_RESULT (subr));
int unsignedp = TREE_UNSIGNED (type);
mode = promote_mode (type, mode, &unsignedp, 1);
#endif
DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
}
else
{
#ifdef FUNCTION_OUTGOING_VALUE
DECL_RTL (DECL_RESULT (subr))
= FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (subr)), subr);
#else
DECL_RTL (DECL_RESULT (subr))
= FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (subr)), subr);
#endif
if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
{
REG_FUNCTION_VALUE_P (DECL_RTL (DECL_RESULT (subr))) = 1;
DECL_REGISTER (DECL_RESULT (subr)) = 1;
}
}
assign_parms (subr, 0);
#if defined (_WIN32) && defined (NEXT_PDO)
{
int length = 0;
char* tail = "";
char parm_size[255];
if( DECL_STDCALL(subr) )
{
char* newName = 0;
_ltoa( current_function_args_size, parm_size, 10 );
newName = (char*)malloc( strlen( IDENTIFIER_POINTER(DECL_NAME(subr)) )
+ strlen( parm_size ) + 7 );
sprintf( newName, "%s@%s", IDENTIFIER_POINTER(DECL_NAME(subr)), parm_size );
DECL_ASSEMBLER_NAME(subr) = get_identifier( newName );
XSTR( XEXP(DECL_RTL(subr), 0), 0 ) = IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(subr));
free( newName );
}
if( DECL_DLLIMPORT(subr) )
{
if( exportNamesForDLL )
length = strlen( exportNamesForDLL );
length += strlen( " -export:" );
length += strlen( IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(subr)) ) + 1; if( exportNamesForDLL )
{
exportNamesForDLL = (char*)realloc( (void*)exportNamesForDLL, length + 1 );
}
else
{
exportNamesForDLL = (char*)malloc( length + 1 );
*exportNamesForDLL = '\0';
}
sprintf( exportNamesForDLL, "%s%s%c%s%s", exportNamesForDLL,
" -export:", '_', IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(subr)), tail );
DECL_DLLIMPORT(subr) = 0;
}
}
#endif
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_PTR, NOTE_INSN_FUNCTION_BEG);
if (GET_CODE (get_last_insn ()) != NOTE)
emit_note (NULL_PTR, NOTE_INSN_DELETED);
parm_birth_insn = get_last_insn ();
if (obey_regdecls)
{
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; i++)
use_variable (regno_reg_rtx[i]);
if (current_function_internal_arg_pointer != virtual_incoming_args_rtx)
use_variable (current_function_internal_arg_pointer);
}
context_display = 0;
if (current_function_needs_context)
{
tem = decl_function_context (current_function_decl);
if (tem && ! obey_regdecls)
{
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, - GET_MODE_SIZE (Pmode));
#endif
last_ptr = copy_to_reg (gen_rtx_MEM (Pmode,
memory_address (Pmode, 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, 0, VOIDmode, 2,
fun, Pmode,
expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
0,
hard_frame_pointer_rtx),
Pmode);
}
tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
{
expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
EXPAND_MEMORY_USE_BAD);
emit_queue ();
}
force_next_line_note ();
}
void
expand_function_end (filename, line, end_bindings)
char *filename;
int line;
int end_bindings;
{
register int i;
tree link;
#ifdef TRAMPOLINE_TEMPLATE
static rtx initial_trampoline;
#endif
#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
if (arg_pointer_save_area)
{
rtx seq;
start_sequence ();
emit_move_insn (validize_mem (arg_pointer_save_area),
virtual_incoming_args_rtx);
seq = gen_sequence ();
end_sequence ();
emit_insn_before (seq, tail_recursion_reentry);
}
for (link = trampoline_list; link; link = TREE_CHAIN (link))
{
tree function = TREE_PURPOSE (link);
rtx context = 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)
{
end_temporary_allocation ();
initial_trampoline
= gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
resume_temporary_allocation ();
}
#endif
start_sequence ();
tramp = round_trampoline_addr (XEXP (tramp, 0));
#ifdef TRAMPOLINE_TEMPLATE
blktramp = change_address (initial_trampoline, BLKmode, tramp);
emit_block_move (blktramp, initial_trampoline,
GEN_INT (TRAMPOLINE_SIZE),
TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
#endif
INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
seq = get_insns ();
end_sequence ();
emit_insns_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_insns_before (seq, tail_recursion_reentry);
break;
}
}
if (warn_unused && extra_warnings)
#if defined (NEXT_SEMANTICS) || defined (NEXT_PDO)
if (warn_unused > 0 || strcmp (lang_identify (), "cplusplus"))
#endif
{
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--;
if (obey_regdecls)
{
rtx tem;
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; i++)
use_variable (regno_reg_rtx[i]);
for (tem = save_expr_regs; tem; tem = XEXP (tem, 1))
{
use_variable (XEXP (tem, 0));
use_variable_after (XEXP (tem, 0), parm_birth_insn);
}
if (current_function_internal_arg_pointer != virtual_incoming_args_rtx)
use_variable (current_function_internal_arg_pointer);
}
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
if (flag_test_coverage)
emit_note (NULL_PTR, NOTE_REPEATED_LINE_NUMBER);
emit_line_note_force (filename, line);
if (return_label)
emit_label (return_label);
if (end_bindings)
expand_end_bindings (0, 0, 0);
{
rtx last = get_last_insn ();
rtx label;
expand_leftover_cleanups ();
if (last != get_last_insn ())
{
label = gen_label_rtx ();
last = emit_jump_insn_after (gen_jump (label), last);
last = emit_barrier_after (last);
emit_label (label);
}
}
if (current_function_instrument_entry_exit)
{
rtx fun = DECL_RTL (current_function_decl);
if (GET_CODE (fun) == MEM)
fun = XEXP (fun, 0);
else
abort ();
emit_library_call (profile_function_exit_libfunc, 0, VOIDmode, 2,
fun, Pmode,
expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
0,
hard_frame_pointer_rtx),
Pmode);
}
#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 (DECL_RTL (DECL_RESULT (current_function_decl)) != 0
&& GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG
&& (REGNO (DECL_RTL (DECL_RESULT (current_function_decl)))
>= FIRST_PSEUDO_REGISTER))
{
rtx real_decl_result;
#ifdef FUNCTION_OUTGOING_VALUE
real_decl_result
= FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (current_function_decl)),
current_function_decl);
#else
real_decl_result
= FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (current_function_decl)),
current_function_decl);
#endif
REG_FUNCTION_VALUE_P (real_decl_result) = 1;
if (GET_MODE (real_decl_result) == BLKmode)
PUT_MODE (real_decl_result,
GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
emit_move_insn (real_decl_result,
DECL_RTL (DECL_RESULT (current_function_decl)));
emit_insn (gen_rtx_USE (VOIDmode, real_decl_result));
current_function_return_rtx = real_decl_result;
}
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;
emit_move_insn (outgoing, value_address);
use_variable (outgoing);
}
expand_eh_return ();
#ifdef HAVE_return
if (HAVE_return)
{
emit_jump_insn (gen_return ());
emit_barrier ();
}
#endif
expand_fixups (get_insns ());
}
static int *prologue;
static int *epilogue;
#if defined (HAVE_prologue) || defined (HAVE_epilogue)
static int *
record_insns (insns)
rtx insns;
{
int *vec;
if (GET_CODE (insns) == SEQUENCE)
{
int len = XVECLEN (insns, 0);
vec = (int *) oballoc ((len + 1) * sizeof (int));
vec[len] = 0;
while (--len >= 0)
vec[len] = INSN_UID (XVECEXP (insns, 0, len));
}
else
{
vec = (int *) oballoc (2 * sizeof (int));
vec[0] = INSN_UID (insns);
vec[1] = 0;
}
return vec;
}
static int
contains (insn, vec)
rtx insn;
int *vec;
{
register 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 = 0; vec[j]; j++)
if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) == vec[j])
count++;
return count;
}
else
{
for (j = 0; vec[j]; j++)
if (INSN_UID (insn) == vec[j])
return 1;
}
return 0;
}
#endif
void
thread_prologue_and_epilogue_insns (f)
rtx f ATTRIBUTE_UNUSED;
{
int insertted = 0;
prologue = 0;
#ifdef HAVE_prologue
if (HAVE_prologue)
{
rtx seq;
start_sequence ();
seq = gen_prologue();
emit_insn (seq);
if (GET_CODE (seq) != SEQUENCE)
seq = get_insns ();
prologue = record_insns (seq);
emit_note (NULL, NOTE_INSN_PROLOGUE_END);
seq = gen_sequence ();
end_sequence ();
if (ENTRY_BLOCK_PTR->succ)
{
if (ENTRY_BLOCK_PTR->succ->succ_next)
abort ();
insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
insertted = 1;
}
else
emit_insn_after (seq, f);
}
#endif
epilogue = 0;
#ifdef HAVE_epilogue
if (HAVE_epilogue)
{
edge e;
basic_block bb = 0;
rtx tail = get_last_insn ();
switch (optimize)
{
default:
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
if ((e->flags & EDGE_FAKE) == 0
&& (e->flags & EDGE_FALLTHRU) != 0)
break;
if (e == NULL)
break;
bb = e->src;
tail = bb->end;
if (GET_CODE (tail) == JUMP_INSN)
bb = 0;
case 0:
{
rtx prev, seq, first_use;
prev = tail;
if (GET_CODE (prev) == BARRIER
|| GET_CODE (prev) == NOTE)
prev = prev_nonnote_insn (prev);
first_use = 0;
if (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE)
{
if (prev == tail)
{
do
tail = PREV_INSN (tail);
while (GET_CODE (tail) == INSN
&& GET_CODE (PATTERN (tail)) == USE);
}
do
{
rtx use = prev;
prev = prev_nonnote_insn (prev);
remove_insn (use);
if (first_use)
{
NEXT_INSN (use) = first_use;
PREV_INSN (first_use) = use;
}
else
NEXT_INSN (use) = NULL_RTX;
first_use = use;
}
while (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE);
}
if (GET_CODE (tail) != BARRIER)
{
prev = next_nonnote_insn (tail);
if (!prev || GET_CODE (prev) != BARRIER)
emit_barrier_after (tail);
}
seq = gen_epilogue ();
prev = tail;
tail = emit_jump_insn_after (seq, tail);
if (first_use)
emit_insns_before (first_use, tail);
emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
if (bb)
bb->end = tail;
epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
}
}
}
#endif
if (insertted)
commit_edge_insertions ();
}
void
reposition_prologue_and_epilogue_notes (f)
rtx f ATTRIBUTE_UNUSED;
{
#if defined (HAVE_prologue) || defined (HAVE_epilogue)
if (n_basic_blocks)
{
int len;
if (prologue)
{
register rtx insn, note = 0;
for (len = 0; prologue[len]; len++)
;
for (insn = f; len && insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
note = insn;
}
else if ((len -= contains (insn, prologue)) == 0)
{
rtx next;
if (note == 0)
{
for (note = insn; (note = NEXT_INSN (note));)
if (GET_CODE (note) == NOTE
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
break;
}
next = NEXT_INSN (note);
if (BLOCK_HEAD (0) == note)
BLOCK_HEAD (0) = next;
remove_insn (note);
add_insn_after (note, insn);
}
}
}
if (epilogue)
{
register rtx insn, note = 0;
for (len = 0; epilogue[len]; len++)
;
for (insn = get_last_insn (); len && insn; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
note = insn;
}
else if ((len -= contains (insn, epilogue)) == 0)
{
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 (n_basic_blocks
&& BLOCK_HEAD (n_basic_blocks-1) == insn)
BLOCK_HEAD (n_basic_blocks-1) = note;
remove_insn (note);
add_insn_before (note, insn);
}
}
}
}
#endif
}