#include "config.h"
#include "system.h"
#include "toplev.h"
#include "tree.h"
#include "tree-inline.h"
#include "rtl.h"
#include "expr.h"
#include "flags.h"
#include "params.h"
#include "input.h"
#include "insn-config.h"
#include "integrate.h"
#include "varray.h"
#include "hashtab.h"
#include "splay-tree.h"
#include "langhooks.h"
#include "cgraph.h"
#include "feedback.h"
#include "function.h"
#ifndef INLINER_FOR_JAVA
#include "c-common.h"
#else
#include "parse.h"
#include "java-tree.h"
#endif
int flag_inline_trees = 0;
typedef struct inline_data
{
varray_type fns;
unsigned first_inlined_fn;
tree ret_label;
splay_tree decl_map;
int in_target_cleanup_p;
varray_type target_exprs;
varray_type inlined_fns;
int inlined_stmts;
bool cloning_p;
htab_t tree_pruner;
tree decl;
double scale;
HOST_WIDEST_INT return_label_execution_count;
} inline_data;
static tree declare_return_variable PARAMS ((inline_data *, tree *));
static tree copy_body_r PARAMS ((tree *, int *, void *));
static tree copy_body PARAMS ((inline_data *));
static tree expand_call_inline PARAMS ((tree *, int *, void *));
static void expand_calls_inline PARAMS ((tree *, inline_data *));
static int inlinable_function_p PARAMS ((tree, inline_data *, int));
static tree remap_decl PARAMS ((tree, inline_data *));
#ifndef INLINER_FOR_JAVA
static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree));
static void remap_block PARAMS ((tree, tree, inline_data *));
static void copy_scope_stmt PARAMS ((tree *, int *, inline_data *));
#else
static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree, tree));
static void remap_block PARAMS ((tree *, tree, inline_data *));
static tree add_stmt_to_compound PARAMS ((tree, tree, tree));
#endif
static tree find_alloca_call_1 PARAMS ((tree *, int *, void *));
static tree find_builtin_longjmp_call_1 PARAMS ((tree *, int *, void *));
#define INSNS_PER_STMT (10)
static tree
remap_decl (decl, id)
tree decl;
inline_data *id;
{
splay_tree_node n;
tree fn;
fn = VARRAY_TOP_TREE (id->fns);
if (! (*lang_hooks.tree_inlining.auto_var_in_fn_p) (decl, fn))
return NULL_TREE;
n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
if (!n)
{
tree t;
t = copy_decl_for_inlining (decl, fn,
VARRAY_TREE (id->fns, 0));
if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
&& TYPE_DOMAIN (TREE_TYPE (t)))
{
TREE_TYPE (t) = copy_node (TREE_TYPE (t));
TYPE_DOMAIN (TREE_TYPE (t))
= copy_node (TYPE_DOMAIN (TREE_TYPE (t)));
walk_tree (&TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))),
copy_body_r, id, NULL);
}
#ifndef INLINER_FOR_JAVA
if (! DECL_NAME (t) && TREE_TYPE (t)
&& (*lang_hooks.tree_inlining.anon_aggr_type_p) (TREE_TYPE (t)))
{
tree members = NULL;
tree src;
for (src = DECL_ANON_UNION_ELEMS (t); src;
src = TREE_CHAIN (src))
{
tree member = remap_decl (TREE_VALUE (src), id);
if (TREE_PURPOSE (src))
abort ();
members = tree_cons (NULL, member, members);
}
DECL_ANON_UNION_ELEMS (t) = nreverse (members);
}
#endif
n = splay_tree_insert (id->decl_map,
(splay_tree_key) decl,
(splay_tree_value) t);
}
return (tree) n->value;
}
#ifndef INLINER_FOR_JAVA
#else
#endif
static void
#ifndef INLINER_FOR_JAVA
remap_block (scope_stmt, decls, id)
tree scope_stmt;
#else
remap_block (block, decls, id)
tree *block;
#endif
tree decls;
inline_data *id;
{
#ifndef INLINER_FOR_JAVA
if (id->in_target_cleanup_p)
{
SCOPE_STMT_BLOCK (scope_stmt) = NULL_TREE;
return;
}
if (SCOPE_BEGIN_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt))
{
tree old_block;
tree new_block;
tree old_var;
tree fn;
old_block = SCOPE_STMT_BLOCK (scope_stmt);
new_block = make_node (BLOCK);
TREE_USED (new_block) = TREE_USED (old_block);
BLOCK_ABSTRACT_ORIGIN (new_block) = old_block;
SCOPE_STMT_BLOCK (scope_stmt) = new_block;
for (old_var = decls ? decls : BLOCK_VARS (old_block);
old_var;
old_var = TREE_CHAIN (old_var))
{
tree new_var;
new_var = remap_decl (old_var, id);
if (!new_var || !DECL_P (new_var))
;
else
{
TREE_CHAIN (new_var) = BLOCK_VARS (new_block);
BLOCK_VARS (new_block) = new_var;
}
}
BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
fn = VARRAY_TREE (id->fns, 0);
if (id->cloning_p)
(*lang_hooks.decls.insert_block) (new_block);
else
{
tree *first_block;
if (DECL_INITIAL (fn))
first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));
else
first_block = &DECL_INITIAL (fn);
BLOCK_CHAIN (new_block) = *first_block;
*first_block = new_block;
}
splay_tree_insert (id->decl_map,
(splay_tree_key) old_block,
(splay_tree_value) new_block);
}
else if (SCOPE_END_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt))
{
splay_tree_node n;
n = splay_tree_lookup (id->decl_map,
(splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt));
if (! n)
abort ();
SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;
}
#else
tree old_block;
tree new_block;
tree old_var;
tree fn;
old_block = *block;
new_block = make_node (BLOCK);
TREE_USED (new_block) = TREE_USED (old_block);
BLOCK_ABSTRACT_ORIGIN (new_block) = old_block;
BLOCK_SUBBLOCKS (new_block) = BLOCK_SUBBLOCKS (old_block);
TREE_SIDE_EFFECTS (new_block) = TREE_SIDE_EFFECTS (old_block);
TREE_TYPE (new_block) = TREE_TYPE (old_block);
*block = new_block;
for (old_var = decls ? decls : BLOCK_VARS (old_block);
old_var;
old_var = TREE_CHAIN (old_var))
{
tree new_var;
if (LOCAL_CLASS_INITIALIZATION_FLAG_P (old_var))
{
if (! splay_tree_lookup (id->decl_map, (splay_tree_key) old_var))
{
tree outermost_block;
new_var = remap_decl (old_var, id);
DECL_ABSTRACT_ORIGIN (new_var) = NULL;
outermost_block = DECL_SAVED_TREE (current_function_decl);
TREE_CHAIN (new_var) = BLOCK_VARS (outermost_block);
BLOCK_VARS (outermost_block) = new_var;
}
continue;
}
new_var = remap_decl (old_var, id);
if (!new_var || !DECL_P (new_var))
;
else
{
TREE_CHAIN (new_var) = BLOCK_VARS (new_block);
BLOCK_VARS (new_block) = new_var;
}
}
BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
fn = VARRAY_TREE (id->fns, 0);
splay_tree_insert (id->decl_map,
(splay_tree_key) old_block,
(splay_tree_value) new_block);
#endif
}
#ifndef INLINER_FOR_JAVA
static void
copy_scope_stmt (tp, walk_subtrees, id)
tree *tp;
int *walk_subtrees;
inline_data *id;
{
tree block;
block = SCOPE_STMT_BLOCK (*tp);
copy_tree_r (tp, walk_subtrees, NULL);
SCOPE_STMT_BLOCK (*tp) = block;
remap_block (*tp, NULL_TREE, id);
}
#endif
static tree
copy_body_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees;
void *data;
{
inline_data* id;
tree fn, orig_tree = *tp;
tree goto_stmt = NULL_TREE;
id = (inline_data *) data;
fn = VARRAY_TOP_TREE (id->fns);
#if 0
if ((TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == LABEL_DECL)
&& DECL_NAMESPACE_SCOPE_P (*tp))
if (! DECL_EXTERNAL (*tp) && ! TREE_STATIC (*tp))
abort ();
#endif
#ifdef INLINER_FOR_JAVA
if (TREE_CODE (*tp) == BLOCK)
remap_block (tp, NULL_TREE, id);
#endif
#ifndef INLINER_FOR_JAVA
if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label)
#else
if (TREE_CODE (*tp) == RETURN_EXPR && id->ret_label)
#endif
{
tree return_stmt = *tp;
#ifndef INLINER_FOR_JAVA
goto_stmt = build_stmt (GOTO_STMT, id->ret_label);
TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt);
GOTO_FAKE_P (goto_stmt) = 1;
#else
tree assignment = TREE_OPERAND (return_stmt, 0);
goto_stmt = build1 (GOTO_EXPR, void_type_node, id->ret_label);
TREE_SIDE_EFFECTS (goto_stmt) = 1;
#endif
#ifndef INLINER_FOR_JAVA
if (RETURN_STMT_EXPR (return_stmt))
{
*tp = build_stmt (EXPR_STMT,
RETURN_STMT_EXPR (return_stmt));
STMT_IS_FULL_EXPR_P (*tp) = 1;
TREE_CHAIN (*tp) = goto_stmt;
}
#else
if (assignment)
{
copy_body_r (&assignment, walk_subtrees, data);
*tp = build (COMPOUND_EXPR, void_type_node, assignment, goto_stmt);
TREE_SIDE_EFFECTS (*tp) = 1;
}
#endif
else
*tp = goto_stmt;
}
else if ((*lang_hooks.tree_inlining.auto_var_in_fn_p) (*tp, fn))
{
tree new_decl;
new_decl = remap_decl (*tp, id);
if (! new_decl)
abort ();
STRIP_TYPE_NOPS (new_decl);
*tp = new_decl;
}
#if 0
else if (nonstatic_local_decl_p (*tp)
&& DECL_CONTEXT (*tp) != VARRAY_TREE (id->fns, 0))
abort ();
#endif
else if (TREE_CODE (*tp) == SAVE_EXPR)
remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0),
walk_subtrees);
else if (TREE_CODE (*tp) == UNSAVE_EXPR)
abort ();
#ifndef INLINER_FOR_JAVA
else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p)
copy_scope_stmt (tp, walk_subtrees, id);
#else
else if (TREE_CODE (*tp) == LABELED_BLOCK_EXPR)
{
tree new_block = copy_node (*tp);
splay_tree_insert (id->decl_map,
(splay_tree_key) *tp,
(splay_tree_value) new_block);
*tp = new_block;
}
else if (TREE_CODE (*tp) == EXIT_BLOCK_EXPR)
{
splay_tree_node n
= splay_tree_lookup (id->decl_map,
(splay_tree_key) TREE_OPERAND (*tp, 0));
if (! n)
abort ();
*tp = copy_node (*tp);
TREE_OPERAND (*tp, 0) = (tree) n->value;
}
#endif
else
{
copy_tree_r (tp, walk_subtrees, NULL);
if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
{
TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
TREE_OPERAND (*tp, 3) = NULL_TREE;
}
else if (TREE_CODE (*tp) == MODIFY_EXPR
&& TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
&& ((*lang_hooks.tree_inlining.auto_var_in_fn_p)
(TREE_OPERAND (*tp, 0), fn)))
{
tree decl = TREE_OPERAND (*tp, 0), value;
splay_tree_node n;
n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
if (n)
{
value = (tree) n->value;
STRIP_TYPE_NOPS (value);
if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
*tp = value;
}
}
}
if (flag_use_feedback)
{
int i;
HOST_WIDEST_INT N;
if (TREE_CODE (orig_tree) == CALL_EXPR)
{
if ((N = times_call_executed (orig_tree)) != -1)
set_times_call_executed (*tp, (HOST_WIDEST_INT)(N * id->scale));
}
else if (TREE_CODE (orig_tree) == TREE_CODE (*tp)
&& TREE_CODE (orig_tree) != FUNCTION_DECL
&& orig_tree != id->ret_label)
{
for (i=0; i < (int)n_slots(orig_tree); i++)
if ((N = times_arc_executed (orig_tree, i)) != -1)
set_times_arc_executed (*tp, i, (HOST_WIDEST_INT)(N * id->scale));
}
else
{
switch (TREE_CODE (orig_tree))
{
#ifdef INLINER_FOR_JAVA
case RETURN_EXPR:
#else
case RETURN_STMT:
#endif
N = times_arc_executed (orig_tree, 0);
if (N != -1)
{
if (TREE_CODE (*tp) == GOTO_STMT)
set_times_arc_executed (goto_stmt, 0,
(HOST_WIDEST_INT)(N * id->scale));
else
set_times_arc_executed (goto_stmt, 0, N);
if (id->ret_label)
set_times_arc_executed (id->ret_label, 0,
times_arc_executed (id->ret_label, 0) - N);
}
break;
case FUNCTION_DECL:
case PARM_DECL:
case RESULT_DECL:
case LABEL_DECL:
break;
default:
abort();
}
}
}
return NULL_TREE;
}
static tree
copy_body (id)
inline_data *id;
{
tree body;
body = DECL_SAVED_TREE (VARRAY_TOP_TREE (id->fns));
walk_tree (&body, copy_body_r, id, NULL);
return body;
}
static tree
#ifndef INLINER_FOR_JAVA
initialize_inlined_parameters (id, args, fn)
#else
initialize_inlined_parameters (id, args, fn, block)
#endif
inline_data *id;
tree args;
tree fn;
#ifdef INLINER_FOR_JAVA
tree block;
#endif
{
tree init_stmts;
tree parms;
tree a;
tree p;
#ifdef INLINER_FOR_JAVA
tree vars = NULL_TREE;
#endif
parms = DECL_ARGUMENTS (fn);
init_stmts = NULL_TREE;
for (p = parms, a = args; p;
a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))
{
#ifndef INLINER_FOR_JAVA
tree init_stmt;
tree cleanup;
#endif
tree var;
tree value;
tree var_sub;
value = (*lang_hooks.tree_inlining.convert_parm_for_inlining)
(p, a ? TREE_VALUE (a) : NULL_TREE, fn);
if (TREE_READONLY (p)
&& !TREE_ADDRESSABLE (p)
&& value && !TREE_SIDE_EFFECTS (value))
{
value = fold (DECL_P (value) ? decl_constant_value (value) : value);
if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
{
if (DECL_P (value))
value = build1 (NOP_EXPR, TREE_TYPE (value), value);
else if (TREE_TYPE (value) != TREE_TYPE (p))
value = fold (build1 (NOP_EXPR, TREE_TYPE (p), value));
splay_tree_insert (id->decl_map,
(splay_tree_key) p,
(splay_tree_value) value);
continue;
}
}
var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
if (TREE_TYPE (var) != TREE_TYPE (p)
&& POINTER_TYPE_P (TREE_TYPE (var))
&& TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))
var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var);
else
var_sub = var;
splay_tree_insert (id->decl_map,
(splay_tree_key) p,
(splay_tree_value) var_sub);
#ifndef INLINER_FOR_JAVA
init_stmt = build_stmt (DECL_STMT, var);
TREE_CHAIN (init_stmt) = init_stmts;
init_stmts = init_stmt;
#else
TREE_CHAIN (var) = vars;
vars = var;
#endif
if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
#ifndef INLINER_FOR_JAVA
DECL_INITIAL (var) = value;
else
{
TREE_READONLY (var) = 0;
{
tree new_type = copy_node (TREE_TYPE (var));
TREE_READONLY (new_type) = 0;
TREE_TYPE (var) = new_type;
}
init_stmt = build_stmt (EXPR_STMT,
build (INIT_EXPR, TREE_TYPE (p),
var, value));
TREE_CHAIN (init_stmt) = init_stmts;
init_stmts = init_stmt;
}
cleanup = (*lang_hooks.maybe_build_cleanup) (var);
if (cleanup)
{
tree cleanup_stmt;
cleanup_stmt = build_stmt (CLEANUP_STMT, var, cleanup);
TREE_CHAIN (cleanup_stmt) = init_stmts;
init_stmts = cleanup_stmt;
}
#else
{
tree assignment = build (MODIFY_EXPR, TREE_TYPE (p), var, value);
init_stmts = add_stmt_to_compound (init_stmts, TREE_TYPE (p),
assignment);
}
else
{
abort ();
}
#endif
}
#ifndef INLINER_FOR_JAVA
for (; a; a = TREE_CHAIN (a))
{
tree init_stmt;
tree value = TREE_VALUE (a);
if (! value || ! TREE_SIDE_EFFECTS (value))
continue;
init_stmt = build_stmt (EXPR_STMT, value);
TREE_CHAIN (init_stmt) = init_stmts;
init_stmts = init_stmt;
}
return nreverse (init_stmts);
#else
BLOCK_VARS (block) = nreverse (vars);
return init_stmts;
#endif
}
#ifndef INLINER_FOR_JAVA
static tree
declare_return_variable (id, use_stmt)
struct inline_data *id;
tree *use_stmt;
#else
static tree
declare_return_variable (id, var)
struct inline_data *id;
tree *var;
#endif
{
tree fn = VARRAY_TOP_TREE (id->fns);
tree result = DECL_RESULT (fn);
#ifndef INLINER_FOR_JAVA
tree var;
#endif
int need_return_decl = 1;
if (!result || VOID_TYPE_P (TREE_TYPE (result)))
{
#ifndef INLINER_FOR_JAVA
*use_stmt = NULL_TREE;
#else
*var = NULL_TREE;
#endif
return NULL_TREE;
}
#ifndef INLINER_FOR_JAVA
var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
(result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
&need_return_decl, &id->target_exprs));
splay_tree_insert (id->decl_map,
(splay_tree_key) result,
(splay_tree_value) var);
if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE (fn)))
*use_stmt = build_stmt (EXPR_STMT, var);
else
*use_stmt = build_stmt (EXPR_STMT,
build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)),
var));
TREE_ADDRESSABLE (*use_stmt) = 1;
if (need_return_decl)
return build_stmt (DECL_STMT, var);
#else
*var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
(result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
&need_return_decl, NULL_TREE));
splay_tree_insert (id->decl_map,
(splay_tree_key) result,
(splay_tree_value) *var);
DECL_IGNORED_P (*var) = 1;
if (need_return_decl)
return *var;
#endif
else
return NULL_TREE;
}
int
tree_inlinable_function_p (fn, nolimit)
tree fn;
int nolimit;
{
return inlinable_function_p (fn, NULL, nolimit);
}
static tree
find_alloca_call_1 (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
if (alloca_call_p (*tp))
return *tp;
return NULL;
}
tree
find_alloca_call (exp)
tree exp;
{
const char *file = input_filename;
tree ret = walk_tree (&exp, find_alloca_call_1, NULL, NULL);
input_filename = file;
return ret;
}
static tree
find_builtin_longjmp_call_1 (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
tree exp = *tp, decl;
if (TREE_CODE (exp) == CALL_EXPR
&& TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& (decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
TREE_CODE (decl) == FUNCTION_DECL)
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (decl) == BUILT_IN_LONGJMP)
return decl;
return NULL;
}
tree
find_builtin_longjmp_call (exp)
tree exp;
{
const char *file = input_filename;
tree ret = walk_tree (&exp, find_builtin_longjmp_call_1, NULL, NULL);
input_filename = file;
return ret;
}
static int
inlinable_function_p (fn, id, nolimit)
tree fn;
inline_data *id;
int nolimit;
{
int inlinable;
int currfn_insns;
int max_inline_insns_single = MAX_INLINE_INSNS_SINGLE;
if (DECL_UNINLINABLE (fn))
return 0;
inlinable = 0;
if (DID_INLINE_FUNC (fn))
max_inline_insns_single = MAX_INLINE_INSNS_AUTO;
currfn_insns = DECL_NUM_STMTS (fn) * INSNS_PER_STMT;
if (! flag_inline_trees)
;
else if (! DECL_INLINE (fn) && !nolimit)
;
#ifdef INLINER_FOR_JAVA
else if (METHOD_SYNCHRONIZED (fn))
;
#endif
else if (!nolimit
&& ! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
&& currfn_insns > max_inline_insns_single)
;
else if (find_builtin_longjmp_call (DECL_SAVED_TREE (fn)))
;
else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL
&& find_alloca_call (DECL_SAVED_TREE (fn)))
;
else
inlinable = 1;
DECL_UNINLINABLE (fn) = ! inlinable;
if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
&& inlinable && !nolimit)
{
int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
+ currfn_insns;
if (sum_insns > MAX_INLINE_INSNS * 128)
inlinable = 0;
else if ((sum_insns > MAX_INLINE_INSNS)
&& (currfn_insns > MIN_INLINE_INSNS))
{
int max_curr = MAX_INLINE_INSNS_SINGLE
- (sum_insns - MAX_INLINE_INSNS) / MAX_INLINE_SLOPE;
if (currfn_insns > max_curr)
inlinable = 0;
}
}
if (inlinable && (*lang_hooks.tree_inlining.cannot_inline_tree_fn) (&fn))
inlinable = 0;
if (! DECL_SAVED_TREE (fn))
inlinable = 0;
if (! inlinable || DECL_UNINLINABLE (fn))
return 0;
if (id)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (id->fns); ++i)
if (VARRAY_TREE (id->fns, i) == fn)
return 0;
if (DECL_INLINED_FNS (fn))
{
int j;
tree inlined_fns = DECL_INLINED_FNS (fn);
for (j = 0; j < TREE_VEC_LENGTH (inlined_fns); ++j)
if (TREE_VEC_ELT (inlined_fns, j) == VARRAY_TREE (id->fns, 0))
return 0;
}
}
return inlinable;
}
tree *
expand_one_call_inline (tp, fn, data)
tree *tp;
tree fn;
void *data;
{
inline_data *id;
tree t;
tree expr;
tree stmt;
#ifndef INLINER_FOR_JAVA
tree chain;
tree scope_stmt;
tree use_stmt;
#else
tree retvar;
#endif
tree *body;
tree arg_inits;
tree *inlined_body;
splay_tree st;
tree actparms;
tree saved_return_type;
tree funtype;
CUMULATIVE_ARGS args_so_far;
id = (inline_data *) data;
t = *tp;
if (TREE_CODE (t) != CALL_EXPR)
return (tree *)NULL;
if (! DECL_INITIAL (fn)
&& DECL_ABSTRACT_ORIGIN (fn)
&& DECL_SAVED_TREE (DECL_ABSTRACT_ORIGIN (fn)))
fn = DECL_ABSTRACT_ORIGIN (fn);
if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
return (tree *)NULL;
push_srcloc (DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn));
#ifndef INLINER_FOR_JAVA
expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), make_node (COMPOUND_STMT));
STMT_EXPR_NO_SCOPE (expr) = 1;
stmt = STMT_EXPR_STMT (expr);
#else
stmt = NULL;
expr = build (BLOCK, TREE_TYPE (TREE_TYPE (fn)), stmt);
#endif
st = id->decl_map;
id->decl_map = splay_tree_new (splay_tree_compare_pointers,
NULL, NULL);
actparms = TREE_OPERAND (t, 1);
if (TREE_ASM_WRITTEN (fn) || DECL_SAVED_INSNS (fn))
{
funtype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
saved_return_type = TREE_TYPE (funtype);
TREE_TYPE (funtype) = TREE_TYPE (t);
INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, 0);
TREE_TYPE (funtype) = saved_return_type;
#ifdef REARRANGE_ARG_LIST
actparms = REARRANGE_ARG_LIST (args_so_far, actparms);
#endif
}
#ifndef INLINER_FOR_JAVA
arg_inits = initialize_inlined_parameters (id, actparms, fn);
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
#else
arg_inits = initialize_inlined_parameters (id, TREE_OPERAND (t, 1), fn, expr);
if (arg_inits)
{
BLOCK_EXPR_BODY (expr) = add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
TREE_TYPE (arg_inits),
arg_inits);
}
#endif
VARRAY_PUSH_TREE (id->fns, fn);
if (! DECL_INLINED_FNS (fn))
{
int i;
for (i = VARRAY_ACTIVE_SIZE (id->inlined_fns) - 1; i >= 0; i--)
if (VARRAY_TREE (id->inlined_fns, i) == fn)
break;
if (i < 0)
VARRAY_PUSH_TREE (id->inlined_fns, fn);
}
id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
if (flag_use_feedback)
set_times_arc_executed (id->ret_label, 0,
(HOST_WIDEST_INT)(times_arc_executed (fn, 1)));
DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
if (! DECL_INITIAL (fn)
|| TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
abort ();
#ifndef INLINER_FOR_JAVA
scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
SCOPE_BEGIN_P (scope_stmt) = 1;
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt);
COMPOUND_BODY (stmt) = scope_stmt;
if (SCOPE_STMT_BLOCK (scope_stmt))
BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt),
declare_return_variable (id, &use_stmt));
#else
{
tree decl = declare_return_variable (id, &retvar);
if (retvar)
{
tree *next = &BLOCK_VARS (expr);
while (*next)
next = &TREE_CHAIN (*next);
*next = decl;
}
}
#endif
#ifndef INLINER_FOR_JAVA
inlined_body = &COMPOUND_BODY (stmt);
while (*inlined_body)
inlined_body = &TREE_CHAIN (*inlined_body);
*inlined_body = copy_body (id);
#else
{
tree new_body;
java_inlining_map_static_initializers (fn, id->decl_map);
new_body = copy_body (id);
TREE_TYPE (new_body) = TREE_TYPE (TREE_TYPE (fn));
BLOCK_EXPR_BODY (expr)
= add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
TREE_TYPE (new_body), new_body);
inlined_body = &BLOCK_EXPR_BODY (expr);
}
#endif
body = inlined_body;
#ifndef INLINER_FOR_JAVA
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt),
build_stmt (LABEL_STMT, id->ret_label));
#else
{
tree label = build1 (LABEL_EXPR, void_type_node, id->ret_label);
BLOCK_EXPR_BODY (expr)
= add_stmt_to_compound (BLOCK_EXPR_BODY (expr), void_type_node, label);
TREE_SIDE_EFFECTS (label) = TREE_SIDE_EFFECTS (t);
}
#endif
set_times_arc_executed (id->ret_label, 0,
(HOST_WIDEST_INT)(times_arc_executed (id->ret_label, 0) * id->scale));
#ifndef INLINER_FOR_JAVA
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), use_stmt);
scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
remap_block (scope_stmt, NULL_TREE, id);
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt), scope_stmt);
#else
if (retvar)
{
if (TREE_TYPE (TREE_TYPE (fn)) != TREE_TYPE (retvar))
retvar = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), retvar);
BLOCK_EXPR_BODY (expr)
= add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
TREE_TYPE (retvar), retvar);
}
java_inlining_merge_static_initializers (fn, id->decl_map);
#endif
splay_tree_delete (id->decl_map);
id->decl_map = st;
TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t);
#ifndef INLINER_FOR_JAVA
chain = TREE_CHAIN (*tp);
*tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn),
0);
#else
*tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn),
DECL_SOURCE_LINE_FIRST(fn),
0);
#endif
EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1;
#ifndef INLINER_FOR_JAVA
TREE_CHAIN (*tp) = chain;
#endif
pop_srcloc ();
TREE_USED (*tp) = 1;
DECL_NUM_STMTS (VARRAY_TREE (id->fns, 0)) += DECL_NUM_STMTS (fn);
id->inlined_stmts += DECL_NUM_STMTS (fn) - 1;
if (id->decl && flag_unit_at_a_time)
{
cgraph_remove_call (id->decl, fn);
cgraph_create_edges (id->decl, *inlined_body);
}
VARRAY_POP (id->fns);
if (VARRAY_ACTIVE_SIZE (id->fns) == id->first_inlined_fn)
id->inlined_stmts = 0;
(*lang_hooks.tree_inlining.end_inlining) (fn);
return body;
}
static tree
expand_call_inline (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees;
void *data;
{
inline_data *id;
tree t;
tree expr;
tree stmt;
#ifndef INLINER_FOR_JAVA
tree chain;
tree scope_stmt;
tree use_stmt;
#else
tree retvar;
#endif
tree fn;
tree arg_inits;
tree *inlined_body;
splay_tree st;
tree actparms;
tree saved_return_type;
tree funtype;
CUMULATIVE_ARGS args_so_far;
id = (inline_data *) data;
t = *tp;
if (TREE_CODE (*tp) == TARGET_EXPR)
{
#ifndef INLINER_FOR_JAVA
int i, len = first_rtl_op (TARGET_EXPR);
*walk_subtrees = 0;
VARRAY_PUSH_TREE (id->target_exprs, *tp);
for (i = 0; i < len; ++i)
{
if (i == 2)
++id->in_target_cleanup_p;
walk_tree (&TREE_OPERAND (*tp, i), expand_call_inline, data,
id->tree_pruner);
if (i == 2)
--id->in_target_cleanup_p;
}
VARRAY_POP (id->target_exprs);
return NULL_TREE;
#else
abort ();
#endif
}
else if (TREE_CODE (t) == EXPR_WITH_FILE_LOCATION)
{
*walk_subtrees = 0;
push_srcloc (EXPR_WFL_FILENAME (t), EXPR_WFL_LINENO (t));
walk_tree (&EXPR_WFL_NODE (t), expand_call_inline, data,
id->tree_pruner);
pop_srcloc ();
return NULL_TREE;
}
if (TYPE_P (t))
*walk_subtrees = 0;
if (TREE_CODE (t) != CALL_EXPR)
return NULL_TREE;
fn = get_callee_fndecl (t);
if (!fn)
return NULL_TREE;
if (! DECL_INITIAL (fn)
&& DECL_ABSTRACT_ORIGIN (fn)
&& DECL_SAVED_TREE (DECL_ABSTRACT_ORIGIN (fn)))
fn = DECL_ABSTRACT_ORIGIN (fn);
if ((!flag_unit_at_a_time || !DECL_SAVED_TREE (fn)
|| !cgraph_global_info (fn)->inline_once)
&& !inlinable_function_p (fn, id, 0))
{
if (warn_inline && DECL_INLINE (fn))
{
warning_with_decl (fn, "inlining failed in call to `%s'");
warning ("called from here");
}
return NULL_TREE;
}
if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
return NULL_TREE;
if (!quiet_flag)
{
fprintf (stderr, "\n[%s inlines %s]",
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
IDENTIFIER_POINTER (DECL_NAME (fn)));
}
push_srcloc (DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn));
#ifndef INLINER_FOR_JAVA
expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), make_node (COMPOUND_STMT));
STMT_EXPR_NO_SCOPE (expr) = 1;
stmt = STMT_EXPR_STMT (expr);
#else
stmt = NULL;
expr = build (BLOCK, TREE_TYPE (TREE_TYPE (fn)), stmt);
#endif
st = id->decl_map;
id->decl_map = splay_tree_new (splay_tree_compare_pointers,
NULL, NULL);
actparms = TREE_OPERAND (t, 1);
if (TREE_ASM_WRITTEN (fn) || DECL_SAVED_INSNS (fn))
{
funtype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
saved_return_type = TREE_TYPE (funtype);
TREE_TYPE (funtype) = TREE_TYPE (t);
INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, 0);
TREE_TYPE (funtype) = saved_return_type;
#ifdef REARRANGE_ARG_LIST
actparms = REARRANGE_ARG_LIST (args_so_far, actparms);
#endif
}
#ifndef INLINER_FOR_JAVA
arg_inits = initialize_inlined_parameters (id, actparms, fn);
expand_calls_inline (&arg_inits, id);
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
#else
arg_inits = initialize_inlined_parameters (id, TREE_OPERAND (t, 1), fn, expr);
if (arg_inits)
{
expand_calls_inline (&arg_inits, id);
BLOCK_EXPR_BODY (expr) = add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
TREE_TYPE (arg_inits),
arg_inits);
}
#endif
VARRAY_PUSH_TREE (id->fns, fn);
if (! DECL_INLINED_FNS (fn))
{
int i;
for (i = VARRAY_ACTIVE_SIZE (id->inlined_fns) - 1; i >= 0; i--)
if (VARRAY_TREE (id->inlined_fns, i) == fn)
break;
if (i < 0)
VARRAY_PUSH_TREE (id->inlined_fns, fn);
}
id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
if (! DECL_INITIAL (fn)
|| TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
abort ();
#ifndef INLINER_FOR_JAVA
scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
SCOPE_BEGIN_P (scope_stmt) = 1;
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt);
COMPOUND_BODY (stmt) = scope_stmt;
if (SCOPE_STMT_BLOCK (scope_stmt))
BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt),
declare_return_variable (id, &use_stmt));
#else
{
tree decl = declare_return_variable (id, &retvar);
if (retvar)
{
tree *next = &BLOCK_VARS (expr);
while (*next)
next = &TREE_CHAIN (*next);
*next = decl;
}
}
#endif
#ifndef INLINER_FOR_JAVA
inlined_body = &COMPOUND_BODY (stmt);
while (*inlined_body)
inlined_body = &TREE_CHAIN (*inlined_body);
*inlined_body = copy_body (id);
#else
{
tree new_body;
java_inlining_map_static_initializers (fn, id->decl_map);
new_body = copy_body (id);
TREE_TYPE (new_body) = TREE_TYPE (TREE_TYPE (fn));
BLOCK_EXPR_BODY (expr)
= add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
TREE_TYPE (new_body), new_body);
inlined_body = &BLOCK_EXPR_BODY (expr);
}
#endif
#ifndef INLINER_FOR_JAVA
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt),
build_stmt (LABEL_STMT, id->ret_label));
#else
{
tree label = build1 (LABEL_EXPR, void_type_node, id->ret_label);
BLOCK_EXPR_BODY (expr)
= add_stmt_to_compound (BLOCK_EXPR_BODY (expr), void_type_node, label);
TREE_SIDE_EFFECTS (label) = TREE_SIDE_EFFECTS (t);
}
#endif
#ifndef INLINER_FOR_JAVA
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), use_stmt);
scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
remap_block (scope_stmt, NULL_TREE, id);
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt), scope_stmt);
#else
if (retvar)
{
if (TREE_TYPE (TREE_TYPE (fn)) != TREE_TYPE (retvar))
retvar = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), retvar);
BLOCK_EXPR_BODY (expr)
= add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
TREE_TYPE (retvar), retvar);
}
java_inlining_merge_static_initializers (fn, id->decl_map);
#endif
splay_tree_delete (id->decl_map);
id->decl_map = st;
TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t);
#ifndef INLINER_FOR_JAVA
chain = TREE_CHAIN (*tp);
*tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn),
0);
#else
*tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn),
DECL_SOURCE_LINE_FIRST(fn),
0);
#endif
EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1;
#ifndef INLINER_FOR_JAVA
TREE_CHAIN (*tp) = chain;
#endif
pop_srcloc ();
TREE_USED (*tp) = 1;
DECL_NUM_STMTS (VARRAY_TREE (id->fns, 0)) += DECL_NUM_STMTS (fn);
id->inlined_stmts += DECL_NUM_STMTS (fn) - 1;
if (id->decl && flag_unit_at_a_time)
{
cgraph_remove_call (id->decl, fn);
cgraph_create_edges (id->decl, *inlined_body);
}
expand_calls_inline (inlined_body, id);
VARRAY_POP (id->fns);
if (VARRAY_ACTIVE_SIZE (id->fns) == id->first_inlined_fn)
id->inlined_stmts = 0;
*walk_subtrees = 0;
(*lang_hooks.tree_inlining.end_inlining) (fn);
return NULL_TREE;
}
static void
expand_calls_inline (tp, id)
tree *tp;
inline_data *id;
{
walk_tree (tp, expand_call_inline, id, id->tree_pruner);
}
void
optimize_inline_calls (fn)
tree fn;
{
inline_data id;
tree prev_fn;
memset (&id, 0, sizeof (id));
id.decl = fn;
VARRAY_TREE_INIT (id.fns, 32, "fns");
VARRAY_PUSH_TREE (id.fns, fn);
prev_fn = NULL_TREE;
if (current_function_decl)
{
VARRAY_PUSH_TREE (id.fns, current_function_decl);
prev_fn = current_function_decl;
}
prev_fn = ((*lang_hooks.tree_inlining.add_pending_fn_decls)
(&id.fns, prev_fn));
VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
id.first_inlined_fn = VARRAY_ACTIVE_SIZE (id.fns);
id.tree_pruner = htab_create (131, htab_hash_pointer,
htab_eq_pointer, NULL);
expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
htab_delete (id.tree_pruner);
if (DECL_LANG_SPECIFIC (fn))
{
tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
if (VARRAY_ACTIVE_SIZE (id.inlined_fns))
memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
DECL_INLINED_FNS (fn) = ifn;
}
}
tree *
inline_this_call (tp, callee, scale)
tree *tp;
tree callee;
double scale;
{
inline_data id;
tree *body, prev_fn;
memset (&id, 0, sizeof (id));
id.scale = scale;
id.return_label_execution_count = (HOST_WIDEST_INT)0;
id.decl = NULL;
VARRAY_TREE_INIT (id.fns, 32, "fns");
prev_fn = NULL_TREE;
if (current_function_decl)
{
VARRAY_PUSH_TREE (id.fns, current_function_decl);
prev_fn = current_function_decl;
}
prev_fn = ((*lang_hooks.tree_inlining.add_pending_fn_decls)
(&id.fns, prev_fn));
VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
id.first_inlined_fn = VARRAY_ACTIVE_SIZE (id.fns);
id.tree_pruner = htab_create (37, htab_hash_pointer,
htab_eq_pointer, NULL);
body = expand_one_call_inline (tp, callee, &id);
htab_delete (id.tree_pruner);
return body;
}
void
clone_body_scaled (clone, fn, arg_map, scale)
tree clone, fn;
void *arg_map;
double scale;
{
inline_data id;
memset (&id, 0, sizeof (id));
VARRAY_TREE_INIT (id.fns, 2, "fns");
VARRAY_PUSH_TREE (id.fns, clone);
VARRAY_PUSH_TREE (id.fns, fn);
id.decl_map = (splay_tree)arg_map;
id.scale = scale;
id.cloning_p = true;
TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
}
void
clone_body (clone, fn, arg_map)
tree clone, fn;
void *arg_map;
{
clone_body_scaled (clone, fn, arg_map, 1.0);
}
tree
copy_and_remap_r (tp, walk_subtrees, v)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
void *v;
{
inline_data *id = (inline_data *)v;
splay_tree_node sp;
if (!tp)
return NULL_TREE;
sp = splay_tree_lookup (id->decl_map, (splay_tree_key)*tp);
if (sp)
*tp = (tree)sp->value;
else
*tp = copy_node (*tp);
return NULL_TREE;
}
tree
clone_tree_into_context (fn, src, arg_map)
tree fn, src;
void *arg_map;
{
inline_data id;
tree clone;
memset (&id, 0, sizeof (id));
VARRAY_TREE_INIT (id.fns, 2, "fns");
VARRAY_PUSH_TREE (id.fns, fn);
id.decl_map = (splay_tree)arg_map;
id.cloning_p = true;
clone = src;
walk_tree (&clone, copy_and_remap_r, &id, NULL);
return clone;
}
tree
walk_tree (tp, func, data, htab_)
tree *tp;
walk_tree_fn func;
void *data;
void *htab_;
{
htab_t htab = (htab_t) htab_;
enum tree_code code;
int walk_subtrees;
tree result;
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
if (result) \
return result; \
} \
while (0)
#define WALK_SUBTREE_TAIL(NODE) \
do \
{ \
tp = & (NODE); \
goto tail_recurse; \
} \
while (0)
tail_recurse:
if (!*tp)
return NULL_TREE;
if (htab)
{
void **slot;
slot = htab_find_slot (htab, *tp, INSERT);
if (*slot)
return NULL_TREE;
*slot = *tp;
}
walk_subtrees = 1;
result = (*func) (tp, &walk_subtrees, data);
if (result)
return result;
code = TREE_CODE (*tp);
#ifndef INLINER_FOR_JAVA
if (!walk_subtrees)
{
if (STATEMENT_CODE_P (code) || code == TREE_LIST
|| (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp))
WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
else
return NULL_TREE;
}
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
|| TREE_CODE_CLASS (code) == 'r'
|| TREE_CODE_CLASS (code) == 's')
#else
if (code != EXIT_BLOCK_EXPR
&& code != SAVE_EXPR
&& (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
|| TREE_CODE_CLASS (code) == 'r'
|| TREE_CODE_CLASS (code) == 's'))
#endif
{
int i, len;
#ifndef INLINER_FOR_JAVA
#endif
len = first_rtl_op (code);
if (code == TARGET_EXPR
&& TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
--len;
for (i = 0; i < len; ++i)
WALK_SUBTREE (TREE_OPERAND (*tp, i));
#ifndef INLINER_FOR_JAVA
if (STATEMENT_CODE_P (code))
{
if (code == DECL_STMT
&& DECL_STMT_DECL (*tp)
&& DECL_P (DECL_STMT_DECL (*tp)))
{
WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp)));
WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp)));
WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp)));
}
WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
}
#endif
return NULL_TREE;
}
else if (TREE_CODE_CLASS (code) == 'd')
{
WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
}
else if (TREE_CODE_CLASS (code) == 't')
{
WALK_SUBTREE (TYPE_SIZE (*tp));
WALK_SUBTREE (TYPE_SIZE_UNIT (*tp));
}
result = (*lang_hooks.tree_inlining.walk_subtrees) (tp, &walk_subtrees, func,
data, htab);
if (result || ! walk_subtrees)
return result;
switch (code)
{
case ERROR_MARK:
case IDENTIFIER_NODE:
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
case REAL_TYPE:
case COMPLEX_TYPE:
case VECTOR_TYPE:
case VOID_TYPE:
case BOOLEAN_TYPE:
case UNION_TYPE:
case ENUMERAL_TYPE:
case BLOCK:
case RECORD_TYPE:
case CHAR_TYPE:
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
break;
case TREE_LIST:
WALK_SUBTREE (TREE_VALUE (*tp));
WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
break;
case TREE_VEC:
{
int len = TREE_VEC_LENGTH (*tp);
if (len == 0)
break;
while (--len)
WALK_SUBTREE (TREE_VEC_ELT (*tp, len));
WALK_SUBTREE_TAIL (TREE_VEC_ELT (*tp, 0));
}
case COMPLEX_CST:
WALK_SUBTREE (TREE_REALPART (*tp));
WALK_SUBTREE_TAIL (TREE_IMAGPART (*tp));
case VECTOR_CST:
WALK_SUBTREE (TREE_VECTOR_CST_ELTS (*tp));
break;
case CONSTRUCTOR:
WALK_SUBTREE_TAIL (CONSTRUCTOR_ELTS (*tp));
case METHOD_TYPE:
WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
case FUNCTION_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
{
tree arg = TYPE_ARG_TYPES (*tp);
for (; arg; arg = TREE_CHAIN (arg))
WALK_SUBTREE (TREE_VALUE (arg));
}
break;
case ARRAY_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp));
case INTEGER_TYPE:
WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp));
case OFFSET_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
WALK_SUBTREE_TAIL (TYPE_OFFSET_BASETYPE (*tp));
#ifdef INLINER_FOR_JAVA
case EXIT_BLOCK_EXPR:
WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 1));
case SAVE_EXPR:
WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0));
#endif
default:
abort ();
}
return NULL_TREE;
#undef WALK_SUBTREE
#undef WALK_SUBTREE_TAIL
}
tree
walk_tree_without_duplicates (tp, func, data)
tree *tp;
walk_tree_fn func;
void *data;
{
tree result;
htab_t htab;
htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
result = walk_tree (tp, func, data, htab);
htab_delete (htab);
return result;
}
tree
copy_tree_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees;
void *data ATTRIBUTE_UNUSED;
{
enum tree_code code = TREE_CODE (*tp);
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
|| TREE_CODE_CLASS (code) == 'r'
|| TREE_CODE_CLASS (code) == 'c'
|| TREE_CODE_CLASS (code) == 's'
|| code == TREE_LIST
|| code == TREE_VEC
|| (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp))
{
tree chain = TREE_CHAIN (*tp);
*tp = copy_node (*tp);
if (code == PARM_DECL || code == TREE_LIST
#ifndef INLINER_FOR_JAVA
|| (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp)
|| STATEMENT_CODE_P (code))
TREE_CHAIN (*tp) = chain;
if (TREE_CODE (*tp) == SCOPE_STMT)
SCOPE_STMT_BLOCK (*tp) = NULL_TREE;
#else
|| (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp))
TREE_CHAIN (*tp) = chain;
#endif
}
else if (TREE_CODE_CLASS (code) == 't' && !variably_modified_type_p (*tp))
*walk_subtrees = 0;
return NULL_TREE;
}
void
remap_save_expr (tp, st_, fn, walk_subtrees)
tree *tp;
void *st_;
tree fn;
int *walk_subtrees;
{
splay_tree st = (splay_tree) st_;
splay_tree_node n;
n = splay_tree_lookup (st, (splay_tree_key) *tp);
if (!n)
{
tree t = copy_node (*tp);
SAVE_EXPR_CONTEXT (t) = fn;
SAVE_EXPR_RTL (t) = NULL_RTX;
n = splay_tree_insert (st,
(splay_tree_key) *tp,
(splay_tree_value) t);
splay_tree_insert (st, (splay_tree_key) t,
(splay_tree_value) error_mark_node);
}
else
*walk_subtrees = 0;
*tp = (tree) n->value;
}
#ifdef INLINER_FOR_JAVA
static tree
add_stmt_to_compound (existing, type, stmt)
tree existing, type, stmt;
{
if (!stmt)
return existing;
else if (existing)
return build (COMPOUND_EXPR, type, existing, stmt);
else
return stmt;
}
#endif