#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "regs.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-flags.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 "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern struct obstack *function_maybepermanent_obstack;
#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
#ifndef INTEGRATE_THRESHOLD
#ifdef NEXT_SEMANTICS
extern char call_used_regs[FIRST_PSEUDO_REGISTER];
static int
num_call_used_regs ()
{
int i;
static int num = 0;
if (num == 0)
{
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i])
num += 1;
}
return num;
}
#define NUM_CALL_USED_REGS num_call_used_regs()
#else
#define NUM_CALL_USED_REGS 8
#endif
#define INTEGRATE_THRESHOLD(DECL) \
(optimize_size \
? (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) \
: (NUM_CALL_USED_REGS * (8 + list_length (DECL_ARGUMENTS (DECL)))))
#endif
static rtx initialize_for_inline PROTO((tree, int, int, int, int));
static void finish_inline PROTO((tree, rtx));
static void adjust_copied_decl_tree PROTO((tree));
static tree copy_decl_list PROTO((tree));
static tree copy_decl_tree PROTO((tree));
static void copy_decl_rtls PROTO((tree));
static void save_constants PROTO((rtx *));
static void note_modified_parmregs PROTO((rtx, rtx));
static rtx copy_for_inline PROTO((rtx));
static void integrate_parm_decls PROTO((tree, struct inline_remap *,
rtvec));
static void integrate_decl_tree PROTO((tree, int,
struct inline_remap *));
static void save_constants_in_decl_trees PROTO ((tree));
static void subst_constants PROTO((rtx *, rtx,
struct inline_remap *));
static void restore_constants PROTO((rtx *));
static void set_block_origin_self PROTO((tree));
static void set_decl_origin_self PROTO((tree));
static void set_block_abstract_flags PROTO((tree, int));
static void process_reg_param PROTO((struct inline_remap *, rtx,
rtx));
void set_decl_abstract_flags PROTO((tree, int));
static tree copy_and_set_decl_abstract_origin PROTO((tree));
int inline_max_insns = 10000;
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;
}
const char *
function_cannot_inline_p (fndecl)
register tree fndecl;
{
register rtx insn;
tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
int max_insns = (DECL_INLINE (fndecl))
? (inline_max_insns
+ 8 * list_length (DECL_ARGUMENTS (fndecl)))
: INTEGRATE_THRESHOLD (fndecl);
register int ninsns = 0;
register tree parms;
rtx result;
if ((last && TREE_VALUE (last) != void_type_node)
|| current_function_varargs)
return N_("varargs function cannot be inline");
if (current_function_calls_alloca)
return N_("function using alloca cannot be inline");
if (current_function_contains_functions)
return N_("function with nested functions cannot be 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 (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 (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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
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 (forced_labels)
return N_("function with label addresses used in initializers cannot inline");
if (current_function_has_nonlocal_goto)
return N_("function with nonlocal goto cannot be inline");
for (insn = get_insns ();
insn
&& ! (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG);
insn = NEXT_INSN (insn))
{
if (insn && GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
return N_("function with complex parameters cannot be inline");
}
result = DECL_RTL (DECL_RESULT (fndecl));
if (result && GET_CODE (result) == PARALLEL)
return N_("inline functions not supported for this return value type");
#ifdef NEXT_SEMANTICS
{
extern char *(*maybe_inline_func_p) PROTO ((tree));
if (maybe_inline_func_p)
{
char *excuse = maybe_inline_func_p (fndecl);
if (excuse)
return excuse;
}
}
#endif
return 0;
}
static rtx *reg_map;
static rtx *label_map;
static rtx *insn_map;
static tree *parmdecl_map;
extern int max_parm_reg;
extern rtx *parm_reg_stack_loc;
static rtvec orig_asm_operands_vector;
static rtvec copy_asm_operands_vector;
static rtvec copy_asm_constraints_vector;
static int in_nonparm_insns;
static rtx
save_for_inline_eh_labelmap (label)
rtx label;
{
int index = CODE_LABEL_NUMBER (label);
return label_map[index];
}
static rtx
initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
tree fndecl;
int min_labelno;
int max_labelno;
int max_reg;
int copy;
{
int function_flags, i;
rtvec arg_vector;
tree parms;
function_flags
= (current_function_calls_alloca * FUNCTION_FLAGS_CALLS_ALLOCA
+ current_function_calls_setjmp * FUNCTION_FLAGS_CALLS_SETJMP
+ current_function_calls_longjmp * FUNCTION_FLAGS_CALLS_LONGJMP
+ current_function_returns_struct * FUNCTION_FLAGS_RETURNS_STRUCT
+ (current_function_returns_pcc_struct
* FUNCTION_FLAGS_RETURNS_PCC_STRUCT)
+ current_function_needs_context * FUNCTION_FLAGS_NEEDS_CONTEXT
+ (current_function_has_nonlocal_label
* FUNCTION_FLAGS_HAS_NONLOCAL_LABEL)
+ current_function_returns_pointer * FUNCTION_FLAGS_RETURNS_POINTER
+ current_function_uses_const_pool * FUNCTION_FLAGS_USES_CONST_POOL
+ (current_function_uses_pic_offset_table
* FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE)
+ current_function_has_computed_jump * FUNCTION_FLAGS_HAS_COMPUTED_JUMP);
bzero ((char *) parmdecl_map, 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);
int copied_incoming = 0;
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);
if (GET_CODE (p) == MEM && copy)
{
rtx new = copy_rtx (p);
if (DECL_RTL (parms) == DECL_INCOMING_RTL (parms)
|| (GET_CODE (DECL_RTL (parms)) == MEM
&& GET_CODE (DECL_INCOMING_RTL (parms)) == MEM
&& (XEXP (DECL_RTL (parms), 0)
== XEXP (DECL_INCOMING_RTL (parms), 0))))
DECL_INCOMING_RTL (parms) = new, copied_incoming = 1;
DECL_RTL (parms) = new;
}
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;
if (copy && ! copied_incoming)
{
p = DECL_INCOMING_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);
if (GET_CODE (p) == MEM)
DECL_INCOMING_RTL (parms) = copy_rtx (p);
}
}
in_nonparm_insns = 0;
return gen_inline_header_rtx (NULL_RTX, NULL_RTX, min_labelno, max_labelno,
max_parm_reg, max_reg,
current_function_args_size,
current_function_pops_args,
stack_slot_list, forced_labels, function_flags,
current_function_outgoing_args_size,
arg_vector, (rtx) DECL_INITIAL (fndecl),
(rtvec) regno_reg_rtx, regno_pointer_flag,
regno_pointer_align,
(rtvec) parm_reg_stack_loc);
}
static void
finish_inline (fndecl, head)
tree fndecl;
rtx head;
{
FIRST_FUNCTION_INSN (head) = get_first_nonparm_insn ();
FIRST_PARM_INSN (head) = get_insns ();
DECL_SAVED_INSNS (fndecl) = head;
DECL_FRAME_SIZE (fndecl) = get_frame_size ();
}
static void
adjust_copied_decl_tree (block)
register tree block;
{
register tree subblock;
register rtx original_end;
original_end = BLOCK_END_NOTE (block);
if (original_end)
{
BLOCK_END_NOTE (block) = (rtx) NOTE_SOURCE_FILE (original_end);
NOTE_SOURCE_FILE (original_end) = 0;
}
for (subblock = BLOCK_SUBBLOCKS (block);
subblock;
subblock = TREE_CHAIN (subblock))
adjust_copied_decl_tree (subblock);
}
void
save_for_inline_copying (fndecl)
tree fndecl;
{
rtx first_insn, last_insn, insn;
rtx head, copy;
int max_labelno, min_labelno, i, len;
int max_reg;
int max_uid;
rtx first_nonparm_insn;
char *new, *new1;
rtx *new_parm_reg_stack_loc;
rtx *new2;
if (return_label == 0)
{
return_label = gen_label_rtx ();
emit_label (return_label);
}
max_labelno = max_label_num ();
min_labelno = get_first_label_num ();
max_reg = max_reg_num ();
parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
head = initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, 1);
if (current_function_uses_const_pool)
{
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
save_constants (&PATTERN (insn));
if (REG_NOTES (insn))
save_constants (®_NOTES (insn));
}
save_constants_in_decl_trees (DECL_INITIAL (fndecl));
init_const_rtx_hash_table ();
clear_const_double_mem ();
}
max_uid = INSN_UID (head);
preserve_data ();
insn = get_insns ();
if (GET_CODE (insn) != NOTE)
abort ();
first_insn = rtx_alloc (NOTE);
NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);
NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);
INSN_UID (first_insn) = INSN_UID (insn);
PREV_INSN (first_insn) = NULL;
NEXT_INSN (first_insn) = NULL;
last_insn = first_insn;
reg_map = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));
len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
for (i = max_reg - 1; i > LAST_VIRTUAL_REGISTER; i--)
reg_map[i] = (rtx)obstack_copy (function_maybepermanent_obstack,
regno_reg_rtx[i], len);
regno_reg_rtx = reg_map;
init_virtual_regs ();
label_map = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
for (i = min_labelno; i < max_labelno; i++)
label_map[i] = gen_label_rtx ();
new_parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
for (i = 0; i < max_parm_reg; i++)
new_parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);
parm_reg_stack_loc = new_parm_reg_stack_loc;
insn_map = (rtx *) alloca (max_uid * sizeof (rtx));
bzero ((char *) insn_map, max_uid * sizeof (rtx));
first_nonparm_insn = get_first_nonparm_insn ();
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_reg; i++)
if (GET_CODE (regno_reg_rtx[i]) == MEM)
XEXP (regno_reg_rtx[i], 0)
= copy_for_inline (XEXP (regno_reg_rtx[i], 0));
new2 = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
bcopy ((char *) parm_reg_stack_loc, (char *) new2,
max_parm_reg * sizeof (rtx));
parm_reg_stack_loc = new2;
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; ++i)
if (parm_reg_stack_loc[i])
parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);
DECL_INITIAL (fndecl) = copy_decl_tree (DECL_INITIAL (fndecl));
DECL_ARGUMENTS (fndecl) = copy_decl_list (DECL_ARGUMENTS (fndecl));
copy_decl_rtls (DECL_INITIAL (fndecl));
DECL_ABSTRACT_ORIGIN (fndecl) = fndecl;
for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
{
orig_asm_operands_vector = 0;
if (insn == first_nonparm_insn)
in_nonparm_insns = 1;
switch (GET_CODE (insn))
{
case NOTE:
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
continue;
copy = rtx_alloc (NOTE);
NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_END)
NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
else
{
NOTE_SOURCE_FILE (insn) = (char *) copy;
NOTE_SOURCE_FILE (copy) = 0;
}
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
{
int new_region = CODE_LABEL_NUMBER
(label_map[NOTE_BLOCK_NUMBER (copy)]);
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region,
save_for_inline_eh_labelmap);
NOTE_BLOCK_NUMBER (copy) = new_region;
}
RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
break;
case INSN:
case JUMP_INSN:
case CALL_INSN:
copy = rtx_alloc (GET_CODE (insn));
if (GET_CODE (insn) == CALL_INSN)
CALL_INSN_FUNCTION_USAGE (copy)
= copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn));
PATTERN (copy) = copy_for_inline (PATTERN (insn));
INSN_CODE (copy) = -1;
LOG_LINKS (copy) = NULL_RTX;
RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
break;
case CODE_LABEL:
copy = label_map[CODE_LABEL_NUMBER (insn)];
LABEL_NAME (copy) = LABEL_NAME (insn);
break;
case BARRIER:
copy = rtx_alloc (BARRIER);
break;
default:
abort ();
}
INSN_UID (copy) = INSN_UID (insn);
insn_map[INSN_UID (insn)] = copy;
NEXT_INSN (last_insn) = copy;
PREV_INSN (copy) = last_insn;
last_insn = copy;
}
adjust_copied_decl_tree (DECL_INITIAL (fndecl));
for (insn = NEXT_INSN (get_insns ()); insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& insn_map[INSN_UID(insn)])
REG_NOTES (insn_map[INSN_UID (insn)])
= copy_for_inline (REG_NOTES (insn));
NEXT_INSN (last_insn) = NULL;
finish_inline (fndecl, head);
new = (char *) savealloc (regno_pointer_flag_length);
bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
new1 = (char *) savealloc (regno_pointer_flag_length);
bcopy (regno_pointer_align, new1, regno_pointer_flag_length);
regno_pointer_flag = new;
regno_pointer_align = new1;
set_new_first_and_last_insn (first_insn, last_insn);
if (label_map)
free (label_map);
}
static tree
copy_and_set_decl_abstract_origin (node)
tree node;
{
tree copy = copy_node (node);
if (DECL_ABSTRACT_ORIGIN (copy) != NULL_TREE)
;
else
DECL_ABSTRACT_ORIGIN (copy) = node;
return copy;
}
static tree
copy_decl_list (list)
tree list;
{
tree head;
register tree prev, next;
if (list == 0)
return 0;
head = prev = copy_and_set_decl_abstract_origin (list);
next = TREE_CHAIN (list);
while (next)
{
register tree copy;
copy = copy_and_set_decl_abstract_origin (next);
TREE_CHAIN (prev) = copy;
prev = copy;
next = TREE_CHAIN (next);
}
return head;
}
static tree
copy_decl_tree (block)
tree block;
{
tree t, vars, subblocks;
vars = copy_decl_list (BLOCK_VARS (block));
subblocks = 0;
for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t))
{
tree copy = copy_decl_tree (t);
TREE_CHAIN (copy) = subblocks;
subblocks = copy;
}
t = copy_node (block);
BLOCK_VARS (t) = vars;
BLOCK_SUBBLOCKS (t) = nreverse (subblocks);
if (BLOCK_ABSTRACT_ORIGIN (t) == NULL_TREE)
BLOCK_ABSTRACT_ORIGIN (t) = block;
return t;
}
static void
copy_decl_rtls (block)
tree block;
{
tree t;
for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t))
if (DECL_RTL (t) && GET_CODE (DECL_RTL (t)) == MEM)
DECL_RTL (t) = copy_for_inline (DECL_RTL (t));
for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t))
copy_decl_rtls (t);
}
void
save_for_inline_nocopy (fndecl)
tree fndecl;
{
rtx insn;
rtx head;
rtx first_nonparm_insn;
parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
if (return_label == 0)
{
return_label = gen_label_rtx ();
emit_label (return_label);
}
head = initialize_for_inline (fndecl, get_first_label_num (),
max_label_num (), max_reg_num (), 0);
insn = get_insns ();
if (GET_CODE (insn) != NOTE)
abort ();
first_nonparm_insn = get_first_nonparm_insn ();
for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
{
if (insn == first_nonparm_insn)
in_nonparm_insns = 1;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
if (current_function_uses_const_pool)
{
save_constants (&PATTERN (insn));
if (REG_NOTES (insn))
save_constants (®_NOTES (insn));
}
note_stores (PATTERN (insn), note_modified_parmregs);
}
}
save_constants_in_decl_trees (DECL_INITIAL (fndecl));
preserve_data ();
finish_inline (fndecl, head);
}
static void
save_constants (px)
rtx *px;
{
rtx x;
int i, j;
again:
x = *px;
if (GET_CODE (x) == CONST_DOUBLE)
return;
else if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x,0)))
{
enum machine_mode const_mode = get_pool_mode (XEXP (x, 0));
rtx new = gen_rtx_CONST (const_mode, get_pool_constant (XEXP (x, 0)));
RTX_INTEGRATED_P (new) = 1;
if (GET_MODE (x) != const_mode)
{
new = gen_rtx_SUBREG (GET_MODE (x), new, 0);
RTX_INTEGRATED_P (new) = 1;
}
*px = new;
save_constants (&XEXP (*px, 0));
}
else if (GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x))
{
*px = gen_rtx_ADDRESS (GET_MODE (x),
gen_rtx_CONST (get_pool_mode (x),
get_pool_constant (x)));
save_constants (&XEXP (*px, 0));
RTX_INTEGRATED_P (*px) = 1;
}
else
{
char *fmt = GET_RTX_FORMAT (GET_CODE (x));
int len = GET_RTX_LENGTH (GET_CODE (x));
for (i = len-1; i >= 0; i--)
{
switch (fmt[i])
{
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
save_constants (&XVECEXP (x, i, j));
break;
case 'e':
if (XEXP (x, i) == 0)
continue;
if (i == 0)
{
px = &XEXP (x, 0);
goto again;
}
save_constants (&XEXP (x, i));
break;
}
}
}
}
static void
note_modified_parmregs (reg, x)
rtx reg;
rtx x 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;
}
static rtx
copy_for_inline (orig)
rtx orig;
{
register rtx x = orig;
register rtx new;
register int i;
register enum rtx_code code;
register char *format_ptr;
if (x == 0)
return x;
code = GET_CODE (x);
switch (code)
{
case QUEUED:
case CONST_INT:
case PC:
case CC0:
return x;
case SYMBOL_REF:
if (! SYMBOL_REF_NEED_ADJUST (x))
return x;
return rethrow_symbol_map (x, save_for_inline_eh_labelmap);
case CONST_DOUBLE:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
REAL_VALUE_TYPE d;
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
return CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x));
}
else
return immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x),
VOIDmode);
case CONST:
if (RTX_INTEGRATED_P (x))
return validize_mem (force_const_mem (GET_MODE (x),
copy_for_inline (XEXP (x, 0))));
break;
case SUBREG:
if (RTX_INTEGRATED_P (x))
{
new = force_const_mem (GET_MODE (SUBREG_REG (x)),
copy_for_inline (XEXP (SUBREG_REG (x), 0)));
PUT_MODE (new, GET_MODE (x));
return validize_mem (new);
}
break;
case ADDRESS:
if (! RTX_INTEGRATED_P (x))
abort ();
new = force_const_mem (GET_MODE (XEXP (x, 0)),
copy_for_inline (XEXP (XEXP (x, 0), 0)));
new = XEXP (new, 0);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (new) != GET_MODE (x))
new = convert_memory_address (GET_MODE (x), new);
#endif
return new;
case ASM_OPERANDS:
if (orig_asm_operands_vector == XVEC (orig, 3))
{
x = rtx_alloc (ASM_OPERANDS);
x->volatil = orig->volatil;
XSTR (x, 0) = XSTR (orig, 0);
XSTR (x, 1) = XSTR (orig, 1);
XINT (x, 2) = XINT (orig, 2);
XVEC (x, 3) = copy_asm_operands_vector;
XVEC (x, 4) = copy_asm_constraints_vector;
XSTR (x, 5) = XSTR (orig, 5);
XINT (x, 6) = XINT (orig, 6);
return x;
}
break;
case MEM:
if (CONSTANT_ADDRESS_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 0)) != LABEL_REF
&& ! (GET_CODE (XEXP (x, 0)) == CONST
&& (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
&& ((GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
== LABEL_REF)
|| (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
== ADDRESS)))))
return x;
break;
case LABEL_REF:
x = gen_rtx_LABEL_REF (GET_MODE (orig),
LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
: label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
LABEL_REF_NONLOCAL_P (x) = LABEL_REF_NONLOCAL_P (orig);
LABEL_OUTSIDE_LOOP_P (x) = LABEL_OUTSIDE_LOOP_P (orig);
return x;
case REG:
if (REGNO (x) > LAST_VIRTUAL_REGISTER)
return reg_map [REGNO (x)];
else
return x;
case SET:
{
rtx dest = SET_DEST (x);
while (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SUBREG)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG
&& REGNO (dest) < max_parm_reg
&& REGNO (dest) >= FIRST_PSEUDO_REGISTER
&& parmdecl_map[REGNO (dest)] != 0
&& in_nonparm_insns)
TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0;
}
break;
#if 0
case PLUS:
if (GET_CODE (XEXP (x, 0)) == CONST_INT
|| (XEXP (x, 1) == frame_pointer_rtx
|| (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& XEXP (x, 1) == arg_pointer_rtx)))
{
rtx t = XEXP (x, 0);
XEXP (x, 0) = XEXP (x, 1);
XEXP (x, 1) = t;
}
break;
#endif
default:
break;
}
x = rtx_alloc (code);
bcopy ((char *) orig, (char *) x,
(sizeof (*x) - sizeof (x->fld)
+ sizeof (x->fld[0]) * GET_RTX_LENGTH (code)));
format_ptr = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (x, i) = copy_for_inline (XEXP (x, i));
break;
case 'u':
XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))];
break;
case 'E':
if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
{
register int j;
XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem);
for (j = 0; j < XVECLEN (x, i); j++)
XVECEXP (x, i, j)
= copy_for_inline (XVECEXP (x, i, j));
}
break;
}
}
if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
{
orig_asm_operands_vector = XVEC (orig, 3);
copy_asm_operands_vector = XVEC (x, 3);
copy_asm_constraints_vector = XVEC (x, 4);
}
return x;
}
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))
{
#if defined (MACHO_PIC) && defined (I386)
if (flag_pic && GET_CODE(copy) == SYMBOL_REF)
{
const char *name = XSTR (copy, 0);
if (machopic_name_defined_p (name))
{
rtx pic_base = gen_rtx (SYMBOL_REF, Pmode,
machopic_function_base_name ());
rtx offset = gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode, copy,
pic_base));
copy = gen_rtx (PLUS, Pmode, pic_offset_table_rtx,
offset);
}
else
{
copy = gen_rtx_MEM (Pmode,
gen_rtx (SYMBOL_REF, Pmode,
machopic_non_lazy_ptr_name (name)));
}
}
#endif
SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM);
}
copy = temp;
}
map->reg_map[REGNO (loc)] = copy;
}
static struct inline_remap *eif_eh_map;
static rtx
expand_inline_function_eh_labelmap (label)
rtx label;
{
int index = CODE_LABEL_NUMBER (label);
return get_label_from_map (eif_eh_map, index);
}
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;
{
tree formal, actual, block;
rtx header = DECL_SAVED_INSNS (fndecl);
rtx insns = FIRST_FUNCTION_INSN (header);
rtx parm_insns = FIRST_PARM_INSN (header);
tree *arg_trees;
rtx *arg_vals;
rtx insn;
int max_regno;
register int i;
int min_labelno = FIRST_LABELNO (header);
int max_labelno = LAST_LABELNO (header);
int nargs;
rtx local_return_label = 0;
rtx loc;
rtx stack_save = 0;
rtx temp;
struct inline_remap *map = 0;
#ifdef HAVE_cc0
rtx cc0_insn = 0;
#endif
rtvec arg_vector = ORIGINAL_ARG_VECTOR (header);
rtx static_chain_value = 0;
rtx *real_label_map = 0;
max_regno = MAX_REGNUM (header) + 3;
if (max_regno < FIRST_PSEUDO_REGISTER)
abort ();
nargs = list_length (DECL_ARGUMENTS (fndecl));
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) (HOST_WIDE_INT) -1;
arg = TREE_VALUE (actual);
mode = TYPE_MODE (DECL_ARG_TYPE (formal));
if (mode != TYPE_MODE (TREE_TYPE (arg))
|| (mode == BLKmode
&& (TYPE_MAIN_VARIANT (TREE_TYPE (arg))
!= TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))
return (rtx) (HOST_WIDE_INT) -1;
}
for (; actual; actual = TREE_CHAIN (actual))
expand_expr (TREE_VALUE (actual), const0_rtx,
TYPE_MODE (TREE_TYPE (TREE_VALUE (actual))), 0);
pushlevel (0);
arg_vals = (rtx *) alloca (nargs * sizeof (rtx));
arg_trees = (tree *) alloca (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_stack_temp (TYPE_MODE (TREE_TYPE (arg)),
int_size_in_bytes (TREE_TYPE (arg)), 1);
MEM_SET_IN_STRUCT_P (stack_slot,
AGGREGATE_TYPE_P (TREE_TYPE (arg)));
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)))
arg_vals[i] = convert_modes (GET_MODE (loc),
TYPE_MODE (TREE_TYPE (arg)),
expand_expr (arg, NULL_RTX, mode,
EXPAND_SUM),
TREE_UNSIGNED (TREE_TYPE (formal)));
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)))
/ BITS_PER_UNIT));
}
map = (struct inline_remap *) alloca (sizeof (struct inline_remap));
map->fndecl = fndecl;
map->reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
bzero ((char *) map->reg_map, max_regno * sizeof (rtx));
real_label_map
= (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
map->label_map = real_label_map;
map->insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));
bzero ((char *) map->insn_map, INSN_UID (header) * sizeof (rtx));
map->min_insnno = 0;
map->max_insnno = INSN_UID (header);
map->integrating = 1;
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_PTR, NOTE_INSN_DELETED);
map->regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (header);
map->regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (header);
if (OUTGOING_ARGS_SIZE (header) > current_function_outgoing_args_size)
current_function_outgoing_args_size = OUTGOING_ARGS_SIZE (header);
if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE)
#ifdef MACHO_PIC
{
int regno = PIC_OFFSET_TABLE_REGNUM;
rtx orig = pic_offset_table_rtx;
if (regno > 0)
{
map->reg_map[regno] = orig;
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);
}
#endif
current_function_uses_pic_offset_table = 1;
#ifdef MACHO_PIC
}
#endif
if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_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)
{
;
}
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 ();
}
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);
subst_constants (&temp, NULL_RTX, map);
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 (DECL_RESULT (fndecl));
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);
subst_constants (&temp, NULL_RTX, map);
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);
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);
subst_constants (&temp, NULL_RTX, map);
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
abort ();
pushlevel (0);
expand_start_bindings (0);
bzero ((char *) &map->label_map [min_labelno],
(max_labelno - min_labelno) * sizeof (rtx));
emit_queue ();
do_pending_stack_adjust ();
global_const_equiv_varray = map->const_equiv_varray;
if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_CALLS_ALLOCA)
emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);
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 (GET_CODE (pattern) == USE
&& find_reg_note (insn, REG_EH_CONTEXT, 0) != 0)
get_eh_context ();
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));
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));
else
break;
}
else if (static_chain_value != 0
&& set != 0
&& GET_CODE (SET_DEST (set)) == REG
&& rtx_equal_p (SET_DEST (set),
static_chain_incoming_rtx))
break;
else if (static_chain_value != 0
&& set != 0
&& rtx_equal_p (SET_SRC (set),
static_chain_incoming_rtx))
{
rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map);
copy = emit_move_insn (newdest, static_chain_value);
static_chain_value = 0;
}
else
copy = emit_insn (copy_rtx_and_substitute (pattern, map));
#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
break;
case JUMP_INSN:
if (GET_CODE (PATTERN (insn)) == RETURN
|| (GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
{
if (local_return_label == 0)
local_return_label = gen_label_rtx ();
pattern = gen_jump (local_return_label);
}
else
pattern = copy_rtx_and_substitute (PATTERN (insn), map);
copy = emit_jump_insn (pattern);
#ifdef HAVE_cc0
if (cc0_insn)
try_constants (cc0_insn, map);
cc0_insn = 0;
#endif
try_constants (copy, map);
if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value)
{
#ifdef HAVE_cc0
delete_insn (PREV_INSN (copy));
#endif
if (map->last_pc_value == pc_rtx)
{
delete_insn (copy);
copy = 0;
}
else
emit_barrier ();
}
break;
case CALL_INSN:
pattern = copy_rtx_and_substitute (PATTERN (insn), map);
copy = emit_call_insn (pattern);
CALL_INSN_FUNCTION_USAGE (copy)
= copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
#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_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_EH_REGION_BEG
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
{
rtx label
= get_label_from_map (map, NOTE_BLOCK_NUMBER (copy));
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
{
eif_eh_map = map;
duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy),
CODE_LABEL_NUMBER (label),
expand_inline_function_eh_labelmap);
}
NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
}
}
else
copy = 0;
break;
default:
abort ();
break;
}
if (copy)
RTX_INTEGRATED_P (copy) = 1;
map->insn_map[INSN_UID (insn)] = copy;
}
map->const_age++;
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& map->insn_map[INSN_UID (insn)]
&& REG_NOTES (insn))
{
rtx tem = copy_rtx_and_substitute (REG_NOTES (insn), map);
subst_constants (&tem, NULL_RTX, map);
#ifdef NEXT_SEMANTICS
if (REG_NOTE_KIND (tem) == REG_EH_RETHROW)
{
int rgn_index = XINT (XEXP (tem, 0), 0);
if (rgn_index > 0)
{
rtx lab = get_label_from_map (map, rgn_index);
XEXP (tem, 0) = GEN_INT (CODE_LABEL_NUMBER (lab));
}
}
#endif
apply_change_group ();
REG_NOTES (map->insn_map[INSN_UID (insn)]) = tem;
}
if (local_return_label)
emit_label (local_return_label);
if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_CALLS_ALLOCA)
emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
inline_function_decl = fndecl;
integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector);
integrate_decl_tree ((tree) ORIGINAL_DECL_INITIAL (header), 0, map);
inline_function_decl = 0;
expand_end_bindings (getdecls (), 1, 1);
block = poplevel (1, 1, 0);
BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL
? fndecl : DECL_ABSTRACT_ORIGIN (fndecl));
poplevel (0, 0, 0);
if (flag_test_coverage)
emit_note (0, NOTE_REPEATED_LINE_NUMBER);
emit_line_note (input_filename, lineno);
if (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));
MEM_SET_IN_STRUCT_P (target, 1);
}
if (real_label_map)
free (real_label_map);
if (map)
VARRAY_FREE (map->const_equiv_varray);
return target;
}
static void
integrate_parm_decls (args, map, arg_vector)
tree args;
struct inline_remap *map;
rtvec arg_vector;
{
register tree tail;
register int i;
for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
{
register tree decl = build_decl (VAR_DECL, DECL_NAME (tail),
TREE_TYPE (tail));
rtx new_decl_rtl
= copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map);
DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (tail);
TREE_USED (decl) = 1;
DECL_ABSTRACT_ORIGIN (decl) = DECL_ORIGIN (tail);
pushdecl (decl);
subst_constants (&new_decl_rtl, NULL_RTX, map);
apply_change_group ();
DECL_RTL (decl) = new_decl_rtl;
}
}
static void
integrate_decl_tree (let, level, map)
tree let;
int level;
struct inline_remap *map;
{
tree t, node;
if (level > 0)
pushlevel (0);
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
{
tree d;
push_obstacks_nochange ();
saveable_allocation ();
d = copy_and_set_decl_abstract_origin (t);
pop_obstacks ();
if (DECL_RTL (t) != 0)
{
DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t), map);
subst_constants (&DECL_RTL (d), NULL_RTX, map);
apply_change_group ();
}
TREE_USED (d) = 1;
if (DECL_LANG_SPECIFIC (d))
copy_lang_decl (d);
pushdecl (d);
}
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
integrate_decl_tree (t, level + 1, map);
if (level > 0)
{
node = poplevel (1, 0, 0);
if (node)
{
TREE_USED (node) = TREE_USED (let);
BLOCK_ABSTRACT_ORIGIN (node) = let;
}
}
}
static void
save_constants_in_decl_trees (let)
tree let;
{
tree t;
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
if (DECL_RTL (t) != 0)
save_constants (&DECL_RTL (t));
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
save_constants_in_decl_trees (t);
}
rtx
copy_rtx_and_substitute (orig, map)
register rtx orig;
struct inline_remap *map;
{
register rtx copy, temp;
register int i, j;
register RTX_CODE code;
register enum machine_mode mode;
register 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)
{
if (map->reg_map[regno] != 0)
return map->reg_map[regno];
if (regno == VIRTUAL_STACK_VARS_REGNUM)
{
rtx loc, seq;
int size = DECL_FRAME_SIZE (map->fndecl);
#ifdef FRAME_GROWS_DOWNWARD
size = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
#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 / BITS_PER_UNIT);
#endif
SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
seq = gen_sequence ();
end_sequence ();
emit_insn_after (seq, map->insns_at_start);
return temp;
}
else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
{
rtx loc, seq;
int size = FUNCTION_ARGS_SIZE (DECL_SAVED_INSNS (map->fndecl));
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 / BITS_PER_UNIT);
#endif
SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
seq = gen_sequence ();
end_sequence ();
emit_insn_after (seq, map->insns_at_start);
return temp;
}
else if (REG_FUNCTION_VALUE_P (orig))
{
if (map->inline_target == 0)
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;
}
return orig;
}
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 (map->regno_pointer_flag[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);
if (GET_CODE (copy) == SUBREG)
return gen_rtx_SUBREG (GET_MODE (orig), SUBREG_REG (copy),
SUBREG_WORD (orig) + SUBREG_WORD (copy));
else if (GET_CODE (copy) == CONCAT)
{
rtx retval = subreg_realpart_p (orig) ? XEXP (copy, 0) : XEXP (copy, 1);
if (GET_MODE (retval) == GET_MODE (orig))
return retval;
else
return gen_rtx_SUBREG (GET_MODE (orig), retval,
(SUBREG_WORD (orig) %
(GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (orig)))
/ (unsigned) UNITS_PER_WORD)));
}
else
return gen_rtx_SUBREG (GET_MODE (orig), copy,
SUBREG_WORD (orig));
case ADDRESSOF:
copy = gen_rtx_ADDRESSOF (mode,
copy_rtx_and_substitute (XEXP (orig, 0), map), 0);
SET_ADDRESSOF_DECL (copy, 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 (map->regno_pointer_flag[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);
if (GET_CODE (copy) == SUBREG && GET_CODE (XEXP (orig, 0)) != SUBREG)
copy = SUBREG_REG (copy);
return gen_rtx_fmt_e (code, VOIDmode, copy);
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:
return orig;
case SYMBOL_REF:
if (CONSTANT_POOL_ADDRESS_P (orig))
{
rtx constant = get_pool_constant (orig);
if (GET_CODE (constant) == LABEL_REF)
return XEXP (force_const_mem (GET_MODE (orig),
copy_rtx_and_substitute (constant,
map)),
0);
}
else
if (SYMBOL_REF_NEED_ADJUST (orig))
{
eif_eh_map = map;
return rethrow_symbol_map (orig,
expand_inline_function_eh_labelmap);
}
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))
{
temp = copy_rtx_and_substitute (XEXP (orig, 0), map);
if (! CONSTANT_P (temp))
return temp;
return validize_mem (force_const_mem (GET_MODE (orig), temp));
}
break;
case ADDRESS:
if (! RTX_INTEGRATED_P (orig))
abort ();
temp
= force_const_mem (GET_MODE (XEXP (orig, 0)),
copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
map));
#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;
case ASM_OPERANDS:
if (map->orig_asm_operands_vector == XVEC (orig, 3))
{
copy = rtx_alloc (ASM_OPERANDS);
copy->volatil = orig->volatil;
XSTR (copy, 0) = XSTR (orig, 0);
XSTR (copy, 1) = XSTR (orig, 1);
XINT (copy, 2) = XINT (orig, 2);
XVEC (copy, 3) = map->copy_asm_operands_vector;
XVEC (copy, 4) = map->copy_asm_constraints_vector;
XSTR (copy, 5) = XSTR (orig, 5);
XINT (copy, 6) = XINT (orig, 6);
return copy;
}
break;
case CALL:
#ifndef NO_FUNCTION_CSE
if (! (optimize && ! flag_no_function_cse))
#endif
return gen_rtx_CALL (GET_MODE (orig),
gen_rtx_MEM (GET_MODE (XEXP (orig, 0)),
copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), map)),
copy_rtx_and_substitute (XEXP (orig, 1), map));
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);
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),
- loc_offset),
NULL_RTX));
}
break;
case MEM:
copy = rtx_alloc (MEM);
PUT_MODE (copy, mode);
XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map);
MEM_COPY_ATTRIBUTES (copy, orig);
MEM_ALIAS_SET (copy) = MEM_ALIAS_SET (orig);
if (! map->integrating)
RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
return copy;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, mode);
copy->in_struct = orig->in_struct;
copy->volatil = orig->volatil;
copy->unchanging = 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':
XEXP (copy, i) = XEXP (orig, i);
break;
case 'e':
XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i), map);
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);
}
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;
default:
abort ();
}
}
if (code == ASM_OPERANDS && map->orig_asm_operands_vector == 0)
{
map->orig_asm_operands_vector = XVEC (orig, 3);
map->copy_asm_operands_vector = XVEC (copy, 3);
map->copy_asm_constraints_vector = XVEC (copy, 4);
}
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);
apply_change_group ();
note_stores (PATTERN (insn), mark_stores);
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)
rtx *loc;
rtx insn;
struct inline_remap *map;
{
rtx x = *loc;
register int i;
register enum rtx_code code;
register 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 SYMBOL_REF:
case CONST:
case LABEL_REF:
case ADDRESS:
return;
#ifdef HAVE_cc0
case CC0:
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);
return;
case REG:
{
int regno = REGNO (x);
struct const_equiv_data *p;
if (! (regno < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x))
&& 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 (GET_CODE (SUBREG_REG (x)) == REG)
{
rtx inner = SUBREG_REG (x);
rtx new = 0;
subst_constants (&inner, NULL_RTX, map);
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
&& GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD
&& GET_MODE (SUBREG_REG (x)) != VOIDmode)
new = operand_subword (inner, SUBREG_WORD (x), 0,
GET_MODE (SUBREG_REG (x)));
cancel_changes (num_changes);
if (new == 0 && subreg_lowpart_p (x))
new = gen_lowpart_common (GET_MODE (x), inner);
if (new)
validate_change (insn, loc, new, 1);
return;
}
break;
case MEM:
subst_constants (&XEXP (x, 0), insn, map);
if (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;
subst_constants (&SET_SRC (x), insn, map);
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);
subst_constants (&XEXP (*dest_loc, 2), insn, map);
}
dest_loc = &XEXP (*dest_loc, 0);
}
if (GET_CODE (*dest_loc) == MEM)
subst_constants (&XEXP (*dest_loc, 0), insn, map);
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))))
{
map->equiv_sets[map->num_sets].equiv = copy_rtx (src);
map->equiv_sets[map->num_sets++].dest = dest;
}
}
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);
break;
case 'u':
case 'i':
case 's':
case 'w':
break;
case 'E':
if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
subst_constants (&XVECEXP (x, i, j), insn, map);
}
break;
default:
abort ();
}
}
if ((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);
}
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)
new = ((new == const0_rtx) ? CONST0_RTX (GET_MODE (x))
: CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
GET_MODE (x)));
#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 ();
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);
}
void
mark_stores (dest, x)
rtx dest;
rtx x ATTRIBUTE_UNUSED;
{
int regno = -1;
enum machine_mode mode;
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)) + SUBREG_WORD (dest);
mode = GET_MODE (SUBREG_REG (dest));
}
if (regno >= 0)
{
int last_reg = (regno >= FIRST_PSEUDO_REGISTER ? regno
: regno + HARD_REGNO_NREGS (regno, mode) - 1);
int i;
if (regno != VIRTUAL_INCOMING_ARGS_REGNUM
&& regno != VIRTUAL_STACK_VARS_REGNUM)
for (i = regno; i <= last_reg; i++)
if (i < VARRAY_SIZE (global_const_equiv_varray))
VARRAY_CONST_EQUIV (global_const_equiv_varray, i).rtx = 0;
}
}
static void
restore_constants (px)
rtx *px;
{
rtx x = *px;
int i, j;
char *fmt;
if (x == 0)
return;
if (GET_CODE (x) == CONST_DOUBLE)
{
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
REAL_VALUE_TYPE d;
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
*px = CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x));
}
else
*px = immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x),
VOIDmode);
}
else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == CONST)
{
restore_constants (&XEXP (x, 0));
*px = validize_mem (force_const_mem (GET_MODE (x), XEXP (x, 0)));
}
else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == SUBREG)
{
rtx new = XEXP (SUBREG_REG (x), 0);
restore_constants (&new);
new = force_const_mem (GET_MODE (SUBREG_REG (x)), new);
PUT_MODE (new, GET_MODE (x));
*px = validize_mem (new);
}
else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == ADDRESS)
{
rtx new = XEXP (force_const_mem (GET_MODE (XEXP (x, 0)),
XEXP (XEXP (x, 0), 0)),
0);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (new) != GET_MODE (x))
new = convert_memory_address (GET_MODE (x), new);
#endif
*px = new;
}
else
{
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
{
switch (*fmt++)
{
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
restore_constants (&XVECEXP (x, i, j));
break;
case 'e':
restore_constants (&XEXP (x, i));
break;
}
}
}
}
static void
set_block_origin_self (stmt)
register tree stmt;
{
if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE)
{
BLOCK_ABSTRACT_ORIGIN (stmt) = stmt;
{
register 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);
}
{
register tree subblock;
for (subblock = BLOCK_SUBBLOCKS (stmt);
subblock != NULL_TREE;
subblock = BLOCK_CHAIN (subblock))
set_block_origin_self (subblock);
}
}
}
static void
set_decl_origin_self (decl)
register tree decl;
{
if (DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE)
{
DECL_ABSTRACT_ORIGIN (decl) = decl;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
register 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)
register tree stmt;
register int setting;
{
register tree local_decl;
register 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)
register tree decl;
register int setting;
{
DECL_ABSTRACT (decl) = setting;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
register 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);
}
}
void
output_inline_function (fndecl)
tree fndecl;
{
rtx head;
rtx last;
temporary_allocation ();
head = DECL_SAVED_INSNS (fndecl);
current_function_decl = fndecl;
init_function_start (fndecl, "lossage", 1);
assign_parms (fndecl, 1);
assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl), 0);
reg_rtx_no = regno_pointer_flag_length = MAX_REGNUM (head);
regno_reg_rtx = (rtx *) INLINE_REGNO_REG_RTX (head);
regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (head);
regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (head);
max_parm_reg = MAX_PARMREG (head);
parm_reg_stack_loc = (rtx *) PARMREG_STACK_LOC (head);
stack_slot_list = STACK_SLOT_LIST (head);
forced_labels = FORCED_LABELS (head);
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_HAS_COMPUTED_JUMP)
current_function_has_computed_jump = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_CALLS_ALLOCA)
current_function_calls_alloca = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_CALLS_SETJMP)
current_function_calls_setjmp = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_CALLS_LONGJMP)
current_function_calls_longjmp = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_RETURNS_STRUCT)
current_function_returns_struct = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_RETURNS_PCC_STRUCT)
current_function_returns_pcc_struct = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_NEEDS_CONTEXT)
current_function_needs_context = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_HAS_NONLOCAL_LABEL)
current_function_has_nonlocal_label = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_RETURNS_POINTER)
current_function_returns_pointer = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_USES_CONST_POOL)
current_function_uses_const_pool = 1;
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE)
current_function_uses_pic_offset_table = 1;
current_function_outgoing_args_size = OUTGOING_ARGS_SIZE (head);
current_function_pops_args = POPS_ARGS (head);
immediate_size_expand--;
for (last = FIRST_PARM_INSN (head);
NEXT_INSN (last); last = NEXT_INSN (last))
{
if (GET_RTX_CLASS (GET_CODE (last)) == 'i')
{
restore_constants (&PATTERN (last));
restore_constants (®_NOTES (last));
}
}
set_new_first_and_last_insn (FIRST_PARM_INSN (head), last);
set_new_first_and_last_label_num (FIRST_LABELNO (head), LAST_LABELNO (head));
set_decl_origin_self (fndecl);
DECL_DEFER_OUTPUT (fndecl) = 0;
DECL_INLINE (fndecl) = 0;
rest_of_compilation (fndecl);
current_function_decl = 0;
}