#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "regs.h"
#include "flags.h"
#include "debug.h"
#include "insn-config.h"
#include "expr.h"
#include "output.h"
#include "recog.h"
#include "integrate.h"
#include "real.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
#include "intl.h"
#include "loop.h"
#include "params.h"
#include "ggc.h"
#include "target.h"
#include "langhooks.h"
#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
#ifndef INTEGRATE_THRESHOLD
#define INTEGRATE_THRESHOLD(DECL) \
(optimize_size \
? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \
: (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
#endif
typedef struct initial_value_pair GTY(()) {
rtx hard_reg;
rtx pseudo;
} initial_value_pair;
typedef struct initial_value_struct GTY(()) {
int num_entries;
int max_entries;
initial_value_pair * GTY ((length ("%h.num_entries"))) entries;
} initial_value_struct;
static void setup_initial_hard_reg_value_integration PARAMS ((struct function *, struct inline_remap *));
static rtvec initialize_for_inline PARAMS ((tree));
static void note_modified_parmregs PARAMS ((rtx, rtx, void *));
static void integrate_parm_decls PARAMS ((tree, struct inline_remap *,
rtvec));
static tree integrate_decl_tree PARAMS ((tree,
struct inline_remap *));
static void subst_constants PARAMS ((rtx *, rtx,
struct inline_remap *, int));
static void set_block_origin_self PARAMS ((tree));
static void set_block_abstract_flags PARAMS ((tree, int));
static void process_reg_param PARAMS ((struct inline_remap *, rtx,
rtx));
void set_decl_abstract_flags PARAMS ((tree, int));
static void mark_stores PARAMS ((rtx, rtx, void *));
static void save_parm_insns PARAMS ((rtx, rtx));
static void copy_insn_list PARAMS ((rtx, struct inline_remap *,
rtx));
static void copy_insn_notes PARAMS ((rtx, struct inline_remap *,
int));
static int compare_blocks PARAMS ((const PTR, const PTR));
static int find_block PARAMS ((const PTR, const PTR));
static struct function *inlining = 0;
rtx
get_label_from_map (map, i)
struct inline_remap *map;
int i;
{
rtx x = map->label_map[i];
if (x == NULL_RTX)
x = map->label_map[i] = gen_label_rtx ();
return x;
}
bool
function_attribute_inlinable_p (fndecl)
tree fndecl;
{
if (targetm.attribute_table)
{
tree a;
for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a);
int i;
for (i = 0; targetm.attribute_table[i].name != NULL; i++)
if (is_attribute_p (targetm.attribute_table[i].name, name))
return (*targetm.function_attribute_inlinable_p) (fndecl);
}
}
return true;
}
const char *
function_cannot_inline_p (fndecl)
tree fndecl;
{
rtx insn;
tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
int max_insns = (DECL_INLINE (fndecl))
? (MAX_INLINE_INSNS_RTL
+ 8 * list_length (DECL_ARGUMENTS (fndecl)))
: INTEGRATE_THRESHOLD (fndecl);
int ninsns = 0;
tree parms;
if (DECL_UNINLINABLE (fndecl))
return N_("function cannot be inline");
if (last && TREE_VALUE (last) != void_type_node)
return N_("varargs function cannot be inline");
if (current_function_calls_alloca)
return N_("function using alloca cannot be inline");
if (current_function_calls_setjmp)
return N_("function using setjmp cannot be inline");
if (current_function_calls_eh_return)
return N_("function uses __builtin_eh_return");
if (current_function_contains_functions)
return N_("function with nested functions cannot be inline");
if (forced_labels)
return
N_("function with label addresses used in initializers cannot inline");
if (current_function_cannot_inline)
return current_function_cannot_inline;
if (get_max_uid () > 3 * max_insns)
return N_("function too large to be inline");
#if 0
for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
{
if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)
TREE_ADDRESSABLE (parms) = 1;
if (last == NULL_TREE && TREE_ADDRESSABLE (parms))
return N_("no prototype, and parameter address used; cannot be inline");
}
#endif
if (current_function_returns_pcc_struct)
return N_("inline functions not supported for this return value type");
if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE
&& int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
return N_("function with varying-size return value cannot be inline");
for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
{
if (int_size_in_bytes (TREE_TYPE (parms)) < 0)
return N_("function with varying-size parameter cannot be inline");
else if (TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE
&& TYPE_TRANSPARENT_UNION (TREE_TYPE (parms)))
return N_("function with transparent unit parameter cannot be inline");
}
if (get_max_uid () > max_insns)
{
for (ninsns = 0, insn = get_first_nonparm_insn ();
insn && ninsns < max_insns;
insn = NEXT_INSN (insn))
if (INSN_P (insn))
ninsns++;
if (ninsns >= max_insns)
return N_("function too large to be inline");
}
if (current_function_has_computed_jump)
return N_("function with computed jump cannot inline");
if (current_function_has_nonlocal_goto)
return N_("function with nonlocal goto cannot be inline");
if (DECL_RTL_SET_P (DECL_RESULT (fndecl)))
{
rtx result = DECL_RTL (DECL_RESULT (fndecl));
if (GET_CODE (result) == PARALLEL)
return N_("inline functions not supported for this return value type");
}
if (!function_attribute_inlinable_p (fndecl))
return N_("function with target specific attribute(s) cannot be inlined");
return NULL;
}
static tree *parmdecl_map;
static int in_nonparm_insns;
static rtvec
initialize_for_inline (fndecl)
tree fndecl;
{
int i;
rtvec arg_vector;
tree parms;
memset ((char *) parmdecl_map, 0, max_parm_reg * sizeof (tree));
arg_vector = rtvec_alloc (list_length (DECL_ARGUMENTS (fndecl)));
for (parms = DECL_ARGUMENTS (fndecl), i = 0;
parms;
parms = TREE_CHAIN (parms), i++)
{
rtx p = DECL_RTL (parms);
if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF
&& GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM)
p = XEXP (XEXP (p, 0), 0);
RTVEC_ELT (arg_vector, i) = p;
if (GET_CODE (p) == REG)
parmdecl_map[REGNO (p)] = parms;
else if (GET_CODE (p) == CONCAT)
{
rtx preal = gen_realpart (GET_MODE (XEXP (p, 0)), p);
rtx pimag = gen_imagpart (GET_MODE (preal), p);
if (GET_CODE (preal) == REG)
parmdecl_map[REGNO (preal)] = parms;
if (GET_CODE (pimag) == REG)
parmdecl_map[REGNO (pimag)] = parms;
}
TREE_READONLY (parms) = 1;
}
return arg_vector;
}
tree
copy_decl_for_inlining (decl, from_fn, to_fn)
tree decl;
tree from_fn;
tree to_fn;
{
tree copy;
if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL)
{
tree type;
int invisiref = 0;
if (TREE_CODE (decl) == PARM_DECL
&& DECL_ARG_TYPE (decl) != TREE_TYPE (decl)
&& POINTER_TYPE_P (DECL_ARG_TYPE (decl))
&& TREE_TYPE (DECL_ARG_TYPE (decl)) == TREE_TYPE (decl))
{
invisiref = 1;
type = DECL_ARG_TYPE (decl);
}
else
type = TREE_TYPE (decl);
copy = build_decl (VAR_DECL, DECL_NAME (decl), type);
if (!invisiref)
{
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
TREE_READONLY (copy) = TREE_READONLY (decl);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
}
else
{
TREE_ADDRESSABLE (copy) = 0;
TREE_READONLY (copy) = 1;
TREE_THIS_VOLATILE (copy) = 0;
}
}
else
{
copy = copy_node (decl);
(*lang_hooks.dup_lang_specific_decl) (copy);
if (TREE_CODE (copy) == LABEL_DECL)
TREE_ADDRESSABLE (copy) = 0;
}
DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl);
SET_DECL_RTL (copy, NULL_RTX);
TREE_USED (copy) = 1;
if (!DECL_CONTEXT (decl))
;
else if (DECL_CONTEXT (decl) != from_fn)
;
else if (TREE_STATIC (decl))
;
else
DECL_CONTEXT (copy) = to_fn;
return copy;
}
void
save_for_inline (fndecl)
tree fndecl;
{
rtx insn;
rtvec argvec;
rtx first_nonparm_insn;
if (! flag_no_inline)
parmdecl_map = (tree *) xmalloc (max_parm_reg * sizeof (tree));
if (return_label == 0)
{
return_label = gen_label_rtx ();
emit_label (return_label);
}
if (! flag_no_inline)
argvec = initialize_for_inline (fndecl);
else
argvec = NULL;
for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK)
delete_related_insns (insn);
insn = get_insns ();
if (GET_CODE (insn) != NOTE)
abort ();
if (! flag_no_inline)
{
first_nonparm_insn = get_first_nonparm_insn ();
in_nonparm_insns = 0;
save_parm_insns (insn, first_nonparm_insn);
cfun->inl_max_label_num = max_label_num ();
cfun->inl_last_parm_insn = cfun->x_last_parm_insn;
cfun->original_arg_vector = argvec;
}
cfun->original_decl_initial = DECL_INITIAL (fndecl);
cfun->no_debugging_symbols = (write_symbols == NO_DEBUG);
DECL_SAVED_INSNS (fndecl) = cfun;
if (! flag_no_inline)
free (parmdecl_map);
}
static void
save_parm_insns (insn, first_nonparm_insn)
rtx insn;
rtx first_nonparm_insn;
{
if (insn == NULL_RTX)
return;
for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
{
if (insn == first_nonparm_insn)
in_nonparm_insns = 1;
if (INSN_P (insn))
{
note_stores (PATTERN (insn), note_modified_parmregs, NULL);
if (GET_CODE (insn) == CALL_INSN
&& GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
{
int i;
for (i = 0; i < 3; i++)
save_parm_insns (XEXP (PATTERN (insn), i),
first_nonparm_insn);
}
}
}
}
static void
note_modified_parmregs (reg, x, data)
rtx reg;
rtx x ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
if (GET_CODE (reg) == REG && in_nonparm_insns
&& REGNO (reg) < max_parm_reg
&& REGNO (reg) >= FIRST_PSEUDO_REGISTER
&& parmdecl_map[REGNO (reg)] != 0)
TREE_READONLY (parmdecl_map[REGNO (reg)]) = 0;
}
varray_type global_const_equiv_varray;
#define FIXED_BASE_PLUS_P(X) \
(GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& GET_CODE (XEXP (X, 0)) == REG \
&& REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER \
&& REGNO (XEXP (X, 0)) <= LAST_VIRTUAL_REGISTER)
static void
process_reg_param (map, loc, copy)
struct inline_remap *map;
rtx loc, copy;
{
if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
|| (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
&& ! REG_USERVAR_P (copy))
|| (GET_CODE (copy) == REG
&& REGNO (copy) < FIRST_PSEUDO_REGISTER))
{
rtx temp = copy_to_mode_reg (GET_MODE (loc), copy);
REG_USERVAR_P (temp) = REG_USERVAR_P (loc);
if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy))
SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM);
copy = temp;
}
map->reg_map[REGNO (loc)] = copy;
}
static int
compare_blocks (v1, v2)
const PTR v1;
const PTR v2;
{
tree b1 = *((const tree *) v1);
tree b2 = *((const tree *) v2);
char *p1 = (char *) BLOCK_ABSTRACT_ORIGIN (b1);
char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2);
if (p1 == p2)
return 0;
return p1 < p2 ? -1 : 1;
}
static int
find_block (v1, v2)
const PTR v1;
const PTR v2;
{
const union tree_node *b1 = (const union tree_node *) v1;
tree b2 = *((const tree *) v2);
char *p1 = (char *) b1;
char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2);
if (p1 == p2)
return 0;
return p1 < p2 ? -1 : 1;
}
rtx
expand_inline_function (fndecl, parms, target, ignore, type,
structure_value_addr)
tree fndecl, parms;
rtx target;
int ignore;
tree type;
rtx structure_value_addr;
{
struct function *inlining_previous;
struct function *inl_f = DECL_SAVED_INSNS (fndecl);
tree formal, actual, block;
rtx parm_insns = inl_f->emit->x_first_insn;
rtx insns = (inl_f->inl_last_parm_insn
? NEXT_INSN (inl_f->inl_last_parm_insn)
: parm_insns);
tree *arg_trees;
rtx *arg_vals;
int max_regno;
int i;
int min_labelno = inl_f->emit->x_first_label_num;
int max_labelno = inl_f->inl_max_label_num;
int nargs;
rtx loc;
rtx stack_save = 0;
rtx temp;
struct inline_remap *map = 0;
rtvec arg_vector = inl_f->original_arg_vector;
rtx static_chain_value = 0;
int inl_max_uid;
int eh_region_offset;
rtx *real_label_map = 0;
max_regno = inl_f->emit->x_reg_rtx_no + 3;
if (max_regno < FIRST_PSEUDO_REGISTER)
abort ();
fndecl = inl_f->decl;
nargs = list_length (DECL_ARGUMENTS (fndecl));
if (cfun->preferred_stack_boundary < inl_f->preferred_stack_boundary)
cfun->preferred_stack_boundary = inl_f->preferred_stack_boundary;
for (formal = DECL_ARGUMENTS (fndecl), actual = parms;
formal;
formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual))
{
tree arg;
enum machine_mode mode;
if (actual == 0)
return (rtx) (size_t) -1;
arg = TREE_VALUE (actual);
mode = TYPE_MODE (DECL_ARG_TYPE (formal));
if (arg == error_mark_node
|| mode != TYPE_MODE (TREE_TYPE (arg))
|| (mode == BLKmode
&& (TYPE_MAIN_VARIANT (TREE_TYPE (arg))
!= TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))
return (rtx) (size_t) -1;
}
for (; actual; actual = TREE_CHAIN (actual))
expand_expr (TREE_VALUE (actual), const0_rtx,
TYPE_MODE (TREE_TYPE (TREE_VALUE (actual))), 0);
arg_vals = (rtx *) xmalloc (nargs * sizeof (rtx));
arg_trees = (tree *) xmalloc (nargs * sizeof (tree));
for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0;
formal;
formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++)
{
tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual));
enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal));
int invisiref = 0;
arg_trees[i] = arg;
loc = RTVEC_ELT (arg_vector, i);
if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG
&& REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
{
rtx stack_slot = assign_temp (TREE_TYPE (arg), 1, 1, 1);
store_expr (arg, stack_slot, 0);
arg_vals[i] = XEXP (stack_slot, 0);
invisiref = 1;
}
else if (GET_CODE (loc) != MEM)
{
if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))
{
int unsignedp = TREE_UNSIGNED (TREE_TYPE (formal));
enum machine_mode pmode = TYPE_MODE (TREE_TYPE (formal));
pmode = promote_mode (TREE_TYPE (formal), pmode,
&unsignedp, 0);
if (GET_MODE (loc) != pmode)
abort ();
arg_vals[i] = convert_modes (pmode,
TYPE_MODE (TREE_TYPE (arg)),
expand_expr (arg, NULL_RTX, mode,
EXPAND_SUM),
unsignedp);
}
else
arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
}
else
arg_vals[i] = 0;
if (arg_vals[i] != 0
&& (! TREE_READONLY (formal)
|| (target != 0
&& ! invisiref
&& (GET_CODE (arg_vals[i]) == REG
|| GET_CODE (arg_vals[i]) == SUBREG
|| GET_CODE (arg_vals[i]) == MEM)
&& reg_overlap_mentioned_p (arg_vals[i], target))
|| (GET_CODE (arg_vals[i]) == SUBREG)))
arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]);
if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG
&& POINTER_TYPE_P (TREE_TYPE (formal)))
mark_reg_pointer (arg_vals[i],
TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal))));
}
map = (struct inline_remap *) xcalloc (1, sizeof (struct inline_remap));
map->fndecl = fndecl;
VARRAY_TREE_INIT (map->block_map, 10, "block_map");
map->reg_map = (rtx *) xcalloc (max_regno, sizeof (rtx));
real_label_map
= (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
map->label_map = real_label_map;
map->local_return_label = NULL_RTX;
inl_max_uid = (inl_f->emit->x_cur_insn_uid + 1);
map->insn_map = (rtx *) xcalloc (inl_max_uid, sizeof (rtx));
map->min_insnno = 0;
map->max_insnno = inl_max_uid;
map->integrating = 1;
map->compare_src = NULL_RTX;
map->compare_mode = VOIDmode;
VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray,
(max_reg_num ()
+ (max_regno - FIRST_PSEUDO_REGISTER)
+ 15 * nargs
+ 10),
"expand_inline_function");
map->const_age = 0;
map->insns_at_start = get_last_insn ();
if (map->insns_at_start == 0)
map->insns_at_start = emit_note (NULL, NOTE_INSN_DELETED);
map->regno_pointer_align = inl_f->emit->regno_pointer_align;
map->x_regno_reg_rtx = inl_f->emit->x_regno_reg_rtx;
if (inl_f->outgoing_args_size > current_function_outgoing_args_size)
current_function_outgoing_args_size = inl_f->outgoing_args_size;
if (inl_f->uses_pic_offset_table)
current_function_uses_pic_offset_table = 1;
if (inl_f->needs_context)
static_chain_value = lookup_static_chain (fndecl);
if (GET_CODE (parm_insns) == NOTE
&& NOTE_LINE_NUMBER (parm_insns) > 0)
{
rtx note = emit_note (NOTE_SOURCE_FILE (parm_insns),
NOTE_LINE_NUMBER (parm_insns));
if (note)
RTX_INTEGRATED_P (note) = 1;
}
for (i = 0; i < nargs; i++)
{
rtx copy = arg_vals[i];
loc = RTVEC_ELT (arg_vector, i);
if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG
&& REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
{
if (GET_CODE (copy) != REG)
{
temp = copy_addr_to_reg (copy);
if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy))
SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM);
copy = temp;
}
map->reg_map[REGNO (XEXP (loc, 0))] = copy;
}
else if (GET_CODE (loc) == MEM)
{
if (DECL_SAVED_INSNS (fndecl)->args_size != 0)
copy_rtx_and_substitute (virtual_incoming_args_rtx, map, 0);
}
else if (GET_CODE (loc) == REG)
process_reg_param (map, loc, copy);
else if (GET_CODE (loc) == CONCAT)
{
rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);
rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);
rtx copyreal = gen_realpart (GET_MODE (locreal), copy);
rtx copyimag = gen_imagpart (GET_MODE (locimag), copy);
process_reg_param (map, locreal, copyreal);
process_reg_param (map, locimag, copyimag);
}
else
abort ();
}
inlining_previous = inlining;
inlining = inl_f;
for (formal = DECL_ARGUMENTS (fndecl), i = 0;
formal; formal = TREE_CHAIN (formal), i++)
{
loc = RTVEC_ELT (arg_vector, i);
if (GET_CODE (loc) == MEM
&& ! (GET_CODE (XEXP (loc, 0)) == REG
&& REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER))
{
rtx note = emit_note (DECL_SOURCE_FILE (formal),
DECL_SOURCE_LINE (formal));
if (note)
RTX_INTEGRATED_P (note) = 1;
temp = copy_rtx_and_substitute (loc, map, 1);
subst_constants (&temp, NULL_RTX, map, 1);
apply_change_group ();
if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
temp = change_address (temp, VOIDmode, XEXP (temp, 0));
store_expr (arg_trees[i], temp, 0);
}
}
map->inline_target = 0;
loc = (DECL_RTL_SET_P (DECL_RESULT (fndecl))
? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
if (TYPE_MODE (type) == VOIDmode)
;
else if (GET_CODE (loc) == MEM)
{
if (GET_CODE (XEXP (loc, 0)) == ADDRESSOF)
{
temp = copy_rtx_and_substitute (loc, map, 1);
subst_constants (&temp, NULL_RTX, map, 1);
apply_change_group ();
target = temp;
}
else
{
if (! structure_value_addr
|| ! aggregate_value_p (DECL_RESULT (fndecl)))
abort ();
if (GET_CODE (XEXP (loc, 0)) == REG)
{
temp = force_operand (structure_value_addr, NULL_RTX);
temp = force_reg (Pmode, temp);
if (REGNO (temp) >= FIRST_VIRTUAL_REGISTER
&& REGNO (temp) <= LAST_VIRTUAL_REGISTER)
temp = copy_to_mode_reg (Pmode, temp);
map->reg_map[REGNO (XEXP (loc, 0))] = temp;
if (CONSTANT_P (structure_value_addr)
|| GET_CODE (structure_value_addr) == ADDRESSOF
|| (GET_CODE (structure_value_addr) == PLUS
&& (XEXP (structure_value_addr, 0)
== virtual_stack_vars_rtx)
&& (GET_CODE (XEXP (structure_value_addr, 1))
== CONST_INT)))
{
SET_CONST_EQUIV_DATA (map, temp, structure_value_addr,
CONST_AGE_PARM);
}
}
else
{
temp = copy_rtx_and_substitute (loc, map, 1);
subst_constants (&temp, NULL_RTX, map, 0);
apply_change_group ();
emit_move_insn (temp, structure_value_addr);
}
}
}
else if (ignore)
;
else if (GET_CODE (loc) == REG)
{
enum machine_mode departing_mode = TYPE_MODE (type);
enum machine_mode arriving_mode
= GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
rtx reg_to_map;
if (target == 0 || GET_CODE (target) != REG
|| GET_MODE (target) != departing_mode)
{
if (departing_mode == BLKmode)
{
if (REG == GET_CODE (DECL_RTL (DECL_RESULT (fndecl))))
{
departing_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
arriving_mode = departing_mode;
}
else
abort ();
}
target = gen_reg_rtx (departing_mode);
}
if (arriving_mode != departing_mode)
{
if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD)
{
if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode),
GET_MODE_BITSIZE (arriving_mode)))
abort ();
reg_to_map = gen_reg_rtx (arriving_mode);
target = gen_lowpart (departing_mode, reg_to_map);
}
else
reg_to_map = gen_rtx_SUBREG (arriving_mode, target, 0);
}
else
reg_to_map = target;
if (REG_FUNCTION_VALUE_P (loc))
map->inline_target = reg_to_map;
else
map->reg_map[REGNO (loc)] = reg_to_map;
}
else if (GET_CODE (loc) == CONCAT)
{
enum machine_mode departing_mode = TYPE_MODE (type);
enum machine_mode arriving_mode
= GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
if (departing_mode != arriving_mode)
abort ();
if (GET_CODE (XEXP (loc, 0)) != REG
|| GET_CODE (XEXP (loc, 1)) != REG)
abort ();
if (target == 0 || GET_CODE (target) != REG
|| GET_MODE (target) != departing_mode)
target = gen_reg_rtx (departing_mode);
if (GET_CODE (target) != CONCAT)
abort ();
map->reg_map[REGNO (XEXP (loc, 0))] = XEXP (target, 0);
map->reg_map[REGNO (XEXP (loc, 1))] = XEXP (target, 1);
}
else
abort ();
temp = get_exception_pointer (inl_f);
if (temp)
map->reg_map[REGNO (temp)] = get_exception_pointer (cfun);
memset ((char *) &map->label_map[min_labelno], 0,
(max_labelno - min_labelno) * sizeof (rtx));
inline_function_decl = fndecl;
integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector);
block = integrate_decl_tree (inl_f->original_decl_initial, map);
BLOCK_ABSTRACT_ORIGIN (block) = DECL_ORIGIN (fndecl);
inline_function_decl = 0;
expand_start_bindings_and_block (0, block);
qsort (&VARRAY_TREE (map->block_map, 0),
map->block_map->elements_used,
sizeof (tree),
compare_blocks);
emit_queue ();
do_pending_stack_adjust ();
global_const_equiv_varray = map->const_equiv_varray;
if (inl_f->calls_alloca)
emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);
setup_initial_hard_reg_value_integration (inl_f, map);
copy_insn_list (insns, map, static_chain_value);
eh_region_offset = duplicate_eh_regions (inl_f, map);
copy_insn_notes (insns, map, eh_region_offset);
if (map->local_return_label)
emit_label (map->local_return_label);
if (inl_f->calls_alloca)
emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
if (! cfun->x_whole_function_mode_p)
(*lang_hooks.decls.insert_block) (block);
else
{
BLOCK_CHAIN (block)
= BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block;
}
expand_end_bindings (NULL_TREE, 1, 1);
if (flag_test_coverage)
emit_note (0, NOTE_INSN_REPEATED_LINE_NUMBER);
emit_line_note (input_filename, lineno);
if (target
&& TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
&& ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
if (structure_value_addr)
{
target = gen_rtx_MEM (TYPE_MODE (type),
memory_address (TYPE_MODE (type),
structure_value_addr));
set_mem_attributes (target, type, 1);
}
if (real_label_map)
free (real_label_map);
VARRAY_FREE (map->const_equiv_varray);
free (map->reg_map);
free (map->insn_map);
free (map);
free (arg_vals);
free (arg_trees);
inlining = inlining_previous;
return target;
}
static void
copy_insn_list (insns, map, static_chain_value)
rtx insns;
struct inline_remap *map;
rtx static_chain_value;
{
int i;
rtx insn;
rtx temp;
#ifdef HAVE_cc0
rtx cc0_insn = 0;
#endif
rtx static_chain_mem = 0;
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
rtx copy, pattern, set;
map->orig_asm_operands_vector = 0;
switch (GET_CODE (insn))
{
case INSN:
pattern = PATTERN (insn);
set = single_set (insn);
copy = 0;
if (GET_CODE (pattern) == USE
&& GET_CODE (XEXP (pattern, 0)) == REG
&& REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
break;
if (map->inline_target == 0
&& set != 0
&& GET_CODE (SET_DEST (set)) == REG
&& REG_FUNCTION_VALUE_P (SET_DEST (set)))
{
if (volatile_refs_p (SET_SRC (set)))
{
rtx new_set;
copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
new_set = single_set (copy);
if (new_set == 0)
abort ();
SET_DEST (new_set)
= gen_reg_rtx (GET_MODE (SET_DEST (new_set)));
}
else if (rtx_equal_p (SET_DEST (set), SET_SRC (set))
&& REG_NOTES (insn) != 0)
copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
else
break;
}
else if (map->inline_target == 0
&& GET_CODE (pattern) == CLOBBER
&& GET_CODE (XEXP (pattern, 0)) == REG
&& REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
break;
else if (static_chain_value != 0
&& set != 0
&& GET_CODE (static_chain_incoming_rtx) == MEM
&& GET_CODE (SET_DEST (set)) == REG
&& rtx_equal_p (SET_SRC (set),
XEXP (static_chain_incoming_rtx, 0)))
{
static_chain_mem =
gen_rtx_MEM (GET_MODE (static_chain_incoming_rtx),
SET_DEST (set));
copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
}
else if (static_chain_value != 0
&& set != 0
&& (rtx_equal_p (SET_DEST (set),
static_chain_incoming_rtx)
|| (static_chain_mem
&& rtx_equal_p (SET_DEST (set), static_chain_mem))))
break;
else if (static_chain_value != 0
&& set != 0
&& (rtx_equal_p (SET_SRC (set),
static_chain_incoming_rtx)
|| (static_chain_mem
&& rtx_equal_p (SET_SRC (set), static_chain_mem))))
{
rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map, 1);
copy = emit_move_insn (newdest, static_chain_value);
if (GET_CODE (static_chain_incoming_rtx) != MEM)
static_chain_value = 0;
}
else if (set != 0
&& rtx_equal_p (SET_DEST (set), virtual_stack_vars_rtx))
{
HOST_WIDE_INT offset;
temp = map->reg_map[REGNO (SET_DEST (set))];
temp = VARRAY_CONST_EQUIV (map->const_equiv_varray,
REGNO (temp)).rtx;
if (rtx_equal_p (temp, virtual_stack_vars_rtx))
offset = 0;
else if (GET_CODE (temp) == PLUS
&& rtx_equal_p (XEXP (temp, 0), virtual_stack_vars_rtx)
&& GET_CODE (XEXP (temp, 1)) == CONST_INT)
offset = INTVAL (XEXP (temp, 1));
else
abort ();
if (rtx_equal_p (SET_SRC (set), stack_pointer_rtx))
temp = SET_SRC (set);
else
temp = force_operand (plus_constant (SET_SRC (set),
- offset),
NULL_RTX);
copy = emit_move_insn (virtual_stack_vars_rtx, temp);
}
else
copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
#ifdef HAVE_cc0
if (sets_cc0_p (PATTERN (copy)) != 0)
cc0_insn = copy;
else
{
if (cc0_insn)
try_constants (cc0_insn, map);
cc0_insn = 0;
try_constants (copy, map);
}
#else
try_constants (copy, map);
#endif
INSN_SCOPE (copy) = INSN_SCOPE (insn);
break;
case JUMP_INSN:
if (map->integrating && returnjump_p (insn))
{
if (map->local_return_label == 0)
map->local_return_label = gen_label_rtx ();
pattern = gen_jump (map->local_return_label);
}
else
pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
copy = emit_jump_insn (pattern);
#ifdef HAVE_cc0
if (cc0_insn)
try_constants (cc0_insn, map);
cc0_insn = 0;
#endif
try_constants (copy, map);
INSN_SCOPE (copy) = INSN_SCOPE (insn);
if (any_condjump_p (insn) && onlyjump_p (insn) && map->last_pc_value)
{
#ifdef HAVE_cc0
if (only_sets_cc0_p (PREV_INSN (copy)))
delete_related_insns (PREV_INSN (copy));
#endif
if (map->last_pc_value == pc_rtx)
{
delete_related_insns (copy);
copy = 0;
}
else
emit_barrier ();
}
break;
case CALL_INSN:
if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
{
rtx sequence[3];
rtx tail_label;
for (i = 0; i < 3; i++)
{
rtx seq;
sequence[i] = NULL_RTX;
seq = XEXP (PATTERN (insn), i);
if (seq)
{
start_sequence ();
copy_insn_list (seq, map, static_chain_value);
sequence[i] = get_insns ();
end_sequence ();
}
}
tail_label = copy_rtx_and_substitute (XEXP (PATTERN (insn), 3),
map, 0);
copy = emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode,
sequence[0],
sequence[1],
sequence[2],
tail_label));
break;
}
pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
copy = emit_call_insn (pattern);
SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn);
CONST_OR_PURE_CALL_P (copy) = CONST_OR_PURE_CALL_P (insn);
INSN_SCOPE (copy) = INSN_SCOPE (insn);
CALL_INSN_FUNCTION_USAGE (copy)
= copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn),
map, 0);
#ifdef HAVE_cc0
if (cc0_insn)
try_constants (cc0_insn, map);
cc0_insn = 0;
#endif
try_constants (copy, map);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
VARRAY_CONST_EQUIV (map->const_equiv_varray, i).rtx = 0;
break;
case CODE_LABEL:
copy = emit_label (get_label_from_map (map,
CODE_LABEL_NUMBER (insn)));
LABEL_NAME (copy) = LABEL_NAME (insn);
map->const_age++;
break;
case BARRIER:
copy = emit_barrier ();
break;
case NOTE:
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)
{
copy = emit_label (get_label_from_map (map,
CODE_LABEL_NUMBER (insn)));
LABEL_NAME (copy) = NOTE_SOURCE_FILE (insn);
map->const_age++;
break;
}
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
{
copy = emit_note (NOTE_SOURCE_FILE (insn),
NOTE_LINE_NUMBER (insn));
if (copy
&& (NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_END)
&& NOTE_BLOCK (insn))
{
tree *mapped_block_p;
mapped_block_p
= (tree *) bsearch (NOTE_BLOCK (insn),
&VARRAY_TREE (map->block_map, 0),
map->block_map->elements_used,
sizeof (tree),
find_block);
if (!mapped_block_p)
abort ();
else
NOTE_BLOCK (copy) = *mapped_block_p;
}
else if (copy
&& NOTE_LINE_NUMBER (copy) == NOTE_INSN_EXPECTED_VALUE)
NOTE_EXPECTED_VALUE (copy)
= copy_rtx_and_substitute (NOTE_EXPECTED_VALUE (insn),
map, 0);
}
else
copy = 0;
break;
default:
abort ();
}
if (copy)
RTX_INTEGRATED_P (copy) = 1;
map->insn_map[INSN_UID (insn)] = copy;
}
}
static void
copy_insn_notes (insns, map, eh_region_offset)
rtx insns;
struct inline_remap *map;
int eh_region_offset;
{
rtx insn, new_insn;
map->const_age++;
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
if (! INSN_P (insn))
continue;
new_insn = map->insn_map[INSN_UID (insn)];
if (! new_insn)
continue;
if (REG_NOTES (insn))
{
rtx next, note = copy_rtx_and_substitute (REG_NOTES (insn), map, 0);
subst_constants (¬e, NULL_RTX, map, 0);
apply_change_group ();
REG_NOTES (new_insn) = note;
for (; note; note = next)
{
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) == REG_LABEL)
remove_note (new_insn, note);
else if (REG_NOTE_KIND (note) == REG_EH_REGION
&& INTVAL (XEXP (note, 0)) > 0)
XEXP (note, 0) = GEN_INT (INTVAL (XEXP (note, 0))
+ eh_region_offset);
}
}
if (GET_CODE (insn) == CALL_INSN
&& GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
{
int i;
for (i = 0; i < 3; i++)
copy_insn_notes (XEXP (PATTERN (insn), i), map, eh_region_offset);
}
if (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == RESX)
XINT (PATTERN (new_insn), 0) += eh_region_offset;
}
}
static void
integrate_parm_decls (args, map, arg_vector)
tree args;
struct inline_remap *map;
rtvec arg_vector;
{
tree tail;
int i;
for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
{
tree decl = copy_decl_for_inlining (tail, map->fndecl,
current_function_decl);
rtx new_decl_rtl
= copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map, 1);
subst_constants (&new_decl_rtl, NULL_RTX, map, 1);
apply_change_group ();
SET_DECL_RTL (decl, new_decl_rtl);
}
}
static tree
integrate_decl_tree (let, map)
tree let;
struct inline_remap *map;
{
tree t;
tree new_block;
tree *next;
new_block = make_node (BLOCK);
VARRAY_PUSH_TREE (map->block_map, new_block);
next = &BLOCK_VARS (new_block);
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
{
tree d;
d = copy_decl_for_inlining (t, map->fndecl, current_function_decl);
if (DECL_RTL_SET_P (t))
{
rtx r;
SET_DECL_RTL (d, copy_rtx_and_substitute (DECL_RTL (t), map, 1));
r = DECL_RTL (d);
subst_constants (&r, NULL_RTX, map, 1);
SET_DECL_RTL (d, r);
if (GET_CODE (r) == REG)
REGNO_DECL (REGNO (r)) = d;
else if (GET_CODE (r) == CONCAT)
{
REGNO_DECL (REGNO (XEXP (r, 0))) = d;
REGNO_DECL (REGNO (XEXP (r, 1))) = d;
}
apply_change_group ();
}
*next = d;
next = &TREE_CHAIN (d);
}
next = &BLOCK_SUBBLOCKS (new_block);
for (t = BLOCK_SUBBLOCKS (let); t; t = BLOCK_CHAIN (t))
{
*next = integrate_decl_tree (t, map);
BLOCK_SUPERCONTEXT (*next) = new_block;
next = &BLOCK_CHAIN (*next);
}
TREE_USED (new_block) = TREE_USED (let);
BLOCK_ABSTRACT_ORIGIN (new_block) = let;
return new_block;
}
rtx
copy_rtx_and_substitute (orig, map, for_lhs)
rtx orig;
struct inline_remap *map;
int for_lhs;
{
rtx copy, temp;
int i, j;
RTX_CODE code;
enum machine_mode mode;
const char *format_ptr;
int regno;
if (orig == 0)
return 0;
code = GET_CODE (orig);
mode = GET_MODE (orig);
switch (code)
{
case REG:
regno = REGNO (orig);
if (regno <= LAST_VIRTUAL_REGISTER
|| (map->integrating
&& DECL_SAVED_INSNS (map->fndecl)->internal_arg_pointer == orig))
{
if (map->reg_map[regno] != 0)
return map->reg_map[regno];
else if (regno == VIRTUAL_STACK_VARS_REGNUM)
{
rtx loc, seq;
int size = get_func_frame_size (DECL_SAVED_INSNS (map->fndecl));
#ifdef FRAME_GROWS_DOWNWARD
int alignment
= (DECL_SAVED_INSNS (map->fndecl)->stack_alignment_needed
/ BITS_PER_UNIT);
if (alignment)
size = CEIL_ROUND (size, alignment);
#endif
start_sequence ();
loc = assign_stack_temp (BLKmode, size, 1);
loc = XEXP (loc, 0);
#ifdef FRAME_GROWS_DOWNWARD
loc = plus_constant (loc, size);
#endif
map->reg_map[regno] = temp
= force_reg (Pmode, force_operand (loc, NULL_RTX));
#ifdef STACK_BOUNDARY
mark_reg_pointer (map->reg_map[regno], STACK_BOUNDARY);
#endif
SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
seq = get_insns ();
end_sequence ();
emit_insn_after (seq, map->insns_at_start);
return temp;
}
else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM
|| (map->integrating
&& (DECL_SAVED_INSNS (map->fndecl)->internal_arg_pointer
== orig)))
{
rtx loc, seq;
int size = DECL_SAVED_INSNS (map->fndecl)->args_size;
start_sequence ();
loc = assign_stack_temp (BLKmode, size, 1);
loc = XEXP (loc, 0);
#ifdef ARGS_GROW_DOWNWARD
loc = plus_constant (loc, size);
#endif
map->reg_map[regno] = temp
= force_reg (Pmode, force_operand (loc, NULL_RTX));
#ifdef STACK_BOUNDARY
mark_reg_pointer (map->reg_map[regno], STACK_BOUNDARY);
#endif
SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
seq = get_insns ();
end_sequence ();
emit_insn_after (seq, map->insns_at_start);
return temp;
}
else if (REG_FUNCTION_VALUE_P (orig))
{
if (map->inline_target == 0)
{
if (rtx_equal_function_value_matters)
return gen_rtx_REG (GET_MODE (orig), regno);
else
return orig;
}
else if (GET_MODE (map->inline_target) != BLKmode
&& mode != GET_MODE (map->inline_target))
return gen_lowpart (mode, map->inline_target);
else
return map->inline_target;
}
#if defined (LEAF_REGISTERS) && defined (LEAF_REG_REMAP)
if (map->integrating && regno < FIRST_PSEUDO_REGISTER
&& LEAF_REGISTERS[regno] && LEAF_REG_REMAP (regno) != regno)
{
if (!map->leaf_reg_map[regno][mode])
map->leaf_reg_map[regno][mode] = gen_rtx_REG (mode, regno);
return map->leaf_reg_map[regno][mode];
}
#endif
else
return orig;
abort ();
}
if (map->reg_map[regno] == NULL)
{
map->reg_map[regno] = gen_reg_rtx (mode);
REG_USERVAR_P (map->reg_map[regno]) = REG_USERVAR_P (orig);
REG_LOOP_TEST_P (map->reg_map[regno]) = REG_LOOP_TEST_P (orig);
RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (orig);
if (REG_POINTER (map->x_regno_reg_rtx[regno]))
mark_reg_pointer (map->reg_map[regno],
map->regno_pointer_align[regno]);
}
return map->reg_map[regno];
case SUBREG:
copy = copy_rtx_and_substitute (SUBREG_REG (orig), map, for_lhs);
return simplify_gen_subreg (GET_MODE (orig), copy,
GET_MODE (SUBREG_REG (orig)),
SUBREG_BYTE (orig));
case ADDRESSOF:
copy = gen_rtx_ADDRESSOF (mode,
copy_rtx_and_substitute (XEXP (orig, 0),
map, for_lhs),
0, ADDRESSOF_DECL (orig));
regno = ADDRESSOF_REGNO (orig);
if (map->reg_map[regno])
regno = REGNO (map->reg_map[regno]);
else if (regno > LAST_VIRTUAL_REGISTER)
{
temp = XEXP (orig, 0);
map->reg_map[regno] = gen_reg_rtx (GET_MODE (temp));
REG_USERVAR_P (map->reg_map[regno]) = REG_USERVAR_P (temp);
REG_LOOP_TEST_P (map->reg_map[regno]) = REG_LOOP_TEST_P (temp);
RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (temp);
if (REG_P (map->x_regno_reg_rtx[regno])
&& REG_POINTER (map->x_regno_reg_rtx[regno]))
mark_reg_pointer (map->reg_map[regno],
map->regno_pointer_align[regno]);
regno = REGNO (map->reg_map[regno]);
}
ADDRESSOF_REGNO (copy) = regno;
return copy;
case USE:
case CLOBBER:
copy = copy_rtx_and_substitute (XEXP (orig, 0), map, code == CLOBBER);
if (GET_CODE (copy) == SUBREG && GET_CODE (XEXP (orig, 0)) != SUBREG)
copy = SUBREG_REG (copy);
return gen_rtx_fmt_e (code, VOIDmode, copy);
case NOTE:
if (NOTE_LINE_NUMBER (orig) != NOTE_INSN_DELETED_LABEL)
break;
case CODE_LABEL:
LABEL_PRESERVE_P (get_label_from_map (map, CODE_LABEL_NUMBER (orig)))
= LABEL_PRESERVE_P (orig);
return get_label_from_map (map, CODE_LABEL_NUMBER (orig));
case LABEL_REF:
copy
= gen_rtx_LABEL_REF
(mode,
LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
: get_label_from_map (map, CODE_LABEL_NUMBER (XEXP (orig, 0))));
LABEL_OUTSIDE_LOOP_P (copy) = LABEL_OUTSIDE_LOOP_P (orig);
LABEL_REF_NONLOCAL_P (copy)
= (LABEL_REF_NONLOCAL_P (orig)
&& ! (CODE_LABEL_NUMBER (XEXP (copy, 0)) >= get_first_label_num ()
&& CODE_LABEL_NUMBER (XEXP (copy, 0)) < max_label_num ()));
if (LABEL_REF_NONLOCAL_P (orig) && ! LABEL_REF_NONLOCAL_P (copy))
function_call_count++;
return copy;
case PC:
case CC0:
case CONST_INT:
case CONST_VECTOR:
return orig;
case SYMBOL_REF:
if (CONSTANT_POOL_ADDRESS_P (orig))
{
struct function *f = inlining ? inlining : cfun;
rtx constant = get_pool_constant_for_function (f, orig);
enum machine_mode const_mode = get_pool_mode_for_function (f, orig);
if (inlining)
{
rtx temp = force_const_mem (const_mode,
copy_rtx_and_substitute (constant,
map, 0));
#if 0
if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0));
#endif
temp = XEXP (temp, 0);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (temp) != GET_MODE (orig))
temp = convert_memory_address (GET_MODE (orig), temp);
#endif
return temp;
}
else if (GET_CODE (constant) == LABEL_REF)
return XEXP (force_const_mem
(GET_MODE (orig),
copy_rtx_and_substitute (constant, map, for_lhs)),
0);
}
return orig;
case CONST_DOUBLE:
if (GET_MODE_CLASS (GET_MODE (orig)) == MODE_FLOAT)
{
REAL_VALUE_TYPE d;
REAL_VALUE_FROM_CONST_DOUBLE (d, orig);
return CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (orig));
}
else
return immed_double_const (CONST_DOUBLE_LOW (orig),
CONST_DOUBLE_HIGH (orig), VOIDmode);
case CONST:
if (RTX_INTEGRATED_P (orig))
abort ();
break;
case ASM_OPERANDS:
if (map->orig_asm_operands_vector == ASM_OPERANDS_INPUT_VEC (orig))
{
copy = rtx_alloc (ASM_OPERANDS);
RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil);
PUT_MODE (copy, GET_MODE (orig));
ASM_OPERANDS_TEMPLATE (copy) = ASM_OPERANDS_TEMPLATE (orig);
ASM_OPERANDS_OUTPUT_CONSTRAINT (copy)
= ASM_OPERANDS_OUTPUT_CONSTRAINT (orig);
ASM_OPERANDS_OUTPUT_IDX (copy) = ASM_OPERANDS_OUTPUT_IDX (orig);
ASM_OPERANDS_INPUT_VEC (copy) = map->copy_asm_operands_vector;
ASM_OPERANDS_INPUT_CONSTRAINT_VEC (copy)
= map->copy_asm_constraints_vector;
ASM_OPERANDS_SOURCE_FILE (copy) = ASM_OPERANDS_SOURCE_FILE (orig);
ASM_OPERANDS_SOURCE_LINE (copy) = ASM_OPERANDS_SOURCE_LINE (orig);
return copy;
}
break;
case CALL:
#ifndef NO_FUNCTION_CSE
if (! (optimize && ! flag_no_function_cse))
#endif
{
rtx copy
= gen_rtx_MEM (GET_MODE (XEXP (orig, 0)),
copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
map, 0));
MEM_COPY_ATTRIBUTES (copy, XEXP (orig, 0));
return
gen_rtx_CALL (GET_MODE (orig), copy,
copy_rtx_and_substitute (XEXP (orig, 1), map, 0));
}
break;
#if 0
case RETURN:
abort ();
#endif
case SET:
if (SET_DEST (orig) == virtual_stack_vars_rtx
|| SET_DEST (orig) == virtual_incoming_args_rtx)
{
rtx equiv_reg;
rtx equiv_loc;
HOST_WIDE_INT loc_offset;
copy_rtx_and_substitute (SET_DEST (orig), map, for_lhs);
equiv_reg = map->reg_map[REGNO (SET_DEST (orig))];
equiv_loc = VARRAY_CONST_EQUIV (map->const_equiv_varray,
REGNO (equiv_reg)).rtx;
loc_offset
= GET_CODE (equiv_loc) == REG ? 0 : INTVAL (XEXP (equiv_loc, 1));
return gen_rtx_SET (VOIDmode, SET_DEST (orig),
force_operand
(plus_constant
(copy_rtx_and_substitute (SET_SRC (orig),
map, 0),
- loc_offset),
NULL_RTX));
}
else
return gen_rtx_SET (VOIDmode,
copy_rtx_and_substitute (SET_DEST (orig), map, 1),
copy_rtx_and_substitute (SET_SRC (orig), map, 0));
break;
case MEM:
if (inlining
&& GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (orig, 0)))
{
enum machine_mode const_mode
= get_pool_mode_for_function (inlining, XEXP (orig, 0));
rtx constant
= get_pool_constant_for_function (inlining, XEXP (orig, 0));
constant = copy_rtx_and_substitute (constant, map, 0);
if (! CONSTANT_P (constant))
return constant;
return validize_mem (force_const_mem (const_mode, constant));
}
copy = gen_rtx_MEM (mode, copy_rtx_and_substitute (XEXP (orig, 0),
map, 0));
MEM_COPY_ATTRIBUTES (copy, orig);
if (inlining && !for_lhs)
RTX_UNCHANGING_P (copy) = 0;
if (inlining && MEM_EXPR (copy)
&& TREE_CODE (MEM_EXPR (copy)) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (MEM_EXPR (copy), 0)) == PARM_DECL)
set_mem_expr (copy, NULL_TREE);
return copy;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, mode);
RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct);
RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil);
RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging);
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
switch (*format_ptr++)
{
case '0':
X0WINT (copy, i) = X0WINT (orig, i);
break;
case 'e':
XEXP (copy, i)
= copy_rtx_and_substitute (XEXP (orig, i), map, for_lhs);
break;
case 'u':
XEXP (copy, i) = map->insn_map[INSN_UID (XEXP (orig, i))];
break;
case 'E':
XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j)
= copy_rtx_and_substitute (XVECEXP (orig, i, j),
map, for_lhs);
}
break;
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
case 'i':
XINT (copy, i) = XINT (orig, i);
break;
case 's':
XSTR (copy, i) = XSTR (orig, i);
break;
case 't':
XTREE (copy, i) = XTREE (orig, i);
break;
default:
abort ();
}
}
if (code == ASM_OPERANDS && map->orig_asm_operands_vector == 0)
{
map->orig_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (orig);
map->copy_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (copy);
map->copy_asm_constraints_vector
= ASM_OPERANDS_INPUT_CONSTRAINT_VEC (copy);
}
return copy;
}
void
try_constants (insn, map)
rtx insn;
struct inline_remap *map;
{
int i;
map->num_sets = 0;
subst_constants (&PATTERN (insn), insn, map, 1);
apply_change_group ();
subst_constants (&PATTERN (insn), insn, map, 0);
apply_change_group ();
note_stores (PATTERN (insn), mark_stores, NULL);
map->last_pc_value = 0;
#ifdef HAVE_cc0
map->last_cc0_value = 0;
#endif
for (i = 0; i < map->num_sets; i++)
{
if (GET_CODE (map->equiv_sets[i].dest) == REG)
{
int regno = REGNO (map->equiv_sets[i].dest);
MAYBE_EXTEND_CONST_EQUIV_VARRAY (map, regno);
if (VARRAY_CONST_EQUIV (map->const_equiv_varray, regno).rtx == 0
|| ! rtx_equal_p (VARRAY_CONST_EQUIV (map->const_equiv_varray,
regno).rtx,
map->equiv_sets[i].equiv))
SET_CONST_EQUIV_DATA (map, map->equiv_sets[i].dest,
map->equiv_sets[i].equiv, map->const_age);
}
else if (map->equiv_sets[i].dest == pc_rtx)
map->last_pc_value = map->equiv_sets[i].equiv;
#ifdef HAVE_cc0
else if (map->equiv_sets[i].dest == cc0_rtx)
map->last_cc0_value = map->equiv_sets[i].equiv;
#endif
}
}
static void
subst_constants (loc, insn, map, memonly)
rtx *loc;
rtx insn;
struct inline_remap *map;
int memonly;
{
rtx x = *loc;
int i, j;
enum rtx_code code;
const char *format_ptr;
int num_changes = num_validated_changes ();
rtx new = 0;
enum machine_mode op0_mode = MAX_MACHINE_MODE;
code = GET_CODE (x);
switch (code)
{
case PC:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
case ADDRESS:
return;
#ifdef HAVE_cc0
case CC0:
if (! memonly)
validate_change (insn, loc, map->last_cc0_value, 1);
return;
#endif
case USE:
case CLOBBER:
if (GET_CODE (XEXP (x, 0)) == MEM)
subst_constants (&XEXP (XEXP (x, 0), 0), insn, map, 0);
return;
case REG:
if (! memonly)
{
int regno = REGNO (x);
struct const_equiv_data *p;
if (! (regno < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x))
&& (size_t) regno < VARRAY_SIZE (map->const_equiv_varray)
&& (p = &VARRAY_CONST_EQUIV (map->const_equiv_varray, regno),
p->rtx != 0)
&& p->age >= map->const_age)
validate_change (insn, loc, p->rtx, 1);
}
return;
case SUBREG:
if (! memonly && GET_CODE (SUBREG_REG (x)) == REG)
{
rtx inner = SUBREG_REG (x);
rtx new = 0;
subst_constants (&inner, NULL_RTX, map, 0);
new = simplify_gen_subreg (GET_MODE (x), inner,
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
if (new)
validate_change (insn, loc, new, 1);
else
cancel_changes (num_changes);
return;
}
break;
case MEM:
subst_constants (&XEXP (x, 0), insn, map, 0);
if (! memonly && insn != 0 && num_validated_changes () != num_changes
&& ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
cancel_changes (num_changes);
return;
case SET:
{
rtx *dest_loc = &SET_DEST (x);
rtx dest = *dest_loc;
rtx src, tem;
enum machine_mode compare_mode = VOIDmode;
if (GET_CODE (SET_SRC (x)) == COMPARE)
{
src = SET_SRC (x);
if (GET_MODE_CLASS (GET_MODE (src)) == MODE_CC
#ifdef HAVE_cc0
|| dest == cc0_rtx
#endif
)
{
compare_mode = GET_MODE (XEXP (src, 0));
if (compare_mode == VOIDmode)
compare_mode = GET_MODE (XEXP (src, 1));
}
}
subst_constants (&SET_SRC (x), insn, map, memonly);
src = SET_SRC (x);
while (GET_CODE (*dest_loc) == ZERO_EXTRACT
|| GET_CODE (*dest_loc) == SUBREG
|| GET_CODE (*dest_loc) == STRICT_LOW_PART)
{
if (GET_CODE (*dest_loc) == ZERO_EXTRACT)
{
subst_constants (&XEXP (*dest_loc, 1), insn, map, memonly);
subst_constants (&XEXP (*dest_loc, 2), insn, map, memonly);
}
dest_loc = &XEXP (*dest_loc, 0);
}
if (GET_CODE (*dest_loc) == MEM)
subst_constants (&XEXP (*dest_loc, 0), insn, map, 0);
if (GET_CODE (dest) == SUBREG
&& GET_MODE_SIZE (GET_MODE (dest)) <= UNITS_PER_WORD
&& GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
<= GET_MODE_SIZE (GET_MODE (dest)))
&& (tem = gen_lowpart_if_possible (GET_MODE (SUBREG_REG (dest)),
src)))
src = tem, dest = SUBREG_REG (dest);
if ((map->num_sets < MAX_RECOG_OPERANDS)
&& (CONSTANT_P (src)
|| (GET_CODE (src) == REG
&& (REGNO (src) == VIRTUAL_INCOMING_ARGS_REGNUM
|| REGNO (src) == VIRTUAL_STACK_VARS_REGNUM))
|| (GET_CODE (src) == PLUS
&& GET_CODE (XEXP (src, 0)) == REG
&& (REGNO (XEXP (src, 0)) == VIRTUAL_INCOMING_ARGS_REGNUM
|| REGNO (XEXP (src, 0)) == VIRTUAL_STACK_VARS_REGNUM)
&& CONSTANT_P (XEXP (src, 1)))
|| GET_CODE (src) == COMPARE
#ifdef HAVE_cc0
|| dest == cc0_rtx
#endif
|| (dest == pc_rtx
&& (src == pc_rtx || GET_CODE (src) == RETURN
|| GET_CODE (src) == LABEL_REF))))
{
rtx src_copy = copy_rtx (src);
map->equiv_sets[map->num_sets].equiv = src_copy;
map->equiv_sets[map->num_sets++].dest = dest;
if (compare_mode != VOIDmode
&& GET_CODE (src) == COMPARE
&& (GET_MODE_CLASS (GET_MODE (src)) == MODE_CC
#ifdef HAVE_cc0
|| dest == cc0_rtx
#endif
)
&& GET_MODE (XEXP (src, 0)) == VOIDmode
&& GET_MODE (XEXP (src, 1)) == VOIDmode)
{
map->compare_src = src_copy;
map->compare_mode = compare_mode;
}
}
}
return;
default:
break;
}
format_ptr = GET_RTX_FORMAT (code);
if (*format_ptr == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*format_ptr++)
{
case '0':
break;
case 'e':
if (XEXP (x, i))
subst_constants (&XEXP (x, i), insn, map, memonly);
break;
case 'u':
case 'i':
case 's':
case 'w':
case 'n':
case 't':
case 'B':
break;
case 'E':
if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
for (j = 0; j < XVECLEN (x, i); j++)
subst_constants (&XVECEXP (x, i, j), insn, map, memonly);
break;
default:
abort ();
}
}
if (! memonly
&& (GET_RTX_CLASS (code) == 'c' || code == NE || code == EQ)
&& CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT)
{
rtx tem = XEXP (x, 0);
validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
validate_change (insn, &XEXP (x, 1), tem, 1);
}
if (! memonly)
switch (GET_RTX_CLASS (code))
{
case '1':
if (op0_mode == MAX_MACHINE_MODE)
abort ();
new = simplify_unary_operation (code, GET_MODE (x),
XEXP (x, 0), op0_mode);
break;
case '<':
{
enum machine_mode op_mode = GET_MODE (XEXP (x, 0));
if (op_mode == VOIDmode)
op_mode = GET_MODE (XEXP (x, 1));
new = simplify_relational_operation (code, op_mode,
XEXP (x, 0), XEXP (x, 1));
#ifdef FLOAT_STORE_FLAG_VALUE
if (new != 0 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
enum machine_mode mode = GET_MODE (x);
if (new == const0_rtx)
new = CONST0_RTX (mode);
else
{
REAL_VALUE_TYPE val;
val = FLOAT_STORE_FLAG_VALUE (mode);
new = CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
}
}
#endif
break;
}
case '2':
case 'c':
new = simplify_binary_operation (code, GET_MODE (x),
XEXP (x, 0), XEXP (x, 1));
break;
case 'b':
case '3':
if (op0_mode == MAX_MACHINE_MODE)
abort ();
if (code == IF_THEN_ELSE)
{
rtx op0 = XEXP (x, 0);
if (GET_RTX_CLASS (GET_CODE (op0)) == '<'
&& GET_MODE (op0) == VOIDmode
&& ! side_effects_p (op0)
&& XEXP (op0, 0) == map->compare_src
&& GET_MODE (XEXP (op0, 1)) == VOIDmode)
{
rtx temp =
simplify_relational_operation (GET_CODE (op0),
map->compare_mode,
XEXP (op0, 0),
XEXP (op0, 1));
if (temp == const0_rtx)
new = XEXP (x, 2);
else if (temp == const1_rtx)
new = XEXP (x, 1);
}
}
if (!new)
new = simplify_ternary_operation (code, GET_MODE (x), op0_mode,
XEXP (x, 0), XEXP (x, 1),
XEXP (x, 2));
break;
}
if (new)
validate_change (insn, loc, new, 1);
}
static void
mark_stores (dest, x, data)
rtx dest;
rtx x ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
int regno = -1;
enum machine_mode mode = VOIDmode;
if (GET_CODE (dest) == REG)
regno = REGNO (dest), mode = GET_MODE (dest);
else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
{
regno = REGNO (SUBREG_REG (dest));
if (regno < FIRST_PSEUDO_REGISTER)
regno += subreg_regno_offset (REGNO (SUBREG_REG (dest)),
GET_MODE (SUBREG_REG (dest)),
SUBREG_BYTE (dest),
GET_MODE (dest));
mode = GET_MODE (SUBREG_REG (dest));
}
if (regno >= 0)
{
unsigned int uregno = regno;
unsigned int last_reg = (uregno >= FIRST_PSEUDO_REGISTER ? uregno
: uregno + HARD_REGNO_NREGS (uregno, mode) - 1);
unsigned int i;
if (uregno != VIRTUAL_INCOMING_ARGS_REGNUM
&& uregno != VIRTUAL_STACK_VARS_REGNUM)
for (i = uregno; i <= last_reg; i++)
if ((size_t) i < VARRAY_SIZE (global_const_equiv_varray))
VARRAY_CONST_EQUIV (global_const_equiv_varray, i).rtx = 0;
}
}
static void
set_block_origin_self (stmt)
tree stmt;
{
if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE)
{
BLOCK_ABSTRACT_ORIGIN (stmt) = stmt;
{
tree local_decl;
for (local_decl = BLOCK_VARS (stmt);
local_decl != NULL_TREE;
local_decl = TREE_CHAIN (local_decl))
set_decl_origin_self (local_decl);
}
{
tree subblock;
for (subblock = BLOCK_SUBBLOCKS (stmt);
subblock != NULL_TREE;
subblock = BLOCK_CHAIN (subblock))
set_block_origin_self (subblock);
}
}
}
void
set_decl_origin_self (decl)
tree decl;
{
if (DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE)
{
DECL_ABSTRACT_ORIGIN (decl) = decl;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree arg;
for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
DECL_ABSTRACT_ORIGIN (arg) = arg;
if (DECL_INITIAL (decl) != NULL_TREE
&& DECL_INITIAL (decl) != error_mark_node)
set_block_origin_self (DECL_INITIAL (decl));
}
}
}
static void
set_block_abstract_flags (stmt, setting)
tree stmt;
int setting;
{
tree local_decl;
tree subblock;
BLOCK_ABSTRACT (stmt) = setting;
for (local_decl = BLOCK_VARS (stmt);
local_decl != NULL_TREE;
local_decl = TREE_CHAIN (local_decl))
set_decl_abstract_flags (local_decl, setting);
for (subblock = BLOCK_SUBBLOCKS (stmt);
subblock != NULL_TREE;
subblock = BLOCK_CHAIN (subblock))
set_block_abstract_flags (subblock, setting);
}
void
set_decl_abstract_flags (decl, setting)
tree decl;
int setting;
{
DECL_ABSTRACT (decl) = setting;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree arg;
for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
DECL_ABSTRACT (arg) = setting;
if (DECL_INITIAL (decl) != NULL_TREE
&& DECL_INITIAL (decl) != error_mark_node)
set_block_abstract_flags (DECL_INITIAL (decl), setting);
}
}
static GTY(()) struct function *old_cfun;
void
output_inline_function (fndecl)
tree fndecl;
{
enum debug_info_type old_write_symbols = write_symbols;
const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks;
struct function *f = DECL_SAVED_INSNS (fndecl);
old_cfun = cfun;
cfun = f;
current_function_decl = fndecl;
set_new_last_label_num (f->inl_max_label_num);
DECL_DEFER_OUTPUT (fndecl) = 0;
if (f->no_debugging_symbols)
{
write_symbols = NO_DEBUG;
debug_hooks = &do_nothing_debug_hooks;
}
rest_of_compilation (fndecl);
DECL_INLINE (fndecl) = 0;
cfun = old_cfun;
current_function_decl = old_cfun ? old_cfun->decl : 0;
write_symbols = old_write_symbols;
debug_hooks = old_debug_hooks;
}
rtx
get_hard_reg_initial_reg (fun, reg)
struct function *fun;
rtx reg;
{
struct initial_value_struct *ivs = fun->hard_reg_initial_vals;
int i;
if (ivs == 0)
return NULL_RTX;
for (i = 0; i < ivs->num_entries; i++)
if (rtx_equal_p (ivs->entries[i].pseudo, reg))
return ivs->entries[i].hard_reg;
return NULL_RTX;
}
rtx
has_func_hard_reg_initial_val (fun, reg)
struct function *fun;
rtx reg;
{
struct initial_value_struct *ivs = fun->hard_reg_initial_vals;
int i;
if (ivs == 0)
return NULL_RTX;
for (i = 0; i < ivs->num_entries; i++)
if (rtx_equal_p (ivs->entries[i].hard_reg, reg))
return ivs->entries[i].pseudo;
return NULL_RTX;
}
rtx
get_func_hard_reg_initial_val (fun, reg)
struct function *fun;
rtx reg;
{
struct initial_value_struct *ivs = fun->hard_reg_initial_vals;
rtx rv = has_func_hard_reg_initial_val (fun, reg);
if (rv)
return rv;
if (ivs == 0)
{
fun->hard_reg_initial_vals = (void *) ggc_alloc (sizeof (initial_value_struct));
ivs = fun->hard_reg_initial_vals;
ivs->num_entries = 0;
ivs->max_entries = 5;
ivs->entries = (initial_value_pair *) ggc_alloc (5 * sizeof (initial_value_pair));
}
if (ivs->num_entries >= ivs->max_entries)
{
ivs->max_entries += 5;
ivs->entries =
(initial_value_pair *) ggc_realloc (ivs->entries,
ivs->max_entries
* sizeof (initial_value_pair));
}
ivs->entries[ivs->num_entries].hard_reg = reg;
ivs->entries[ivs->num_entries].pseudo = gen_reg_rtx (GET_MODE (reg));
return ivs->entries[ivs->num_entries++].pseudo;
}
rtx
get_hard_reg_initial_val (mode, regno)
enum machine_mode mode;
int regno;
{
return get_func_hard_reg_initial_val (cfun, gen_rtx_REG (mode, regno));
}
rtx
has_hard_reg_initial_val (mode, regno)
enum machine_mode mode;
int regno;
{
return has_func_hard_reg_initial_val (cfun, gen_rtx_REG (mode, regno));
}
static void
setup_initial_hard_reg_value_integration (inl_f, remap)
struct function *inl_f;
struct inline_remap *remap;
{
struct initial_value_struct *ivs = inl_f->hard_reg_initial_vals;
int i;
if (ivs == 0)
return;
for (i = 0; i < ivs->num_entries; i ++)
remap->reg_map[REGNO (ivs->entries[i].pseudo)]
= get_func_hard_reg_initial_val (cfun, ivs->entries[i].hard_reg);
}
void
emit_initial_value_sets ()
{
struct initial_value_struct *ivs = cfun->hard_reg_initial_vals;
int i;
rtx seq;
if (ivs == 0)
return;
start_sequence ();
for (i = 0; i < ivs->num_entries; i++)
emit_move_insn (ivs->entries[i].pseudo, ivs->entries[i].hard_reg);
seq = get_insns ();
end_sequence ();
emit_insn_after (seq, get_insns ());
}
void
allocate_initial_values (reg_equiv_memory_loc)
rtx *reg_equiv_memory_loc ATTRIBUTE_UNUSED;
{
#ifdef ALLOCATE_INITIAL_VALUE
struct initial_value_struct *ivs = cfun->hard_reg_initial_vals;
int i;
if (ivs == 0)
return;
for (i = 0; i < ivs->num_entries; i++)
{
int regno = REGNO (ivs->entries[i].pseudo);
rtx x = ALLOCATE_INITIAL_VALUE (ivs->entries[i].hard_reg);
if (x == NULL_RTX || REG_N_SETS (REGNO (ivs->entries[i].pseudo)) > 1)
;
else if (GET_CODE (x) == MEM)
reg_equiv_memory_loc[regno] = x;
else if (GET_CODE (x) == REG)
{
reg_renumber[regno] = REGNO (x);
REGNO (ivs->entries[i].pseudo) = REGNO (x);
}
else abort ();
}
#endif
}
#include "gt-integrate.h"