* @author Michael Beck
* @version $Id$
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
#include <string.h>
#include <assert.h>
#include "debug.h"
#include "iroptimize.h"
#include "scalar_replace.h"
-#include "array.h"
+#include "array_t.h"
#include "irprog_t.h"
#include "irgwalk.h"
#include "irgmod.h"
#include "irouts.h"
#include "irhooks.h"
#include "ircons_t.h"
-#include "xmalloc.h"
+#include "irpass.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg);
/**
* the environment for collecting data
*/
-typedef struct _collect_t {
+typedef struct collect_t {
ir_node *proj_X; /**< initial exec proj */
ir_node *block; /**< old first block */
int blk_idx; /**< cfgpred index of the initial exec in block */
/**
* walker for collecting data, fills a collect_t environment
*/
-static void collect_data(ir_node *node, void *env) {
+static void collect_data(ir_node *node, void *env)
+{
collect_t *data = env;
ir_node *pred;
ir_op *op;
* @param rets linked list of all rets
* @param n_tail_calls number of tail-recursion calls
*/
-static void do_opt_tail_rec(ir_graph *irg, tr_env *env) {
+static void do_opt_tail_rec(ir_graph *irg, tr_env *env)
+{
ir_node *end_block = get_irg_end_block(irg);
ir_node *block, *jmp, *call, *calls;
ir_node **in;
ir_node *block = get_nodes_block(p);
n = get_irn_link(p);
- in[i++] = new_r_Jmp(irg, block);
+ in[i++] = new_r_Jmp(block);
// exchange(p, new_r_Bad(irg));
/* create a new block at start */
block = new_r_Block(irg, env->n_tail_calls + 1, in);
- jmp = new_r_Jmp(irg, block);
+ jmp = new_r_Jmp(block);
/* the old first block is now the second one */
set_Block_cfgpred(data.block, data.blk_idx, jmp);
/* build the memory phi */
i = 0;
- in[i] = new_r_Proj(irg, get_irg_start_block(irg), get_irg_start(irg), mode_M, pn_Start_M);
+ in[i] = new_r_Proj(get_irg_start(irg), mode_M, pn_Start_M);
set_irg_initial_mem(irg, in[i]);
++i;
}
assert(i == env->n_tail_calls + 1);
- phis[0] = new_r_Phi(irg, block, env->n_tail_calls + 1, in, mode_M);
+ phis[0] = new_r_Phi(block, env->n_tail_calls + 1, in, mode_M);
/* build the data Phi's */
if (n_params > 0) {
for (i = 0; i < n_params; ++i) {
ir_mode *mode = get_type_mode(get_method_param_type(method_tp, i));
- in[0] = new_r_Proj(irg, args_bl, args, mode, i);
+ in[0] = new_r_Proj(args, mode, i);
for (j = 0; j < env->n_tail_calls; ++j)
in[j + 1] = call_params[j][i];
- phis[i + 1] = new_r_Phi(irg, block, env->n_tail_calls + 1, in, mode);
+ phis[i + 1] = new_r_Phi(block, env->n_tail_calls + 1, in, mode);
}
}
modes[i] = mode;
if (env->variants[i] == TR_ADD) {
- set_value(i, new_Const(mode, get_mode_null(mode)));
+ set_value(i, new_Const(get_mode_null(mode)));
} else if (env->variants[i] == TR_MUL) {
- set_value(i, new_Const(mode, get_mode_one(mode)));
+ set_value(i, new_Const(get_mode_one(mode)));
}
}
mature_immBlock(start_block);
set_Tuple_pred(call, pn_Call_X_regular, jmp);
set_Tuple_pred(call, pn_Call_X_except, bad);
set_Tuple_pred(call, pn_Call_T_result, tuple);
- set_Tuple_pred(call, pn_Call_M_except, mem);
set_Tuple_pred(call, pn_Call_P_value_res_base, bad);
for (i = 0; i < env->n_ress; ++i) {
*
* @return non-zero if it's ok to do tail recursion
*/
-static int check_lifetime_of_locals(ir_graph *irg) {
- ir_node *irg_frame, *irg_val_param_base;
+static int check_lifetime_of_locals(ir_graph *irg)
+{
+ ir_node *irg_frame;
int i;
+ ir_type *frame_tp = get_irg_frame_type(irg);
irg_frame = get_irg_frame(irg);
for (i = get_irn_n_outs(irg_frame) - 1; i >= 0; --i) {
ir_node *succ = get_irn_out(irg_frame, i);
- if (is_Sel(succ) && is_address_taken(succ))
- return 0;
- }
-
- /* Check if we have compound arguments.
- For now, we cannot handle them, */
- irg_val_param_base = get_irg_value_param_base(irg);
- if (get_irn_n_outs(irg_val_param_base) > 0)
- return 0;
+ if (is_Sel(succ)) {
+ /* Check if we have compound arguments.
+ For now, we cannot handle them, */
+ if (get_entity_owner(get_Sel_entity(succ)) != frame_tp)
+ return 0;
+ if (is_address_taken(succ))
+ return 0;
+ }
+ }
return 1;
}
/**
* Examine irn and detect the recursion variant.
*/
-static tail_rec_variants find_variant(ir_node *irn, ir_node *call) {
+static tail_rec_variants find_variant(ir_node *irn, ir_node *call)
+{
ir_node *a, *b;
tail_rec_variants va, vb, res;
case iro_Add:
/* try additive */
a = get_Add_left(irn);
- if (get_irn_MacroBlock(a) != get_irn_MacroBlock(call)) {
+ if (get_nodes_block(a) != get_nodes_block(call)) {
/* we are outside, ignore */
va = TR_UNKNOWN;
} else {
return TR_BAD;
}
b = get_Add_right(irn);
- if (get_irn_MacroBlock(b) != get_irn_MacroBlock(call)) {
+ if (get_nodes_block(b) != get_nodes_block(call)) {
/* we are outside, ignore */
vb = TR_UNKNOWN;
} else {
case iro_Sub:
/* try additive, but return value must be left */
a = get_Sub_left(irn);
- if (get_irn_MacroBlock(a) != get_irn_MacroBlock(call)) {
+ if (get_nodes_block(a) != get_nodes_block(call)) {
/* we are outside, ignore */
va = TR_UNKNOWN;
} else {
return TR_BAD;
}
b = get_Sub_right(irn);
- if (get_irn_MacroBlock(b) != get_irn_MacroBlock(call)) {
+ if (get_nodes_block(b) != get_nodes_block(call)) {
/* we are outside, ignore */
vb = TR_UNKNOWN;
} else {
case iro_Mul:
/* try multiplicative */
a = get_Mul_left(irn);
- if (get_irn_MacroBlock(a) != get_irn_MacroBlock(call)) {
+ if (get_nodes_block(a) != get_nodes_block(call)) {
/* we are outside, ignore */
va = TR_UNKNOWN;
} else {
return TR_BAD;
}
b = get_Mul_right(irn);
- if (get_irn_MacroBlock(b) != get_irn_MacroBlock(call)) {
+ if (get_nodes_block(b) != get_nodes_block(call)) {
/* we are outside, ignore */
vb = TR_UNKNOWN;
} else {
/*
* convert simple tail-calls into loops
*/
-int opt_tail_rec_irg(ir_graph *irg) {
+int opt_tail_rec_irg(ir_graph *irg)
+{
tr_env env;
ir_node *end_block;
int i, n_ress, n_tail_calls = 0;
ir_type *mtd_type, *call_type;
ir_entity *ent;
+ FIRM_DBG_REGISTER(dbg, "firm.opt.tailrec");
+
assure_irg_outs(irg);
if (! check_lifetime_of_locals(irg))
return 0;
-
ent = get_irg_entity(irg);
mtd_type = get_entity_type(ent);
n_ress = get_method_n_ress(mtd_type);
return n_tail_calls;
}
+ir_graph_pass_t *opt_tail_rec_irg_pass(const char *name)
+{
+ return def_graph_pass_ret(name ? name : "tailrec", opt_tail_rec_irg);
+}
+
/*
* optimize tail recursion away
*/
-void opt_tail_recursion(void) {
+void opt_tail_recursion(void)
+{
int i;
int n_opt_applications = 0;
ir_graph *irg;
DB((dbg, LEVEL_1, "Performed tail recursion for %d of %d graphs\n",
n_opt_applications, get_irp_n_irgs()));
}
+
+ir_prog_pass_t *opt_tail_recursion_pass(const char *name)
+{
+ return def_prog_pass(name ? name : "tailrec", opt_tail_recursion);
+}