Commit d6a32989 authored by Michael Beck's avatar Michael Beck
Browse files

Move Stores below the CF.

[r3990]
parent 6ac5dadb
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
# include "dbginfo_t.h" # include "dbginfo_t.h"
# include "iropt_dbg.h" # include "iropt_dbg.h"
# include "irflag_t.h" # include "irflag_t.h"
# include "array.h"
# include "firmstat.h" # include "firmstat.h"
#undef IMAX #undef IMAX
...@@ -40,6 +41,8 @@ typedef struct _walk_env_t { ...@@ -40,6 +41,8 @@ typedef struct _walk_env_t {
*/ */
typedef struct _ldst_info_t { typedef struct _ldst_info_t {
ir_node *projs[MAX_PROJ]; /**< list of Proj's of this node */ ir_node *projs[MAX_PROJ]; /**< list of Proj's of this node */
ir_node *exc_block; /**< the exception block if available */
int exc_idx; /**< predecessor index in the exception block */
} ldst_info_t; } ldst_info_t;
/** /**
...@@ -68,9 +71,9 @@ static ldst_info_t *get_info(ir_node *node, walk_env_t *env) ...@@ -68,9 +71,9 @@ static ldst_info_t *get_info(ir_node *node, walk_env_t *env)
} }
/** /**
* update the info for a Load/Store * update the projection info for a Load/Store
*/ */
static void update_projs(ldst_info_t *info, ir_node *proj) static int update_projs(ldst_info_t *info, ir_node *proj)
{ {
long nr = get_Proj_proj(proj); long nr = get_Proj_proj(proj);
...@@ -79,27 +82,55 @@ static void update_projs(ldst_info_t *info, ir_node *proj) ...@@ -79,27 +82,55 @@ static void update_projs(ldst_info_t *info, ir_node *proj)
if (info->projs[nr]) { if (info->projs[nr]) {
/* there is already one, do CSE */ /* there is already one, do CSE */
exchange(proj, info->projs[nr]); exchange(proj, info->projs[nr]);
return 1;
} }
else else {
info->projs[nr] = proj; info->projs[nr] = proj;
return 0;
}
}
/**
* update the exception block info for a Load/Store
*/
static int update_exc(ldst_info_t *info, ir_node *block, int pos)
{
assert(info->exc_block == NULL && "more than one exception block found");
info->exc_block = block;
info->exc_idx = pos;
return 0;
} }
/** /**
* walker, collects all Load/Store/Proj nodes * walker, collects all Load/Store/Proj nodes
*/ */
static void collect_nodes(ir_node *n, void *env) static void collect_nodes(ir_node *node, void *env)
{ {
ir_node *pred; ir_node *pred;
ldst_info_t *info; ldst_info_t *info;
walk_env_t *wenv = env; walk_env_t *wenv = env;
if (get_irn_op(n) == op_Proj) { if (get_irn_op(node) == op_Proj) {
pred = get_Proj_pred(n); pred = get_Proj_pred(node);
if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) { if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) {
info = get_info(pred, wenv); info = get_info(pred, wenv);
update_projs(info, n); wenv->changes |= update_projs(info, node);
}
}
else if (get_irn_op(node) == op_Block) { /* check, if it's an exception block */
int i, n;
for (i = 0, n = get_Block_n_cfgpreds(node); i < n; ++i) {
pred = skip_Proj(get_Block_cfgpred(node, i));
if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) {
info = get_info(pred, wenv);
wenv->changes |= update_exc(info, node, i);
}
} }
} }
} }
...@@ -248,6 +279,127 @@ static int optimize_store(ir_node *store) ...@@ -248,6 +279,127 @@ static int optimize_store(ir_node *store)
return res; return res;
} }
/**
* walker, optimizes Phi after Stores:
* Does the following optimization:
*
* val1 val2 val3 val1 val2 val3
* | | | \ | /
* Str Str Str \ | /
* \ | / Phi
* \ | / |
* \ | / Str
* Phi
*
* This removes teh number of stores and allows for predicated execution.
* Moves Stores back to the end of a function which may be bad
*
* Note: that even works, if one of the Stores is already in our current block
*/
static int optimize_phi(ir_node *phi)
{
int i, n;
ir_node *store, *ptr, *block, *phiM, *phiD, *exc;
ir_mode *mode;
ir_node **inM, **inD;
int *idx;
dbg_info *db = NULL;
ldst_info_t *info;
/* Must be a memory Phi */
if (get_irn_mode(phi) != mode_M)
return 0;
n = get_Phi_n_preds(phi);
if (n <= 0)
return 0;
store = skip_Proj(get_Phi_pred(phi, 0));
if (get_irn_op(store) != op_Store)
return 0;
/* this is the address of the store */
ptr = get_Store_ptr(store);
mode = get_irn_mode(get_Store_value(store));
info = get_irn_link(store);
exc = info->exc_block;
for (i = 1; i < n; ++i) {
ir_node *pred = skip_Proj(get_Phi_pred(phi, i));
if (get_irn_op(pred) != op_Store)
return 0;
if (mode != get_irn_mode(get_Store_value(pred)) || ptr != get_Store_ptr(pred))
return 0;
info = get_irn_link(pred);
/* check, if all stores have the same exception flow */
if (exc != info->exc_block)
return 0;
}
/*
* ok, when we are here, we found all predecessors of a Phi that
* are Stores to the same address. That means whatever we do before
* we enter the block of the Phi, we do a Store.
* So, we can move the store to the current block:
*
* val1 val2 val3 val1 val2 val3
* | | | \ | /
* | Str | | Str | | Str | \ | /
* \ | / Phi
* \ | / |
* \ | / Str
* Phi
*
* Note: that even works, if one of the Stores is already in our current block
*/
/* first step: collect all inputs */
NEW_ARR_A(ir_node *, inM, n);
NEW_ARR_A(ir_node *, inD, n);
NEW_ARR_A(int, idx, n);
for (i = 0; i < n; ++i) {
ir_node *pred = skip_Proj(get_Phi_pred(phi, i));
info = get_irn_link(pred);
inM[i] = get_Store_mem(pred);
inD[i] = get_Store_value(pred);
idx[i] = info->exc_idx;
}
block = get_nodes_block(phi);
/* second step: create a new memory Phi */
phiM = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inM, mode_M);
/* third step: create a new data Phi */
phiD = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inD, mode);
/* fourth step: create the Store */
store = new_rd_Store(db, current_ir_graph, block, phiM, ptr, phiD);
/* fifths step: repair exception flow */
if (exc) {
ir_node *projX = new_rd_Proj(NULL, current_ir_graph, block, store, mode_X, pn_Store_X_except);
for (i = 0; i < n; ++i) {
set_Block_cfgpred(exc, idx[i], projX);
}
if (n > 1) {
/* the exception block should be optimized as some inputs are identical now */
}
}
/* sixt step: replace old Phi */
exchange(phi, new_rd_Proj(NULL, current_ir_graph, block, store, mode_M, pn_Store_M));
return 1;
}
/** /**
* walker, collects all Load/Store/Proj nodes * walker, collects all Load/Store/Proj nodes
*/ */
...@@ -265,6 +417,9 @@ static void do_load_store_optimize(ir_node *n, void *env) ...@@ -265,6 +417,9 @@ static void do_load_store_optimize(ir_node *n, void *env)
wenv->changes |= optimize_store(n); wenv->changes |= optimize_store(n);
break; break;
case iro_Phi:
wenv->changes |= optimize_phi(n);
default: default:
; ;
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment