#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "errors.h"
#include "ggc.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "diagnostic.h"
#include "tree-inline.h"
#include "tree-flow.h"
#include "tree-gimple.h"
#include "tree-dump.h"
#include "timevar.h"
#include "fibheap.h"
#include "hashtab.h"
#include "tree-iterator.h"
#include "real.h"
#include "alloc-pool.h"
#include "tree-pass.h"
#include "flags.h"
struct expr_info;
static void clear_all_eref_arrays (void);
static inline bool expr_lexically_eq (const tree, const tree);
static void free_expr_info (struct expr_info *);
static bitmap compute_idfs (bitmap *, tree);
static void set_var_phis (struct expr_info *, tree);
static inline bool names_match_p (const tree, const tree);
static bool is_strred_cand (const tree);
static int pre_expression (struct expr_info *, void *, bitmap);
static bool is_injuring_def (struct expr_info *, tree);
static inline bool okay_injuring_def (tree, tree);
static bool expr_phi_insertion (bitmap *, struct expr_info *);
static tree factor_through_injuries (struct expr_info *, tree, tree, bool *);
static inline tree maybe_find_rhs_use_for_var (tree, tree, unsigned int);
static inline tree find_rhs_use_for_var (tree, tree);
static tree create_ephi_node (basic_block, unsigned int);
static inline int opnum_of_phi (tree, int);
static inline int opnum_of_ephi (const tree, const edge);
static tree subst_phis (struct expr_info *, tree, basic_block, basic_block);
static void generate_expr_as_of_bb (tree, basic_block, basic_block);
static void generate_vops_as_of_bb (tree, basic_block, basic_block);
static void rename_1 (struct expr_info *);
static void process_delayed_rename (struct expr_info *, tree, tree);
static void assign_new_class (tree, varray_type *, varray_type *);
static void create_and_insert_occ_in_preorder_dt_order (struct expr_info *);
static void insert_euse_in_preorder_dt_order (struct expr_info *);
static bool ephi_has_unsafe_arg (tree);
static void reset_down_safe (tree, int);
static void compute_down_safety (struct expr_info *);
static void compute_will_be_avail (struct expr_info *);
static void compute_stops (struct expr_info *);
static bool finalize_1 (struct expr_info *);
static void finalize_2 (struct expr_info *);
static tree occ_identical_to (tree);
static void require_phi (struct expr_info *, basic_block);
static bool really_available_def (tree node);
struct ephi_df_search
{
bool (*seen) (tree);
void (*set_seen) (tree);
void (*reach_from_to) (tree, int, tree);
bool (*start_from) (tree);
bool (*continue_from_to) (tree, int, tree);
};
static bool repl_search_seen (tree);
static void repl_search_set_seen (tree);
static void repl_search_reach_from_to (tree, int, tree);
static bool repl_search_start_from (tree);
static bool repl_search_continue_from_to (tree, int, tree);
static bool stops_search_seen (tree);
static void stops_search_set_seen (tree);
static void stops_search_reach_from_to (tree, int, tree);
static bool stops_search_start_from (tree);
static bool stops_search_continue_from_to (tree, int, tree);
static bool cba_search_seen (tree);
static void cba_search_set_seen (tree);
static bool cba_search_start_from (tree);
static bool cba_search_continue_from_to (tree, int, tree);
struct ephi_df_search cant_be_avail_search = {
cba_search_seen,
cba_search_set_seen,
NULL,
cba_search_start_from,
cba_search_continue_from_to
};
struct ephi_df_search stops_search = {
stops_search_seen,
stops_search_set_seen,
stops_search_reach_from_to,
stops_search_start_from,
stops_search_continue_from_to
};
struct ephi_df_search replacing_search = {
repl_search_seen,
repl_search_set_seen,
repl_search_reach_from_to,
repl_search_start_from,
repl_search_continue_from_to
};
static void do_ephi_df_search_1 (struct ephi_df_search, tree);
static void do_ephi_df_search (struct expr_info *, struct ephi_df_search);
static inline bool any_operand_injured (tree);
static void code_motion (struct expr_info *);
static tree pick_ssa_name (tree stmt);
#if 0
static tree calculate_increment (struct expr_info *, tree);
#endif
static bool can_insert (tree, int);
static void set_save (struct expr_info *, tree);
static tree reaching_def (tree, tree, basic_block, tree);
static tree do_proper_save (tree , tree, int);
static void process_left_occs_and_kills (varray_type, tree);
static tree create_expr_ref (struct expr_info *, tree, enum tree_code,
basic_block, tree);
static inline bool ephi_will_be_avail (tree);
static inline tree ephi_at_block (basic_block);
static tree get_default_def (tree, htab_t);
static inline bool same_e_version_real_occ_real_occ (struct expr_info *,
const tree,
const tree);
static inline bool load_modified_phi_result (basic_block, tree);
static inline bool same_e_version_phi_result (struct expr_info *,
tree, tree, tree);
static inline bool load_modified_real_occ_real_occ (tree, tree);
static inline bool same_e_version_real_occ_phi_opnd (struct expr_info *,
tree, basic_block,
int, tree, bool *);
static inline bool injured_real_occ_real_occ (struct expr_info *,
tree, tree);
static inline bool injured_phi_result_real_occ (struct expr_info *,
tree, tree, basic_block);
static inline bool injured_real_occ_phi_opnd (struct expr_info *,
tree, basic_block, int);
static void compute_du_info (struct expr_info *);
static void add_ephi_use (tree, tree, int);
static void insert_one_operand (struct expr_info *, tree, int, tree, edge,
tree **);
static void collect_expressions (basic_block, varray_type *);
static int build_dfn_array (basic_block, int);
static int eref_compare (const void *, const void *);
static bitmap created_phi_preds;
static bitmap *pre_dfs;
static int class_count = 0;
static bitmap *idfs_cache;
static struct pre_stats_d
{
int reloads;
int saves;
int repairs;
int newphis;
int ephi_allocated;
int ephis_current;
int eref_allocated;
int exprs_generated;
} pre_stats = {0, 0, 0, 0, 0, 0, 0, 0};
struct ephi_use_entry
{
tree phi;
int opnd_indx;
};
struct expr_info
{
tree expr;
varray_type occurs;
varray_type kills;
varray_type lefts;
varray_type reals;
bool strred_cand;
bool loadpre_cand;
varray_type euses_dt_order;
tree temp;
};
static tree *phi_pred_cache;
static int n_phi_preds;
typedef struct ephi_pred_index_elt
{
tree ephi;
edge edge;
int opnd;
} ephi_pindex_t;
static hashval_t
ephi_pindex_hash (const void *p)
{
const ephi_pindex_t *ep = (const ephi_pindex_t *)p;
return htab_hash_pointer (ep->ephi) + htab_hash_pointer (ep->edge);
}
static int
ephi_pindex_eq (const void *p1, const void *p2)
{
const ephi_pindex_t *ep1 = (const ephi_pindex_t *)p1;
const ephi_pindex_t *ep2 = (const ephi_pindex_t *)p2;
return ep1->ephi == ep2->ephi && ep1->edge == ep2->edge;
}
static htab_t ephi_pindex_htab;
static int
add_ephi_pred (tree phi, tree def, edge e)
{
int i = EPHI_NUM_ARGS (phi);
void **slot;
ephi_pindex_t ep, *epp;
EPHI_ARG_PRED (phi, i) = def;
EPHI_ARG_EDGE (phi, i) = e;
ep.ephi = phi;
ep.edge = e;
slot = htab_find_slot (ephi_pindex_htab, (void *)&ep, INSERT);
if (*slot == NULL)
{
epp = xmalloc (sizeof (*epp));
epp->ephi = phi;
epp->edge = e;
epp->opnd = i;
*slot = (void *)epp;
}
else
abort ();
EPHI_NUM_ARGS (phi)++;
return i;
}
static tree
create_ephi_node (basic_block bb, unsigned int add)
{
tree phi;
int len;
edge e;
size_t size;
bb_ann_t ann;
for (len = 0, e = bb->pred; e; e = e->pred_next)
len++;
size = (sizeof (struct tree_ephi_node)
+ ((len - 1) * sizeof (struct ephi_arg_d)));
phi = xmalloc (size);
memset (phi, 0, size);
if (add)
{
ann = bb_ann (bb);
if (ann->ephi_nodes == NULL)
ann->ephi_nodes = phi;
else
chainon (ann->ephi_nodes, phi);
}
pre_stats.ephi_allocated += size;
pre_stats.ephis_current += 1;
TREE_SET_CODE (phi, EPHI_NODE);
EPHI_NUM_ARGS (phi) = 0;
EPHI_ARG_CAPACITY (phi) = len;
set_bb_for_stmt (phi, bb);
return phi;
}
static inline tree
find_rhs_use_for_var (tree def, tree var)
{
tree ret = maybe_find_rhs_use_for_var (def, var, 0);
if (!ret)
abort ();
return ret;
}
static inline bool
names_match_p (const tree t1, const tree t2)
{
tree name1, name2;
if (t1 == t2)
return true;
if (TREE_CODE (t1) == INDIRECT_REF)
return names_match_p (TREE_OPERAND (t1, 0), t2);
if (TREE_CODE (t2) == INDIRECT_REF)
return names_match_p (t1, TREE_OPERAND (t2, 0));
if (TREE_CODE (t1) == SSA_NAME)
name1 = SSA_NAME_VAR (t1);
else if (DECL_P (t1))
name1 = t1;
else
name1 = NULL_TREE;
if (TREE_CODE (t2) == SSA_NAME)
name2 = SSA_NAME_VAR (t2);
else if (DECL_P (t2))
name2 = t2;
else
name2 = NULL_TREE;
if (name1 == NULL_TREE && name2 != NULL_TREE)
return false;
if (name2 == NULL_TREE && name1 != NULL_TREE)
return false;
if (name1 == NULL_TREE && name2 == NULL_TREE)
return operand_equal_p (t1, t2, 0);
return name1 == name2;
}
static inline tree
maybe_find_rhs_use_for_var (tree def, tree var, unsigned int startpos)
{
use_optype uses;
size_t i;
if (SSA_VAR_P (def))
{
if (names_match_p (var, def))
return def;
return NULL_TREE;
}
get_stmt_operands (def);
uses = STMT_USE_OPS (def);
for (i = startpos; i < NUM_USES (uses); i++)
{
tree use = USE_OP (uses, i);
if (names_match_p (use, var))
return use;
}
return NULL_TREE;
}
static inline bool
okay_injuring_def (tree inj, tree var)
{
if (!inj || IS_EMPTY_STMT (inj)
|| TREE_CODE (inj) == PHI_NODE
|| !maybe_find_rhs_use_for_var (inj, var, 0))
return false;
return true;
}
static bool
is_injuring_def (struct expr_info *ei, tree inj)
{
if (!inj || IS_EMPTY_STMT (inj) || TREE_CODE (inj) == PHI_NODE)
return false;
if (TREE_CODE (TREE_OPERAND (inj, 1)) != PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (inj, 1)) != MINUS_EXPR)
return false;
if (!names_match_p (TREE_OPERAND (inj, 0), TREE_OPERAND (ei->expr, 0))
|| !TREE_OPERAND (TREE_OPERAND (inj, 1), 0)
|| !names_match_p (TREE_OPERAND (TREE_OPERAND (inj, 1), 0),
TREE_OPERAND (ei->expr, 0)))
return false;
if (TREE_CODE (ei->expr) == MULT_EXPR)
{
tree irhs1;
tree irhs2;
tree irhs;
irhs = TREE_OPERAND (inj, 1);
irhs1 = TREE_OPERAND (irhs, 0);
irhs2 = TREE_OPERAND (irhs, 1);
if (TREE_CODE (irhs2) != INTEGER_CST)
return false;
if (tree_low_cst (irhs2, 0) == 1)
return true;
if (really_constant_p (irhs2)
&& really_constant_p (TREE_OPERAND (ei->expr, 1)))
return true;
return false;
}
return true;
}
static tree
factor_through_injuries (struct expr_info *ei, tree start, tree var,
bool *injured)
{
tree end = start;
while (is_injuring_def (ei, SSA_NAME_DEF_STMT (end)))
{
if (injured)
*injured = true;
end = find_rhs_use_for_var (SSA_NAME_DEF_STMT (end), var);
if (!okay_injuring_def (SSA_NAME_DEF_STMT (end), var))
break;
if (dump_file)
{
fprintf (dump_file, "Found a real injury:");
print_generic_stmt (dump_file, SSA_NAME_DEF_STMT (end), dump_flags);
fprintf (dump_file, "\n");
}
if (injured)
*injured = true;
end = find_rhs_use_for_var (SSA_NAME_DEF_STMT (end), var);
}
return end;
}
static inline bool
ephi_will_be_avail (tree ephi)
{
if (!EPHI_CANT_BE_AVAIL (ephi))
if (EPHI_STOPS (ephi))
return true;
return false;
}
static alloc_pool euse_node_pool;
static alloc_pool eref_node_pool;
static int eref_id_counter = 0;
static tree
create_expr_ref (struct expr_info *ei, tree expr, enum tree_code type,
basic_block bb, tree parent)
{
tree ret;
if (type == EPHI_NODE)
{
int len;
edge e;
ret = create_ephi_node (bb, 1);
for (len = 0, e = bb->pred; e; e = e->pred_next)
len++;
EREF_TEMP (ret) = make_phi_node (ei->temp, len);
}
else
{
if (type == EUSE_NODE)
ret = (tree) pool_alloc (euse_node_pool);
else
ret = (tree) pool_alloc (eref_node_pool);
TREE_SET_CODE (ret, type);
memset (ret, 0, tree_size (ret));
TREE_SET_CODE (ret, type);
pre_stats.eref_allocated += tree_size (ret);
}
EREF_NAME (ret) = expr;
set_bb_for_stmt (ret, bb);
EREF_STMT (ret) = parent;
EREF_SAVE (ret) = false;
EREF_ID (ret) = eref_id_counter++;
return ret;
}
static bitmap dfphis;
static bitmap varphis;
static void
set_var_phis (struct expr_info *ei, tree phi)
{
basic_block bb = bb_for_stmt (phi);
if (!bitmap_bit_p (varphis, bb->index)
&& !bitmap_bit_p (dfphis, bb->index))
{
tree phi_operand;
int curr_phi_operand;
bitmap_set_bit (varphis, bb->index);
for (curr_phi_operand = 0;
curr_phi_operand < PHI_NUM_ARGS (phi);
curr_phi_operand++)
{
phi_operand = PHI_ARG_DEF (phi, curr_phi_operand);
if (ei->strred_cand && TREE_CODE (phi_operand) != PHI_NODE)
{
phi_operand = factor_through_injuries (ei, phi_operand,
SSA_NAME_VAR (phi_operand),
NULL);
phi_operand = SSA_NAME_DEF_STMT (phi_operand);
if (dump_file)
{
fprintf (dump_file, "After factoring through injuries:");
print_generic_stmt (dump_file, phi_operand, dump_flags);
fprintf (dump_file, "\n");
}
}
if (TREE_CODE (phi_operand) == PHI_NODE)
set_var_phis (ei, phi_operand);
}
}
}
static void
clear_all_eref_arrays (void)
{
basic_block bb;
bb_ann_t ann;
FOR_ALL_BB (bb)
{
ann = bb_ann (bb);
if (ann->ephi_nodes)
{
free (ann->ephi_nodes);
pre_stats.ephis_current -= 1;
}
ann->ephi_nodes = NULL;
}
}
static bool
expr_phi_insertion (bitmap *dfs, struct expr_info *ei)
{
size_t i, j;
vuse_optype vuses;
use_optype uses;
bool retval = true;
dfphis = BITMAP_XMALLOC ();
bitmap_zero (dfphis);
varphis = BITMAP_XMALLOC ();
bitmap_zero (varphis);
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->occurs); i++)
{
tree occurp = VARRAY_TREE (ei->occurs, i);
tree occur = occurp ? occurp : NULL;
tree killp = VARRAY_TREE (ei->kills, i);
tree kill = killp ? killp : NULL;
tree leftp = VARRAY_TREE (ei->lefts, i);
tree left = leftp ? leftp : NULL;
bitmap temp;
stmt_ann_t ann;
#ifdef ENABLE_CHECKING
if ((kill && occur) || (left && occur) || (kill && left))
abort();
#endif
occurp = occur ? occurp : kill ? killp : leftp;
occur = occur ? occur : kill ? kill : left;
temp = compute_idfs (dfs, occur);
bitmap_a_or_b (dfphis, dfphis, temp);
if (kill != NULL)
continue;
get_stmt_operands (occurp);
ann = stmt_ann (occurp);
uses = USE_OPS (ann);
for (j = 0; j < NUM_USES (uses); j ++)
{
tree use = USE_OP (uses, j);
if (ei->strred_cand)
use = factor_through_injuries (ei, use, SSA_NAME_VAR (use),
NULL);
if (TREE_CODE (SSA_NAME_DEF_STMT (use)) != PHI_NODE)
continue;
set_var_phis (ei, SSA_NAME_DEF_STMT (use));
}
if (ei->loadpre_cand && TREE_CODE (ei->expr) == INDIRECT_REF)
{
vuses = VUSE_OPS (ann);
for (j = 0; j < NUM_VUSES (vuses); j ++)
{
tree use = VUSE_OP (vuses, j);
if (ei->strred_cand)
use = factor_through_injuries (ei, use, SSA_NAME_VAR (use),
NULL);
if (TREE_CODE (SSA_NAME_DEF_STMT (use)) != PHI_NODE)
continue;
set_var_phis (ei, SSA_NAME_DEF_STMT (use));
}
}
}
bitmap_a_or_b (dfphis, dfphis, varphis);
EXECUTE_IF_SET_IN_BITMAP(dfphis, 0, i,
{
tree ref = create_expr_ref (ei, ei->expr, EPHI_NODE, BASIC_BLOCK (i),
NULL);
EREF_PROCESSED (ref) = false;
EPHI_DOWNSAFE (ref) = true;
EPHI_DEAD (ref) = true;
});
#if 0
if (bitmap_first_set_bit (dfphis) == -1)
retval = false;
#endif
BITMAP_XFREE (dfphis);
BITMAP_XFREE (varphis);
return retval;
}
static inline tree
ephi_at_block (basic_block bb)
{
bb_ann_t ann = bb_ann (bb);
if (ann->ephi_nodes)
return ann->ephi_nodes;
else
return NULL_TREE;
}
static int *dfn;
static int
build_dfn_array (basic_block bb, int num)
{
basic_block son;
if (bb->index >= 0)
dfn[bb->index] = num;
for (son = first_dom_son (CDI_DOMINATORS, bb);
son;
son = next_dom_son (CDI_DOMINATORS, son))
num = build_dfn_array (son, ++num);
return num;
}
static int
eref_compare (const void *elem1, const void *elem2)
{
tree t1 = *(tree *)elem1;
tree t2 = *(tree *)elem2;
basic_block bb1, bb2;
if (t1 == t2)
return 0;
bb1 = bb_for_stmt (t1);
bb2 = bb_for_stmt (t2);
if (bb1 == bb2)
{
if (TREE_CODE (t1) == EEXIT_NODE)
return 1;
if (TREE_CODE (t2) == EEXIT_NODE)
return -1;
if (TREE_CODE (t1) == EPHI_NODE)
return -1;
if (TREE_CODE (t2) == EPHI_NODE)
return 1;
if ((TREE_CODE (t1) == EUSE_NODE && EUSE_PHIOP (t1))
&& (TREE_CODE (t2) == EUSE_NODE && !EUSE_PHIOP (t2)))
return 1;
if ((TREE_CODE (t1) == EUSE_NODE && !EUSE_PHIOP (t1))
&& (TREE_CODE (t2) == EUSE_NODE && EUSE_PHIOP (t2)))
return -1;
if (TREE_CODE (t1) == EUSE_NODE && TREE_CODE (t2) == EUSE_NODE)
return EREF_ID (t1) - EREF_ID (t2);
if (TREE_CODE (t1) == EPHI_NODE && TREE_CODE (t2) == EPHI_NODE)
abort ();
}
else
{
if (dfn[bb1->index] == dfn[bb2->index])
{
if (dominated_by_p (CDI_DOMINATORS, bb1, bb2))
return 1;
else
return -1;
}
else
return (dfn[bb1->index] < dfn[bb2->index]) ? -1 : 1;
}
abort ();
}
static void
create_and_insert_occ_in_preorder_dt_order (struct expr_info *ei)
{
size_t i;
edge succ;
tree curr_phi_pred = NULL_TREE;
basic_block block;
FOR_EACH_BB (block)
{
tree ephi = ephi_at_block (block);
if (ephi != NULL_TREE)
VARRAY_PUSH_TREE (ei->euses_dt_order, ephi);
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->occurs); i++)
{
tree newref;
tree current;
current = VARRAY_TREE (ei->occurs, i);
current = current ? current : VARRAY_TREE (ei->kills, i);
current = current ? current : VARRAY_TREE (ei->lefts, i);
block = bb_for_stmt (current);
if (VARRAY_TREE (ei->kills, i) != NULL)
{
tree killexpr = VARRAY_TREE (ei->kills, i);
tree killname = ei->expr;
newref = create_expr_ref (ei, killname, EKILL_NODE, block, killexpr);
VARRAY_PUSH_TREE (ei->euses_dt_order, newref);
}
else if (VARRAY_TREE (ei->lefts, i) != NULL)
{
tree occurexpr = VARRAY_TREE (ei->lefts, i);
tree occurname;
occurname = ei->expr;
newref = create_expr_ref (ei, occurname, EUSE_NODE, block,
occurexpr);
EUSE_DEF (newref) = NULL_TREE;
EUSE_LVAL (newref) = true;
EREF_CLASS (newref) = -1;
EUSE_PHIOP (newref) = false;
EREF_PROCESSED (newref) = false;
VARRAY_PUSH_TREE (ei->euses_dt_order, newref);
}
else
{
tree occurexpr = VARRAY_TREE (ei->occurs, i);
tree occurname;
occurname = ei->expr;
newref = create_expr_ref (ei, occurname, EUSE_NODE, block,
occurexpr);
EUSE_DEF (newref) = NULL_TREE;
EREF_CLASS (newref) = -1;
EUSE_PHIOP (newref) = false;
EREF_PROCESSED (newref) = false;
VARRAY_PUSH_TREE (ei->euses_dt_order, newref);
}
}
FOR_ALL_BB (block)
{
for (succ = block->succ; succ; succ = succ->succ_next)
{
if (succ->dest != EXIT_BLOCK_PTR)
{
tree ephi = ephi_at_block (succ->dest);
if (ephi != NULL
&& !bitmap_bit_p (created_phi_preds, block->index))
{
tree newref = create_expr_ref (ei, 0, EUSE_NODE, block, NULL);
curr_phi_pred = newref;
VARRAY_PUSH_TREE (ei->euses_dt_order, newref);
EUSE_DEF (newref) = NULL_TREE;
EREF_CLASS (newref) = -1;
EUSE_PHIOP (newref) = true;
EREF_SAVE (newref) = false;
EREF_RELOAD (newref) = false;
EUSE_INSERTED (newref) = false;
EREF_PROCESSED (newref) = false;
bitmap_set_bit (created_phi_preds, block->index);
add_ephi_pred (ephi, newref, succ);
}
else if (ephi != NULL)
{
#ifdef ENABLE_CHECKING
if (curr_phi_pred == NULL_TREE)
abort();
#endif
add_ephi_pred (ephi, curr_phi_pred, succ);
}
}
else if (succ->dest == EXIT_BLOCK_PTR && !(succ->flags & EDGE_FAKE))
{
tree newref;
newref = create_expr_ref (ei, ei->expr, EEXIT_NODE,
block,
NULL);
VARRAY_PUSH_TREE (ei->euses_dt_order, newref);
}
}
}
qsort (ei->euses_dt_order->data.tree,
VARRAY_ACTIVE_SIZE (ei->euses_dt_order),
sizeof (tree),
eref_compare);
}
static void
assign_new_class (tree occ, varray_type * stack, varray_type * stack2)
{
EREF_CLASS (occ) = class_count;
VARRAY_PUSH_TREE (*stack, occ);
if (stack2)
VARRAY_PUSH_TREE (*stack2, occ);
class_count++;
}
static inline bool
same_e_version_real_occ_real_occ (struct expr_info *ei,
const tree def, const tree use)
{
hashval_t expr1val;
hashval_t expr2val;
vuse_optype vuses;
size_t i;
const tree t1 = EREF_STMT (def);
const tree t2 = EREF_STMT (use);
expr1val = iterative_hash_expr (TREE_OPERAND (t1, 1), 0);
expr2val = iterative_hash_expr (TREE_OPERAND (t2, 1), 0);
if (expr1val == expr2val)
{
vuses = STMT_VUSE_OPS (t1);
for (i = 0; i < NUM_VUSES (vuses); i++)
expr1val = iterative_hash_expr (VUSE_OP (vuses, i), expr1val);
vuses = STMT_VUSE_OPS (t2);
for (i = 0; i < NUM_VUSES (vuses); i++)
expr2val = iterative_hash_expr (VUSE_OP (vuses, i), expr2val);
if (expr1val != expr2val)
return false;
}
if (expr1val == expr2val)
{
if (EREF_INJURED (def))
EREF_INJURED (use) = true;
return true;
}
if (expr1val != expr2val && ei->strred_cand)
{
if (injured_real_occ_real_occ (ei, def, use))
{
EREF_INJURED (use) = true;
return true;
}
}
return false;
}
static inline bool
injured_real_occ_real_occ (struct expr_info *ei ATTRIBUTE_UNUSED,
tree def ATTRIBUTE_UNUSED,
tree use ATTRIBUTE_UNUSED)
{
tree defstmt;
tree defvar;
defstmt = EREF_STMT (def);
if (TREE_CODE (TREE_OPERAND (defstmt, 0)) != SSA_NAME)
return false;
defvar = TREE_OPERAND (defstmt, 0);
return false;
}
static inline int
opnum_of_ephi (const tree ephi, const edge e)
{
ephi_pindex_t ep, *epp;
ep.ephi = ephi;
ep.edge = e;
epp = htab_find (ephi_pindex_htab, &ep);
if (epp == NULL)
abort ();
return epp->opnd;
}
static inline int
opnum_of_phi (tree phi, int j)
{
int i;
for (i = 0 ; i < PHI_NUM_ARGS (phi); i++)
if (PHI_ARG_EDGE (phi, i)->src->index == j)
return i;
abort();
}
static void
generate_expr_as_of_bb (tree expr, basic_block pred, basic_block bb)
{
use_optype uses = STMT_USE_OPS (expr);
bool replaced_constants = false;
size_t k;
for (k = 0; k < NUM_USES (uses); k++)
{
tree *vp = USE_OP_PTR (uses, k);
tree v = *vp;
tree phi;
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
{
if (PHI_RESULT (phi) == v)
{
int opnum = opnum_of_phi (phi, pred->index);
tree p = PHI_ARG_DEF (phi, opnum);
replace_exp (vp, p);
if (!phi_ssa_name_p (p))
replaced_constants = true;
break;
}
}
}
if (replaced_constants)
fold_stmt (&expr);
}
static void
generate_vops_as_of_bb (tree expr, basic_block pred, basic_block bb)
{
vuse_optype vuses = STMT_VUSE_OPS (expr);
size_t i;
for (i = 0; i < NUM_VUSES (vuses); i++)
{
tree v = VUSE_OP (vuses, i);
tree phi;
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
{
if (PHI_RESULT (phi) == v)
{
int opnum = opnum_of_phi (phi, pred->index);
tree p = PHI_ARG_DEF (phi, opnum);
replace_exp (VUSE_OP_PTR (vuses, i), p);
break;
}
}
}
}
static tree
subst_phis (struct expr_info *ei, tree Z, basic_block pred, basic_block bb)
{
tree stmt_copy;
size_t i;
if (pred->index < n_phi_preds
&& phi_pred_cache[pred->index] != NULL_TREE)
return phi_pred_cache[pred->index];
pre_stats.exprs_generated++;
stmt_copy = unshare_expr (Z);
create_stmt_ann (stmt_copy);
modify_stmt (stmt_copy);
get_stmt_operands (stmt_copy);
generate_expr_as_of_bb (stmt_copy, pred, bb);
set_bb_for_stmt (stmt_copy, bb);
modify_stmt (stmt_copy);
get_stmt_operands (stmt_copy);
if (ei->loadpre_cand
&& NUM_VUSES (STMT_VUSE_OPS (Z)) != 0
&& NUM_USES (STMT_USE_OPS (stmt_copy)) != 0)
{
vuse_optype vuses = STMT_VUSE_OPS (Z);
remove_vuses (stmt_copy);
start_ssa_stmt_operands (stmt_copy);
for (i = 0; i < NUM_VUSES (vuses); i++)
add_vuse (VUSE_OP (vuses, i), stmt_copy);
finalize_ssa_stmt_operands (stmt_copy);
generate_vops_as_of_bb (stmt_copy, pred, bb);
}
else
{
remove_vuses (stmt_copy);
remove_vdefs (stmt_copy);
}
if (pred->index < n_phi_preds)
phi_pred_cache[pred->index] = stmt_copy;
return stmt_copy;
}
static inline bool
same_e_version_real_occ_phi_opnd (struct expr_info *ei, tree def,
basic_block use_bb, int opnd_num,
tree use_tree, bool *injured)
{
bool not_mod = true;
*injured = false;
if (load_modified_real_occ_real_occ (EREF_STMT (def),
use_tree))
not_mod = false;
if (not_mod)
return true;
else if (ei->strred_cand)
{
if (injured_real_occ_phi_opnd (ei, def, use_bb, opnd_num))
return true;
}
return false;
}
static inline bool
injured_real_occ_phi_opnd (struct expr_info *ei ATTRIBUTE_UNUSED,
tree def ATTRIBUTE_UNUSED,
basic_block use_bb ATTRIBUTE_UNUSED,
int opnd_num ATTRIBUTE_UNUSED)
{
return false;
}
static inline bool
load_modified_real_occ_real_occ (tree def, tree use)
{
hashval_t expr1val;
hashval_t expr2val;
vuse_optype vuses;
size_t i;
if (TREE_CODE (def) == VA_ARG_EXPR)
expr1val = iterative_hash_expr (def, 0);
else
expr1val = iterative_hash_expr (TREE_OPERAND (def, 1), 0);
if (TREE_CODE (use) == VA_ARG_EXPR)
expr2val = iterative_hash_expr (use, 0);
else
expr2val = iterative_hash_expr (TREE_OPERAND (use, 1), 0);
if (expr1val == expr2val)
{
vuses = STMT_VUSE_OPS (def);
for (i = 0; i < NUM_VUSES (vuses); i++)
expr1val = iterative_hash_expr (VUSE_OP (vuses, i), expr1val);
vuses = STMT_VUSE_OPS (use);
for (i = 0; i < NUM_VUSES (vuses); i++)
expr2val = iterative_hash_expr (VUSE_OP (vuses, i), expr2val);
if (expr1val != expr2val)
return false;
}
return expr1val != expr2val;
}
static bool
load_modified_phi_result (basic_block bb, tree use)
{
basic_block defbb = bb_for_stmt (SSA_NAME_DEF_STMT (use));
if (defbb != bb)
{
if (!defbb && TREE_CODE (SSA_NAME_VAR (use)) != PARM_DECL)
return true;
else if (!defbb && TREE_CODE (SSA_NAME_VAR (use)) == PARM_DECL)
return false;
if (dominated_by_p (CDI_DOMINATORS, bb, defbb))
return false;
}
else
{
if (TREE_CODE (SSA_NAME_DEF_STMT (use)) == PHI_NODE)
return false;
}
return true;
}
static bool
same_e_version_phi_result (struct expr_info *ei, tree def, tree exp,
tree use)
{
stmt_ann_t ann = stmt_ann (exp);
bool not_mod = true;
size_t i;
use_optype real_expuses = USE_OPS (ann);
vuse_optype expuses;
if (NUM_USES (real_expuses) == 0)
return false;
for (i = 0; i < NUM_USES (real_expuses) && not_mod; i++)
{
tree *use1p = USE_OP_PTR (real_expuses, i);
tree use1;
if (!use1p)
continue;
use1 = *use1p;
if (load_modified_phi_result (bb_for_stmt (def), use1))
not_mod = false;
}
if (not_mod && ei->loadpre_cand)
{
expuses = VUSE_OPS (ann);
for (i = 0; i < NUM_VUSES (expuses) && not_mod; i++)
{
tree use1 = VUSE_OP (expuses, i);
if (load_modified_phi_result (bb_for_stmt (def), use1))
not_mod = false;
}
}
if (not_mod)
return true;
else if (ei->strred_cand)
{
if (injured_phi_result_real_occ (ei, def, exp, bb_for_stmt (use)))
{
EREF_INJURED (use) = true;
return true;
}
}
return false;
}
static inline bool
injured_phi_result_real_occ (struct expr_info *ei ATTRIBUTE_UNUSED,
tree def ATTRIBUTE_UNUSED,
tree use_tree ATTRIBUTE_UNUSED,
basic_block use_bb ATTRIBUTE_UNUSED)
{
return false;
}
static void
process_delayed_rename (struct expr_info *ei, tree use, tree real_occ)
{
tree exp_phi = use;
int opnd_num = 0;
for (opnd_num = 0; opnd_num < EPHI_NUM_ARGS (exp_phi); opnd_num++)
{
tree opnd = EPHI_ARG_DEF (exp_phi, opnd_num);
if (EPHI_ARG_DELAYED_RENAME (exp_phi, opnd_num))
{
tree def;
tree newexp;
EPHI_ARG_DELAYED_RENAME (exp_phi, opnd_num) = false;
def = opnd;
newexp = subst_phis (ei, real_occ,
EPHI_ARG_EDGE (exp_phi, opnd_num)->src,
bb_for_stmt (exp_phi));
if (TREE_CODE (def) == EPHI_NODE)
{
tree tmp_use = EPHI_ARG_PRED (exp_phi, opnd_num);
EREF_STMT (tmp_use) = newexp;
if (same_e_version_phi_result (ei, def, newexp,
tmp_use))
{
if (EREF_INJURED (tmp_use))
{
EREF_INJURED (tmp_use) = false;
EPHI_ARG_INJURED (exp_phi, opnd_num) = true;
}
if (EREF_STMT (def) == NULL)
{
if (EPHI_ARG_INJURED (exp_phi, opnd_num))
{
}
EREF_STMT (def) = newexp;
process_delayed_rename (ei, def, newexp);
}
}
else
{
EPHI_DOWNSAFE (def) = false;
EPHI_ARG_DEF (exp_phi, opnd_num) = NULL;
}
}
else if (TREE_CODE (def) == EUSE_NODE && !EUSE_PHIOP (def))
{
bool injured = false;
if (same_e_version_real_occ_phi_opnd (ei, def,
bb_for_stmt (use),
opnd_num, newexp, &injured))
{
tree tmp_use = EPHI_ARG_PRED (exp_phi, opnd_num);
EPHI_ARG_HAS_REAL_USE (exp_phi, opnd_num) = true;
if (injured || EREF_INJURED (def))
EREF_INJURED (def) = true;
if (injured || EREF_INJURED (def))
EREF_INJURED (opnd) = true;
else
EREF_STMT (tmp_use) = EREF_STMT (def);
if (EUSE_DEF (def) != NULL)
EPHI_ARG_DEF (exp_phi, opnd_num) = EUSE_DEF (def);
else
EPHI_ARG_DEF (exp_phi, opnd_num) = def;
}
else
{
EPHI_ARG_DEF (exp_phi, opnd_num) = NULL;
}
}
}
}
}
static void
rename_1 (struct expr_info *ei)
{
tree occur;
basic_block phi_bb;
size_t i;
varray_type stack;
VARRAY_GENERIC_PTR_NOGC_INIT (stack, 1, "Stack for renaming");
create_and_insert_occ_in_preorder_dt_order (ei);
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
occur = VARRAY_TREE (ei->euses_dt_order, i);
while (VARRAY_ACTIVE_SIZE (stack) > 0
&& !dominated_by_p (CDI_DOMINATORS,
bb_for_stmt (occur),
bb_for_stmt (VARRAY_TOP_TREE (stack))))
VARRAY_POP (stack);
if (VARRAY_ACTIVE_SIZE (stack) == 0 || VARRAY_TOP_TREE (stack) == NULL)
{
if (TREE_CODE (occur) == EPHI_NODE)
assign_new_class (occur, &stack, NULL);
else if (TREE_CODE (occur) == EUSE_NODE && !EUSE_PHIOP (occur))
assign_new_class (occur, &stack, NULL);
}
else
{
if (TREE_CODE (occur) == EUSE_NODE && !EUSE_PHIOP (occur))
{
tree tos = VARRAY_TOP_TREE (stack);
if (TREE_CODE (tos) == EUSE_NODE && !EUSE_PHIOP (tos))
{
if (!EUSE_LVAL (occur)
&& same_e_version_real_occ_real_occ (ei, tos, occur))
{
tree newdef;
EREF_CLASS (occur) = EREF_CLASS (tos);
newdef = EUSE_DEF (tos) != NULL ? EUSE_DEF (tos) : tos;
EUSE_DEF (occur) = newdef;
}
else
assign_new_class (occur, &stack, NULL);
}
else if (TREE_CODE (tos) == EPHI_NODE)
{
if (!EUSE_LVAL (occur)
&& same_e_version_phi_result (ei, tos, EREF_STMT (occur),
occur))
{
EREF_CLASS (occur) = EREF_CLASS (tos);
EUSE_DEF (occur) = tos;
EREF_STMT (tos) = EREF_STMT (occur);
VARRAY_PUSH_TREE (stack, occur);
}
else
{
EPHI_DOWNSAFE (tos) = false;
assign_new_class (occur, &stack, NULL);
}
}
}
else if (TREE_CODE (occur) == EPHI_NODE)
{
assign_new_class (occur, &stack, NULL);
}
else if (TREE_CODE (occur) == EUSE_NODE && EUSE_PHIOP (occur))
{
basic_block pred_bb = bb_for_stmt (occur);
edge e;
tree tos = VARRAY_TOP_TREE (stack);
for (e = pred_bb->succ; e; e = e->succ_next)
{
tree ephi = ephi_at_block (e->dest);
if (ephi != NULL_TREE)
{
int opnum = opnum_of_ephi (ephi, e);
EPHI_ARG_DELAYED_RENAME (ephi, opnum) = true;
EPHI_ARG_DEF (ephi, opnum) = tos;
}
}
}
else if (TREE_CODE (occur) == EEXIT_NODE)
{
if (VARRAY_ACTIVE_SIZE (stack) > 0
&& TREE_CODE (VARRAY_TOP_TREE (stack)) == EPHI_NODE)
EPHI_DOWNSAFE (VARRAY_TOP_TREE (stack)) = false;
}
}
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
size_t i;
fprintf (dump_file, "Occurrences for expression ");
print_generic_expr (dump_file, ei->expr, dump_flags);
fprintf (dump_file, " after Rename 1\n");
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
print_generic_expr (dump_file,
VARRAY_TREE (ei->euses_dt_order, i), 1);
fprintf (dump_file, "\n");
}
}
FOR_EACH_BB (phi_bb)
{
tree ephi = ephi_at_block (phi_bb);
if (ephi != NULL && EREF_STMT (ephi) != NULL)
process_delayed_rename (ei, ephi, EREF_STMT (ephi));
}
FOR_EACH_BB (phi_bb)
{
tree ephi = ephi_at_block (phi_bb);
if (ephi != NULL)
{
int j;
for (j = 0; j < EPHI_NUM_ARGS (ephi); j++)
{
if (EPHI_ARG_DELAYED_RENAME (ephi, j))
{
tree def = EPHI_ARG_DEF (ephi, j);
if (def && TREE_CODE (def) == EPHI_NODE)
EPHI_DOWNSAFE (def) = false;
EPHI_ARG_DEF (ephi, j) = NULL;
}
}
}
}
VARRAY_FREE (stack);
}
static bool
ephi_has_unsafe_arg (tree ephi)
{
int i;
for (i = 0; i < EPHI_NUM_ARGS (ephi); i++)
if (EPHI_ARG_EDGE (ephi, i)->flags & EDGE_ABNORMAL)
return true;
return false;
}
static void
reset_down_safe (tree currphi, int opnum)
{
tree ephi;
int i;
if (EPHI_ARG_HAS_REAL_USE (currphi, opnum))
return;
ephi = EPHI_ARG_DEF (currphi, opnum);
if (!ephi || TREE_CODE (ephi) != EPHI_NODE)
return;
if (!EPHI_DOWNSAFE (ephi))
return;
EPHI_DOWNSAFE (ephi) = false;
for (i = 0; i < EPHI_NUM_ARGS (ephi); i++)
reset_down_safe (ephi, i);
}
static void
compute_down_safety (struct expr_info *ei)
{
size_t i;
basic_block bb;
FOR_EACH_BB (bb)
{
tree ephi = ephi_at_block (bb);
if (ephi == NULL_TREE)
continue;
if (ephi_has_unsafe_arg (ephi))
EPHI_DOWNSAFE (ephi) = false;
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
int j;
tree ephi = VARRAY_TREE (ei->euses_dt_order, i);
if (TREE_CODE (ephi) != EPHI_NODE)
continue;
if (!EPHI_DOWNSAFE (ephi))
for (j = 0; j < EPHI_NUM_ARGS (ephi); j++)
reset_down_safe (ephi, j);
}
}
static alloc_pool ephi_use_pool;
static void
add_ephi_use (tree def, tree use, int opnd_indx)
{
struct ephi_use_entry *entry;
if (EPHI_USES (def) == NULL)
VARRAY_GENERIC_PTR_INIT (EPHI_USES (def), 1, "EPHI uses");
entry = (struct ephi_use_entry *) pool_alloc (ephi_use_pool);
entry->phi = use;
entry->opnd_indx = opnd_indx;
VARRAY_PUSH_GENERIC_PTR (EPHI_USES (def), entry);
}
static void
compute_du_info (struct expr_info *ei)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
int j;
tree ephi = VARRAY_TREE (ei->euses_dt_order, i);
if (TREE_CODE (ephi) != EPHI_NODE)
continue;
for (j = 0; j < EPHI_NUM_ARGS (ephi); j++)
{
tree def = EPHI_ARG_DEF (ephi, j);
if (def != NULL_TREE)
{
if (TREE_CODE (def) == EPHI_NODE)
add_ephi_use (def, ephi, j);
#ifdef ENABLE_CHECKING
else
if (! (TREE_CODE (def) == EUSE_NODE && !EUSE_PHIOP (def)))
abort();
#endif
}
}
}
}
static void
compute_stops (struct expr_info *ei)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
tree ephi = VARRAY_TREE (ei->euses_dt_order, i);
int j;
if (TREE_CODE (ephi) != EPHI_NODE)
continue;
if (EPHI_CANT_BE_AVAIL (ephi))
EPHI_STOPS (ephi) = true;
for (j = 0; j < EPHI_NUM_ARGS (ephi); j++)
if (EPHI_ARG_HAS_REAL_USE (ephi, j))
EPHI_ARG_STOPS (ephi, j) = true;
}
do_ephi_df_search (ei, stops_search);
}
static void
compute_will_be_avail (struct expr_info *ei)
{
do_ephi_df_search (ei, cant_be_avail_search);
compute_stops (ei);
}
static void
insert_euse_in_preorder_dt_order (struct expr_info *ei)
{
varray_type new_euses_dt_order;
size_t i;
VARRAY_GENERIC_PTR_NOGC_INIT (new_euses_dt_order, 1, "EUSEs");
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
tree ref = VARRAY_TREE (ei->euses_dt_order, i);
if (TREE_CODE (ref) == EUSE_NODE || TREE_CODE (ref) == EPHI_NODE)
VARRAY_PUSH_TREE (new_euses_dt_order, ref);
}
VARRAY_FREE (ei->euses_dt_order);
ei->euses_dt_order = new_euses_dt_order;
qsort (ei->euses_dt_order->data.tree,
VARRAY_ACTIVE_SIZE (ei->euses_dt_order),
sizeof (tree),
eref_compare);
}
static bool
can_insert (tree ephi, int opnd_indx)
{
tree def;
if (EPHI_ARG_DEF (ephi, opnd_indx) == NULL_TREE)
return true;
def = EPHI_ARG_DEF (ephi, opnd_indx);
if (!EPHI_ARG_HAS_REAL_USE (ephi, opnd_indx))
if (TREE_CODE (def) == EPHI_NODE && !(ephi_will_be_avail (def)))
return true;
return false;
}
static tree
get_default_def (tree var, htab_t seen)
{
def_optype defs;
size_t i;
tree defstmt = SSA_NAME_DEF_STMT (var);
if (IS_EMPTY_STMT (defstmt))
return var;
*(htab_find_slot (seen, var, INSERT)) = var;
if (TREE_CODE (defstmt) == PHI_NODE)
{
int j;
for (j = 0; j < PHI_NUM_ARGS (defstmt); j++)
if (htab_find (seen, PHI_ARG_DEF (defstmt, j)) == NULL)
{
if (TREE_CODE (PHI_ARG_DEF (defstmt, j)) == SSA_NAME)
{
tree temp = get_default_def (PHI_ARG_DEF (defstmt, j), seen);
if (temp != NULL_TREE)
return temp;
}
}
}
defs = STMT_DEF_OPS (defstmt);
for (i = 0; i < NUM_DEFS (defs); i++)
{
tree def = DEF_OP (defs, i);
if (SSA_NAME_VAR (def) == SSA_NAME_VAR (var))
{
if (htab_find (seen, def) != NULL)
return NULL;
return get_default_def (def, seen);
}
}
abort ();
}
static tree
reaching_def (tree var, tree currstmt, basic_block bb, tree ignore)
{
tree curruse = NULL_TREE;
block_stmt_iterator bsi;
basic_block dom;
tree phi;
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
{
if (phi == currstmt)
break;
if (phi == ignore)
continue;
if (names_match_p (var, PHI_RESULT (phi)))
curruse = PHI_RESULT (phi);
}
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
tree *def;
def_optype defs;
size_t i;
if (stmt == currstmt)
break;
get_stmt_operands (stmt);
defs = STMT_DEF_OPS (stmt);
for (i = 0; i < NUM_DEFS (defs); i++)
{
def = DEF_OP_PTR (defs, i);
if (def && *def != ignore && names_match_p (var, *def))
{
curruse = *def;
break;
}
}
}
if (curruse != NULL_TREE)
return curruse;
dom = get_immediate_dominator (CDI_DOMINATORS, bb);
if (bb == ENTRY_BLOCK_PTR)
{
htab_t temp;
temp = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL);
curruse = get_default_def (var, temp);
htab_delete (temp);
}
if (!dom)
return curruse;
return reaching_def (var, currstmt, dom, ignore);
}
static void
insert_one_operand (struct expr_info *ei, tree ephi, int opnd_indx,
tree x, edge succ, tree **avdefsp)
{
tree expr;
tree temp = ei->temp;
tree copy;
tree newtemp;
basic_block bb = bb_for_stmt (x);
copy = TREE_OPERAND (EREF_STMT (ephi), 1);
copy = unshare_expr (copy);
expr = build (MODIFY_EXPR, TREE_TYPE (ei->expr),
temp, copy);
expr = subst_phis (ei, expr, bb, bb_for_stmt (ephi));
newtemp = make_ssa_name (temp, expr);
TREE_OPERAND (expr, 0) = newtemp;
copy = TREE_OPERAND (expr, 1);
if (dump_file)
{
fprintf (dump_file, "In BB %d, insert save of ", bb->index);
print_generic_expr (dump_file, expr, dump_flags);
fprintf (dump_file, " to ");
print_generic_expr (dump_file, newtemp, dump_flags);
fprintf (dump_file, " after ");
print_generic_stmt (dump_file, last_stmt (bb), dump_flags);
fprintf (dump_file, " (on edge), because of EPHI");
fprintf (dump_file, " in BB %d\n", bb_for_stmt (ephi)->index);
}
bsi_insert_on_edge_immediate (succ, expr);
EPHI_ARG_DEF (ephi, opnd_indx)
= create_expr_ref (ei, ei->expr, EUSE_NODE, bb, 0);
EUSE_DEF (x) = EPHI_ARG_DEF (ephi, opnd_indx);
VARRAY_PUSH_TREE (ei->euses_dt_order, EPHI_ARG_DEF (ephi, opnd_indx));
qsort (ei->euses_dt_order->data.tree,
VARRAY_ACTIVE_SIZE (ei->euses_dt_order),
sizeof (tree),
eref_compare);
EREF_TEMP (EUSE_DEF (x)) = newtemp;
EREF_RELOAD (EUSE_DEF (x)) = false;
EREF_SAVE (EUSE_DEF (x)) = false;
EUSE_INSERTED (EUSE_DEF (x)) = true;
EUSE_PHIOP (EUSE_DEF (x)) = false;
EREF_SAVE (x) = false;
EREF_RELOAD (x) = false;
EUSE_INSERTED (x) = true;
EREF_CLASS (x) = class_count++;
EREF_CLASS (EUSE_DEF (x)) = class_count++;
*avdefsp = xrealloc (*avdefsp, sizeof (tree) * (class_count + 1));
(*avdefsp)[class_count - 2] = x;
(*avdefsp)[class_count - 1] = EUSE_DEF (x);
pre_stats.saves++;
}
static bool
finalize_1 (struct expr_info *ei)
{
tree x;
int nx;
bool made_a_reload = false;
size_t i;
tree *avdefs;
avdefs = xcalloc (class_count + 1, sizeof (tree));
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
x = VARRAY_TREE (ei->euses_dt_order, i);
nx = EREF_CLASS (x);
if (TREE_CODE (x) == EPHI_NODE)
{
if (ephi_will_be_avail (x))
avdefs[nx] = x;
}
else if (TREE_CODE (x) == EUSE_NODE && EUSE_LVAL (x))
{
avdefs[nx] = x;
}
else if (TREE_CODE (x) == EUSE_NODE && !EUSE_PHIOP (x))
{
if (avdefs[nx] == NULL
|| !dominated_by_p (CDI_DOMINATORS, bb_for_stmt (x),
bb_for_stmt (avdefs[nx])))
{
EREF_RELOAD (x) = false;
avdefs[nx] = x;
EUSE_DEF (x) = NULL;
}
else
{
EREF_RELOAD (x) = true;
made_a_reload = true;
EUSE_DEF (x) = avdefs[nx];
#ifdef ENABLE_CHECKING
if (EREF_CLASS (x) != EREF_CLASS (avdefs[nx]))
abort ();
#endif
}
}
else
{
edge succ;
basic_block bb = bb_for_stmt (x);
for (succ = bb->succ; succ; succ = succ->succ_next)
{
tree ephi = ephi_at_block (succ->dest);
if (ephi == NULL_TREE)
continue;
if (ephi_will_be_avail (ephi))
{
int opnd_indx = opnum_of_ephi (ephi, succ);
#ifdef ENABLE_CHECKING
if (EPHI_ARG_PRED (ephi, opnd_indx) != x)
abort ();
#endif
if (can_insert (ephi, opnd_indx))
{
insert_one_operand (ei, ephi, opnd_indx, x, succ,
&avdefs);
}
else
{
nx = EREF_CLASS (EPHI_ARG_DEF (ephi,opnd_indx));
EPHI_ARG_DEF (ephi, opnd_indx) = avdefs[nx];
}
}
}
}
}
free (avdefs);
return made_a_reload;
}
static void
set_save (struct expr_info *ei, tree X)
{
if (TREE_CODE (X) == EUSE_NODE && !EUSE_PHIOP (X))
EREF_SAVE (X) = true;
else if (TREE_CODE (X) == EPHI_NODE)
{
int curr_phiop;
for (curr_phiop = 0; curr_phiop < EPHI_NUM_ARGS (X); curr_phiop++)
{
tree w = EPHI_ARG_DEF (X, curr_phiop);
if (!EPHI_ARG_PROCESSED2 (X, curr_phiop))
{
EPHI_ARG_PROCESSED2 (X, curr_phiop) = true;
if (w)
set_save (ei, w);
}
}
}
}
static bool
cba_search_seen (tree phi)
{
return EPHI_CANT_BE_AVAIL (phi);
}
static void
cba_search_set_seen (tree phi)
{
EPHI_CANT_BE_AVAIL (phi) = true;
}
static bool
cba_search_start_from (tree phi)
{
if (!EPHI_DOWNSAFE (phi))
{
int i;
for (i = 0; i < EPHI_NUM_ARGS (phi); i++)
if (EPHI_ARG_DEF (phi, i) == NULL_TREE
|| EPHI_ARG_EDGE (phi, i)->flags & EDGE_ABNORMAL)
return true;
}
return false;
}
static bool
cba_search_continue_from_to (tree def_phi ATTRIBUTE_UNUSED,
int opnd_indx,
tree use_phi)
{
if (EPHI_ARG_HAS_REAL_USE (use_phi, opnd_indx) &&
!(EPHI_ARG_EDGE (use_phi, opnd_indx)->flags & EDGE_ABNORMAL))
return false;
if (!EPHI_DOWNSAFE (use_phi))
return true;
return false;
}
static bool
stops_search_seen (tree phi)
{
return EPHI_STOPS (phi);
}
static void
stops_search_set_seen (tree phi)
{
EPHI_STOPS (phi) = true;
}
static void
stops_search_reach_from_to (tree def_phi ATTRIBUTE_UNUSED,
int opnd_indx,
tree use_phi)
{
EPHI_ARG_STOPS (use_phi, opnd_indx) = true;
}
static bool
stops_search_start_from (tree phi)
{
int i;
for (i = 0; i < EPHI_NUM_ARGS (phi); i++)
if (EPHI_ARG_STOPS (phi, i))
return true;
return false;
}
static bool
stops_search_continue_from_to (tree def_phi ATTRIBUTE_UNUSED,
int opnd_indx ATTRIBUTE_UNUSED,
tree use_phi)
{
return stops_search_start_from (use_phi);
}
static bool
repl_search_seen (tree phi)
{
return EPHI_REP_OCCUR_KNOWN (phi);
}
static void
repl_search_set_seen (tree phi)
{
int i;
#ifdef ENABLE_CHECKING
if (!ephi_will_be_avail (phi))
abort ();
#endif
if (EPHI_IDENTICAL_TO (phi) == NULL_TREE)
{
for (i = 0; i < EPHI_NUM_ARGS (phi); i++)
{
tree identical_to = occ_identical_to (EPHI_ARG_DEF (phi, i));
if (identical_to != NULL_TREE)
{
if (EPHI_IDENTICAL_TO (phi) == NULL)
EPHI_IDENTICAL_TO (phi) = identical_to;
if (EPHI_ARG_INJURED (phi, i))
EPHI_IDENT_INJURED (phi) = true;
}
}
}
EPHI_REP_OCCUR_KNOWN (phi) = true;
}
static inline bool
any_operand_injured (tree ephi)
{
int i;
for (i = 0; i < EPHI_NUM_ARGS (ephi); i++)
if (EPHI_ARG_INJURED (ephi, i))
return true;
return false;
}
static void
repl_search_reach_from_to (tree def_phi, int opnd_indx ATTRIBUTE_UNUSED,
tree use_phi)
{
if (ephi_will_be_avail (use_phi)
&& EPHI_IDENTITY (use_phi)
&& EPHI_IDENTICAL_TO (use_phi) == NULL_TREE)
{
EPHI_IDENTICAL_TO (use_phi) = EPHI_IDENTICAL_TO (def_phi);
if (EPHI_IDENT_INJURED (def_phi)
|| any_operand_injured (use_phi))
EPHI_IDENT_INJURED (use_phi) = true;
}
}
static bool
repl_search_start_from (tree phi)
{
if (ephi_will_be_avail (phi) && EPHI_IDENTITY (phi))
{
int i;
for (i = 0; i < EPHI_NUM_ARGS (phi); i++)
if (occ_identical_to (EPHI_ARG_DEF (phi, i)) != NULL_TREE)
return true;
}
return false;
}
static bool
repl_search_continue_from_to (tree def_phi ATTRIBUTE_UNUSED,
int opnd_indx ATTRIBUTE_UNUSED,
tree use_phi)
{
return ephi_will_be_avail (use_phi) && EPHI_IDENTITY (use_phi);
}
static void
require_phi (struct expr_info *ei, basic_block bb)
{
size_t i;
EXECUTE_IF_SET_IN_BITMAP (pre_dfs[bb->index], 0, i,
{
tree ephi;
ephi = ephi_at_block (BASIC_BLOCK (i));
if (ephi != NULL_TREE
&& ephi_will_be_avail (ephi)
&& EPHI_IDENTITY (ephi))
{
EPHI_IDENTITY (ephi) = false;
require_phi (ei, BASIC_BLOCK (i));
}
});
}
static tree
occ_identical_to (tree t)
{
if (TREE_CODE (t) == EUSE_NODE && !EUSE_PHIOP (t))
return t;
else if (TREE_CODE (t) == EUSE_NODE && EUSE_PHIOP (t))
return t;
else if (TREE_CODE (t) == EPHI_NODE)
{
if (EPHI_IDENTITY (t) && EPHI_REP_OCCUR_KNOWN (t))
return EPHI_IDENTICAL_TO (t);
else if (!EPHI_IDENTITY (t))
return t;
}
return NULL_TREE;
}
static bool
really_available_def (tree node)
{
if (TREE_CODE (node) == EUSE_NODE
&& EUSE_PHIOP (node)
&& EUSE_INSERTED (node))
return true;
if (TREE_CODE (node) == EUSE_NODE
&& EUSE_DEF (node) == NULL_TREE)
return true;
return false;
}
static void
finalize_2 (struct expr_info *ei)
{
size_t i;
insert_euse_in_preorder_dt_order (ei);
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
tree ref = VARRAY_TREE (ei->euses_dt_order, i);
if (TREE_CODE (ref) == EUSE_NODE
&& !EUSE_PHIOP (ref)
&& EREF_RELOAD (ref))
{
set_save (ei, EUSE_DEF (ref));
}
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
tree ephi = VARRAY_TREE (ei->euses_dt_order, i);
if (TREE_CODE (ephi) != EPHI_NODE)
continue;
EPHI_IDENTITY (ephi) = true;
EPHI_IDENTICAL_TO (ephi) = NULL;
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
tree ephi = VARRAY_TREE (ei->euses_dt_order, i);
if (!ephi || TREE_CODE (ephi) != EPHI_NODE)
continue;
if (ephi_will_be_avail (ephi))
{
int k;
for (k = 0; k < EPHI_NUM_ARGS (ephi); k++)
{
if (EPHI_ARG_INJURED (ephi, k))
require_phi (ei, EPHI_ARG_EDGE (ephi, k)->src);
else if (EPHI_ARG_DEF (ephi, k)
&& TREE_CODE (EPHI_ARG_DEF (ephi, k)) == EUSE_NODE
&& really_available_def (EPHI_ARG_DEF (ephi, k)))
require_phi (ei, bb_for_stmt (EPHI_ARG_DEF (ephi, k)));
}
}
}
do_ephi_df_search (ei, replacing_search);
}
static void
do_ephi_df_search_1 (struct ephi_df_search search, tree ephi)
{
varray_type uses;
size_t i;
search.set_seen (ephi);
uses = EPHI_USES (ephi);
if (!uses)
return;
for (i = 0; i < VARRAY_ACTIVE_SIZE (uses); i++)
{
struct ephi_use_entry *use = VARRAY_GENERIC_PTR (uses, i);
if (search.reach_from_to)
search.reach_from_to (ephi, use->opnd_indx, use->phi);
if (!search.seen (use->phi) &&
search.continue_from_to (ephi, use->opnd_indx, use->phi))
{
do_ephi_df_search_1 (search, use->phi);
}
}
}
static void
do_ephi_df_search (struct expr_info *ei, struct ephi_df_search search)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
tree ephi = VARRAY_TREE (ei->euses_dt_order, i);
if (!ephi || TREE_CODE (ephi) != EPHI_NODE)
continue;
if (!search.seen (ephi)
&& search.start_from (ephi))
do_ephi_df_search_1 (search, ephi);
}
}
#if 0
static tree
calculate_increment (struct expr_info *ei, tree expr)
{
tree incr;
incr = TREE_OPERAND (TREE_OPERAND (expr, 1), 1);
if (TREE_CODE (incr) != INTEGER_CST)
abort();
if (TREE_CODE (ei->expr) == MULT_EXPR)
incr = fold (build (MULT_EXPR, TREE_TYPE (ei->expr),
incr, TREE_OPERAND (ei->expr, 1)));
#if DEBUGGING_STRRED
if (dump_file)
{
fprintf (dump_file, "Increment calculated to be: ");
print_generic_expr (dump_file, incr, 0);
fprintf (dump_file, "\n");
}
#endif
return incr;
}
#endif
static tree
do_proper_save (tree use, tree expr, int before)
{
basic_block bb = bb_for_stmt (use);
block_stmt_iterator bsi;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
if (bsi_stmt (bsi) == use)
{
if (before)
bsi_insert_before (&bsi, expr, BSI_SAME_STMT);
else
bsi_insert_after (&bsi, expr, BSI_SAME_STMT);
return use;
}
}
abort ();
}
static tree
get_temp (tree use)
{
tree newtemp;
if (TREE_CODE (use) == EPHI_NODE && EPHI_IDENTITY (use))
{
tree newuse = use;
while (TREE_CODE (newuse) == EPHI_NODE
&& EPHI_IDENTITY (newuse))
{
#ifdef ENABLE_CHECKING
if (!EPHI_IDENTICAL_TO (newuse))
abort ();
#endif
newuse = EPHI_IDENTICAL_TO (newuse);
if (TREE_CODE (newuse) != EPHI_NODE)
break;
}
if (TREE_CODE (EREF_TEMP (newuse)) == PHI_NODE)
newtemp = PHI_RESULT (EREF_TEMP (newuse));
else
newtemp = EREF_TEMP (newuse);
}
else
{
if (TREE_CODE (EREF_TEMP (use)) == PHI_NODE)
newtemp = PHI_RESULT (EREF_TEMP (use));
else
newtemp = EREF_TEMP (use);
}
return newtemp;
}
static tree
pick_ssa_name (tree stmt)
{
if (TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME)
return TREE_OPERAND (stmt, 0);
else if (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME)
return TREE_OPERAND (stmt, 1);
else
abort ();
}
static void
code_motion (struct expr_info *ei)
{
tree use;
tree newtemp;
size_t euse_iter;
tree temp = ei->temp;
basic_block bb;
for (euse_iter = 0;
euse_iter < VARRAY_ACTIVE_SIZE (ei->euses_dt_order);
euse_iter++)
{
use = VARRAY_TREE (ei->euses_dt_order, euse_iter);
if (TREE_CODE (use) != EPHI_NODE)
continue;
if (ephi_will_be_avail (use) && !EPHI_IDENTITY (use))
{
bb = bb_for_stmt (use);
bb_ann (bb)->phi_nodes = chainon (phi_nodes (bb), EREF_TEMP (use));
}
else if (EPHI_IDENTITY (use))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Pointless EPHI in block %d\n",
bb_for_stmt (use)->index);
}
}
}
for (euse_iter = 0;
euse_iter < VARRAY_ACTIVE_SIZE (ei->euses_dt_order);
euse_iter++)
{
use = VARRAY_TREE (ei->euses_dt_order, euse_iter);
#ifdef ENABLE_CHECKING
if (TREE_CODE (use) == EUSE_NODE && EUSE_PHIOP (use)
&& (EREF_RELOAD (use) || EREF_SAVE (use)))
abort ();
#endif
if (EREF_SAVE (use) && !EUSE_INSERTED (use))
{
tree newexpr;
tree use_stmt;
tree copy;
basic_block usebb = bb_for_stmt (use);
use_stmt = EREF_STMT (use);
copy = TREE_OPERAND (use_stmt, 1);
copy = unshare_expr (copy);
newexpr = build (MODIFY_EXPR, TREE_TYPE (temp), temp, copy);
newtemp = make_ssa_name (temp, newexpr);
EREF_TEMP (use) = newtemp;
TREE_OPERAND (newexpr, 0) = newtemp;
TREE_OPERAND (use_stmt, 1) = newtemp;
if (dump_file)
{
fprintf (dump_file, "In BB %d, insert save of ",
usebb->index);
print_generic_expr (dump_file, copy, dump_flags);
fprintf (dump_file, " to ");
print_generic_expr (dump_file, newtemp, dump_flags);
fprintf (dump_file, " before statement ");
print_generic_expr (dump_file, use_stmt, dump_flags);
fprintf (dump_file, "\n");
if (EXPR_HAS_LOCATION (use_stmt))
fprintf (dump_file, " on line %d\n",
EXPR_LINENO (use_stmt));
}
modify_stmt (newexpr);
modify_stmt (use_stmt);
set_bb_for_stmt (newexpr, usebb);
EREF_STMT (use) = do_proper_save (use_stmt, newexpr, true);
pre_stats.saves++;
}
else if (EREF_RELOAD (use))
{
tree use_stmt;
tree newtemp;
use_stmt = EREF_STMT (use);
bb = bb_for_stmt (use_stmt);
newtemp = get_temp (EUSE_DEF (use));
if (!newtemp)
abort ();
if (dump_file)
{
fprintf (dump_file, "In BB %d, insert reload of ",
bb->index);
print_generic_expr (dump_file,
TREE_OPERAND (use_stmt, 1), 0);
fprintf (dump_file, " from ");
print_generic_expr (dump_file, newtemp, dump_flags);
fprintf (dump_file, " in statement ");
print_generic_stmt (dump_file, use_stmt, dump_flags);
fprintf (dump_file, "\n");
if (EXPR_HAS_LOCATION (use_stmt))
fprintf (dump_file, " on line %d\n",
EXPR_LINENO (use_stmt));
}
TREE_OPERAND (use_stmt, 1) = newtemp;
EREF_TEMP (use) = newtemp;
modify_stmt (use_stmt);
pre_stats.reloads++;
}
}
for (euse_iter = 0;
euse_iter < VARRAY_ACTIVE_SIZE (ei->euses_dt_order);
euse_iter++)
{
use = VARRAY_TREE (ei->euses_dt_order, euse_iter);
if (TREE_CODE (use) == EPHI_NODE
&& ephi_will_be_avail (use)
&& !EPHI_IDENTITY (use))
{
int i;
tree argdef;
bb = bb_for_stmt (use);
if (dump_file)
{
fprintf (dump_file,
"In BB %d, insert PHI to replace EPHI\n", bb->index);
}
newtemp = EREF_TEMP (use);
for (i = 0; i < EPHI_NUM_ARGS (use); i++)
{
tree rdef;
argdef = EPHI_ARG_DEF (use, i);
if (argdef == use)
rdef = get_temp (use);
else if (EREF_RELOAD (argdef) || EREF_SAVE (argdef))
rdef = get_temp (argdef);
else if (TREE_CODE (argdef) == EPHI_NODE)
rdef = get_temp (argdef);
else if (argdef
&& EPHI_ARG_HAS_REAL_USE (use, i)
&& EREF_STMT (argdef)
&& !EPHI_ARG_INJURED (use, i))
rdef = pick_ssa_name (EREF_STMT (argdef));
else
abort ();
if (!rdef)
abort();
add_phi_arg (&newtemp, rdef, EPHI_ARG_EDGE (use, i));
}
set_bb_for_stmt (EREF_TEMP (use), bb);
pre_stats.newphis++;
}
}
}
static bitmap
compute_idfs (bitmap * dfs, tree stmt)
{
fibheap_t worklist;
sbitmap inworklist, done;
bitmap idf;
size_t i;
basic_block block;
block = bb_for_stmt (stmt);
if (idfs_cache[block->index] != NULL)
return idfs_cache[block->index];
inworklist = sbitmap_alloc (last_basic_block);
done = sbitmap_alloc (last_basic_block);
worklist = fibheap_new ();
sbitmap_zero (inworklist);
sbitmap_zero (done);
idf = BITMAP_XMALLOC ();
bitmap_zero (idf);
block = bb_for_stmt (stmt);
fibheap_insert (worklist, block->index, (void *)(size_t)block->index);
SET_BIT (inworklist, block->index);
while (!fibheap_empty (worklist))
{
int a = (size_t) fibheap_extract_min (worklist);
if (TEST_BIT (done, a))
continue;
SET_BIT (done, a);
if (idfs_cache[a])
{
bitmap_a_or_b (idf, idf, idfs_cache[a]);
EXECUTE_IF_SET_IN_BITMAP (idfs_cache[a], 0, i,
{
SET_BIT (inworklist, i);
SET_BIT (done, i);
});
}
else
{
bitmap_a_or_b (idf, idf, dfs[a]);
EXECUTE_IF_SET_IN_BITMAP (dfs[a], 0, i,
{
if (!TEST_BIT (inworklist, i))
{
SET_BIT (inworklist, i);
fibheap_insert (worklist, i, (void *)i);
}
});
}
}
fibheap_delete (worklist);
sbitmap_free (inworklist);
sbitmap_free (done);
idfs_cache[block->index] = idf;
return idf;
}
static bool
is_strred_cand (const tree expr ATTRIBUTE_UNUSED)
{
#if 0
if (TREE_CODE (TREE_OPERAND (expr, 1)) != MULT_EXPR
&& TREE_CODE (TREE_OPERAND (expr, 1)) != MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (expr, 1)) != NEGATE_EXPR
&& TREE_CODE (TREE_OPERAND (expr, 1)) != PLUS_EXPR)
return false;
return true;
#endif
return false;
}
static inline bool
expr_lexically_eq (const tree v1, const tree v2)
{
if (TREE_CODE_CLASS (TREE_CODE (v1)) != TREE_CODE_CLASS (TREE_CODE (v2)))
return false;
if (TREE_CODE (v1) != TREE_CODE (v2))
return false;
switch (TREE_CODE_CLASS (TREE_CODE (v1)))
{
case 'r':
case '1':
return names_match_p (TREE_OPERAND (v1, 0), TREE_OPERAND (v2, 0));
case 'x':
case 'd':
return names_match_p (v1, v2);
case '2':
{
bool match;
match = names_match_p (TREE_OPERAND (v1, 0), TREE_OPERAND (v2, 0));
if (!match)
return false;
match = names_match_p (TREE_OPERAND (v1, 1), TREE_OPERAND (v2, 1));
if (!match)
return false;
return true;
}
default:
return false;
}
}
static void
free_expr_info (struct expr_info *v1)
{
struct expr_info *e1 = (struct expr_info *)v1;
VARRAY_FREE (e1->occurs);
VARRAY_FREE (e1->kills);
VARRAY_FREE (e1->lefts);
VARRAY_FREE (e1->reals);
VARRAY_FREE (e1->euses_dt_order);
}
static void
process_left_occs_and_kills (varray_type bexprs, tree expr)
{
size_t i, j, k;
stmt_ann_t ann = stmt_ann (expr);
vdef_optype vdefs;
vuse_optype vuses;
def_optype defs;
defs = DEF_OPS (ann);
vdefs = VDEF_OPS (ann);
if (NUM_DEFS (defs) == 0 && NUM_VDEFS (vdefs) == 0)
return;
for (j = 0; j < VARRAY_ACTIVE_SIZE (bexprs); j++)
{
struct expr_info *ei = VARRAY_GENERIC_PTR (bexprs, j);
tree vuse_name;
tree random_occur;
stmt_ann_t ann;
if (!ei->loadpre_cand)
continue;
for (i = 0; i < NUM_DEFS (defs); i++)
{
if (names_match_p (DEF_OP (defs, i), ei->expr))
{
if (TREE_CODE (expr) == ASM_EXPR)
{
ei->loadpre_cand = false;
continue;
}
VARRAY_PUSH_TREE (ei->lefts, expr);
VARRAY_PUSH_TREE (ei->occurs, NULL);
VARRAY_PUSH_TREE (ei->kills, NULL);
}
}
random_occur = VARRAY_TREE (ei->occurs, 0);
ann = stmt_ann (random_occur);
vuses = VUSE_OPS (ann);
if (NUM_VDEFS (vdefs) != 0)
{
for (k = 0; k < NUM_VUSES (vuses); k++)
{
vuse_name = VUSE_OP (vuses, k);
for (i = 0; i < NUM_VDEFS (vdefs); i++)
{
if (names_match_p (VDEF_OP (vdefs, i), vuse_name))
{
VARRAY_PUSH_TREE (ei->lefts, expr);
VARRAY_PUSH_TREE (ei->occurs, NULL);
VARRAY_PUSH_TREE (ei->kills, NULL);
}
}
}
}
}
}
static int
pre_expression (struct expr_info *slot, void *data, bitmap vars_to_rename)
{
struct expr_info *ei = (struct expr_info *) slot;
basic_block bb;
class_count = 0;
eref_id_counter = 0;
if (VARRAY_ACTIVE_SIZE (ei->reals) < 2)
return 1;
memset (&pre_stats, 0, sizeof (struct pre_stats_d));
ei->temp = create_tmp_var (TREE_TYPE (ei->expr), "pretmp");
add_referenced_tmp_var (ei->temp);
bitmap_clear (created_phi_preds);
ephi_pindex_htab = htab_create (500, ephi_pindex_hash, ephi_pindex_eq, free);
phi_pred_cache = xcalloc (last_basic_block, sizeof (tree));
n_phi_preds = last_basic_block;
if (!expr_phi_insertion ((bitmap *)data, ei))
goto cleanup;
rename_1 (ei);
if (dump_file && (dump_flags & TDF_DETAILS))
{
size_t i;
fprintf (dump_file, "Occurrences for expression ");
print_generic_expr (dump_file, ei->expr, dump_flags);
fprintf (dump_file, " after Rename 2\n");
for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++)
{
print_generic_expr (dump_file,
VARRAY_TREE (ei->euses_dt_order, i), 1);
fprintf (dump_file, "\n");
}
}
compute_down_safety (ei);
compute_du_info (ei);
compute_will_be_avail (ei);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "EPHI's for expression ");
print_generic_expr (dump_file, ei->expr, dump_flags);
fprintf (dump_file,
" after down safety and will_be_avail computation\n");
FOR_EACH_BB (bb)
{
tree ephi = ephi_at_block (bb);
if (ephi != NULL)
{
print_generic_expr (dump_file, ephi, 1);
fprintf (dump_file, "\n");
}
}
}
if (finalize_1 (ei))
{
finalize_2 (ei);
code_motion (ei);
if (ei->loadpre_cand)
bitmap_set_bit (vars_to_rename, var_ann (ei->temp)->uid);
}
clear_all_eref_arrays ();
if (dump_file)
if (dump_flags & TDF_STATS)
{
fprintf (dump_file, "PRE stats:\n");
fprintf (dump_file, "Reloads:%d\n", pre_stats.reloads);
fprintf (dump_file, "Saves:%d\n", pre_stats.saves);
fprintf (dump_file, "Repairs:%d\n", pre_stats.repairs);
fprintf (dump_file, "New phis:%d\n", pre_stats.newphis);
fprintf (dump_file, "EPHI memory allocated:%d\n",
pre_stats.ephi_allocated);
fprintf (dump_file, "EREF memory allocated:%d\n",
pre_stats.eref_allocated);
fprintf (dump_file, "Expressions generated for rename2:%d\n",
pre_stats.exprs_generated);
}
cleanup:
free (phi_pred_cache);
if (ephi_pindex_htab)
{
htab_delete (ephi_pindex_htab);
ephi_pindex_htab = NULL;
}
return 0;
}
static void
collect_expressions (basic_block block, varray_type *bexprsp)
{
size_t k;
block_stmt_iterator j;
basic_block son;
varray_type bexprs = *bexprsp;
for (j = bsi_start (block); !bsi_end_p (j); bsi_next (&j))
{
tree stmt = bsi_stmt (j);
tree expr = stmt;
tree orig_expr = expr;
stmt_ann_t ann;
struct expr_info *slot = NULL;
get_stmt_operands (expr);
ann = stmt_ann (expr);
if (NUM_USES (USE_OPS (ann)) == 0)
{
process_left_occs_and_kills (bexprs, expr);
continue;
}
if (TREE_CODE (expr) == MODIFY_EXPR)
expr = TREE_OPERAND (expr, 1);
if ((TREE_CODE_CLASS (TREE_CODE (expr)) == '2'
|| TREE_CODE_CLASS (TREE_CODE (expr)) == '<'
|| TREE_CODE (expr) == SSA_NAME
|| TREE_CODE (expr) == INDIRECT_REF)
&& !ann->makes_aliased_stores
&& !ann->has_volatile_ops)
{
bool is_scalar = true;
tree origop0 = TREE_OPERAND (orig_expr, 0);
if (AGGREGATE_TYPE_P (TREE_TYPE (origop0))
|| TREE_CODE (TREE_TYPE (origop0)) == COMPLEX_TYPE)
is_scalar = false;
if (is_scalar
&& (TREE_CODE (expr) == SSA_NAME
|| (TREE_CODE (expr) == INDIRECT_REF
&& !DECL_P (TREE_OPERAND (expr, 0)))
||(!DECL_P (TREE_OPERAND (expr, 0))
&& (!TREE_OPERAND (expr, 1)
|| !DECL_P (TREE_OPERAND (expr, 1))))))
{
for (k = 0; k < VARRAY_ACTIVE_SIZE (bexprs); k++)
{
slot = VARRAY_GENERIC_PTR (bexprs, k);
if (expr_lexically_eq (slot->expr, expr))
break;
}
if (k >= VARRAY_ACTIVE_SIZE (bexprs))
slot = NULL;
if (slot)
{
VARRAY_PUSH_TREE (slot->occurs, orig_expr);
VARRAY_PUSH_TREE (slot->kills, NULL);
VARRAY_PUSH_TREE (slot->lefts, NULL);
VARRAY_PUSH_TREE (slot->reals, stmt);
slot->strred_cand &= is_strred_cand (orig_expr);
}
else
{
slot = ggc_alloc (sizeof (struct expr_info));
slot->expr = expr;
VARRAY_GENERIC_PTR_NOGC_INIT (slot->occurs, 1, "Occurrence");
VARRAY_GENERIC_PTR_NOGC_INIT (slot->kills, 1, "Kills");
VARRAY_GENERIC_PTR_NOGC_INIT (slot->lefts, 1, "Left occurrences");
VARRAY_GENERIC_PTR_NOGC_INIT (slot->reals, 1, "Real occurrences");
VARRAY_GENERIC_PTR_NOGC_INIT (slot->euses_dt_order, 1, "EUSEs");
VARRAY_PUSH_TREE (slot->occurs, orig_expr);
VARRAY_PUSH_TREE (slot->kills, NULL);
VARRAY_PUSH_TREE (slot->lefts, NULL);
VARRAY_PUSH_TREE (slot->reals, stmt);
VARRAY_PUSH_GENERIC_PTR (bexprs, slot);
slot->strred_cand = is_strred_cand (orig_expr);
slot->loadpre_cand = false;
if (TREE_CODE (expr) == SSA_NAME
|| TREE_CODE (expr) == INDIRECT_REF)
slot->loadpre_cand = true;
}
}
}
process_left_occs_and_kills (bexprs, orig_expr);
}
*bexprsp = bexprs;
for (son = first_dom_son (CDI_DOMINATORS, block);
son;
son = next_dom_son (CDI_DOMINATORS, son))
collect_expressions (son, bexprsp);
}
static void
execute_pre (void)
{
int currbbs;
varray_type bexprs;
size_t k;
int i;
if (ENTRY_BLOCK_PTR->succ->dest->pred->pred_next)
if (!(ENTRY_BLOCK_PTR->succ->flags & EDGE_ABNORMAL))
split_edge (ENTRY_BLOCK_PTR->succ);
euse_node_pool = create_alloc_pool ("EUSE node pool",
sizeof (struct tree_euse_node), 30);
eref_node_pool = create_alloc_pool ("EREF node pool",
sizeof (struct tree_eref_common), 30);
ephi_use_pool = create_alloc_pool ("EPHI use node pool",
sizeof (struct ephi_use_entry), 30);
VARRAY_GENERIC_PTR_INIT (bexprs, 1, "bexprs");
calculate_dominance_info (CDI_DOMINATORS);
currbbs = n_basic_blocks;
dfn = xcalloc (last_basic_block + 1, sizeof (int));
build_dfn_array (ENTRY_BLOCK_PTR, 0);
idfs_cache = xcalloc (currbbs, sizeof (bitmap));
pre_dfs = (bitmap *) xmalloc (sizeof (bitmap) * currbbs);
for (i = 0; i < currbbs; i++)
pre_dfs[i] = BITMAP_XMALLOC ();
compute_dominance_frontiers (pre_dfs);
created_phi_preds = BITMAP_XMALLOC ();
collect_expressions (ENTRY_BLOCK_PTR, &bexprs);
ggc_push_context ();
for (k = 0; k < VARRAY_ACTIVE_SIZE (bexprs); k++)
{
pre_expression (VARRAY_GENERIC_PTR (bexprs, k), pre_dfs, vars_to_rename);
free_alloc_pool (euse_node_pool);
free_alloc_pool (eref_node_pool);
free_alloc_pool (ephi_use_pool);
euse_node_pool = create_alloc_pool ("EUSE node pool",
sizeof (struct tree_euse_node), 30);
eref_node_pool = create_alloc_pool ("EREF node pool",
sizeof (struct tree_eref_common), 30);
ephi_use_pool = create_alloc_pool ("EPHI use node pool",
sizeof (struct ephi_use_entry), 30);
free_expr_info (VARRAY_GENERIC_PTR (bexprs, k));
#ifdef ENABLE_CHECKING
if (pre_stats.ephis_current != 0)
abort ();
#endif
ggc_collect ();
}
ggc_pop_context ();
memset (&pre_stats, 0, sizeof (struct pre_stats_d));
free_alloc_pool (euse_node_pool);
free_alloc_pool (eref_node_pool);
free_alloc_pool (ephi_use_pool);
VARRAY_CLEAR (bexprs);
for (i = 0; i < currbbs; i++)
BITMAP_XFREE (pre_dfs[i]);
free (pre_dfs);
BITMAP_XFREE (created_phi_preds);
for (i = 0; i < currbbs; i++)
if (idfs_cache[i] != NULL)
BITMAP_XFREE (idfs_cache[i]);
free (dfn);
free (idfs_cache);
}
static bool
gate_pre (void)
{
return flag_tree_pre != 0;
}
struct tree_opt_pass pass_pre =
{
"pre",
gate_pre,
execute_pre,
NULL,
NULL,
0,
TV_TREE_PRE,
PROP_no_crit_edges | PROP_cfg | PROP_ssa,
0,
0,
0,
TODO_dump_func | TODO_rename_vars
| TODO_ggc_collect | TODO_verify_ssa
};