/* Procedure integration for GCC.
- Copyright (C) 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "params.h"
#include "ggc.h"
#include "target.h"
-
-#include "obstack.h"
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
-extern struct obstack *function_maybepermanent_obstack;
+#include "langhooks.h"
/* Similar, but round to the next highest integer that meets the
alignment. */
\f
/* Private type used by {get/has}_func_hard_reg_initial_val. */
-typedef struct initial_value_pair {
+typedef struct initial_value_pair GTY(()) {
rtx hard_reg;
rtx pseudo;
} initial_value_pair;
-typedef struct initial_value_struct {
+typedef struct initial_value_struct GTY(()) {
int num_entries;
int max_entries;
- initial_value_pair *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 *));
function_attribute_inlinable_p (fndecl)
tree fndecl;
{
- bool has_machine_attr = false;
- tree a;
-
- for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a))
+ if (targetm.attribute_table)
{
- tree name = TREE_PURPOSE (a);
- int i;
+ tree a;
- for (i = 0; targetm.attribute_table[i].name != NULL; i++)
+ for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a))
{
- if (is_attribute_p (targetm.attribute_table[i].name, name))
- {
- has_machine_attr = true;
- break;
- }
+ 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);
}
- if (has_machine_attr)
- break;
}
- if (has_machine_attr)
- return (*targetm.function_attribute_inlinable_p) (fndecl);
- else
- return true;
+ return true;
}
/* Zero if the current function (whose FUNCTION_DECL is FNDECL)
return N_("function cannot be inline");
/* No inlines with varargs. */
- if ((last && TREE_VALUE (last) != void_type_node)
- || current_function_varargs)
+ if (last && TREE_VALUE (last) != void_type_node)
return N_("varargs function cannot be inline");
if (current_function_calls_alloca)
/* We will not inline a function which uses computed goto. The addresses of
its local labels, which may be tucked into global storage, are of course
- not constant across instantiations, which causes unexpected behaviour. */
+ not constant across instantiations, which causes unexpected behavior. */
if (current_function_has_computed_jump)
return N_("function with computed jump cannot inline");
}
/* If the function has a target specific attribute attached to it,
- then we assume that we should not inline it. This can be overriden
+ then we assume that we should not inline it. This can be overridden
by the target if it defines TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. */
if (!function_attribute_inlinable_p (fndecl))
return N_("function with target specific attribute(s) cannot be inlined");
/* Copy the declaration. */
if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL)
{
+ tree type;
+ int invisiref = 0;
+
+ /* See if the frontend wants to pass this by invisible reference. */
+ 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);
+
/* For a parameter, we must make an equivalent VAR_DECL, not a
new PARM_DECL. */
- copy = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
- TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
- TREE_READONLY (copy) = TREE_READONLY (decl);
- TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (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);
- if (DECL_LANG_SPECIFIC (copy))
- copy_lang_decl (copy);
+ (*lang_hooks.dup_lang_specific_decl) (copy);
/* TREE_ADDRESSABLE isn't used to indicate that a label's
address has been taken; it's for internal bookkeeping in
DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl);
/* The new variable/label has no RTL, yet. */
- SET_DECL_RTL (copy, NULL_RTX);
+ if (!TREE_STATIC (copy) && !DECL_EXTERNAL (copy))
+ SET_DECL_RTL (copy, NULL_RTX);
/* These args would always appear unused, if not for this. */
TREE_USED (copy) = 1;
;
else if (DECL_CONTEXT (decl) != from_fn)
/* Things that weren't in the scope of the function we're inlining
- from aren't in the scope we're inlining too, either. */
+ from aren't in the scope we're inlining to, either. */
;
else if (TREE_STATIC (decl))
- /* Function-scoped static variables should say in the original
+ /* Function-scoped static variables should stay in the original
function. */
;
else
}
/* Compare two BLOCKs for qsort. The key we sort on is the
- BLOCK_ABSTRACT_ORIGIN of the blocks. */
+ BLOCK_ABSTRACT_ORIGIN of the blocks. We cannot just subtract the
+ two pointers, because it may overflow sizeof(int). */
static int
compare_blocks (v1, 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);
- return ((char *) BLOCK_ABSTRACT_ORIGIN (b1)
- - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+ if (p1 == p2)
+ return 0;
+ return p1 < p2 ? -1 : 1;
}
/* Compare two BLOCKs for bsearch. The first pointer corresponds to
{
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);
- return ((const char *) b1 - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+ if (p1 == p2)
+ return 0;
+ return p1 < p2 ? -1 : 1;
}
/* Integrate the procedure defined by FNDECL. Note that this function
rtx stack_save = 0;
rtx temp;
struct inline_remap *map = 0;
- rtvec arg_vector = (rtvec) inl_f->original_arg_vector;
+ rtvec arg_vector = inl_f->original_arg_vector;
rtx static_chain_value = 0;
int inl_max_uid;
int eh_region_offset;
??? These numbers are quite arbitrary and were obtained by
experimentation. At some point, we should try to allocate the
- table after all the parameters are set up so we an more accurately
+ table after all the parameters are set up so we can more accurately
estimate the number of pseudos we will need. */
VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray,
if (inl_f->needs_context)
static_chain_value = lookup_static_chain (fndecl);
+ /* If the inlined function calls __builtin_constant_p, then we'll
+ need to call purge_builtin_constant_p on this function. */
+ if (inl_f->calls_constant_p)
+ current_function_calls_constant_p = 1;
+
if (GET_CODE (parm_insns) == NOTE
&& NOTE_LINE_NUMBER (parm_insns) > 0)
{
this block to the list of blocks at this binding level. We
can't do it the way it's done for function-at-a-time mode the
superblocks have not been created yet. */
- insert_block (block);
+ (*lang_hooks.decls.insert_block) (block);
else
{
BLOCK_CHAIN (block)
free (real_label_map);
VARRAY_FREE (map->const_equiv_varray);
free (map->reg_map);
- VARRAY_FREE (map->block_map);
free (map->insn_map);
free (map);
free (arg_vals);
Copying is done in two passes, first the insns and then their REG_NOTES.
- If static_chain_value is non-zero, it represents the context-pointer
+ If static_chain_value is nonzero, it represents the context-pointer
register for the function. */
static void
memory references via that register can then be
identified as static chain references. We assume that
the register is only assigned once, and that the static
- chain address is only live in one register at a time. */
+ chain address is only live in one register at a time. */
else if (static_chain_value != 0
&& set != 0
#else
try_constants (copy, map);
#endif
+ INSN_SCOPE (copy) = INSN_SCOPE (insn);
break;
case JUMP_INSN:
cc0_insn = 0;
#endif
try_constants (copy, map);
+ INSN_SCOPE (copy) = INSN_SCOPE (insn);
/* If this used to be a conditional jump insn but whose branch
direction is now know, we must do something special. */
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);
/* Because the USAGE information potentially contains objects other
than hard registers, we need to copy it. */
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 ();
}
SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
- seq = gen_sequence ();
+ seq = get_insns ();
end_sequence ();
emit_insn_after (seq, map->insns_at_start);
return temp;
SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
- seq = gen_sequence ();
+ seq = get_insns ();
end_sequence ();
emit_insn_after (seq, map->insns_at_start);
return temp;
RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (temp);
/* A reg with REG_FUNCTION_VALUE_P true will never reach here. */
- if (REG_POINTER (map->x_regno_reg_rtx[regno]))
+ /* Objects may initially be represented as registers, but
+ but turned into a MEM if their address is taken by
+ put_var_into_stack. Therefore, the register table may have
+ entries which are MEMs.
+
+ We briefly tried to clear such entries, but that ended up
+ cascading into many changes due to the optimizers not being
+ prepared for empty entries in the register table. So we've
+ decided to allow the MEMs in the register table for now. */
+ 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]);
if (map->orig_asm_operands_vector == ASM_OPERANDS_INPUT_VEC (orig))
{
copy = rtx_alloc (ASM_OPERANDS);
- copy->volatil = orig->volatil;
+ 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)
if (inlining && !for_lhs)
RTX_UNCHANGING_P (copy) = 0;
+ /* If inlining, squish aliasing data that references the subroutine's
+ parameter list, since that's no longer applicable. */
+ 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:
copy = rtx_alloc (code);
PUT_MODE (copy, mode);
- copy->in_struct = orig->in_struct;
- copy->volatil = orig->volatil;
- copy->unchanging = orig->unchanging;
+ 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));
{
src = SET_SRC (x);
if (GET_MODE_CLASS (GET_MODE (src)) == MODE_CC
-#ifdef HAVE_cc0
- || dest == cc0_rtx
-#endif
- )
+ || CC0_P (dest))
{
compare_mode = GET_MODE (XEXP (src, 0));
if (compare_mode == VOIDmode)
|| REGNO (XEXP (src, 0)) == VIRTUAL_STACK_VARS_REGNUM)
&& CONSTANT_P (XEXP (src, 1)))
|| GET_CODE (src) == COMPARE
-#ifdef HAVE_cc0
- || dest == cc0_rtx
-#endif
+ || CC0_P (dest)
|| (dest == pc_rtx
&& (src == pc_rtx || GET_CODE (src) == RETURN
|| GET_CODE (src) == LABEL_REF))))
if (compare_mode != VOIDmode
&& GET_CODE (src) == COMPARE
&& (GET_MODE_CLASS (GET_MODE (src)) == MODE_CC
-#ifdef HAVE_cc0
- || dest == cc0_rtx
-#endif
- )
+ || CC0_P (dest))
&& GET_MODE (XEXP (src, 0)) == VOIDmode
&& GET_MODE (XEXP (src, 1)) == VOIDmode)
{
case 'w':
case 'n':
case 't':
+ case 'B':
break;
case 'E':
from its DECL_SAVED_INSNS. Used for inline functions that are output
at end of compilation instead of where they came in the source. */
+static GTY(()) struct function *old_cfun;
+
void
output_inline_function (fndecl)
tree fndecl;
{
- struct function *old_cfun = cfun;
enum debug_info_type old_write_symbols = write_symbols;
- struct gcc_debug_hooks *old_debug_hooks = debug_hooks;
+ 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;
- clear_emit_caches ();
set_new_last_label_num (f->inl_max_label_num);
debug_hooks = &do_nothing_debug_hooks;
}
+ /* Make sure warnings emitted by the optimizers (e.g. control reaches
+ end of non-void function) is not wildly incorrect. */
+ input_filename = DECL_SOURCE_FILE (fndecl);
+ lineno = DECL_SOURCE_LINE (fndecl);
+
/* Compile this function all the way down to assembly code. As a
side effect this destroys the saved RTL representation, but
that's okay, because we don't need to inline this anymore. */
if (ivs == 0)
{
- fun->hard_reg_initial_vals = (void *) xmalloc (sizeof (initial_value_struct));
+ 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 *) xmalloc (5 * sizeof (initial_value_pair));
+ 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 *) xrealloc (ivs->entries,
- ivs->max_entries
- * sizeof (initial_value_pair));
+ (initial_value_pair *) ggc_realloc (ivs->entries,
+ ivs->max_entries
+ * sizeof (initial_value_pair));
}
ivs->entries[ivs->num_entries].hard_reg = reg;
return has_func_hard_reg_initial_val (cfun, gen_rtx_REG (mode, regno));
}
-void
-mark_hard_reg_initial_vals (fun)
- struct function *fun;
-{
- struct initial_value_struct *ivs = fun->hard_reg_initial_vals;
- int i;
-
- if (ivs == 0)
- return;
-
- for (i = 0; i < ivs->num_entries; i ++)
- {
- ggc_mark_rtx (ivs->entries[i].hard_reg);
- ggc_mark_rtx (ivs->entries[i].pseudo);
- }
-}
-
static void
setup_initial_hard_reg_value_integration (inl_f, remap)
struct function *inl_f;
seq = get_insns ();
end_sequence ();
- emit_insns_after (seq, get_insns ());
+ emit_insn_after (seq, get_insns ());
}
/* If the backend knows where to allocate pseudos for hard
}
#endif
}
+
+#include "gt-integrate.h"