Commit c90186eb by Daniel Berlin Committed by Daniel Berlin

tree.h (VALUE_HANDLE_VUSES): New.

2005-12-29  Daniel Berlin  <dberlin@dberlin.org>

	* tree.h (VALUE_HANDLE_VUSES): New.
	(struct tree_value_handle): Add vuses.

	* tree-vn.c (struct val_expr_pair_d): Remove stmt, add vuses.
	(vn_compute): Remove stmt argument.
	Don't use vuses in hash value computation.
	(val_expr_pair_eq): Compare vuse lists.
	(copy_vuses_from_stmt): New function.
	(shared_vuses_from_stmt): Ditto.
	(vn_add): Rewrite in terms of vn_add_with_vuses.
	(vn_add_with_vuses): New function.
	(vn_lookup): Rewrite in terms of vn_lookup_with_vuses.
	(vn_lookup_with_vuses): New function.
	(vuses_compare): New function.
	(print_creation_to_file): Ditto.
	(vn_lookup_or_add): Rewrite to handle vuses.
	(sort_vuses): New function.
	(vn_lookup_or_add_with_vuses): Ditto.
	(vn_init): Initialize shared_lookup_vuses.
	(vn_delete): Free shared_lookup_vuses.

	* tree-ssa-pre.c: Update todo list.
	(bb_value_sets_t): Add rvuse_in, rvuse_out, rvuse_gen, and
	rvuse_kill.
	(RVUSE_IN): New macro.
	(RVUSE_GEN): Ditto.
	(RVUSE_KILL): Ditto.
	(RVUSE_OUT): Ditto.
	(modify_expr_node_pool): New function.
	(pretemp): New.
	(storetemp): Ditto.
	(mergephitemp): Ditto.
	(prephitemp): Ditto.
	(struct expr_pred_trans_d): Add vuses member.
	(expr_pred_trans_eq): Compare vuses.
	(phi_trans_lookup): Add vuses argument.
	(phi_trans_add): Ditto.
	(translate_vuses_through_block): New function.
	(phi_translate): Use vuses to ask about those expressions that can
	have vuses.
	Properly translate virtual uses through phis, and use
	vn_lookup_or_add_with vuses.  Handle tcc_reference.
	(phi_translate_set): Don't add pointless translations to the
	cache.
	(get_representative): New function.
	(vuses_dies_in_block_x): Ditto.
	(valid_in_set): Add block argument.  Check virtual use validity.
	(clean): Add block argument. Update call to valid_in_set
	(compute_antic_aux): Update call to clean.
	(dump_bitmap_of_names): New function.
	(compute_vuse_representatives): Ditto.
	(compute_rvuse): Ditto.
	(can_value_number_call): Modified to accept calls with vuses.
	(can_value_number_operation): New function.
	(can_PRE_operation): Ditto.
	(need_creation): New vector of stores that may need creation.
	(find_or_generate_expression): use can_PRE_operation.
	(create_expression_by_pieces): Handle INDIRECT_REF.
	Only create one temp until we have to change types.
	Mark new vars for renaming.
	(insert_into_preds_of_block): Ignore loopiness of loads.
	Use can_PRE_operation.
	Only create one temp until we have to chnge types.
	(insert_aux): Use can_PRE_operation.
	Don't pass name to insert_into_preds_of_block.
	(insert_extra_phis): Only use one temp until we have to change
	types.
	(poolify_tree): New function.
	(modify_expr_template): New var.
	(poolify_modify_expr): New function.
	(insert_fake_stores): Ditto.
	(realify_fake_stores): Ditto.
	(compute_avail): Use can_value_number_operation.
	(mark_operand_necessary): Return NULL for non-SSA names.
	(remove_dead_inserted_code): Update comment.
	(init_pre): Initialize pretemp, need_creation, storetemp,
	mergephitemp, prephitemp.
	Create modify_expr_node_pool.
	(fini_pre): Free modify_expr_node_pool and need_creation array.
	(execute_pre): Call insert_fake_stores, compute_rvuse, and
	realify_fake_stores. 
	* tree-flow.h (vn_compute): Fix prototype.
	(vn_add): Ditto.
	(vn_lookup): Ditto.
	(sort_vuses): New.
	(vn_lookup_or_add_with_vuses): Ditto.
	(vn_add_with_vuses): Ditto.
	(vn_lookup_with_vuses): Ditto.
	* passes.c (pass_may_alias): Add.

From-SVN: r109180
parent a176426f
2005-12-29 Daniel Berlin <dberlin@dberlin.org>
* tree.h (VALUE_HANDLE_VUSES): New.
(struct tree_value_handle): Add vuses.
* tree-vn.c (struct val_expr_pair_d): Remove stmt, add vuses.
(vn_compute): Remove stmt argument.
Don't use vuses in hash value computation.
(val_expr_pair_eq): Compare vuse lists.
(copy_vuses_from_stmt): New function.
(shared_vuses_from_stmt): Ditto.
(vn_add): Rewrite in terms of vn_add_with_vuses.
(vn_add_with_vuses): New function.
(vn_lookup): Rewrite in terms of vn_lookup_with_vuses.
(vn_lookup_with_vuses): New function.
(vuses_compare): New function.
(print_creation_to_file): Ditto.
(vn_lookup_or_add): Rewrite to handle vuses.
(sort_vuses): New function.
(vn_lookup_or_add_with_vuses): Ditto.
(vn_init): Initialize shared_lookup_vuses.
(vn_delete): Free shared_lookup_vuses.
* tree-ssa-pre.c: Update todo list.
(bb_value_sets_t): Add rvuse_in, rvuse_out, rvuse_gen, and
rvuse_kill.
(RVUSE_IN): New macro.
(RVUSE_GEN): Ditto.
(RVUSE_KILL): Ditto.
(RVUSE_OUT): Ditto.
(modify_expr_node_pool): New function.
(pretemp): New.
(storetemp): Ditto.
(mergephitemp): Ditto.
(prephitemp): Ditto.
(struct expr_pred_trans_d): Add vuses member.
(expr_pred_trans_eq): Compare vuses.
(phi_trans_lookup): Add vuses argument.
(phi_trans_add): Ditto.
(translate_vuses_through_block): New function.
(phi_translate): Use vuses to ask about those expressions that can
have vuses.
Properly translate virtual uses through phis, and use
vn_lookup_or_add_with vuses. Handle tcc_reference.
(phi_translate_set): Don't add pointless translations to the
cache.
(get_representative): New function.
(vuses_dies_in_block_x): Ditto.
(valid_in_set): Add block argument. Check virtual use validity.
(clean): Add block argument. Update call to valid_in_set
(compute_antic_aux): Update call to clean.
(dump_bitmap_of_names): New function.
(compute_vuse_representatives): Ditto.
(compute_rvuse): Ditto.
(can_value_number_call): Modified to accept calls with vuses.
(can_value_number_operation): New function.
(can_PRE_operation): Ditto.
(need_creation): New vector of stores that may need creation.
(find_or_generate_expression): use can_PRE_operation.
(create_expression_by_pieces): Handle INDIRECT_REF.
Only create one temp until we have to change types.
Mark new vars for renaming.
(insert_into_preds_of_block): Ignore loopiness of loads.
Use can_PRE_operation.
Only create one temp until we have to chnge types.
(insert_aux): Use can_PRE_operation.
Don't pass name to insert_into_preds_of_block.
(insert_extra_phis): Only use one temp until we have to change
types.
(poolify_tree): New function.
(modify_expr_template): New var.
(poolify_modify_expr): New function.
(insert_fake_stores): Ditto.
(realify_fake_stores): Ditto.
(compute_avail): Use can_value_number_operation.
(mark_operand_necessary): Return NULL for non-SSA names.
(remove_dead_inserted_code): Update comment.
(init_pre): Initialize pretemp, need_creation, storetemp,
mergephitemp, prephitemp.
Create modify_expr_node_pool.
(fini_pre): Free modify_expr_node_pool and need_creation array.
(execute_pre): Call insert_fake_stores, compute_rvuse, and
realify_fake_stores.
* tree-flow.h (vn_compute): Fix prototype.
(vn_add): Ditto.
(vn_lookup): Ditto.
(sort_vuses): New.
(vn_lookup_or_add_with_vuses): Ditto.
(vn_add_with_vuses): Ditto.
(vn_lookup_with_vuses): Ditto.
* passes.c (pass_may_alias): Add.
2005-12-30 Gabriel Dos Reis <gdr@integrable-solutions.net> 2005-12-30 Gabriel Dos Reis <gdr@integrable-solutions.net>
* c-pretty-print.h (struct c_pretty_print_info): Add new member * c-pretty-print.h (struct c_pretty_print_info): Add new member
......
...@@ -554,6 +554,7 @@ init_optimization_passes (void) ...@@ -554,6 +554,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_cse_reciprocals); NEXT_PASS (pass_cse_reciprocals);
NEXT_PASS (pass_split_crit_edges); NEXT_PASS (pass_split_crit_edges);
NEXT_PASS (pass_pre); NEXT_PASS (pass_pre);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_sink_code); NEXT_PASS (pass_sink_code);
NEXT_PASS (pass_tree_loop); NEXT_PASS (pass_tree_loop);
NEXT_PASS (pass_reassoc); NEXT_PASS (pass_reassoc);
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
int main(int *a, int argc)
{
int c;
int d, e;
/* Should be able to eliminate the second load of *a along the main path. */
d = *a;
if (argc)
{
a = &c;
}
e = *a;
return d + e;
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
int main(int *a, int argc)
{
int b;
int i;
int d, e;
/* Should be able to hoist this out of the loop. */
for (i = 0; i < argc; i++)
{
e = *a;
}
return d + e;
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
int main(int **a,int argc)
{
int b;
int d, e;
if (argc)
{
d = *(*a);
}
else
{
}
/* Should be able to eliminate one of the *(*a)'s along the if path
by pushing it into the else path. We will also eliminate
one of the *a's. */
e = *(*a);
return d + e;
}
/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
int main(int *a, int argc)
{
int b;
int c;
int i;
int d, e;
/* With smarter load PRE, we'd be able to recompute the value at the
kill point. arguably not worth it. */
for (i = 0; i < argc; i++)
{
e = *a;
*a = 9;
}
return d + e;
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
int p;
int r;
int a(void)
{
return p;
}
int main(int argc)
{
int q;
q = a();
/* We should be able to move the call to a into the if path.
in a perfect world, we'd actually decide that it can't touch
r, and not recompute it at all!. */
if (argc)
r = 9;
return q + a();
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
union tree_node;
typedef union tree_node *tree;
struct tree_common
{
tree chain;
};
struct tree_list
{
struct tree_common common;
tree value;
};
union tree_node
{
struct tree_common common;
struct tree_list list;
};
extern void abort (void) __attribute__((noreturn));
void __attribute__((noinline))
foo (void)
{
abort ();
}
void __attribute__((noinline))
remove_useless_vars (tree *unexpanded_var_list, int dump_file)
{
tree var, *cell;
int c = 0;
for (cell = unexpanded_var_list; *cell; )
{
var = (*cell)->list.value;
if (var)
{
if (dump_file)
foo ();
*cell = ((*cell)->common.chain);
continue;
}
cell = &((*cell)->common.chain);
}
}
extern void *malloc (int) __attribute__ ((malloc));
int
main (void)
{
int i;
tree unexpanded_var_list, last = (tree) 0;
for (i = 0; i < 2; i++)
{
unexpanded_var_list = malloc (sizeof (struct tree_list));
unexpanded_var_list->list.value = (tree) (long unsigned) (i & 1);
unexpanded_var_list->common.chain = last;
last = unexpanded_var_list;
}
remove_useless_vars (&unexpanded_var_list, 0);
return 0;
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
/* We can't eliminate the *p load here in any sane way, as eshup8 may
change it. */
void
enormlz (x)
unsigned short x[];
{
register unsigned short *p;
p = &x[2];
while ((*p & 0xff00) == 0)
{
eshup8 (x);
}
}
/* { dg-final { scan-tree-dump-times "Eliminated: 0" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
typedef union tree_node *tree;
struct tree_common
{
tree chain;
}
VEC_constructor_elt_base;
struct tree_ssa_name
{
tree var;
};
union tree_node
{
struct tree_common common;
struct tree_ssa_name ssa_name;
};
struct edge_def
{
struct basic_block_def *dest;
};
typedef struct edge_def *edge;
typedef struct VEC_edge_base
{
}
VEC_edge_base;
edge
VEC_edge_base_index (const VEC_edge_base * vec_, unsigned ix_)
{
}
typedef struct VEC_edge_gc
{
VEC_edge_base base;
}
VEC_edge_gc;
struct basic_block_def
{
VEC_edge_gc *succs;
};
typedef struct basic_block_def *basic_block;
typedef struct
{
unsigned index;
VEC_edge_gc **container;
}
edge_iterator;
__inline__ VEC_edge_gc *
ei_container (edge_iterator i)
{
return *i.container;
}
__inline__ edge_iterator
ei_start_1 (VEC_edge_gc ** ev)
{
edge_iterator i;
i.container = ev;
return i;
}
ei_next (edge_iterator * i)
{
}
static __inline__ edge
ei_edge (edge_iterator i)
{
return (edge) (VEC_edge_base_index ((((ei_container (i))) ? &((ei_container (i)))->base : 0), (i.index)));
}
static __inline__ unsigned char
ei_cond (edge_iterator ei, edge * p)
{
*p = ei_edge (ei);
}
typedef tree *def_operand_p;
extern tree *get_phi_result_ptr (tree);
static __inline__ tree
get_def_from_ptr (def_operand_p def)
{
}
tree
phi_nodes (basic_block bb)
{
}
/* We can eliminate a load of the SRA'd variable edge_iterator.container */
rewrite_add_phi_arguments (basic_block bb)
{
edge e;
edge_iterator ei;
for ((ei) = ei_start_1 (&((bb->succs))); ei_cond ((ei), &(e));
ei_next (&(ei)))
{
tree phi;
for (phi = phi_nodes (e->dest); phi; phi = (((phi))->common.chain))
get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
}
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */
...@@ -776,10 +776,14 @@ void print_value_expressions (FILE *, tree); ...@@ -776,10 +776,14 @@ void print_value_expressions (FILE *, tree);
/* In tree-vn.c */ /* In tree-vn.c */
bool expressions_equal_p (tree, tree); bool expressions_equal_p (tree, tree);
tree get_value_handle (tree); tree get_value_handle (tree);
hashval_t vn_compute (tree, hashval_t, tree); hashval_t vn_compute (tree, hashval_t);
void sort_vuses (VEC (tree, gc) *);
tree vn_lookup_or_add (tree, tree); tree vn_lookup_or_add (tree, tree);
void vn_add (tree, tree, tree); tree vn_lookup_or_add_with_vuses (tree, VEC (tree, gc) *);
void vn_add (tree, tree);
void vn_add_with_vuses (tree, tree, VEC (tree, gc) *);
tree vn_lookup (tree, tree); tree vn_lookup (tree, tree);
tree vn_lookup_with_vuses (tree, VEC (tree, gc) *);
void vn_init (void); void vn_init (void);
void vn_delete (void); void vn_delete (void);
......
...@@ -49,13 +49,9 @@ Boston, MA 02110-1301, USA. */ ...@@ -49,13 +49,9 @@ Boston, MA 02110-1301, USA. */
1. Avail sets can be shared by making an avail_find_leader that 1. Avail sets can be shared by making an avail_find_leader that
walks up the dominator tree and looks in those avail sets. walks up the dominator tree and looks in those avail sets.
This might affect code optimality, it's unclear right now. This might affect code optimality, it's unclear right now.
2. Load motion can be performed by value numbering the loads the 2. Strength reduction can be performed by anticipating expressions
same as we do other expressions. This requires iterative
hashing the vuses into the values. Right now we simply assign
a new value every time we see a statement with a vuse.
3. Strength reduction can be performed by anticipating expressions
we can repair later on. we can repair later on.
4. We can do back-substitution or smarter value numbering to catch 3. We can do back-substitution or smarter value numbering to catch
commutative expressions split up over multiple statements. commutative expressions split up over multiple statements.
*/ */
...@@ -247,7 +243,7 @@ typedef struct bb_value_sets ...@@ -247,7 +243,7 @@ typedef struct bb_value_sets
a given basic block. */ a given basic block. */
bitmap_set_t avail_out; bitmap_set_t avail_out;
/* The ANTIC_IN set, which represents which values are anticiptable /* The ANTIC_IN set, which represents which values are anticipatable
in a given basic block. */ in a given basic block. */
value_set_t antic_in; value_set_t antic_in;
...@@ -255,6 +251,13 @@ typedef struct bb_value_sets ...@@ -255,6 +251,13 @@ typedef struct bb_value_sets
AVAIL_OUT set of blocks with the new insertions performed during AVAIL_OUT set of blocks with the new insertions performed during
the current iteration. */ the current iteration. */
bitmap_set_t new_sets; bitmap_set_t new_sets;
/* The RVUSE sets, which are used during ANTIC computation to ensure
that we don't mark loads ANTIC once they have died. */
bitmap rvuse_in;
bitmap rvuse_out;
bitmap rvuse_gen;
bitmap rvuse_kill;
} *bb_value_sets_t; } *bb_value_sets_t;
#define EXP_GEN(BB) ((bb_value_sets_t) ((BB)->aux))->exp_gen #define EXP_GEN(BB) ((bb_value_sets_t) ((BB)->aux))->exp_gen
...@@ -262,6 +265,10 @@ typedef struct bb_value_sets ...@@ -262,6 +265,10 @@ typedef struct bb_value_sets
#define TMP_GEN(BB) ((bb_value_sets_t) ((BB)->aux))->tmp_gen #define TMP_GEN(BB) ((bb_value_sets_t) ((BB)->aux))->tmp_gen
#define AVAIL_OUT(BB) ((bb_value_sets_t) ((BB)->aux))->avail_out #define AVAIL_OUT(BB) ((bb_value_sets_t) ((BB)->aux))->avail_out
#define ANTIC_IN(BB) ((bb_value_sets_t) ((BB)->aux))->antic_in #define ANTIC_IN(BB) ((bb_value_sets_t) ((BB)->aux))->antic_in
#define RVUSE_IN(BB) ((bb_value_sets_t) ((BB)->aux))->rvuse_in
#define RVUSE_GEN(BB) ((bb_value_sets_t) ((BB)->aux))->rvuse_gen
#define RVUSE_KILL(BB) ((bb_value_sets_t) ((BB)->aux))->rvuse_kill
#define RVUSE_OUT(BB) ((bb_value_sets_t) ((BB)->aux))->rvuse_out
#define NEW_SETS(BB) ((bb_value_sets_t) ((BB)->aux))->new_sets #define NEW_SETS(BB) ((bb_value_sets_t) ((BB)->aux))->new_sets
/* This structure is used to keep track of statistics on what /* This structure is used to keep track of statistics on what
...@@ -309,8 +316,18 @@ static alloc_pool reference_node_pool; ...@@ -309,8 +316,18 @@ static alloc_pool reference_node_pool;
static alloc_pool comparison_node_pool; static alloc_pool comparison_node_pool;
static alloc_pool expression_node_pool; static alloc_pool expression_node_pool;
static alloc_pool list_node_pool; static alloc_pool list_node_pool;
static alloc_pool modify_expr_node_pool;
static bitmap_obstack grand_bitmap_obstack; static bitmap_obstack grand_bitmap_obstack;
/* To avoid adding 300 temporary variables when we only need one, we
only create one temporary variable, on demand, and build ssa names
off that. We do have to change the variable if the types don't
match the current variable's type. */
static tree pretemp;
static tree storetemp;
static tree mergephitemp;
static tree prephitemp;
/* Set of blocks with statements that have had its EH information /* Set of blocks with statements that have had its EH information
cleaned up. */ cleaned up. */
static bitmap need_eh_cleanup; static bitmap need_eh_cleanup;
...@@ -331,9 +348,13 @@ typedef struct expr_pred_trans_d ...@@ -331,9 +348,13 @@ typedef struct expr_pred_trans_d
/* The predecessor block along which we translated the expression. */ /* The predecessor block along which we translated the expression. */
basic_block pred; basic_block pred;
/* vuses associated with the expression. */
VEC (tree, gc) *vuses;
/* The value that resulted from the translation. */ /* The value that resulted from the translation. */
tree v; tree v;
/* The hashcode for the expression, pred pair. This is cached for /* The hashcode for the expression, pred pair. This is cached for
speed reasons. */ speed reasons. */
hashval_t hashcode; hashval_t hashcode;
...@@ -358,33 +379,50 @@ expr_pred_trans_eq (const void *p1, const void *p2) ...@@ -358,33 +379,50 @@ expr_pred_trans_eq (const void *p1, const void *p2)
const expr_pred_trans_t ve2 = (expr_pred_trans_t) p2; const expr_pred_trans_t ve2 = (expr_pred_trans_t) p2;
basic_block b1 = ve1->pred; basic_block b1 = ve1->pred;
basic_block b2 = ve2->pred; basic_block b2 = ve2->pred;
int i;
tree vuse1;
/* If they are not translations for the same basic block, they can't /* If they are not translations for the same basic block, they can't
be equal. */ be equal. */
if (b1 != b2) if (b1 != b2)
return false; return false;
/* If they are for the same basic block, determine if the /* If they are for the same basic block, determine if the
expressions are equal. */ expressions are equal. */
if (expressions_equal_p (ve1->e, ve2->e)) if (!expressions_equal_p (ve1->e, ve2->e))
return false;
/* Make sure the vuses are equivalent. */
if (ve1->vuses == ve2->vuses)
return true; return true;
if (VEC_length (tree, ve1->vuses) != VEC_length (tree, ve2->vuses))
return false;
for (i = 0; VEC_iterate (tree, ve1->vuses, i, vuse1); i++)
{
if (VEC_index (tree, ve2->vuses, i) != vuse1)
return false; return false;
}
return true;
} }
/* Search in the phi translation table for the translation of /* Search in the phi translation table for the translation of
expression E in basic block PRED. Return the translated value, if expression E in basic block PRED with vuses VUSES.
found, NULL otherwise. */ Return the translated value, if found, NULL otherwise. */
static inline tree static inline tree
phi_trans_lookup (tree e, basic_block pred) phi_trans_lookup (tree e, basic_block pred, VEC (tree, gc) *vuses)
{ {
void **slot; void **slot;
struct expr_pred_trans_d ept; struct expr_pred_trans_d ept;
ept.e = e; ept.e = e;
ept.pred = pred; ept.pred = pred;
ept.hashcode = vn_compute (e, (unsigned long) pred, NULL); ept.vuses = vuses;
ept.hashcode = vn_compute (e, (unsigned long) pred);
slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode, slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode,
NO_INSERT); NO_INSERT);
if (!slot) if (!slot)
...@@ -394,18 +432,19 @@ phi_trans_lookup (tree e, basic_block pred) ...@@ -394,18 +432,19 @@ phi_trans_lookup (tree e, basic_block pred)
} }
/* Add the tuple mapping from {expression E, basic block PRED} to /* Add the tuple mapping from {expression E, basic block PRED, vuses VUSES} to
value V, to the phi translation table. */ value V, to the phi translation table. */
static inline void static inline void
phi_trans_add (tree e, tree v, basic_block pred) phi_trans_add (tree e, tree v, basic_block pred, VEC (tree, gc) *vuses)
{ {
void **slot; void **slot;
expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d); expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d);
new_pair->e = e; new_pair->e = e;
new_pair->pred = pred; new_pair->pred = pred;
new_pair->vuses = vuses;
new_pair->v = v; new_pair->v = v;
new_pair->hashcode = vn_compute (e, (unsigned long) pred, NULL); new_pair->hashcode = vn_compute (e, (unsigned long) pred);
slot = htab_find_slot_with_hash (phi_translate_table, new_pair, slot = htab_find_slot_with_hash (phi_translate_table, new_pair,
new_pair->hashcode, INSERT); new_pair->hashcode, INSERT);
if (*slot) if (*slot)
...@@ -936,7 +975,42 @@ pool_copy_list (tree list) ...@@ -936,7 +975,42 @@ pool_copy_list (tree list)
return head; return head;
} }
/* Translate the vuses in the VUSES vector backwards through phi
nodes, so that they have the value they would have in BLOCK. */
static VEC(tree, gc) *
translate_vuses_through_block (VEC (tree, gc) *vuses, basic_block block)
{
tree oldvuse;
VEC(tree, gc) *result = NULL;
int i;
for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); i++)
{
tree phi = SSA_NAME_DEF_STMT (oldvuse);
if (TREE_CODE (phi) == PHI_NODE)
{
edge e = find_edge (block, bb_for_stmt (phi));
if (e)
{
tree def = PHI_ARG_DEF (phi, e->dest_idx);
if (def != oldvuse)
{
if (!result)
result = VEC_copy (tree, gc, vuses);
VEC_replace (tree, result, i, def);
}
}
}
}
if (result)
{
sort_vuses (result);
return result;
}
return vuses;
}
/* Translate EXPR using phis in PHIBLOCK, so that it has the values of /* Translate EXPR using phis in PHIBLOCK, so that it has the values of
the phis in PRED. Return NULL if we can't find a leader for each the phis in PRED. Return NULL if we can't find a leader for each
part of the translated expression. */ part of the translated expression. */
...@@ -947,7 +1021,6 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -947,7 +1021,6 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
{ {
tree phitrans = NULL; tree phitrans = NULL;
tree oldexpr = expr; tree oldexpr = expr;
if (expr == NULL) if (expr == NULL)
return NULL; return NULL;
...@@ -955,7 +1028,19 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -955,7 +1028,19 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
return expr; return expr;
/* Phi translations of a given expression don't change. */ /* Phi translations of a given expression don't change. */
phitrans = phi_trans_lookup (expr, pred); if (EXPR_P (expr))
{
tree vh;
vh = get_value_handle (expr);
if (vh && TREE_CODE (vh) == VALUE_HANDLE)
phitrans = phi_trans_lookup (expr, pred, VALUE_HANDLE_VUSES (vh));
else
phitrans = phi_trans_lookup (expr, pred, NULL);
}
else
phitrans = phi_trans_lookup (expr, pred, NULL);
if (phitrans) if (phitrans)
return phitrans; return phitrans;
...@@ -976,7 +1061,10 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -976,7 +1061,10 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
tree oldwalker; tree oldwalker;
tree newwalker; tree newwalker;
tree newexpr; tree newexpr;
tree vh = get_value_handle (expr);
bool listchanged = false; bool listchanged = false;
VEC (tree, gc) *vuses = VALUE_HANDLE_VUSES (vh);
VEC (tree, gc) *tvuses;
/* Call expressions are kind of weird because they have an /* Call expressions are kind of weird because they have an
argument list. We don't want to value number the list argument list. We don't want to value number the list
...@@ -1028,7 +1116,10 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -1028,7 +1116,10 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
if (listchanged) if (listchanged)
vn_lookup_or_add (newarglist, NULL); vn_lookup_or_add (newarglist, NULL);
if (listchanged || (newop0 != oldop0) || (oldop2 != newop2)) tvuses = translate_vuses_through_block (vuses, pred);
if (listchanged || (newop0 != oldop0) || (oldop2 != newop2)
|| vuses != tvuses)
{ {
newexpr = (tree) pool_alloc (expression_node_pool); newexpr = (tree) pool_alloc (expression_node_pool);
memcpy (newexpr, expr, tree_size (expr)); memcpy (newexpr, expr, tree_size (expr));
...@@ -1036,18 +1127,77 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -1036,18 +1127,77 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
TREE_OPERAND (newexpr, 1) = listchanged ? newarglist : oldarglist; TREE_OPERAND (newexpr, 1) = listchanged ? newarglist : oldarglist;
TREE_OPERAND (newexpr, 2) = newop2 == oldop2 ? oldop2 : get_value_handle (newop2); TREE_OPERAND (newexpr, 2) = newop2 == oldop2 ? oldop2 : get_value_handle (newop2);
create_tree_ann (newexpr); create_tree_ann (newexpr);
vn_lookup_or_add (newexpr, NULL); vn_lookup_or_add_with_vuses (newexpr, tvuses);
expr = newexpr; expr = newexpr;
phi_trans_add (oldexpr, newexpr, pred); phi_trans_add (oldexpr, newexpr, pred, tvuses);
} }
} }
} }
return expr; return expr;
case tcc_declaration:
{
VEC (tree, gc) * oldvuses = NULL;
VEC (tree, gc) * newvuses = NULL;
oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr));
if (oldvuses)
newvuses = translate_vuses_through_block (oldvuses, pred);
if (oldvuses != newvuses)
vn_lookup_or_add_with_vuses (expr, newvuses);
phi_trans_add (oldexpr, expr, pred, newvuses);
}
return expr;
case tcc_reference: case tcc_reference:
/* XXX: Until we have PRE of loads working, none will be ANTIC. */ {
tree oldop1 = TREE_OPERAND (expr, 0);
tree newop1;
tree newexpr;
VEC (tree, gc) * oldvuses = NULL;
VEC (tree, gc) * newvuses = NULL;
if (TREE_CODE (expr) != INDIRECT_REF)
return NULL;
newop1 = phi_translate (find_leader (set, oldop1),
set, pred, phiblock);
if (newop1 == NULL)
return NULL; return NULL;
oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr));
if (oldvuses)
newvuses = translate_vuses_through_block (oldvuses, pred);
if (newop1 != oldop1 || newvuses != oldvuses)
{
tree t;
newexpr = pool_alloc (reference_node_pool);
memcpy (newexpr, expr, tree_size (expr));
TREE_OPERAND (newexpr, 0) = get_value_handle (newop1);
t = fully_constant_expression (newexpr);
if (t != newexpr)
{
pool_free (reference_node_pool, newexpr);
newexpr = t;
}
else
{
create_tree_ann (newexpr);
vn_lookup_or_add_with_vuses (newexpr, newvuses);
}
expr = newexpr;
phi_trans_add (oldexpr, newexpr, pred, newvuses);
}
}
return expr;
break;
case tcc_binary: case tcc_binary:
case tcc_comparison: case tcc_comparison:
{ {
...@@ -1084,7 +1234,7 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -1084,7 +1234,7 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
vn_lookup_or_add (newexpr, NULL); vn_lookup_or_add (newexpr, NULL);
} }
expr = newexpr; expr = newexpr;
phi_trans_add (oldexpr, newexpr, pred); phi_trans_add (oldexpr, newexpr, pred, NULL);
} }
} }
return expr; return expr;
...@@ -1117,7 +1267,7 @@ phi_translate (tree expr, value_set_t set, basic_block pred, ...@@ -1117,7 +1267,7 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
vn_lookup_or_add (newexpr, NULL); vn_lookup_or_add (newexpr, NULL);
} }
expr = newexpr; expr = newexpr;
phi_trans_add (oldexpr, newexpr, pred); phi_trans_add (oldexpr, newexpr, pred, NULL);
} }
} }
return expr; return expr;
...@@ -1162,8 +1312,22 @@ phi_translate_set (value_set_t dest, value_set_t set, basic_block pred, ...@@ -1162,8 +1312,22 @@ phi_translate_set (value_set_t dest, value_set_t set, basic_block pred,
node = node->next) node = node->next)
{ {
tree translated; tree translated;
translated = phi_translate (node->expr, set, pred, phiblock); translated = phi_translate (node->expr, set, pred, phiblock);
phi_trans_add (node->expr, translated, pred);
/* Don't add constants or empty translations to the cache, since
we won't look them up that way, or use the result, anyway. */
if (translated && !is_gimple_min_invariant (translated))
{
tree vh = get_value_handle (translated);
VEC (tree, gc) *vuses;
/* The value handle itself may also be an invariant, in
which case, it has no vuses. */
vuses = !is_gimple_min_invariant (vh)
? VALUE_HANDLE_VUSES (vh) : NULL;
phi_trans_add (node->expr, translated, pred, vuses);
}
if (translated != NULL) if (translated != NULL)
value_insert_into_set (dest, translated); value_insert_into_set (dest, translated);
...@@ -1245,6 +1409,42 @@ find_leader (value_set_t set, tree val) ...@@ -1245,6 +1409,42 @@ find_leader (value_set_t set, tree val)
return NULL; return NULL;
} }
/* Given the vuse representative map, MAP, and an SSA version number,
ID, return the bitmap of names ID represents, or NULL, if none
exists. */
static bitmap
get_representative (bitmap *map, int id)
{
if (map[id] != NULL)
return map[id];
return NULL;
}
/* A vuse is anticipable at the top of block x, from the bottom of the
block, if it reaches the top of the block, and is not killed in the
block. In effect, we are trying to see if the vuse is transparent
backwards in the block. */
static bool
vuses_dies_in_block_x (VEC (tree, gc) *vuses, basic_block block)
{
int i;
tree vuse;
for (i = 0; VEC_iterate (tree, vuses, i, vuse); i++)
{
/* Any places where this is too conservative, are places
where we created a new version and shouldn't have. */
if (!bitmap_bit_p (RVUSE_IN (block), SSA_NAME_VERSION (vuse))
|| bitmap_bit_p (RVUSE_KILL (block), SSA_NAME_VERSION
(vuse)))
return true;
}
return false;
}
/* Determine if the expression EXPR is valid in SET. This means that /* Determine if the expression EXPR is valid in SET. This means that
we have a leader for each part of the expression (if it consists of we have a leader for each part of the expression (if it consists of
values), or the expression is an SSA_NAME. values), or the expression is an SSA_NAME.
...@@ -1255,8 +1455,9 @@ find_leader (value_set_t set, tree val) ...@@ -1255,8 +1455,9 @@ find_leader (value_set_t set, tree val)
(IE VALUE1 + VALUE2, *VALUE1, VALUE1 < VALUE2) */ (IE VALUE1 + VALUE2, *VALUE1, VALUE1 < VALUE2) */
static bool static bool
valid_in_set (value_set_t set, tree expr) valid_in_set (value_set_t set, tree expr, basic_block block)
{ {
tree vh = get_value_handle (expr);
switch (TREE_CODE_CLASS (TREE_CODE (expr))) switch (TREE_CODE_CLASS (TREE_CODE (expr)))
{ {
case tcc_binary: case tcc_binary:
...@@ -1292,13 +1493,27 @@ valid_in_set (value_set_t set, tree expr) ...@@ -1292,13 +1493,27 @@ valid_in_set (value_set_t set, tree expr)
if (!set_contains_value (set, TREE_VALUE (arglist))) if (!set_contains_value (set, TREE_VALUE (arglist)))
return false; return false;
} }
return true; return !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), block);
} }
return false; return false;
} }
case tcc_reference: case tcc_reference:
/* XXX: Until PRE of loads works, no reference nodes are ANTIC. */ {
if (TREE_CODE (expr) == INDIRECT_REF)
{
tree op0 = TREE_OPERAND (expr, 0);
if (is_gimple_min_invariant (op0)
|| TREE_CODE (op0) == VALUE_HANDLE)
{
bool retval = set_contains_value (set, op0);
if (retval)
return !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh),
block);
return false;
}
}
}
return false; return false;
case tcc_exceptional: case tcc_exceptional:
...@@ -1306,8 +1521,7 @@ valid_in_set (value_set_t set, tree expr) ...@@ -1306,8 +1521,7 @@ valid_in_set (value_set_t set, tree expr)
return true; return true;
case tcc_declaration: case tcc_declaration:
/* VAR_DECL and PARM_DECL are never anticipatable. */ return !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), block);
return false;
default: default:
/* No other cases should be encountered. */ /* No other cases should be encountered. */
...@@ -1320,7 +1534,7 @@ valid_in_set (value_set_t set, tree expr) ...@@ -1320,7 +1534,7 @@ valid_in_set (value_set_t set, tree expr)
in SET. */ in SET. */
static void static void
clean (value_set_t set) clean (value_set_t set, basic_block block)
{ {
value_set_node_t node; value_set_node_t node;
value_set_node_t next; value_set_node_t next;
...@@ -1328,7 +1542,7 @@ clean (value_set_t set) ...@@ -1328,7 +1542,7 @@ clean (value_set_t set)
while (node) while (node)
{ {
next = node->next; next = node->next;
if (!valid_in_set (set, node->expr)) if (!valid_in_set (set, node->expr, block))
set_remove (set, node->expr); set_remove (set, node->expr);
node = next; node = next;
} }
...@@ -1402,6 +1616,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge) ...@@ -1402,6 +1616,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
{ {
tree val; tree val;
value_set_node_t next = node->next; value_set_node_t next = node->next;
val = get_value_handle (node->expr); val = get_value_handle (node->expr);
if (!set_contains_value (ANTIC_IN (bprime), val)) if (!set_contains_value (ANTIC_IN (bprime), val))
set_remove (ANTIC_OUT, node->expr); set_remove (ANTIC_OUT, node->expr);
...@@ -1424,7 +1639,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge) ...@@ -1424,7 +1639,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
for (node = S->head; node; node = node->next) for (node = S->head; node; node = node->next)
value_insert_into_set (ANTIC_IN (block), node->expr); value_insert_into_set (ANTIC_IN (block), node->expr);
clean (ANTIC_IN (block)); clean (ANTIC_IN (block), block);
if (!set_equal (old, ANTIC_IN (block))) if (!set_equal (old, ANTIC_IN (block)))
changed = true; changed = true;
...@@ -1492,7 +1707,304 @@ compute_antic (void) ...@@ -1492,7 +1707,304 @@ compute_antic (void)
fprintf (dump_file, "compute_antic required %d iterations\n", num_iterations); fprintf (dump_file, "compute_antic required %d iterations\n", num_iterations);
} }
/* Print the names represented by the bitmap NAMES, to the file OUT. */
static void
dump_bitmap_of_names (FILE *out, bitmap names)
{
bitmap_iterator bi;
unsigned int i;
fprintf (out, " { ");
EXECUTE_IF_SET_IN_BITMAP (names, 0, i, bi)
{
print_generic_expr (out, ssa_name (i), 0);
fprintf (out, " ");
}
fprintf (out, "}\n");
}
/* Compute a set of representative vuse versions for each phi. This
is so we can compute conservative kill sets in terms of all vuses
that are killed, instead of continually walking chains.
We also have to be able kill all names associated with a phi when
the phi dies in order to ensure we don't generate overlapping
live ranges, which are not allowed in virtual SSA. */
static bitmap *vuse_names;
static void
compute_vuse_representatives (void)
{
tree phi;
basic_block bb;
VEC (tree, heap) *phis = NULL;
bool changed = true;
size_t i;
FOR_EACH_BB (bb)
{
for (phi = phi_nodes (bb);
phi;
phi = PHI_CHAIN (phi))
if (!is_gimple_reg (PHI_RESULT (phi)))
VEC_safe_push (tree, heap, phis, phi);
}
while (changed)
{
changed = false;
for (i = 0; VEC_iterate (tree, phis, i, phi); i++)
{
size_t ver = SSA_NAME_VERSION (PHI_RESULT (phi));
use_operand_p usep;
ssa_op_iter iter;
if (vuse_names[ver] == NULL)
{
vuse_names[ver] = BITMAP_ALLOC (&grand_bitmap_obstack);
bitmap_set_bit (vuse_names[ver], ver);
}
FOR_EACH_PHI_ARG (usep, phi, iter, SSA_OP_ALL_USES)
{
tree use = USE_FROM_PTR (usep);
bitmap usebitmap = get_representative (vuse_names,
SSA_NAME_VERSION (use));
if (usebitmap != NULL)
{
changed |= bitmap_ior_into (vuse_names[ver],
usebitmap);
}
else
{
changed |= !bitmap_bit_p (vuse_names[ver],
SSA_NAME_VERSION (use));
if (changed)
bitmap_set_bit (vuse_names[ver],
SSA_NAME_VERSION (use));
}
}
}
}
if (dump_file && (dump_flags & TDF_DETAILS))
for (i = 0; VEC_iterate (tree, phis, i, phi); i++)
{
bitmap reps = get_representative (vuse_names,
SSA_NAME_VERSION (PHI_RESULT (phi)));
if (reps)
{
print_generic_expr (dump_file, PHI_RESULT (phi), 0);
fprintf (dump_file, " represents ");
dump_bitmap_of_names (dump_file, reps);
}
}
VEC_free (tree, heap, phis);
}
/* Compute reaching vuses. This is a small bit of iterative dataflow
to determine what virtual uses reach what blocks. Because we can't
generate overlapping virtual uses, and virtual uses *do* actually
die, this ends up being faster in most cases than continually
walking the virtual use/def chains to determine whether we are
inside a block where a given virtual is still available to be
used. */
static void
compute_rvuse (void)
{
size_t i;
tree phi;
basic_block bb;
int *postorder;
bool changed = true;
compute_vuse_representatives ();
FOR_ALL_BB (bb)
{
RVUSE_IN (bb) = BITMAP_ALLOC (&grand_bitmap_obstack);
RVUSE_GEN (bb) = BITMAP_ALLOC (&grand_bitmap_obstack);
RVUSE_KILL (bb) = BITMAP_ALLOC (&grand_bitmap_obstack);
RVUSE_OUT (bb) = BITMAP_ALLOC (&grand_bitmap_obstack);
}
/* Mark live on entry */
for (i = 0; i < num_ssa_names; i++)
{
tree name = ssa_name (i);
if (name && !is_gimple_reg (name)
&& IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
bitmap_set_bit (RVUSE_OUT (ENTRY_BLOCK_PTR),
SSA_NAME_VERSION (name));
}
/* Compute local sets for reaching vuses.
GEN(block) = generated in block and not locally killed.
KILL(block) = set of vuses killed in block.
*/
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi;
ssa_op_iter iter;
def_operand_p defp;
use_operand_p usep;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
FOR_EACH_SSA_USE_OPERAND (usep, stmt, iter, SSA_OP_VIRTUAL_KILLS
| SSA_OP_VMAYUSE)
{
tree use = USE_FROM_PTR (usep);
bitmap repbit = get_representative (vuse_names,
SSA_NAME_VERSION (use));
if (repbit != NULL)
{
bitmap_and_compl_into (RVUSE_GEN (bb), repbit);
bitmap_ior_into (RVUSE_KILL (bb), repbit);
}
else
{
bitmap_set_bit (RVUSE_KILL (bb), SSA_NAME_VERSION (use));
bitmap_clear_bit (RVUSE_GEN (bb), SSA_NAME_VERSION (use));
}
}
FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_VIRTUAL_DEFS)
{
tree def = DEF_FROM_PTR (defp);
bitmap_set_bit (RVUSE_GEN (bb), SSA_NAME_VERSION (def));
}
}
}
FOR_EACH_BB (bb)
{
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
if (!is_gimple_reg (PHI_RESULT (phi)))
{
edge e;
edge_iterator ei;
tree def = PHI_RESULT (phi);
/* In reality, the PHI result is generated at the end of
each predecessor block. This will make the value
LVUSE_IN for the bb containing the PHI, which is
correct. */
FOR_EACH_EDGE (e, ei, bb->preds)
bitmap_set_bit (RVUSE_GEN (e->src), SSA_NAME_VERSION (def));
}
}
}
/* Solve reaching vuses.
RVUSE_IN[BB] = Union of RVUSE_OUT of predecessors.
RVUSE_OUT[BB] = RVUSE_GEN[BB] U (RVUSE_IN[BB] - RVUSE_KILL[BB])
*/
postorder = xmalloc (sizeof (int) * (n_basic_blocks - NUM_FIXED_BLOCKS));
pre_and_rev_post_order_compute (NULL, postorder, false);
changed = true;
while (changed)
{
int j;
changed = false;
for (j = 0; j < n_basic_blocks - NUM_FIXED_BLOCKS; j++)
{
edge e;
edge_iterator ei;
bb = BASIC_BLOCK (postorder[j]);
FOR_EACH_EDGE (e, ei, bb->preds)
bitmap_ior_into (RVUSE_IN (bb), RVUSE_OUT (e->src));
changed |= bitmap_ior_and_compl (RVUSE_OUT (bb),
RVUSE_GEN (bb),
RVUSE_IN (bb),
RVUSE_KILL (bb));
}
}
free (postorder);
if (dump_file && (dump_flags & TDF_DETAILS))
{
FOR_ALL_BB (bb)
{
fprintf (dump_file, "RVUSE_IN (%d) =", bb->index);
dump_bitmap_of_names (dump_file, RVUSE_IN (bb));
fprintf (dump_file, "RVUSE_KILL (%d) =", bb->index);
dump_bitmap_of_names (dump_file, RVUSE_KILL (bb));
fprintf (dump_file, "RVUSE_GEN (%d) =", bb->index);
dump_bitmap_of_names (dump_file, RVUSE_GEN (bb));
fprintf (dump_file, "RVUSE_OUT (%d) =", bb->index);
dump_bitmap_of_names (dump_file, RVUSE_OUT (bb));
}
}
}
/* Return true if we can value number the call in STMT. This is true
if we have a pure or constant call. */
static bool
can_value_number_call (tree stmt)
{
tree call = get_call_expr_in (stmt);
if (call_expr_flags (call) & (ECF_PURE | ECF_CONST))
return true;
return false;
}
/* Return true if OP is a tree which we can perform value numbering
on. */
static bool
can_value_number_operation (tree op)
{
return UNARY_CLASS_P (op)
|| BINARY_CLASS_P (op)
|| COMPARISON_CLASS_P (op)
|| REFERENCE_CLASS_P (op)
|| (TREE_CODE (op) == CALL_EXPR
&& can_value_number_call (op));
}
/* Return true if OP is a tree which we can perform PRE on
on. This may not match the operations we can value number, but in
a perfect world would. */
static bool
can_PRE_operation (tree op)
{
return UNARY_CLASS_P (op)
|| BINARY_CLASS_P (op)
|| COMPARISON_CLASS_P (op)
|| TREE_CODE (op) == INDIRECT_REF
|| TREE_CODE (op) == CALL_EXPR;
}
/* Inserted expressions are placed onto this worklist, which is used
for performing quick dead code elimination of insertions we made
that didn't turn out to be necessary. */
static VEC(tree,heap) *inserted_exprs; static VEC(tree,heap) *inserted_exprs;
/* Pool allocated fake store expressions are placed onto this
worklist, which, after performing dead code elimination, is walked
to see which expressions need to be put into GC'able memory */
static VEC(tree, heap) *need_creation;
/* Find a leader for an expression, or generate one using /* Find a leader for an expression, or generate one using
create_expression_by_pieces if it's ANTIC but create_expression_by_pieces if it's ANTIC but
complex. complex.
...@@ -1512,11 +2024,8 @@ find_or_generate_expression (basic_block block, tree expr, tree stmts) ...@@ -1512,11 +2024,8 @@ find_or_generate_expression (basic_block block, tree expr, tree stmts)
if (genop == NULL) if (genop == NULL)
{ {
genop = VALUE_HANDLE_EXPR_SET (expr)->head->expr; genop = VALUE_HANDLE_EXPR_SET (expr)->head->expr;
gcc_assert (UNARY_CLASS_P (genop)
|| BINARY_CLASS_P (genop) gcc_assert (can_PRE_operation (genop));
|| COMPARISON_CLASS_P (genop)
|| REFERENCE_CLASS_P (genop)
|| TREE_CODE (genop) == CALL_EXPR);
genop = create_expression_by_pieces (block, genop, stmts); genop = create_expression_by_pieces (block, genop, stmts);
} }
return genop; return genop;
...@@ -1568,8 +2077,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) ...@@ -1568,8 +2077,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
genwalker && walker; genwalker && walker;
genwalker = TREE_CHAIN (genwalker), walker = TREE_CHAIN (walker)) genwalker = TREE_CHAIN (genwalker), walker = TREE_CHAIN (walker))
{ {
TREE_VALUE (genwalker) = find_or_generate_expression (block, TREE_VALUE (genwalker)
TREE_VALUE (walker), = find_or_generate_expression (block, TREE_VALUE (walker),
stmts); stmts);
} }
...@@ -1582,6 +2091,16 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) ...@@ -1582,6 +2091,16 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
} }
break; break;
case tcc_reference:
gcc_assert (TREE_CODE (expr) == INDIRECT_REF);
{
tree op1 = TREE_OPERAND (expr, 0);
tree genop1 = find_or_generate_expression (block, op1, stmts);
folded = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr),
genop1);
break;
}
case tcc_binary: case tcc_binary:
case tcc_comparison: case tcc_comparison:
...@@ -1628,9 +2147,11 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) ...@@ -1628,9 +2147,11 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
tree val = vn_lookup_or_add (forcedexpr, NULL); tree val = vn_lookup_or_add (forcedexpr, NULL);
VEC_safe_push (tree, heap, inserted_exprs, stmt); VEC_safe_push (tree, heap, inserted_exprs, stmt);
vn_add (forcedname, val, NULL); vn_add (forcedname, val);
bitmap_value_replace_in_set (NEW_SETS (block), forcedname); bitmap_value_replace_in_set (NEW_SETS (block), forcedname);
bitmap_value_replace_in_set (AVAIL_OUT (block), forcedname); bitmap_value_replace_in_set (AVAIL_OUT (block), forcedname);
update_stmt (stmt);
mark_new_vars_to_rename (tsi_stmt (tsi));
} }
tsi = tsi_last (stmts); tsi = tsi_last (stmts);
tsi_link_after (&tsi, forced_stmts, TSI_CONTINUE_LINKING); tsi_link_after (&tsi, forced_stmts, TSI_CONTINUE_LINKING);
...@@ -1638,17 +2159,28 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) ...@@ -1638,17 +2159,28 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
/* Build and insert the assignment of the end result to the temporary /* Build and insert the assignment of the end result to the temporary
that we will return. */ that we will return. */
temp = create_tmp_var (TREE_TYPE (expr), "pretmp"); if (!pretemp || TREE_TYPE (expr) != TREE_TYPE (pretemp))
{
pretemp = create_tmp_var (TREE_TYPE (expr), "pretmp");
get_var_ann (pretemp);
}
temp = pretemp;
add_referenced_tmp_var (temp); add_referenced_tmp_var (temp);
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
DECL_COMPLEX_GIMPLE_REG_P (temp) = 1; DECL_COMPLEX_GIMPLE_REG_P (temp) = 1;
newexpr = build2 (MODIFY_EXPR, TREE_TYPE (expr), temp, newexpr); newexpr = build2 (MODIFY_EXPR, TREE_TYPE (expr), temp, newexpr);
name = make_ssa_name (temp, newexpr); name = make_ssa_name (temp, newexpr);
TREE_OPERAND (newexpr, 0) = name; TREE_OPERAND (newexpr, 0) = name;
NECESSARY (newexpr) = 0; NECESSARY (newexpr) = 0;
tsi = tsi_last (stmts); tsi = tsi_last (stmts);
tsi_link_after (&tsi, newexpr, TSI_CONTINUE_LINKING); tsi_link_after (&tsi, newexpr, TSI_CONTINUE_LINKING);
VEC_safe_push (tree, heap, inserted_exprs, newexpr); VEC_safe_push (tree, heap, inserted_exprs, newexpr);
update_stmt (newexpr);
mark_new_vars_to_rename (newexpr);
/* Add a value handle to the temporary. /* Add a value handle to the temporary.
The value may already exist in either NEW_SETS, or AVAIL_OUT, because The value may already exist in either NEW_SETS, or AVAIL_OUT, because
...@@ -1656,7 +2188,7 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) ...@@ -1656,7 +2188,7 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
the expression may have been represented. There is no harm in replacing the expression may have been represented. There is no harm in replacing
here. */ here. */
v = get_value_handle (expr); v = get_value_handle (expr);
vn_add (name, v, NULL); vn_add (name, v);
bitmap_value_replace_in_set (NEW_SETS (block), name); bitmap_value_replace_in_set (NEW_SETS (block), name);
bitmap_value_replace_in_set (AVAIL_OUT (block), name); bitmap_value_replace_in_set (AVAIL_OUT (block), name);
...@@ -1671,14 +2203,14 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) ...@@ -1671,14 +2203,14 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
return name; return name;
} }
/* Insert the to-be-made-available values of NODE for each predecessor, stored /* Insert the to-be-made-available values of NODE for each
in AVAIL, into the predecessors of BLOCK, and merge the result with a phi predecessor, stored in AVAIL, into the predecessors of BLOCK, and
node, given the same value handle as NODE. The prefix of the phi node is merge the result with a phi node, given the same value handle as
given with TMPNAME. Return true if we have inserted new stuff. */ NODE. Return true if we have inserted new stuff. */
static bool static bool
insert_into_preds_of_block (basic_block block, value_set_node_t node, insert_into_preds_of_block (basic_block block, value_set_node_t node,
tree *avail, const char *tmpname) tree *avail)
{ {
tree val = get_value_handle (node->expr); tree val = get_value_handle (node->expr);
edge pred; edge pred;
...@@ -1694,11 +2226,15 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node, ...@@ -1694,11 +2226,15 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node,
{ {
fprintf (dump_file, "Found partial redundancy for expression "); fprintf (dump_file, "Found partial redundancy for expression ");
print_generic_expr (dump_file, node->expr, 0); print_generic_expr (dump_file, node->expr, 0);
fprintf (dump_file, " (");
print_generic_expr (dump_file, val, 0);
fprintf (dump_file, ")");
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
} }
/* Make sure we aren't creating an induction variable. */ /* Make sure we aren't creating an induction variable. */
if (block->loop_depth > 0 && EDGE_COUNT (block->preds) == 2) if (block->loop_depth > 0 && EDGE_COUNT (block->preds) == 2
&& TREE_CODE_CLASS (TREE_CODE (node->expr)) != tcc_reference )
{ {
bool firstinsideloop = false; bool firstinsideloop = false;
bool secondinsideloop = false; bool secondinsideloop = false;
...@@ -1723,11 +2259,32 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node, ...@@ -1723,11 +2259,32 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node,
tree builtexpr; tree builtexpr;
bprime = pred->src; bprime = pred->src;
eprime = avail[bprime->index]; eprime = avail[bprime->index];
if (BINARY_CLASS_P (eprime)
|| COMPARISON_CLASS_P (eprime) if (can_PRE_operation (eprime))
|| UNARY_CLASS_P (eprime) {
|| TREE_CODE (eprime) == CALL_EXPR) #ifdef ENABLE_CHECKING
tree vh;
/* eprime may be an invariant. */
vh = TREE_CODE (eprime) == VALUE_HANDLE
? eprime
: get_value_handle (eprime);
/* ensure that the virtual uses we need reach our block. */
if (TREE_CODE (vh) == VALUE_HANDLE)
{ {
int i;
tree vuse;
for (i = 0;
VEC_iterate (tree, VALUE_HANDLE_VUSES (vh), i, vuse);
i++)
{
size_t id = SSA_NAME_VERSION (vuse);
gcc_assert (bitmap_bit_p (RVUSE_OUT (bprime), id)
|| IS_EMPTY_STMT (SSA_NAME_DEF_STMT (vuse)));
}
}
#endif
builtexpr = create_expression_by_pieces (bprime, builtexpr = create_expression_by_pieces (bprime,
eprime, eprime,
stmts); stmts);
...@@ -1746,17 +2303,25 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node, ...@@ -1746,17 +2303,25 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node,
return false; return false;
/* Now build a phi for the new variable. */ /* Now build a phi for the new variable. */
temp = create_tmp_var (type, tmpname); if (!prephitemp || TREE_TYPE (prephitemp) != type)
{
prephitemp = create_tmp_var (type, "prephitmp");
get_var_ann (prephitemp);
}
temp = prephitemp;
add_referenced_tmp_var (temp); add_referenced_tmp_var (temp);
if (TREE_CODE (type) == COMPLEX_TYPE) if (TREE_CODE (type) == COMPLEX_TYPE)
DECL_COMPLEX_GIMPLE_REG_P (temp) = 1; DECL_COMPLEX_GIMPLE_REG_P (temp) = 1;
temp = create_phi_node (temp, block); temp = create_phi_node (temp, block);
NECESSARY (temp) = 0; NECESSARY (temp) = 0;
VEC_safe_push (tree, heap, inserted_exprs, temp); VEC_safe_push (tree, heap, inserted_exprs, temp);
FOR_EACH_EDGE (pred, ei, block->preds) FOR_EACH_EDGE (pred, ei, block->preds)
add_phi_arg (temp, avail[pred->src->index], pred); add_phi_arg (temp, avail[pred->src->index], pred);
vn_add (PHI_RESULT (temp), val, NULL); vn_add (PHI_RESULT (temp), val);
/* The value should *not* exist in PHI_GEN, or else we wouldn't be doing /* The value should *not* exist in PHI_GEN, or else we wouldn't be doing
this insertion, since we test for the existence of this value in PHI_GEN this insertion, since we test for the existence of this value in PHI_GEN
...@@ -1840,10 +2405,7 @@ insert_aux (basic_block block) ...@@ -1840,10 +2405,7 @@ insert_aux (basic_block block)
node; node;
node = node->next) node = node->next)
{ {
if (BINARY_CLASS_P (node->expr) if (can_PRE_operation (node->expr))
|| COMPARISON_CLASS_P (node->expr)
|| UNARY_CLASS_P (node->expr)
|| TREE_CODE (node->expr) == CALL_EXPR)
{ {
tree *avail; tree *avail;
tree val; tree val;
...@@ -1927,8 +2489,7 @@ insert_aux (basic_block block) ...@@ -1927,8 +2489,7 @@ insert_aux (basic_block block)
partially redundant. */ partially redundant. */
if (!cant_insert && !all_same && by_some) if (!cant_insert && !all_same && by_some)
{ {
if (insert_into_preds_of_block (block, node, avail, if (insert_into_preds_of_block (block, node, avail))
"prephitmp"))
new_stuff = true; new_stuff = true;
} }
/* If all edges produce the same value and that value is /* If all edges produce the same value and that value is
...@@ -1940,11 +2501,12 @@ insert_aux (basic_block block) ...@@ -1940,11 +2501,12 @@ insert_aux (basic_block block)
{ {
value_set_t exprset = VALUE_HANDLE_EXPR_SET (val); value_set_t exprset = VALUE_HANDLE_EXPR_SET (val);
value_set_node_t node; value_set_node_t node;
for (node = exprset->head; node; node = node->next) for (node = exprset->head; node; node = node->next)
{ {
if (TREE_CODE (node->expr) == SSA_NAME) if (TREE_CODE (node->expr) == SSA_NAME)
{ {
vn_add (node->expr, eprime, NULL); vn_add (node->expr, eprime);
pre_stats.constified++; pre_stats.constified++;
} }
} }
...@@ -2007,7 +2569,7 @@ is_undefined_value (tree expr) ...@@ -2007,7 +2569,7 @@ is_undefined_value (tree expr)
S1 and its value handle to S2. S1 and its value handle to S2.
VUSES represent the virtual use operands associated with EXPR (if VUSES represent the virtual use operands associated with EXPR (if
any). They are used when computing the hash value for EXPR. */ any). */
static inline void static inline void
add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1, add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1,
...@@ -2020,7 +2582,7 @@ add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1, ...@@ -2020,7 +2582,7 @@ add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1,
statements that make aliased stores). In those cases, we are statements that make aliased stores). In those cases, we are
only interested in making VAR available as its own value. */ only interested in making VAR available as its own value. */
if (var != expr) if (var != expr)
vn_add (var, val, NULL_TREE); vn_add (var, val);
if (s1) if (s1)
bitmap_insert_into_set (s1, var); bitmap_insert_into_set (s1, var);
...@@ -2033,8 +2595,7 @@ add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1, ...@@ -2033,8 +2595,7 @@ add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1,
replaced with the value handles of each of the operands of EXPR. replaced with the value handles of each of the operands of EXPR.
VUSES represent the virtual use operands associated with EXPR (if VUSES represent the virtual use operands associated with EXPR (if
any). They are used when computing the hash value for EXPR. any). Insert EXPR's operands into the EXP_GEN set for BLOCK. */
Insert EXPR's operands into the EXP_GEN set for BLOCK. */
static inline tree static inline tree
create_value_expr_from (tree expr, basic_block block, tree stmt) create_value_expr_from (tree expr, basic_block block, tree stmt)
...@@ -2049,7 +2610,8 @@ create_value_expr_from (tree expr, basic_block block, tree stmt) ...@@ -2049,7 +2610,8 @@ create_value_expr_from (tree expr, basic_block block, tree stmt)
|| TREE_CODE_CLASS (code) == tcc_comparison || TREE_CODE_CLASS (code) == tcc_comparison
|| TREE_CODE_CLASS (code) == tcc_reference || TREE_CODE_CLASS (code) == tcc_reference
|| TREE_CODE_CLASS (code) == tcc_expression || TREE_CODE_CLASS (code) == tcc_expression
|| TREE_CODE_CLASS (code) == tcc_exceptional); || TREE_CODE_CLASS (code) == tcc_exceptional
|| TREE_CODE_CLASS (code) == tcc_declaration);
if (TREE_CODE_CLASS (code) == tcc_unary) if (TREE_CODE_CLASS (code) == tcc_unary)
pool = unary_node_pool; pool = unary_node_pool;
...@@ -2167,21 +2729,6 @@ create_value_expr_from (tree expr, basic_block block, tree stmt) ...@@ -2167,21 +2729,6 @@ create_value_expr_from (tree expr, basic_block block, tree stmt)
} }
/* Return true if we can value number a call. This is true if we have
a pure or constant call. */
static bool
can_value_number_call (tree stmt)
{
tree call = get_call_expr_in (stmt);
/* This is a temporary restriction until we translate vuses through
phi nodes. This is only needed for PRE, of course. */
if (!in_fre && !ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
return false;
if (call_expr_flags (call) & (ECF_PURE | ECF_CONST))
return true;
return false;
}
/* Insert extra phis to merge values that are fully available from /* Insert extra phis to merge values that are fully available from
preds of BLOCK, but have no dominating representative coming from preds of BLOCK, but have no dominating representative coming from
...@@ -2221,7 +2768,16 @@ insert_extra_phis (basic_block block, basic_block dom) ...@@ -2221,7 +2768,16 @@ insert_extra_phis (basic_block block, basic_block dom)
{ {
tree name = ssa_name (i); tree name = ssa_name (i);
tree val = get_value_handle (name); tree val = get_value_handle (name);
tree temp = create_tmp_var (TREE_TYPE (name), "mergephitmp"); tree temp;
if (!mergephitemp
|| TREE_TYPE (name) != TREE_TYPE (mergephitemp))
{
mergephitemp = create_tmp_var (TREE_TYPE (name),
"mergephitmp");
get_var_ann (mergephitemp);
}
temp = mergephitemp;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
...@@ -2249,7 +2805,7 @@ insert_extra_phis (basic_block block, basic_block dom) ...@@ -2249,7 +2805,7 @@ insert_extra_phis (basic_block block, basic_block dom)
} }
} }
vn_add (PHI_RESULT (temp), val, NULL); vn_add (PHI_RESULT (temp), val);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
...@@ -2329,6 +2885,174 @@ try_look_through_load (tree lhs, tree mem_ref, tree stmt, basic_block block) ...@@ -2329,6 +2885,174 @@ try_look_through_load (tree lhs, tree mem_ref, tree stmt, basic_block block)
return false; return false;
} }
/* Return a copy of NODE that is stored in the temporary alloc_pool's.
This is made recursively true, so that the operands are stored in
the pool as well. */
static tree
poolify_tree (tree node)
{
switch (TREE_CODE (node))
{
case INDIRECT_REF:
{
tree temp = pool_alloc (reference_node_pool);
memcpy (temp, node, tree_size (node));
TREE_OPERAND (temp, 0) = poolify_tree (TREE_OPERAND (temp, 0));
return temp;
}
break;
case MODIFY_EXPR:
{
tree temp = pool_alloc (modify_expr_node_pool);
memcpy (temp, node, tree_size (node));
TREE_OPERAND (temp, 0) = poolify_tree (TREE_OPERAND (temp, 0));
TREE_OPERAND (temp, 1) = poolify_tree (TREE_OPERAND (temp, 1));
return temp;
}
break;
case SSA_NAME:
case INTEGER_CST:
case STRING_CST:
case REAL_CST:
case PARM_DECL:
case VAR_DECL:
case RESULT_DECL:
return node;
default:
gcc_unreachable ();
}
}
static tree modify_expr_template;
/* Allocate a MODIFY_EXPR with TYPE, and operands OP1, OP2 in the
alloc pools and return it. */
static tree
poolify_modify_expr (tree type, tree op1, tree op2)
{
if (modify_expr_template == NULL)
modify_expr_template = build2 (MODIFY_EXPR, type, op1, op2);
TREE_OPERAND (modify_expr_template, 0) = op1;
TREE_OPERAND (modify_expr_template, 1) = op2;
TREE_TYPE (modify_expr_template) = type;
return poolify_tree (modify_expr_template);
}
/* For each real store operation of the form
*a = <value> that we see, create a corresponding fake store of the
form storetmp_<version> = *a.
This enables AVAIL computation to mark the results of stores as
available. Without this, you'd need to do some computation to
mark the result of stores as ANTIC and AVAIL at all the right
points.
To save memory, we keep the store
statements pool allocated until we decide whether they are
necessary or not. */
static void
insert_fake_stores (void)
{
basic_block block;
FOR_ALL_BB (block)
{
block_stmt_iterator bsi;
for (bsi = bsi_start (block); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
/* We can't generate SSA names for stores that are complex
or aggregate. We also want to ignore things whose
virtual uses occur in abnormal phis. */
if (TREE_CODE (stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (stmt, 0)) == INDIRECT_REF
&& !AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 0)))
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (stmt, 0))) != COMPLEX_TYPE)
{
ssa_op_iter iter;
def_operand_p defp;
tree lhs = TREE_OPERAND (stmt, 0);
tree rhs = TREE_OPERAND (stmt, 1);
tree new;
bool notokay = false;
FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_VIRTUAL_DEFS)
{
tree defvar = DEF_FROM_PTR (defp);
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (defvar))
{
notokay = true;
break;
}
}
if (notokay)
continue;
if (!storetemp || TREE_TYPE (rhs) != TREE_TYPE (storetemp))
{
storetemp = create_tmp_var (TREE_TYPE (rhs), "storetmp");
get_var_ann (storetemp);
}
new = poolify_modify_expr (TREE_TYPE (stmt), storetemp, lhs);
lhs = make_ssa_name (storetemp, new);
TREE_OPERAND (new, 0) = lhs;
create_ssa_artficial_load_stmt (new, stmt);
NECESSARY (new) = 0;
VEC_safe_push (tree, heap, inserted_exprs, new);
VEC_safe_push (tree, heap, need_creation, new);
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
}
}
}
}
/* Turn the pool allocated fake stores that we created back into real
GC allocated ones if they turned out to be necessary to PRE some
expressions. */
static void
realify_fake_stores (void)
{
unsigned int i;
tree stmt;
for (i = 0; VEC_iterate (tree, need_creation, i, stmt); i++)
{
if (NECESSARY (stmt))
{
block_stmt_iterator bsi;
tree newstmt;
/* Mark the temp variable as referenced */
add_referenced_tmp_var (SSA_NAME_VAR (TREE_OPERAND (stmt, 0)));
/* Put the new statement in GC memory, fix up the annotation
and SSA_NAME_DEF_STMT on it, and then put it in place of
the old statement in the IR stream. */
newstmt = unshare_expr (stmt);
SSA_NAME_DEF_STMT (TREE_OPERAND (newstmt, 0)) = newstmt;
newstmt->common.ann = stmt->common.ann;
bsi = bsi_for_stmt (stmt);
bsi_replace (&bsi, newstmt, true);
}
else
release_defs (stmt);
}
}
/* Compute the AVAIL set for all basic blocks. /* Compute the AVAIL set for all basic blocks.
This function performs value numbering of the statements in each basic This function performs value numbering of the statements in each basic
...@@ -2410,10 +3134,10 @@ compute_avail (void) ...@@ -2410,10 +3134,10 @@ compute_avail (void)
stmt = bsi_stmt (bsi); stmt = bsi_stmt (bsi);
ann = stmt_ann (stmt); ann = stmt_ann (stmt);
/* We are only interested in assignments of the form /* For regular value numbering, we are only interested in
X_i = EXPR, where EXPR represents an "interesting" assignments of the form X_i = EXPR, where EXPR represents
computation, it has no volatile operands and X_i an "interesting" computation, it has no volatile operands
doesn't flow through an abnormal edge. */ and X_i doesn't flow through an abnormal edge. */
if (TREE_CODE (stmt) == MODIFY_EXPR if (TREE_CODE (stmt) == MODIFY_EXPR
&& !ann->has_volatile_ops && !ann->has_volatile_ops
&& TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME
...@@ -2429,17 +3153,11 @@ compute_avail (void) ...@@ -2429,17 +3153,11 @@ compute_avail (void)
continue; continue;
STRIP_USELESS_TYPE_CONVERSION (rhs); STRIP_USELESS_TYPE_CONVERSION (rhs);
if (UNARY_CLASS_P (rhs) if (can_value_number_operation (rhs))
|| BINARY_CLASS_P (rhs) {
|| COMPARISON_CLASS_P (rhs) /* For value numberable operation, create a
|| REFERENCE_CLASS_P (rhs) duplicate expression with the operands replaced
|| (TREE_CODE (rhs) == CALL_EXPR with the value handles of the original RHS. */
&& can_value_number_call (stmt)))
{
/* For binary, unary, and reference expressions,
create a duplicate expression with the operands
replaced with the value handles of the original
RHS. */
tree newt = create_value_expr_from (rhs, block, stmt); tree newt = create_value_expr_from (rhs, block, stmt);
if (newt) if (newt)
{ {
...@@ -2582,6 +3300,9 @@ mark_operand_necessary (tree op) ...@@ -2582,6 +3300,9 @@ mark_operand_necessary (tree op)
gcc_assert (op); gcc_assert (op);
if (TREE_CODE (op) != SSA_NAME)
return NULL;
stmt = SSA_NAME_DEF_STMT (op); stmt = SSA_NAME_DEF_STMT (op);
gcc_assert (stmt); gcc_assert (stmt);
...@@ -2614,14 +3335,12 @@ remove_dead_inserted_code (void) ...@@ -2614,14 +3335,12 @@ remove_dead_inserted_code (void)
while (VEC_length (tree, worklist) > 0) while (VEC_length (tree, worklist) > 0)
{ {
t = VEC_pop (tree, worklist); t = VEC_pop (tree, worklist);
if (TREE_CODE (t) == PHI_NODE)
{
/* PHI nodes are somewhat special in that each PHI alternative has /* PHI nodes are somewhat special in that each PHI alternative has
data and control dependencies. All the statements feeding the data and control dependencies. All the statements feeding the
PHI node's arguments are always necessary. In aggressive mode, PHI node's arguments are always necessary. */
we also consider the control dependent edges leading to the if (TREE_CODE (t) == PHI_NODE)
predecessor block associated with each PHI alternative as {
necessary. */
int k; int k;
VEC_reserve (tree, heap, worklist, PHI_NUM_ARGS (t)); VEC_reserve (tree, heap, worklist, PHI_NUM_ARGS (t));
...@@ -2657,16 +3376,19 @@ remove_dead_inserted_code (void) ...@@ -2657,16 +3376,19 @@ remove_dead_inserted_code (void)
} }
} }
} }
for (i = 0; VEC_iterate (tree, inserted_exprs, i, t); i++) for (i = 0; VEC_iterate (tree, inserted_exprs, i, t); i++)
{ {
if (!NECESSARY (t)) if (!NECESSARY (t))
{ {
block_stmt_iterator bsi; block_stmt_iterator bsi;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "Removing unnecessary insertion:"); fprintf (dump_file, "Removing unnecessary insertion:");
print_generic_stmt (dump_file, t, 0); print_generic_stmt (dump_file, t, 0);
} }
if (TREE_CODE (t) == PHI_NODE) if (TREE_CODE (t) == PHI_NODE)
{ {
remove_phi_node (t, NULL); remove_phi_node (t, NULL);
...@@ -2675,11 +3397,13 @@ remove_dead_inserted_code (void) ...@@ -2675,11 +3397,13 @@ remove_dead_inserted_code (void)
{ {
bsi = bsi_for_stmt (t); bsi = bsi_for_stmt (t);
bsi_remove (&bsi); bsi_remove (&bsi);
release_defs (t);
} }
} }
} }
VEC_free (tree, heap, worklist); VEC_free (tree, heap, worklist);
} }
/* Initialize data structures used by PRE. */ /* Initialize data structures used by PRE. */
static void static void
...@@ -2690,9 +3414,16 @@ init_pre (bool do_fre) ...@@ -2690,9 +3414,16 @@ init_pre (bool do_fre)
in_fre = do_fre; in_fre = do_fre;
inserted_exprs = NULL; inserted_exprs = NULL;
need_creation = NULL;
pretemp = NULL_TREE;
storetemp = NULL_TREE;
mergephitemp = NULL_TREE;
prephitemp = NULL_TREE;
vn_init (); vn_init ();
if (!do_fre) if (!do_fre)
current_loops = loop_optimizer_init (dump_file); current_loops = loop_optimizer_init (dump_file);
connect_infinite_loops_to_exit (); connect_infinite_loops_to_exit ();
memset (&pre_stats, 0, sizeof (pre_stats)); memset (&pre_stats, 0, sizeof (pre_stats));
...@@ -2733,6 +3464,11 @@ init_pre (bool do_fre) ...@@ -2733,6 +3464,11 @@ init_pre (bool do_fre)
tree_code_size (TREE_LIST), 30); tree_code_size (TREE_LIST), 30);
comparison_node_pool = create_alloc_pool ("Comparison tree nodes", comparison_node_pool = create_alloc_pool ("Comparison tree nodes",
tree_code_size (EQ_EXPR), 30); tree_code_size (EQ_EXPR), 30);
modify_expr_node_pool = create_alloc_pool ("MODIFY_EXPR nodes",
tree_code_size (MODIFY_EXPR),
30);
modify_expr_template = NULL;
FOR_ALL_BB (bb) FOR_ALL_BB (bb)
{ {
EXP_GEN (bb) = set_new (true); EXP_GEN (bb) = set_new (true);
...@@ -2754,6 +3490,7 @@ fini_pre (bool do_fre) ...@@ -2754,6 +3490,7 @@ fini_pre (bool do_fre)
unsigned int i; unsigned int i;
VEC_free (tree, heap, inserted_exprs); VEC_free (tree, heap, inserted_exprs);
VEC_free (tree, heap, need_creation);
bitmap_obstack_release (&grand_bitmap_obstack); bitmap_obstack_release (&grand_bitmap_obstack);
free_alloc_pool (value_set_pool); free_alloc_pool (value_set_pool);
free_alloc_pool (bitmap_set_pool); free_alloc_pool (bitmap_set_pool);
...@@ -2764,6 +3501,7 @@ fini_pre (bool do_fre) ...@@ -2764,6 +3501,7 @@ fini_pre (bool do_fre)
free_alloc_pool (list_node_pool); free_alloc_pool (list_node_pool);
free_alloc_pool (expression_node_pool); free_alloc_pool (expression_node_pool);
free_alloc_pool (comparison_node_pool); free_alloc_pool (comparison_node_pool);
free_alloc_pool (modify_expr_node_pool);
htab_delete (phi_translate_table); htab_delete (phi_translate_table);
remove_fake_exit_edges (); remove_fake_exit_edges ();
...@@ -2804,7 +3542,6 @@ fini_pre (bool do_fre) ...@@ -2804,7 +3542,6 @@ fini_pre (bool do_fre)
} }
} }
/* Main entry point to the SSA-PRE pass. DO_FRE is true if the caller /* Main entry point to the SSA-PRE pass. DO_FRE is true if the caller
only wants to do full redundancy elimination. */ only wants to do full redundancy elimination. */
...@@ -2813,6 +3550,9 @@ execute_pre (bool do_fre) ...@@ -2813,6 +3550,9 @@ execute_pre (bool do_fre)
{ {
init_pre (do_fre); init_pre (do_fre);
if (!do_fre)
insert_fake_stores ();
/* Collect and value number expressions computed in each basic block. */ /* Collect and value number expressions computed in each basic block. */
compute_avail (); compute_avail ();
...@@ -2837,8 +3577,11 @@ execute_pre (bool do_fre) ...@@ -2837,8 +3577,11 @@ execute_pre (bool do_fre)
computing ANTIC, either, even though it's plenty fast. */ computing ANTIC, either, even though it's plenty fast. */
if (!do_fre && n_basic_blocks < 4000) if (!do_fre && n_basic_blocks < 4000)
{ {
vuse_names = xcalloc (num_ssa_names, sizeof (bitmap));
compute_rvuse ();
compute_antic (); compute_antic ();
insert (); insert ();
free (vuse_names);
} }
/* Remove all the redundant expressions. */ /* Remove all the redundant expressions. */
...@@ -2854,13 +3597,17 @@ execute_pre (bool do_fre) ...@@ -2854,13 +3597,17 @@ execute_pre (bool do_fre)
} }
bsi_commit_edge_inserts (); bsi_commit_edge_inserts ();
if (!do_fre) if (!do_fre)
{
remove_dead_inserted_code (); remove_dead_inserted_code ();
realify_fake_stores ();
}
fini_pre (do_fre); fini_pre (do_fre);
} }
/* Gate and execute functions for PRE. */ /* Gate and execute functions for PRE. */
static void static void
......
...@@ -48,8 +48,8 @@ typedef struct val_expr_pair_d ...@@ -48,8 +48,8 @@ typedef struct val_expr_pair_d
/* Associated expression. */ /* Associated expression. */
tree e; tree e;
/* for comparing Virtual uses in E. */ /* For comparing virtual uses in E. */
tree stmt; VEC (tree, gc) *vuses;
/* E's hash value. */ /* E's hash value. */
hashval_t hashcode; hashval_t hashcode;
...@@ -77,16 +77,11 @@ make_value_handle (tree type) ...@@ -77,16 +77,11 @@ make_value_handle (tree type)
any). any).
VAL can be used to iterate by passing previous value numbers (it is VAL can be used to iterate by passing previous value numbers (it is
used by iterative_hash_expr). used by iterative_hash_expr). */
STMT is the stmt associated with EXPR for comparing virtual operands. */
hashval_t hashval_t
vn_compute (tree expr, hashval_t val, tree stmt) vn_compute (tree expr, hashval_t val)
{ {
ssa_op_iter iter;
tree vuse;
/* EXPR must not be a statement. We are only interested in value /* EXPR must not be a statement. We are only interested in value
numbering expressions on the RHS of assignments. */ numbering expressions on the RHS of assignments. */
gcc_assert (expr); gcc_assert (expr);
...@@ -94,17 +89,9 @@ vn_compute (tree expr, hashval_t val, tree stmt) ...@@ -94,17 +89,9 @@ vn_compute (tree expr, hashval_t val, tree stmt)
|| expr->common.ann->common.type != STMT_ANN); || expr->common.ann->common.type != STMT_ANN);
val = iterative_hash_expr (expr, val); val = iterative_hash_expr (expr, val);
/* If the expression has virtual uses, incorporate them into the
hash value computed for EXPR. */
if (stmt)
FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, iter, SSA_OP_VUSE)
val = iterative_hash_expr (vuse, val);
return val; return val;
} }
/* Compare two expressions E1 and E2 and return true if they are /* Compare two expressions E1 and E2 and return true if they are
equal. */ equal. */
...@@ -163,15 +150,26 @@ val_expr_pair_hash (const void *p) ...@@ -163,15 +150,26 @@ val_expr_pair_hash (const void *p)
static int static int
val_expr_pair_expr_eq (const void *p1, const void *p2) val_expr_pair_expr_eq (const void *p1, const void *p2)
{ {
bool ret; int i;
tree vuse1;
const val_expr_pair_t ve1 = (val_expr_pair_t) p1; const val_expr_pair_t ve1 = (val_expr_pair_t) p1;
const val_expr_pair_t ve2 = (val_expr_pair_t) p2; const val_expr_pair_t ve2 = (val_expr_pair_t) p2;
if (! expressions_equal_p (ve1->e, ve2->e)) if (! expressions_equal_p (ve1->e, ve2->e))
return false; return false;
ret = compare_ssa_operands_equal (ve1->stmt, ve2->stmt, SSA_OP_VUSE); if (ve1->vuses == ve2->vuses)
return ret; return true;
if (VEC_length (tree, ve1->vuses) != VEC_length (tree, ve2->vuses))
return false;
for (i = 0; VEC_iterate (tree, ve1->vuses, i, vuse1); i++)
{
if (VEC_index (tree, ve2->vuses, i) != vuse1)
return false;
}
return true;
} }
...@@ -190,13 +188,68 @@ set_value_handle (tree e, tree v) ...@@ -190,13 +188,68 @@ set_value_handle (tree e, tree v)
gcc_assert (is_gimple_min_invariant (e)); gcc_assert (is_gimple_min_invariant (e));
} }
/* Copy the virtual uses from STMT into a newly allocated VEC(tree),
and return the VEC(tree). */
static VEC (tree, gc) *
copy_vuses_from_stmt (tree stmt)
{
ssa_op_iter iter;
tree vuse;
VEC (tree, gc) *vuses = NULL;
if (!stmt)
return NULL;
FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, iter, SSA_OP_VUSE)
VEC_safe_push (tree, gc, vuses, vuse);
return vuses;
}
/* Place for shared_vuses_from_stmt to shove vuses. */
static VEC (tree, gc) *shared_lookup_vuses;
/* Copy the virtual uses from STMT into SHARED_LOOKUP_VUSES.
This function will overwrite the current SHARED_LOOKUP_VUSES
variable. */
static VEC (tree, gc) *
shared_vuses_from_stmt (tree stmt)
{
ssa_op_iter iter;
tree vuse;
if (!stmt)
return NULL;
VEC_truncate (tree, shared_lookup_vuses, 0);
FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, iter, SSA_OP_VUSE)
VEC_safe_push (tree, gc, shared_lookup_vuses, vuse);
if (VEC_length (tree, shared_lookup_vuses) > 1)
sort_vuses (shared_lookup_vuses);
return shared_lookup_vuses;
}
/* Insert EXPR into VALUE_TABLE with value VAL, and add expression
EXPR to the value set for value VAL. */
void
vn_add (tree expr, tree val)
{
vn_add_with_vuses (expr, val, NULL);
}
/* Insert EXPR into VALUE_TABLE with value VAL, and add expression /* Insert EXPR into VALUE_TABLE with value VAL, and add expression
EXPR to the value set for value VAL. STMT represents the stmt EXPR to the value set for value VAL. VUSES represents the virtual
associated with EXPR. It is used when computing a hash value for EXPR. */ use operands associated with EXPR. It is used when computing a
hash value for EXPR. */
void void
vn_add (tree expr, tree val, tree stmt) vn_add_with_vuses (tree expr, tree val, VEC (tree, gc) *vuses)
{ {
void **slot; void **slot;
val_expr_pair_t new_pair; val_expr_pair_t new_pair;
...@@ -204,8 +257,8 @@ vn_add (tree expr, tree val, tree stmt) ...@@ -204,8 +257,8 @@ vn_add (tree expr, tree val, tree stmt)
new_pair = XNEW (struct val_expr_pair_d); new_pair = XNEW (struct val_expr_pair_d);
new_pair->e = expr; new_pair->e = expr;
new_pair->v = val; new_pair->v = val;
new_pair->stmt = stmt; new_pair->vuses = vuses;
new_pair->hashcode = vn_compute (expr, 0, stmt); new_pair->hashcode = vn_compute (expr, 0);
slot = htab_find_slot_with_hash (value_table, new_pair, new_pair->hashcode, slot = htab_find_slot_with_hash (value_table, new_pair, new_pair->hashcode,
INSERT); INSERT);
if (*slot) if (*slot)
...@@ -213,6 +266,7 @@ vn_add (tree expr, tree val, tree stmt) ...@@ -213,6 +266,7 @@ vn_add (tree expr, tree val, tree stmt)
*slot = (void *) new_pair; *slot = (void *) new_pair;
set_value_handle (expr, val); set_value_handle (expr, val);
if (TREE_CODE (val) == VALUE_HANDLE)
add_to_value (val, expr); add_to_value (val, expr);
} }
...@@ -225,6 +279,17 @@ vn_add (tree expr, tree val, tree stmt) ...@@ -225,6 +279,17 @@ vn_add (tree expr, tree val, tree stmt)
tree tree
vn_lookup (tree expr, tree stmt) vn_lookup (tree expr, tree stmt)
{ {
return vn_lookup_with_vuses (expr, shared_vuses_from_stmt (stmt));
}
/* Search in VALUE_TABLE for an existing instance of expression EXPR,
and return its value, or NULL if none has been set. VUSES is the
list of virtual use operands associated with EXPR. It is used when
computing the hash value for EXPR. */
tree
vn_lookup_with_vuses (tree expr, VEC (tree, gc) *vuses)
{
void **slot; void **slot;
struct val_expr_pair_d vep = {NULL, NULL, NULL, 0}; struct val_expr_pair_d vep = {NULL, NULL, NULL, 0};
...@@ -233,8 +298,8 @@ vn_lookup (tree expr, tree stmt) ...@@ -233,8 +298,8 @@ vn_lookup (tree expr, tree stmt)
return expr; return expr;
vep.e = expr; vep.e = expr;
vep.stmt = stmt; vep.vuses = vuses;
vep.hashcode = vn_compute (expr, 0, stmt); vep.hashcode = vn_compute (expr, 0);
slot = htab_find_slot_with_hash (value_table, &vep, vep.hashcode, NO_INSERT); slot = htab_find_slot_with_hash (value_table, &vep, vep.hashcode, NO_INSERT);
if (!slot) if (!slot)
return NULL_TREE; return NULL_TREE;
...@@ -243,10 +308,53 @@ vn_lookup (tree expr, tree stmt) ...@@ -243,10 +308,53 @@ vn_lookup (tree expr, tree stmt)
} }
/* A comparison function for use in qsort to compare vuses. Simply
subtracts version numbers. */
static int
vuses_compare (const void *pa, const void *pb)
{
const tree vusea = *((const tree *)pa);
const tree vuseb = *((const tree *)pb);
int sn = SSA_NAME_VERSION (vusea) - SSA_NAME_VERSION (vuseb);
return sn;
}
/* Print out the "Created value <x> for <Y>" statement to the
dump_file.
This is factored because both versions of lookup use it, and it
obscures the real work going on in those functions. */
static void
print_creation_to_file (tree v, tree expr, VEC (tree, gc) *vuses)
{
fprintf (dump_file, "Created value ");
print_generic_expr (dump_file, v, dump_flags);
fprintf (dump_file, " for ");
print_generic_expr (dump_file, expr, dump_flags);
if (vuses && VEC_length (tree, vuses) != 0)
{
size_t i;
tree vuse;
fprintf (dump_file, " vuses: (");
for (i = 0; VEC_iterate (tree, vuses, i, vuse); i++)
{
print_generic_expr (dump_file, vuse, dump_flags);
if (VEC_length (tree, vuses) - 1 != i)
fprintf (dump_file, ",");
}
fprintf (dump_file, ")");
}
fprintf (dump_file, "\n");
}
/* Like vn_lookup, but creates a new value for expression EXPR, if /* Like vn_lookup, but creates a new value for expression EXPR, if
EXPR doesn't already have a value. Return the existing/created EXPR doesn't already have a value. Return the existing/created
value for EXPR. STMT represents the stmt associated with EXPR. It is used value for EXPR. STMT represents the stmt associated with EXPR. It
when computing the hash value for EXPR. */ is used when computing the VUSES for EXPR. */
tree tree
vn_lookup_or_add (tree expr, tree stmt) vn_lookup_or_add (tree expr, tree stmt)
...@@ -254,18 +362,56 @@ vn_lookup_or_add (tree expr, tree stmt) ...@@ -254,18 +362,56 @@ vn_lookup_or_add (tree expr, tree stmt)
tree v = vn_lookup (expr, stmt); tree v = vn_lookup (expr, stmt);
if (v == NULL_TREE) if (v == NULL_TREE)
{ {
VEC(tree,gc) *vuses;
v = make_value_handle (TREE_TYPE (expr)); v = make_value_handle (TREE_TYPE (expr));
vuses = copy_vuses_from_stmt (stmt);
sort_vuses (vuses);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ print_creation_to_file (v, expr, vuses);
fprintf (dump_file, "Created value ");
print_generic_expr (dump_file, v, dump_flags); VALUE_HANDLE_VUSES (v) = vuses;
fprintf (dump_file, " for "); vn_add_with_vuses (expr, v, vuses);
print_generic_expr (dump_file, expr, dump_flags);
fprintf (dump_file, "\n");
} }
vn_add (expr, v, stmt); set_value_handle (expr, v);
return v;
}
/* Sort the VUSE array so that we can do equality comparisons
quicker on two vuse vecs. */
void
sort_vuses (VEC (tree,gc) *vuses)
{
if (VEC_length (tree, vuses) > 1)
qsort (VEC_address (tree, vuses),
VEC_length (tree, vuses),
sizeof (tree),
vuses_compare);
}
/* Like vn_lookup, but creates a new value for expression EXPR, if
EXPR doesn't already have a value. Return the existing/created
value for EXPR. STMT represents the stmt associated with EXPR. It is used
when computing the hash value for EXPR. */
tree
vn_lookup_or_add_with_vuses (tree expr, VEC (tree, gc) *vuses)
{
tree v = vn_lookup_with_vuses (expr, vuses);
if (v == NULL_TREE)
{
v = make_value_handle (TREE_TYPE (expr));
sort_vuses (vuses);
if (dump_file && (dump_flags & TDF_DETAILS))
print_creation_to_file (v, expr, vuses);
VALUE_HANDLE_VUSES (v) = vuses;
vn_add_with_vuses (expr, v, vuses);
} }
set_value_handle (expr, v); set_value_handle (expr, v);
...@@ -274,6 +420,7 @@ vn_lookup_or_add (tree expr, tree stmt) ...@@ -274,6 +420,7 @@ vn_lookup_or_add (tree expr, tree stmt)
} }
/* Get the value handle of EXPR. This is the only correct way to get /* Get the value handle of EXPR. This is the only correct way to get
the value handle for a "thing". If EXPR does not have a value the value handle for a "thing". If EXPR does not have a value
handle associated, it returns NULL_TREE. handle associated, it returns NULL_TREE.
...@@ -306,6 +453,7 @@ vn_init (void) ...@@ -306,6 +453,7 @@ vn_init (void)
{ {
value_table = htab_create (511, val_expr_pair_hash, value_table = htab_create (511, val_expr_pair_hash,
val_expr_pair_expr_eq, free); val_expr_pair_expr_eq, free);
shared_lookup_vuses = NULL;
} }
...@@ -315,5 +463,6 @@ void ...@@ -315,5 +463,6 @@ void
vn_delete (void) vn_delete (void)
{ {
htab_delete (value_table); htab_delete (value_table);
VEC_free (tree, gc, shared_lookup_vuses);
value_table = NULL; value_table = NULL;
} }
...@@ -2814,6 +2814,9 @@ struct tree_statement_list ...@@ -2814,6 +2814,9 @@ struct tree_statement_list
#define VALUE_HANDLE_EXPR_SET(NODE) \ #define VALUE_HANDLE_EXPR_SET(NODE) \
(VALUE_HANDLE_CHECK (NODE)->value_handle.expr_set) (VALUE_HANDLE_CHECK (NODE)->value_handle.expr_set)
#define VALUE_HANDLE_VUSES(NODE) \
(VALUE_HANDLE_CHECK (NODE)->value_handle.vuses)
/* Defined and used in tree-ssa-pre.c. */ /* Defined and used in tree-ssa-pre.c. */
struct value_set; struct value_set;
...@@ -2828,6 +2831,9 @@ struct tree_value_handle GTY(()) ...@@ -2828,6 +2831,9 @@ struct tree_value_handle GTY(())
conveniently dense form starting at 0, so that we can make conveniently dense form starting at 0, so that we can make
bitmaps of value handles. */ bitmaps of value handles. */
unsigned int id; unsigned int id;
/* Set of virtual uses represented by this handle. */
VEC (tree, gc) *vuses;
}; };
/* Define the overall contents of a tree node. /* Define the overall contents of a tree node.
......
Markdown is supported
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