diff options
Diffstat (limited to 'gcc/uninline-innermost-loops.c')
-rw-r--r-- | gcc/uninline-innermost-loops.c | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/gcc/uninline-innermost-loops.c b/gcc/uninline-innermost-loops.c deleted file mode 100644 index 3726e6efeeec..000000000000 --- a/gcc/uninline-innermost-loops.c +++ /dev/null @@ -1,456 +0,0 @@ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "hash-set.h" -#include "machmode.h" -#include "vec.h" -#include "double-int.h" -#include "input.h" -#include "alias.h" -#include "symtab.h" -#include "options.h" -#include "wide-int.h" -#include "inchash.h" -#include "tree.h" -#include "fold-const.h" -#include "hashtab.h" -#include "tm.h" -#include "hard-reg-set.h" -#include "function.h" -#include "rtl.h" -#include "flags.h" -#include "statistics.h" -#include "real.h" -#include "fixed-value.h" -#include "insn-config.h" -#include "expmed.h" -#include "dojump.h" -#include "explow.h" -#include "calls.h" -#include "varasm.h" -#include "stmt.h" -#include "expr.h" -#include "gimple-pretty-print.h" -#include "predict.h" -#include "dominance.h" -#include "cfg.h" -#include "cfgloop.h" -#include "cfghooks.h" -#include "basic-block.h" -#include "tree-ssa-alias.h" -#include "internal-fn.h" -#include "gimple-expr.h" -#include "is-a.h" -#include "gimple.h" -#include "gimplify.h" -#include "gimple-iterator.h" -#include "tree-cfg.h" -#include "gimplify-me.h" -#include "gimple-ssa.h" -#include "tree-ssa-operands.h" -#include "tree-phinodes.h" -#include "ssa-iterators.h" -#include "dumpfile.h" -#include "tree-pass.h" -#include "ipa-ref.h" -#include "plugin-api.h" -#include "cgraph.h" -#include "function.h" -#include "tree-ssa.h" - -void -print_generic_expr (FILE *file, tree t, int flags); - -typedef vec <tree> expr_vec; - -extern const char * uninlined_function_postfix; -const char * uninlined_function_postfix = "innermost_loop"; - -static bool -is_defined_in_stmt (gimple *stmt, tree var) -{ - tree lhs; - if (gimple_code (stmt) == GIMPLE_ASSIGN) - { - lhs = gimple_assign_lhs (stmt); - if (lhs == var) - return true; - } - return false; -} - -static bool -is_defined_in_bb (gimple_stmt_iterator gsi, tree var) -{ - for (; !gsi_end_p (gsi); gsi_prev (&gsi)) - { - if (is_defined_in_stmt (gsi_stmt (gsi), var)) - return true; - } - return false; -} - -static bool -is_defined_outside (gimple *use, tree var) -{ - gimple_stmt_iterator gsi; - gsi = gsi_for_stmt (use); - gsi_prev (&gsi); - /* FIXME Recursively search other also predecessor bbs. */ - return !is_defined_in_bb (gsi, var); -} - -/* FIXME Is there a standard function to do this? */ -static bool -contained (expr_vec v, tree var) -{ - int i = 0; - tree u; - - FOR_EACH_VEC_ELT (v, i, u) - { - if (u == var) - return true; - } - return false; -} - -typedef void (*op_callback) (void * g, tree op, gimple *stmt, unsigned index); - -static void -for_each_operand_in_loop (struct loop * loop, op_callback cb, void * g) -{ - basic_block * bbs; - basic_block bb; - unsigned num_nodes; - unsigned i; - unsigned j; - gimple *stmt; - tree op; - - bbs = get_loop_body (loop); - num_nodes = loop->num_nodes; - for (i = 0; i < num_nodes; i++) - { - bb = bbs[i]; - gimple_stmt_iterator iter = gsi_start_bb (bb); - while (!gsi_end_p (iter)) - { - stmt = gsi_stmt (iter); - for (j = 0; j < gimple_num_ops (stmt); j++) - { - op = gimple_op (stmt, j); - if (op) - { - /* Here is the callback. */ - cb (g, op, stmt, j); - } - } - gsi_next (&iter); - } - } - free (bbs); -} - -static void -collect_cb (void * g, tree op, gimple *stmt, unsigned index) -{ - expr_vec * v = (expr_vec *) g; - enum tree_code code; - - if (gimple_code (stmt) == GIMPLE_ASSIGN && index == 0) - { - /* I assume operand 0 of an assignment is the lhs. */ - return; - } - - code = TREE_CODE (op); - if ((code == VAR_DECL || code == PARM_DECL) && - ! contained (*v, op) && - is_defined_outside (stmt, op)) - { - v->safe_push (op); - } -} - -static expr_vec -collect_def_outside (struct loop * loop) -{ - expr_vec v = vNULL; - for_each_operand_in_loop (loop, collect_cb, (void *) & v); - return v; -} - -static void -contains_call_cb (void * r, tree, gimple *stmt, unsigned) -{ - bool * ret = (bool *) r; - if (gimple_code (stmt) == GIMPLE_CALL) - *ret |= true; - else - *ret |= false; -} - -static bool -contains_call (struct loop * loop) -{ - bool ret; - ret = false; - for_each_operand_in_loop (loop, contains_call_cb, &ret); - return ret; -} - -struct var_to_parm_cb_p -{ - tree d; - tree d_parm; -}; - -static void -var_to_parm_cb (void * g, tree op, gimple *stmt, unsigned index) -{ - struct var_to_parm_cb_p * p = (struct var_to_parm_cb_p *) g; - - if (p->d == op) - { - gimple_set_op (stmt, index, p->d_parm); - } -} - -static void -convert_var_to_parm_uses (struct loop * loop, tree d, tree d_parm) -{ - struct var_to_parm_cb_p c; - c.d = d; - c.d_parm = d_parm; - for_each_operand_in_loop (loop, var_to_parm_cb, (void *) & c); -} - -static void -body_to_fun (struct loop * loop, expr_vec uv) -{ - tree name, decl, type, t, block; - gimple_seq body = NULL; - gimple *bind; - int i; - vec<tree> args; - struct function *fun; - basic_block new_bb, preheader; - edge out; - basic_block in_bb, out_bb; - - /* Make the new function similar to create_omp_child_function. */ - name = clone_function_name (cfun->decl, uninlined_function_postfix); - decl = build_decl (input_location, FUNCTION_DECL, name, NULL_TREE); - - TREE_STATIC (decl) = 1; - TREE_USED (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - DECL_NAMELESS (decl) = 0; - DECL_IGNORED_P (decl) = 0; - TREE_PUBLIC (decl) = 0; - DECL_UNINLINABLE (decl) = 1; - DECL_EXTERNAL (decl) = 0; - DECL_CONTEXT (decl) = NULL_TREE; - - block = make_node (BLOCK); - DECL_INITIAL (decl) = block; - - t = build_decl (DECL_SOURCE_LOCATION (decl), - RESULT_DECL, NULL_TREE, void_type_node); - - DECL_ARTIFICIAL (t) = 1; - DECL_IGNORED_P (t) = 1; - DECL_CONTEXT (t) = decl; - DECL_RESULT (decl) = t; - - tree d_parm = NULL; - tree d = NULL; - tree t_first = NULL; - t = NULL; - - tree type_new = NULL; - - tree types = NULL_TREE; - tree *pp = &types; - - args = vNULL; - - /* Prepare the arguments collected earlier on. */ - i = 0; - FOR_EACH_VEC_ELT (uv, i, d) - { - args.safe_push (d); - - type_new = copy_node (TREE_TYPE (d)); - - *pp = build_tree_list (NULL, type_new); - pp = &TREE_CHAIN (*pp); - - d_parm = build_decl (DECL_SOURCE_LOCATION (decl), PARM_DECL, - DECL_NAME (d), type_new); - DECL_ARG_TYPE (d_parm) = TREE_TYPE (d); - DECL_ARTIFICIAL (d_parm) = 1; - DECL_CONTEXT (d_parm) = decl; - TYPE_RESTRICT (TREE_TYPE (d_parm)) = 1; - convert_var_to_parm_uses (loop, d, d_parm); - - if (!t_first) - { - t = d_parm; - t_first = d_parm; - } - else - { - DECL_CHAIN (t) = d_parm; - t = d_parm; - } - } - - type = build_function_type (void_type_node, types); - - DECL_ARGUMENTS (decl) = t_first; - TREE_TYPE (decl) = type; - - push_struct_function (decl); - cfun->function_end_locus = DECL_SOURCE_LOCATION (decl); - pop_cfun (); - - /* Fill the function body. */ - bind = gimple_build_bind (NULL, body, block); - gimple_seq_add_stmt (&body, bind); - - gimple_set_body (decl, body); - - fun = DECL_STRUCT_FUNCTION (decl); - - init_tree_ssa (fun); - - out = single_exit (loop); - - out_bb = split_edge (out); - - /* FIXME I patched this function such that - it always creates the - preheader. - */ - preheader = create_preheader (loop, 128); - in_bb = preheader; - - new_bb = move_sese_region_to_fn (fun, in_bb, - out_bb, NULL_TREE); - - DECL_STRUCT_FUNCTION (decl)->curr_properties = cfun->curr_properties; - - /* Make the new function known. */ - cgraph_node::add_new_function (decl, true); - - gimple_stmt_iterator call_iter = gsi_start_bb (new_bb); - gimple *call_stmt; - call_stmt = gimple_build_call_vec (decl, args); - gsi_insert_after (&call_iter, call_stmt, - GSI_NEW_STMT); - - cgraph_edge::rebuild_edges (); - - push_cfun (fun); - cgraph_edge::rebuild_edges (); - pop_cfun (); -} - -static unsigned int -extract_loop_to_function (void) -{ - struct loop *loop; - struct loop *lu; - expr_vec v = vNULL; - bool cc; - - const char * fun_to_uninline; - unsigned n; - - lu = NULL; - - record_loop_exits (); - - fun_to_uninline = noalias; - - n = 0; - FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST) - { - /* FIXME Try to generalize this. */ - /* We assume that we outline at most one - innermost loop. - We choose the biggest loop, assuming - it will bring the most benefit. - FIXME Make sure there flows no data out of - the loop. - */ - if (single_exit (loop) && - strcmp (function_name (cfun), fun_to_uninline) == 0) - { - cc = contains_call (loop); - if (!cc && n < loop->num_nodes) - { - n = loop->num_nodes; - lu = loop; - } - } - } - - if (lu) - { - if (dump_file) - fprintf (dump_file, - "%s:%d (%s): uninlining in %s\n", - __FILE__, __LINE__, __func__, fun_to_uninline); - v = collect_def_outside (lu); - body_to_fun (lu, v); - } - - release_recorded_exits (cfun); - - return 0; -} - -static bool -gate_uninline_innermost_loops (void) -{ - return noalias != 0; -} - -namespace { - -const pass_data pass_data_uninline_innermost_loops = -{ - GIMPLE_PASS, /* type */ - "uninline-innermost-loops", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_UNINLINE_INNERMOST_LOOPS, /* tv_id */ - PROP_gimple_any, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_uninline_innermost_loops: public gimple_opt_pass -{ -public: - pass_uninline_innermost_loops (gcc::context *ctxt) - : gimple_opt_pass (pass_data_uninline_innermost_loops, ctxt) - {} - - /* opt_pass methods: */ - bool gate (function *) { return gate_uninline_innermost_loops (); } - unsigned int execute (function *) { return extract_loop_to_function (); } - -}; - -} // anon namespace - -gimple_opt_pass * -make_pass_uninline_innermost_loops (gcc::context *ctxt) -{ - return new pass_uninline_innermost_loops (ctxt); -} |