Fix PR tree-optimization/23455 Fix PR tree-optimization/35286 Fix PR tree-optimization/35287
2008-07-05 Daniel Berlin <dberlin@dberlin.org> Fix PR tree-optimization/23455 Fix PR tree-optimization/35286 Fix PR tree-optimization/35287 * Makefile.in (OBJS-common): Remove tree-vn.o. tree-vn.o: Remove. * dbgcnt.def: Add treepre_insert debug counter. * gcc/tree-flow.h (add_to_value): Updated for other changes. (debug_value_expressions): Ditto. (print_value_expressions): Ditto. * tree-pretty-print.c (dump_generic_node): Updated for VALUE_HANDLE removal. * tree-ssa-dom.c (record_equality): Ditto. (cprop_operand): Ditto. (lookup_avail_expr): Ditto. * tree-ssa-threadedge.c (record_temporary_equivalences_from_stmts_at_dest): Ditto. (simplify_control_stmt_condition): Ditto. * tree.c (tree_code_size): Ditto. (tree_node_structure): Ditto. (iterative_hash_expr): Ditto. * tree.def: Ditto. * tree.h (VALUE_HANDLE_ID): Ditto. (VALUE_HANDLE_EXPR_SET): Ditto. (struct tree_value_handle): Ditto. (union tree_node): Ditto. * treestruct.def: Ditto. * tree-vn.c: Removed. * tree-ssa-pre.c: Rewritten entirely. * tree-ssa-sccvn.c (constant_to_value_id): New hashtable. (constant_value_ids): Ditto. (vn_nary_op_t): Moved to header. (vn_phi_t): Ditto. (vn_reference_op_t): Ditto (vn_reference_t): Ditto. (next_value_id): New variable. (VN_INFO): Add an assert. (vn_constant_eq): New function. (vn_constant_hash): Ditto. (get_or_alloc_constant_value_id): Ditto. (value_id_constant_p): Ditto. (vn_reference_compute_hash): De-staticify. (copy_reference_ops_from_ref): Don't use get_callee_fndecl. Disable some code with a FIXME. Remove VALUE_HANDLE use. (valueize_refs): Update opcode if it changes from ssa name to constant. (vn_reference_lookup_1): Add new argument. (vn_reference_lookup): Ditto. (vn_reference_lookup_pieces): New function. (vn_reference_insert): Add return type. Modify to deal with value ids. (vn_reference_insert_pieces): New function. (vn_nary_op_compute_hash): De-staticify. (vn_nary_op_eq): Ditto. (vn_nary_op_lookup_pieces): New function. (vn_nary_op_lookup): Add new argument. (vn_nary_op_insert_pieces): New function. (vn_nary_op_insert): Add return type. Modify to deal with value ids. (vn_phi_insert): Ditto. (visit_unary_op): Update for callee changes. (visit_binary_op): Ditto. (visit_reference_op_load): Ditto. (visit_reference_op_store): Ditto. (init_scc_vn): Init next_value_id, constant_to_value_id and constant_value_ids. (free_scc_vn): Free them. (set_hashtable_value_ids): New function. (run_scc_vn): Use it. (get_max_value_id): New function. (get_next_value_id): Ditto. (expressions_equal_p): Moved from tree-vn.c (sort_vuses): Ditto. (sort_vuses_heap): Ditto. * tree-ssa-sccvn.h: Structures moved from tree-ssa-sccvn.c (noted above). * tree.c (iterative_hash_hashval_t): Made non-static * tree.h (iterative_hash_hashval_t): Declare it. From-SVN: r137631
This commit is contained in:
parent
771578a0df
commit
c91457541d
@ -1,3 +1,84 @@
|
||||
2008-07-05 Daniel Berlin <dberlin@dberlin.org>
|
||||
|
||||
Fix PR tree-optimization/23455
|
||||
Fix PR tree-optimization/35286
|
||||
Fix PR tree-optimization/35287
|
||||
* Makefile.in (OBJS-common): Remove tree-vn.o.
|
||||
tree-vn.o: Remove.
|
||||
* dbgcnt.def: Add treepre_insert debug counter.
|
||||
* gcc/tree-flow.h (add_to_value): Updated for other changes.
|
||||
(debug_value_expressions): Ditto.
|
||||
(print_value_expressions): Ditto.
|
||||
* tree-pretty-print.c (dump_generic_node): Updated for
|
||||
VALUE_HANDLE removal.
|
||||
* tree-ssa-dom.c (record_equality): Ditto.
|
||||
(cprop_operand): Ditto.
|
||||
(lookup_avail_expr): Ditto.
|
||||
* tree-ssa-threadedge.c
|
||||
(record_temporary_equivalences_from_stmts_at_dest): Ditto.
|
||||
(simplify_control_stmt_condition): Ditto.
|
||||
* tree.c (tree_code_size): Ditto.
|
||||
(tree_node_structure): Ditto.
|
||||
(iterative_hash_expr): Ditto.
|
||||
* tree.def: Ditto.
|
||||
* tree.h (VALUE_HANDLE_ID): Ditto.
|
||||
(VALUE_HANDLE_EXPR_SET): Ditto.
|
||||
(struct tree_value_handle): Ditto.
|
||||
(union tree_node): Ditto.
|
||||
* treestruct.def: Ditto.
|
||||
* tree-vn.c: Removed.
|
||||
* tree-ssa-pre.c: Rewritten entirely.
|
||||
* tree-ssa-sccvn.c (constant_to_value_id): New hashtable.
|
||||
(constant_value_ids): Ditto.
|
||||
(vn_nary_op_t): Moved to header.
|
||||
(vn_phi_t): Ditto.
|
||||
(vn_reference_op_t): Ditto
|
||||
(vn_reference_t): Ditto.
|
||||
(next_value_id): New variable.
|
||||
(VN_INFO): Add an assert.
|
||||
(vn_constant_eq): New function.
|
||||
(vn_constant_hash): Ditto.
|
||||
(get_or_alloc_constant_value_id): Ditto.
|
||||
(value_id_constant_p): Ditto.
|
||||
(vn_reference_compute_hash): De-staticify.
|
||||
(copy_reference_ops_from_ref): Don't use get_callee_fndecl.
|
||||
Disable some code with a FIXME.
|
||||
Remove VALUE_HANDLE use.
|
||||
(valueize_refs): Update opcode if it changes from ssa name to
|
||||
constant.
|
||||
(vn_reference_lookup_1): Add new argument.
|
||||
(vn_reference_lookup): Ditto.
|
||||
(vn_reference_lookup_pieces): New function.
|
||||
(vn_reference_insert): Add return type. Modify to deal with value
|
||||
ids.
|
||||
(vn_reference_insert_pieces): New function.
|
||||
(vn_nary_op_compute_hash): De-staticify.
|
||||
(vn_nary_op_eq): Ditto.
|
||||
(vn_nary_op_lookup_pieces): New function.
|
||||
(vn_nary_op_lookup): Add new argument.
|
||||
(vn_nary_op_insert_pieces): New function.
|
||||
(vn_nary_op_insert): Add return type. Modify to deal with value
|
||||
ids.
|
||||
(vn_phi_insert): Ditto.
|
||||
(visit_unary_op): Update for callee changes.
|
||||
(visit_binary_op): Ditto.
|
||||
(visit_reference_op_load): Ditto.
|
||||
(visit_reference_op_store): Ditto.
|
||||
(init_scc_vn): Init next_value_id, constant_to_value_id and
|
||||
constant_value_ids.
|
||||
(free_scc_vn): Free them.
|
||||
(set_hashtable_value_ids): New function.
|
||||
(run_scc_vn): Use it.
|
||||
(get_max_value_id): New function.
|
||||
(get_next_value_id): Ditto.
|
||||
(expressions_equal_p): Moved from tree-vn.c
|
||||
(sort_vuses): Ditto.
|
||||
(sort_vuses_heap): Ditto.
|
||||
* tree-ssa-sccvn.h: Structures moved from tree-ssa-sccvn.c (noted
|
||||
above).
|
||||
* tree.c (iterative_hash_hashval_t): Made non-static
|
||||
* tree.h (iterative_hash_hashval_t): Declare it.
|
||||
|
||||
2008-07-08 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* ipa-cp.c (ipcp_init_cloned_node): Call ipa_check_create_node_params
|
||||
|
@ -1223,7 +1223,6 @@ OBJS-common = \
|
||||
tree-vect-patterns.o \
|
||||
tree-vect-transform.o \
|
||||
tree-vectorizer.o \
|
||||
tree-vn.o \
|
||||
tree-vrp.o \
|
||||
tree.o \
|
||||
value-prof.o \
|
||||
@ -2109,16 +2108,14 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \
|
||||
$(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
|
||||
$(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(CFGLOOP_H) \
|
||||
alloc-pool.h $(BASIC_BLOCK_H) bitmap.h $(HASHTAB_H) $(TREE_GIMPLE_H) \
|
||||
$(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H)
|
||||
$(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H) \
|
||||
$(DBGCNT_H)
|
||||
tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
|
||||
$(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
|
||||
$(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(CFGLOOP_H) \
|
||||
alloc-pool.h $(BASIC_BLOCK_H) bitmap.h $(HASHTAB_H) $(TREE_GIMPLE_H) \
|
||||
$(TREE_INLINE_H) tree-iterator.h tree-ssa-propagate.h tree-ssa-sccvn.h \
|
||||
$(PARAMS_H)
|
||||
tree-vn.o : tree-vn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \
|
||||
$(TREE_H) $(TREE_FLOW_H) $(HASHTAB_H) langhooks.h tree-pass.h \
|
||||
$(TREE_DUMP_H) $(DIAGNOSTIC_H) tree-ssa-sccvn.h
|
||||
tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
|
||||
$(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(GGC_H) \
|
||||
$(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \
|
||||
|
@ -166,6 +166,7 @@ DEBUG_COUNTER (jump_bypass)
|
||||
DEBUG_COUNTER (local_alloc_for_sched)
|
||||
DEBUG_COUNTER (postreload_cse)
|
||||
DEBUG_COUNTER (pre_insn)
|
||||
DEBUG_COUNTER (treepre_insert)
|
||||
DEBUG_COUNTER (sched2_func)
|
||||
DEBUG_COUNTER (sched_block)
|
||||
DEBUG_COUNTER (sched_func)
|
||||
@ -174,4 +175,3 @@ DEBUG_COUNTER (sched_region)
|
||||
DEBUG_COUNTER (sms_sched_loop)
|
||||
DEBUG_COUNTER (split_for_sched2)
|
||||
DEBUG_COUNTER (tail_call)
|
||||
|
||||
|
43
gcc/testsuite/gcc.c-torture/compile/20080704-1.c
Normal file
43
gcc/testsuite/gcc.c-torture/compile/20080704-1.c
Normal file
@ -0,0 +1,43 @@
|
||||
/* This code used to crash fold_convert due to PRE
|
||||
wanting to fold_convert from a REA_TYPE to an INTEGER_TYPE. */
|
||||
typedef unsigned int uint32_t;
|
||||
union double_union
|
||||
{
|
||||
double d;
|
||||
uint32_t i[2];
|
||||
};
|
||||
struct _Jv_reent
|
||||
{
|
||||
int _errno;
|
||||
};
|
||||
_Jv_strtod_r (struct _Jv_reent *ptr, char **se)
|
||||
{
|
||||
int bb2, sign;
|
||||
double aadj, aadj1, adj;
|
||||
unsigned long y, z;
|
||||
union double_union rv, *bs = ((void *) 0), *delta = ((void *) 0);
|
||||
{
|
||||
ovfl:ptr->_errno = 34;
|
||||
{
|
||||
(((uint32_t) 0xfffffL) | ((uint32_t) 0x100000L) * (1024 + 1023 - 1));
|
||||
}
|
||||
if ((aadj = _Jv_ratio (delta, bs)) <= 2.)
|
||||
{
|
||||
{
|
||||
if (aadj < 2. / 2)
|
||||
aadj = 1. / 2;
|
||||
aadj1 = -aadj;
|
||||
}
|
||||
}
|
||||
{
|
||||
(rv.i[1]) -= 53 * ((uint32_t) 0x100000L);
|
||||
adj = aadj1 * _Jv_ulp (rv.d);
|
||||
rv.d += adj;
|
||||
if (((rv.i[1]) & ((uint32_t) 0x7ff00000L)) >=
|
||||
((uint32_t) 0x100000L) * (1024 + 1023 - 53))
|
||||
{
|
||||
goto ovfl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ int foo(int argc)
|
||||
return d + e;
|
||||
}
|
||||
|
||||
/* PRE of globals doesn't work. */
|
||||
/* We will move the load of a out of the loop. */
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
||||
|
23
gcc/testsuite/gcc.dg/tree-ssa/pr23455.c
Normal file
23
gcc/testsuite/gcc.dg/tree-ssa/pr23455.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
|
||||
unsigned long outcnt;
|
||||
extern void flush_outbuf(void);
|
||||
|
||||
void
|
||||
bi_windup(unsigned int *outbuf, unsigned int bi_buf)
|
||||
{
|
||||
unsigned long t1 = outcnt;
|
||||
outbuf[t1] = bi_buf;
|
||||
|
||||
unsigned long t2 = outcnt;
|
||||
if (t2 == 16384)
|
||||
flush_outbuf();
|
||||
|
||||
unsigned long t3 = outcnt;
|
||||
outbuf[t3] = bi_buf;
|
||||
}
|
||||
/* We should eliminate one load of outcnt, which will in turn let us eliminate
|
||||
one multiply of outcnt which will in turn let us eliminate
|
||||
one add involving outcnt and outbuf. */
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 3" 1 "pre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
23
gcc/testsuite/gcc.dg/tree-ssa/pr35286.c
Normal file
23
gcc/testsuite/gcc.dg/tree-ssa/pr35286.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
|
||||
int g2;
|
||||
struct A {
|
||||
int a; int b;
|
||||
}g1;
|
||||
int foo(int a, int b)
|
||||
{
|
||||
if (a > 0)
|
||||
{
|
||||
g1.a = a+ b;
|
||||
}
|
||||
else
|
||||
g1.a = b;
|
||||
|
||||
g2 = a+b;
|
||||
|
||||
return g1.a;
|
||||
}
|
||||
/* We will eliminate the g1.a from the return statement as fully redundant,
|
||||
and remove one calculation of a + b. */
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
15
gcc/testsuite/gcc.dg/tree-ssa/pr35287.c
Normal file
15
gcc/testsuite/gcc.dg/tree-ssa/pr35287.c
Normal file
@ -0,0 +1,15 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
|
||||
int *gp;
|
||||
int foo(int p)
|
||||
{
|
||||
int t = 0;
|
||||
if (p)
|
||||
t = *gp + 1;
|
||||
|
||||
return (*gp + t);
|
||||
}
|
||||
|
||||
/* We will eliminate one load of gp and one indirect load of *gp. */
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
@ -1124,9 +1124,10 @@ extern bool remove_stmt_from_eh_region (tree);
|
||||
extern bool maybe_clean_or_replace_eh_stmt (tree, tree);
|
||||
|
||||
/* In tree-ssa-pre.c */
|
||||
void add_to_value (tree, tree);
|
||||
void debug_value_expressions (tree);
|
||||
void print_value_expressions (FILE *, tree);
|
||||
struct pre_expr_d;
|
||||
void add_to_value (unsigned int, struct pre_expr_d *);
|
||||
void debug_value_expressions (unsigned int);
|
||||
void print_value_expressions (FILE *, unsigned int);
|
||||
|
||||
|
||||
/* In tree-vn.c */
|
||||
|
@ -952,16 +952,12 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
|
||||
pp_character (buffer, ')');
|
||||
pp_string (buffer, str);
|
||||
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
|
||||
|
||||
if (TREE_CODE (op0) != VALUE_HANDLE)
|
||||
op0 = component_ref_field_offset (node);
|
||||
if (op0 && TREE_CODE (op0) != INTEGER_CST)
|
||||
{
|
||||
op0 = component_ref_field_offset (node);
|
||||
if (op0 && TREE_CODE (op0) != INTEGER_CST)
|
||||
{
|
||||
pp_string (buffer, "{off: ");
|
||||
pp_string (buffer, "{off: ");
|
||||
dump_generic_node (buffer, op0, spc, flags, false);
|
||||
pp_character (buffer, '}');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1789,10 +1785,6 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
|
||||
pp_string (buffer, ">");
|
||||
break;
|
||||
|
||||
case VALUE_HANDLE:
|
||||
pp_printf (buffer, "VH.%d", VALUE_HANDLE_ID (node));
|
||||
break;
|
||||
|
||||
case ASSERT_EXPR:
|
||||
pp_string (buffer, "ASSERT_EXPR <");
|
||||
dump_generic_node (buffer, ASSERT_EXPR_VAR (node), spc, flags, false);
|
||||
|
@ -1163,7 +1163,7 @@ record_equality (tree x, tree y)
|
||||
prev_x = x, x = y, y = prev_x, prev_x = prev_y;
|
||||
else if (prev_x && is_gimple_min_invariant (prev_x))
|
||||
x = y, y = prev_x, prev_x = prev_y;
|
||||
else if (prev_y && TREE_CODE (prev_y) != VALUE_HANDLE)
|
||||
else if (prev_y)
|
||||
y = prev_y;
|
||||
|
||||
/* After the swapping, we must have one SSA_NAME. */
|
||||
@ -1629,7 +1629,7 @@ cprop_operand (tree stmt, use_operand_p op_p)
|
||||
copy of some other variable, use the value or copy stored in
|
||||
CONST_AND_COPIES. */
|
||||
val = SSA_NAME_VALUE (op);
|
||||
if (val && val != op && TREE_CODE (val) != VALUE_HANDLE)
|
||||
if (val && val != op)
|
||||
{
|
||||
tree op_type, val_type;
|
||||
|
||||
@ -1969,7 +1969,7 @@ lookup_avail_expr (tree stmt, bool insert)
|
||||
if (TREE_CODE (lhs) == SSA_NAME)
|
||||
{
|
||||
temp = SSA_NAME_VALUE (lhs);
|
||||
if (temp && TREE_CODE (temp) != VALUE_HANDLE)
|
||||
if (temp)
|
||||
lhs = temp;
|
||||
}
|
||||
|
||||
|
3025
gcc/tree-ssa-pre.c
3025
gcc/tree-ssa-pre.c
File diff suppressed because it is too large
Load Diff
@ -115,72 +115,9 @@ typedef struct vn_tables_s
|
||||
alloc_pool references_pool;
|
||||
} *vn_tables_t;
|
||||
|
||||
/* Nary operations in the hashtable consist of length operands, an
|
||||
opcode, and a type. Result is the value number of the operation,
|
||||
and hashcode is stored to avoid having to calculate it
|
||||
repeatedly. */
|
||||
static htab_t constant_to_value_id;
|
||||
static bitmap constant_value_ids;
|
||||
|
||||
typedef struct vn_nary_op_s
|
||||
{
|
||||
ENUM_BITFIELD(tree_code) opcode : 16;
|
||||
unsigned length : 16;
|
||||
hashval_t hashcode;
|
||||
tree result;
|
||||
tree type;
|
||||
tree op[4];
|
||||
} *vn_nary_op_t;
|
||||
typedef const struct vn_nary_op_s *const_vn_nary_op_t;
|
||||
|
||||
/* Phi nodes in the hashtable consist of their non-VN_TOP phi
|
||||
arguments, and the basic block the phi is in. Result is the value
|
||||
number of the operation, and hashcode is stored to avoid having to
|
||||
calculate it repeatedly. Phi nodes not in the same block are never
|
||||
considered equivalent. */
|
||||
|
||||
typedef struct vn_phi_s
|
||||
{
|
||||
VEC (tree, heap) *phiargs;
|
||||
basic_block block;
|
||||
hashval_t hashcode;
|
||||
tree result;
|
||||
} *vn_phi_t;
|
||||
typedef const struct vn_phi_s *const_vn_phi_t;
|
||||
|
||||
/* Reference operands only exist in reference operations structures.
|
||||
They consist of an opcode, type, and some number of operands. For
|
||||
a given opcode, some, all, or none of the operands may be used.
|
||||
The operands are there to store the information that makes up the
|
||||
portion of the addressing calculation that opcode performs. */
|
||||
|
||||
typedef struct vn_reference_op_struct
|
||||
{
|
||||
enum tree_code opcode;
|
||||
tree type;
|
||||
tree op0;
|
||||
tree op1;
|
||||
} vn_reference_op_s;
|
||||
typedef vn_reference_op_s *vn_reference_op_t;
|
||||
typedef const vn_reference_op_s *const_vn_reference_op_t;
|
||||
|
||||
DEF_VEC_O(vn_reference_op_s);
|
||||
DEF_VEC_ALLOC_O(vn_reference_op_s, heap);
|
||||
|
||||
/* A reference operation in the hashtable is representation as a
|
||||
collection of vuses, representing the memory state at the time of
|
||||
the operation, and a collection of operands that make up the
|
||||
addressing calculation. If two vn_reference_t's have the same set
|
||||
of operands, they access the same memory location. We also store
|
||||
the resulting value number, and the hashcode. The vuses are
|
||||
always stored in order sorted by ssa name version. */
|
||||
|
||||
typedef struct vn_reference_s
|
||||
{
|
||||
VEC (tree, gc) *vuses;
|
||||
VEC (vn_reference_op_s, heap) *operands;
|
||||
hashval_t hashcode;
|
||||
tree result;
|
||||
} *vn_reference_t;
|
||||
typedef const struct vn_reference_s *const_vn_reference_t;
|
||||
|
||||
/* Valid hashtables storing information we have proven to be
|
||||
correct. */
|
||||
@ -215,6 +152,10 @@ static int *rpo_numbers;
|
||||
|
||||
tree VN_TOP;
|
||||
|
||||
/* Unique counter for our value ids. */
|
||||
|
||||
static unsigned int next_value_id;
|
||||
|
||||
/* Next DFS number and the stack for strongly connected component
|
||||
detection. */
|
||||
|
||||
@ -239,8 +180,10 @@ static struct obstack vn_ssa_aux_obstack;
|
||||
vn_ssa_aux_t
|
||||
VN_INFO (tree name)
|
||||
{
|
||||
return VEC_index (vn_ssa_aux_t, vn_ssa_aux_table,
|
||||
SSA_NAME_VERSION (name));
|
||||
vn_ssa_aux_t res = VEC_index (vn_ssa_aux_t, vn_ssa_aux_table,
|
||||
SSA_NAME_VERSION (name));
|
||||
gcc_assert (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Set the value numbering info for a given SSA name to a given
|
||||
@ -290,6 +233,58 @@ free_reference (void *vp)
|
||||
VEC_free (vn_reference_op_s, heap, vr->operands);
|
||||
}
|
||||
|
||||
/* Hash table equality function for vn_constant_t. */
|
||||
|
||||
static int
|
||||
vn_constant_eq (const void *p1, const void *p2)
|
||||
{
|
||||
const struct vn_constant_s *vc1 = (const struct vn_constant_s *) p1;
|
||||
const struct vn_constant_s *vc2 = (const struct vn_constant_s *) p2;
|
||||
|
||||
return expressions_equal_p (vc1->constant, vc2->constant);
|
||||
}
|
||||
|
||||
/* Hash table hash function for vn_constant_t. */
|
||||
|
||||
static hashval_t
|
||||
vn_constant_hash (const void *p1)
|
||||
{
|
||||
const struct vn_constant_s *vc1 = (const struct vn_constant_s *) p1;
|
||||
return vc1->hashcode;
|
||||
}
|
||||
|
||||
/* Lookup a value id for CONSTANT, and if it does not exist, create a
|
||||
new one and return it. If it does exist, return it. */
|
||||
|
||||
unsigned int
|
||||
get_or_alloc_constant_value_id (tree constant)
|
||||
{
|
||||
void **slot;
|
||||
vn_constant_t vc = XNEW (struct vn_constant_s);
|
||||
|
||||
vc->hashcode = iterative_hash_expr (constant, 0);
|
||||
vc->constant = constant;
|
||||
slot = htab_find_slot_with_hash (constant_to_value_id, vc,
|
||||
vc->hashcode, INSERT);
|
||||
if (*slot)
|
||||
{
|
||||
free (vc);
|
||||
return ((vn_constant_t)*slot)->value_id;
|
||||
}
|
||||
vc->value_id = get_next_value_id ();
|
||||
*slot = vc;
|
||||
bitmap_set_bit (constant_value_ids, vc->value_id);
|
||||
return vc->value_id;
|
||||
}
|
||||
|
||||
/* Return true if V is a value id for a constant. */
|
||||
|
||||
bool
|
||||
value_id_constant_p (unsigned int v)
|
||||
{
|
||||
return bitmap_bit_p (constant_value_ids, v);
|
||||
}
|
||||
|
||||
/* Compare two reference operands P1 and P2 for equality. Return true if
|
||||
they are equal, and false otherwise. */
|
||||
|
||||
@ -301,7 +296,8 @@ vn_reference_op_eq (const void *p1, const void *p2)
|
||||
return vro1->opcode == vro2->opcode
|
||||
&& vro1->type == vro2->type
|
||||
&& expressions_equal_p (vro1->op0, vro2->op0)
|
||||
&& expressions_equal_p (vro1->op1, vro2->op1);
|
||||
&& expressions_equal_p (vro1->op1, vro2->op1)
|
||||
&& expressions_equal_p (vro1->op2, vro2->op2);
|
||||
}
|
||||
|
||||
/* Compute the hash for a reference operand VRO1. */
|
||||
@ -324,7 +320,7 @@ vn_reference_hash (const void *p1)
|
||||
|
||||
/* Compute a hash for the reference operation VR1 and return it. */
|
||||
|
||||
static inline hashval_t
|
||||
hashval_t
|
||||
vn_reference_compute_hash (const vn_reference_t vr1)
|
||||
{
|
||||
hashval_t result = 0;
|
||||
@ -343,7 +339,7 @@ vn_reference_compute_hash (const vn_reference_t vr1)
|
||||
/* Return true if reference operations P1 and P2 are equivalent. This
|
||||
means they have the same set of operands and vuses. */
|
||||
|
||||
static int
|
||||
int
|
||||
vn_reference_eq (const void *p1, const void *p2)
|
||||
{
|
||||
tree v;
|
||||
@ -484,10 +480,18 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
|
||||
temp.type = TREE_TYPE (ref);
|
||||
temp.opcode = CALL_EXPR;
|
||||
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
|
||||
|
||||
/* We make no attempt to simplify the called function because
|
||||
the typical &FUNCTION_DECL form is also used in function pointer
|
||||
cases that become constant. If we simplify the original to
|
||||
FUNCTION_DECL but not the function pointer case (which can
|
||||
happen because we have no fold functions that operate on
|
||||
vn_reference_t), we will claim they are not equivalent.
|
||||
|
||||
callfn = get_callee_fndecl (ref);
|
||||
if (!callfn)
|
||||
callfn = CALL_EXPR_FN (ref);
|
||||
An example of this behavior can be see if CALL_EXPR_FN below is
|
||||
replaced with get_callee_fndecl and gcc.dg/tree-ssa/ssa-pre-13.c
|
||||
is compiled. */
|
||||
callfn = CALL_EXPR_FN (ref);
|
||||
temp.type = TREE_TYPE (callfn);
|
||||
temp.opcode = TREE_CODE (callfn);
|
||||
temp.op0 = callfn;
|
||||
@ -554,6 +558,7 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
|
||||
a matching type is not necessary and a mismatching type
|
||||
is always a spurious difference. */
|
||||
temp.type = NULL_TREE;
|
||||
#if FIXME
|
||||
/* If this is a reference to a union member, record the union
|
||||
member size as operand. Do so only if we are doing
|
||||
expression insertion (during FRE), as PRE currently gets
|
||||
@ -564,14 +569,17 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
|
||||
&& integer_zerop (DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1))))
|
||||
temp.op0 = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)));
|
||||
else
|
||||
#endif
|
||||
/* Record field as operand. */
|
||||
temp.op0 = TREE_OPERAND (ref, 1);
|
||||
temp.op1 = TREE_OPERAND (ref, 2);
|
||||
break;
|
||||
case ARRAY_RANGE_REF:
|
||||
case ARRAY_REF:
|
||||
/* Record index as operand. */
|
||||
temp.op0 = TREE_OPERAND (ref, 1);
|
||||
temp.op1 = TREE_OPERAND (ref, 3);
|
||||
temp.op1 = TREE_OPERAND (ref, 2);
|
||||
temp.op2 = TREE_OPERAND (ref, 3);
|
||||
break;
|
||||
case STRING_CST:
|
||||
case INTEGER_CST:
|
||||
@ -579,7 +587,6 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
|
||||
case VECTOR_CST:
|
||||
case REAL_CST:
|
||||
case CONSTRUCTOR:
|
||||
case VALUE_HANDLE:
|
||||
case VAR_DECL:
|
||||
case PARM_DECL:
|
||||
case CONST_DECL:
|
||||
@ -653,7 +660,16 @@ valueize_refs (VEC (vn_reference_op_s, heap) *orig)
|
||||
{
|
||||
if (vro->opcode == SSA_NAME
|
||||
|| (vro->op0 && TREE_CODE (vro->op0) == SSA_NAME))
|
||||
vro->op0 = SSA_VAL (vro->op0);
|
||||
{
|
||||
vro->op0 = SSA_VAL (vro->op0);
|
||||
/* If it transforms from an SSA_NAME to a constant, update
|
||||
the opcode. */
|
||||
if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME)
|
||||
vro->opcode = TREE_CODE (vro->op0);
|
||||
}
|
||||
/* TODO: Do we want to valueize op2 and op1 of
|
||||
ARRAY_REF/COMPONENT_REF for Ada */
|
||||
|
||||
}
|
||||
|
||||
return orig;
|
||||
@ -733,10 +749,11 @@ cont:
|
||||
|
||||
/* Lookup a SCCVN reference operation VR in the current hash table.
|
||||
Returns the resulting value number if it exists in the hash table,
|
||||
NULL_TREE otherwise. */
|
||||
NULL_TREE otherwise. VNRESULT will be filled in with the actual
|
||||
vn_reference_t stored in the hashtable if something is found. */
|
||||
|
||||
static tree
|
||||
vn_reference_lookup_1 (vn_reference_t vr)
|
||||
vn_reference_lookup_1 (vn_reference_t vr, vn_reference_t *vnresult)
|
||||
{
|
||||
void **slot;
|
||||
hashval_t hash;
|
||||
@ -748,25 +765,58 @@ vn_reference_lookup_1 (vn_reference_t vr)
|
||||
slot = htab_find_slot_with_hash (valid_info->references, vr,
|
||||
hash, NO_INSERT);
|
||||
if (slot)
|
||||
return ((vn_reference_t)*slot)->result;
|
||||
|
||||
{
|
||||
if (vnresult)
|
||||
*vnresult = (vn_reference_t)*slot;
|
||||
return ((vn_reference_t)*slot)->result;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Lookup OP in the current hash table, and return the resulting
|
||||
value number if it exists in the hash table. Return NULL_TREE if
|
||||
it does not exist in the hash table. */
|
||||
|
||||
/* Lookup a reference operation by it's parts, in the current hash table.
|
||||
Returns the resulting value number if it exists in the hash table,
|
||||
NULL_TREE otherwise. VNRESULT will be filled in with the actual
|
||||
vn_reference_t stored in the hashtable if something is found. */
|
||||
|
||||
tree
|
||||
vn_reference_lookup (tree op, VEC (tree, gc) *vuses, bool maywalk)
|
||||
vn_reference_lookup_pieces (VEC (tree, gc) *vuses,
|
||||
VEC (vn_reference_op_s, heap) *operands,
|
||||
vn_reference_t *vnresult)
|
||||
{
|
||||
struct vn_reference_s vr1;
|
||||
tree result;
|
||||
if (vnresult)
|
||||
*vnresult = NULL;
|
||||
|
||||
vr1.vuses = valueize_vuses (vuses);
|
||||
vr1.operands = valueize_refs (operands);
|
||||
vr1.hashcode = vn_reference_compute_hash (&vr1);
|
||||
result = vn_reference_lookup_1 (&vr1, vnresult);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Lookup OP in the current hash table, and return the resulting value
|
||||
number if it exists in the hash table. Return NULL_TREE if it does
|
||||
not exist in the hash table or if the result field of the structure
|
||||
was NULL.. VNRESULT will be filled in with the vn_reference_t
|
||||
stored in the hashtable if one exists. */
|
||||
|
||||
tree
|
||||
vn_reference_lookup (tree op, VEC (tree, gc) *vuses, bool maywalk,
|
||||
vn_reference_t *vnresult)
|
||||
{
|
||||
struct vn_reference_s vr1;
|
||||
tree result, def_stmt;
|
||||
if (vnresult)
|
||||
*vnresult = NULL;
|
||||
|
||||
vr1.vuses = valueize_vuses (vuses);
|
||||
vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
|
||||
vr1.hashcode = vn_reference_compute_hash (&vr1);
|
||||
result = vn_reference_lookup_1 (&vr1);
|
||||
result = vn_reference_lookup_1 (&vr1, vnresult);
|
||||
|
||||
/* If there is a single defining statement for all virtual uses, we can
|
||||
use that, following virtual use-def chains. */
|
||||
@ -786,23 +836,27 @@ vn_reference_lookup (tree op, VEC (tree, gc) *vuses, bool maywalk)
|
||||
vdefs_to_vec (def_stmt, &vuses);
|
||||
vr1.vuses = valueize_vuses (vuses);
|
||||
vr1.hashcode = vn_reference_compute_hash (&vr1);
|
||||
result = vn_reference_lookup_1 (&vr1);
|
||||
result = vn_reference_lookup_1 (&vr1, vnresult);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Insert OP into the current hash table with a value number of
|
||||
RESULT. */
|
||||
|
||||
void
|
||||
/* Insert OP into the current hash table with a value number of
|
||||
RESULT, and return the resulting reference structure we created. */
|
||||
|
||||
vn_reference_t
|
||||
vn_reference_insert (tree op, tree result, VEC (tree, gc) *vuses)
|
||||
{
|
||||
void **slot;
|
||||
vn_reference_t vr1;
|
||||
|
||||
vr1 = (vn_reference_t) pool_alloc (current_info->references_pool);
|
||||
|
||||
if (TREE_CODE (result) == SSA_NAME)
|
||||
vr1->value_id = VN_INFO (result)->value_id;
|
||||
else
|
||||
vr1->value_id = get_or_alloc_constant_value_id (result);
|
||||
vr1->vuses = valueize_vuses (vuses);
|
||||
vr1->operands = valueize_refs (create_reference_ops_from_ref (op));
|
||||
vr1->hashcode = vn_reference_compute_hash (vr1);
|
||||
@ -824,11 +878,48 @@ vn_reference_insert (tree op, tree result, VEC (tree, gc) *vuses)
|
||||
free_reference (*slot);
|
||||
|
||||
*slot = vr1;
|
||||
return vr1;
|
||||
}
|
||||
|
||||
/* Insert a reference by it's pieces into the current hash table with
|
||||
a value number of RESULT. Return the resulting reference
|
||||
structure we created. */
|
||||
|
||||
vn_reference_t
|
||||
vn_reference_insert_pieces (VEC (tree, gc) *vuses,
|
||||
VEC (vn_reference_op_s, heap) *operands,
|
||||
tree result, unsigned int value_id)
|
||||
|
||||
{
|
||||
void **slot;
|
||||
vn_reference_t vr1;
|
||||
|
||||
vr1 = (vn_reference_t) pool_alloc (current_info->references_pool);
|
||||
vr1->value_id = value_id;
|
||||
vr1->vuses = valueize_vuses (vuses);
|
||||
vr1->operands = valueize_refs (operands);
|
||||
vr1->hashcode = vn_reference_compute_hash (vr1);
|
||||
if (result && TREE_CODE (result) == SSA_NAME)
|
||||
result = SSA_VAL (result);
|
||||
vr1->result = result;
|
||||
|
||||
slot = htab_find_slot_with_hash (current_info->references, vr1, vr1->hashcode,
|
||||
INSERT);
|
||||
|
||||
/* At this point we should have all the things inserted that we have
|
||||
seen before, and we should never try inserting something that
|
||||
already exists. */
|
||||
gcc_assert (!*slot);
|
||||
if (*slot)
|
||||
free_reference (*slot);
|
||||
|
||||
*slot = vr1;
|
||||
return vr1;
|
||||
}
|
||||
|
||||
/* Compute and return the hash value for nary operation VBO1. */
|
||||
|
||||
static inline hashval_t
|
||||
inline hashval_t
|
||||
vn_nary_op_compute_hash (const vn_nary_op_t vno1)
|
||||
{
|
||||
hashval_t hash = 0;
|
||||
@ -865,7 +956,7 @@ vn_nary_op_hash (const void *p1)
|
||||
/* Compare nary operations P1 and P2 and return true if they are
|
||||
equivalent. */
|
||||
|
||||
static int
|
||||
int
|
||||
vn_nary_op_eq (const void *p1, const void *p2)
|
||||
{
|
||||
const_vn_nary_op_t const vno1 = (const_vn_nary_op_t) p1;
|
||||
@ -883,17 +974,56 @@ vn_nary_op_eq (const void *p1, const void *p2)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Lookup OP in the current hash table, and return the resulting
|
||||
value number if it exists in the hash table. Return NULL_TREE if
|
||||
it does not exist in the hash table. */
|
||||
/* Lookup a n-ary operation by its pieces and return the resulting value
|
||||
number if it exists in the hash table. Return NULL_TREE if it does
|
||||
not exist in the hash table or if the result field of the operation
|
||||
is NULL. VNRESULT will contain the vn_nary_op_t from the hashtable
|
||||
if it exists. */
|
||||
|
||||
tree
|
||||
vn_nary_op_lookup (tree op)
|
||||
vn_nary_op_lookup_pieces (unsigned int length, enum tree_code code,
|
||||
tree type, tree op0, tree op1, tree op2,
|
||||
tree op3, vn_nary_op_t *vnresult)
|
||||
{
|
||||
void **slot;
|
||||
struct vn_nary_op_s vno1;
|
||||
if (vnresult)
|
||||
*vnresult = NULL;
|
||||
vno1.opcode = code;
|
||||
vno1.length = length;
|
||||
vno1.type = type;
|
||||
vno1.op[0] = op0;
|
||||
vno1.op[1] = op1;
|
||||
vno1.op[2] = op2;
|
||||
vno1.op[3] = op3;
|
||||
vno1.hashcode = vn_nary_op_compute_hash (&vno1);
|
||||
slot = htab_find_slot_with_hash (current_info->nary, &vno1, vno1.hashcode,
|
||||
NO_INSERT);
|
||||
if (!slot && current_info == optimistic_info)
|
||||
slot = htab_find_slot_with_hash (valid_info->nary, &vno1, vno1.hashcode,
|
||||
NO_INSERT);
|
||||
if (!slot)
|
||||
return NULL_TREE;
|
||||
if (vnresult)
|
||||
*vnresult = (vn_nary_op_t)*slot;
|
||||
return ((vn_nary_op_t)*slot)->result;
|
||||
}
|
||||
|
||||
/* Lookup OP in the current hash table, and return the resulting value
|
||||
number if it exists in the hash table. Return NULL_TREE if it does
|
||||
not exist in the hash table or if the result field of the operation
|
||||
is NULL. VNRESULT will contain the vn_nary_op_t from the hashtable
|
||||
if it exists. */
|
||||
|
||||
tree
|
||||
vn_nary_op_lookup (tree op, vn_nary_op_t *vnresult)
|
||||
{
|
||||
void **slot;
|
||||
struct vn_nary_op_s vno1;
|
||||
unsigned i;
|
||||
|
||||
if (vnresult)
|
||||
*vnresult = NULL;
|
||||
vno1.opcode = TREE_CODE (op);
|
||||
vno1.length = TREE_CODE_LENGTH (TREE_CODE (op));
|
||||
vno1.type = TREE_TYPE (op);
|
||||
@ -907,13 +1037,56 @@ vn_nary_op_lookup (tree op)
|
||||
NO_INSERT);
|
||||
if (!slot)
|
||||
return NULL_TREE;
|
||||
if (vnresult)
|
||||
*vnresult = (vn_nary_op_t)*slot;
|
||||
return ((vn_nary_op_t)*slot)->result;
|
||||
}
|
||||
|
||||
/* Insert OP into the current hash table with a value number of
|
||||
RESULT. */
|
||||
/* Insert a n-ary operation into the current hash table using it's
|
||||
pieces. Return the vn_nary_op_t structure we created and put in
|
||||
the hashtable. */
|
||||
|
||||
void
|
||||
vn_nary_op_t
|
||||
vn_nary_op_insert_pieces (unsigned int length, enum tree_code code,
|
||||
tree type, tree op0,
|
||||
tree op1, tree op2, tree op3,
|
||||
tree result,
|
||||
unsigned int value_id)
|
||||
{
|
||||
void **slot;
|
||||
vn_nary_op_t vno1;
|
||||
|
||||
vno1 = (vn_nary_op_t) obstack_alloc (¤t_info->nary_obstack,
|
||||
(sizeof (struct vn_nary_op_s)
|
||||
- sizeof (tree) * (4 - length)));
|
||||
vno1->value_id = value_id;
|
||||
vno1->opcode = code;
|
||||
vno1->length = length;
|
||||
vno1->type = type;
|
||||
if (length >= 1)
|
||||
vno1->op[0] = op0;
|
||||
if (length >= 2)
|
||||
vno1->op[1] = op1;
|
||||
if (length >= 3)
|
||||
vno1->op[2] = op2;
|
||||
if (length >= 4)
|
||||
vno1->op[3] = op3;
|
||||
vno1->result = result;
|
||||
vno1->hashcode = vn_nary_op_compute_hash (vno1);
|
||||
slot = htab_find_slot_with_hash (current_info->nary, vno1, vno1->hashcode,
|
||||
INSERT);
|
||||
gcc_assert (!*slot);
|
||||
|
||||
*slot = vno1;
|
||||
return vno1;
|
||||
|
||||
}
|
||||
|
||||
/* Insert OP into the current hash table with a value number of
|
||||
RESULT. Return the vn_nary_op_t structure we created and put in
|
||||
the hashtable. */
|
||||
|
||||
vn_nary_op_t
|
||||
vn_nary_op_insert (tree op, tree result)
|
||||
{
|
||||
unsigned length = TREE_CODE_LENGTH (TREE_CODE (op));
|
||||
@ -924,6 +1097,7 @@ vn_nary_op_insert (tree op, tree result)
|
||||
vno1 = (vn_nary_op_t) obstack_alloc (¤t_info->nary_obstack,
|
||||
(sizeof (struct vn_nary_op_s)
|
||||
- sizeof (tree) * (4 - length)));
|
||||
vno1->value_id = VN_INFO (result)->value_id;
|
||||
vno1->opcode = TREE_CODE (op);
|
||||
vno1->length = length;
|
||||
vno1->type = TREE_TYPE (op);
|
||||
@ -936,6 +1110,7 @@ vn_nary_op_insert (tree op, tree result)
|
||||
gcc_assert (!*slot);
|
||||
|
||||
*slot = vno1;
|
||||
return vno1;
|
||||
}
|
||||
|
||||
/* Compute a hashcode for PHI operation VP1 and return it. */
|
||||
@ -1034,7 +1209,7 @@ vn_phi_lookup (tree phi)
|
||||
/* Insert PHI into the current hash table with a value number of
|
||||
RESULT. */
|
||||
|
||||
static void
|
||||
static vn_phi_t
|
||||
vn_phi_insert (tree phi, tree result)
|
||||
{
|
||||
void **slot;
|
||||
@ -1049,6 +1224,7 @@ vn_phi_insert (tree phi, tree result)
|
||||
def = TREE_CODE (def) == SSA_NAME ? SSA_VAL (def) : def;
|
||||
VEC_safe_push (tree, heap, args, def);
|
||||
}
|
||||
vp1->value_id = VN_INFO (result)->value_id;
|
||||
vp1->phiargs = args;
|
||||
vp1->block = bb_for_stmt (phi);
|
||||
vp1->result = result;
|
||||
@ -1060,6 +1236,7 @@ vn_phi_insert (tree phi, tree result)
|
||||
/* Because we iterate over phi operations more than once, it's
|
||||
possible the slot might already exist here, hence no assert.*/
|
||||
*slot = vp1;
|
||||
return vp1;
|
||||
}
|
||||
|
||||
|
||||
@ -1168,7 +1345,7 @@ static bool
|
||||
visit_unary_op (tree lhs, tree op)
|
||||
{
|
||||
bool changed = false;
|
||||
tree result = vn_nary_op_lookup (op);
|
||||
tree result = vn_nary_op_lookup (op, NULL);
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -1190,7 +1367,7 @@ static bool
|
||||
visit_binary_op (tree lhs, tree op)
|
||||
{
|
||||
bool changed = false;
|
||||
tree result = vn_nary_op_lookup (op);
|
||||
tree result = vn_nary_op_lookup (op, NULL);
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -1212,7 +1389,8 @@ static bool
|
||||
visit_reference_op_load (tree lhs, tree op, tree stmt)
|
||||
{
|
||||
bool changed = false;
|
||||
tree result = vn_reference_lookup (op, shared_vuses_from_stmt (stmt), true);
|
||||
tree result = vn_reference_lookup (op, shared_vuses_from_stmt (stmt), true,
|
||||
NULL);
|
||||
|
||||
/* We handle type-punning through unions by value-numbering based
|
||||
on offset and size of the access. Be prepared to handle a
|
||||
@ -1236,7 +1414,7 @@ visit_reference_op_load (tree lhs, tree op, tree stmt)
|
||||
result = val;
|
||||
if (!is_gimple_min_invariant (val)
|
||||
&& TREE_CODE (val) != SSA_NAME)
|
||||
result = vn_nary_op_lookup (val);
|
||||
result = vn_nary_op_lookup (val, NULL);
|
||||
/* If the expression is not yet available, value-number lhs to
|
||||
a new SSA_NAME we create. */
|
||||
if (!result && may_insert)
|
||||
@ -1319,7 +1497,8 @@ visit_reference_op_store (tree lhs, tree op, tree stmt)
|
||||
Otherwise, the vdefs for the store are used when inserting into
|
||||
the table, since the store generates a new memory state. */
|
||||
|
||||
result = vn_reference_lookup (lhs, shared_vuses_from_stmt (stmt), false);
|
||||
result = vn_reference_lookup (lhs, shared_vuses_from_stmt (stmt), false,
|
||||
NULL);
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -2146,12 +2325,18 @@ init_scc_vn (void)
|
||||
|
||||
calculate_dominance_info (CDI_DOMINATORS);
|
||||
sccstack = NULL;
|
||||
constant_to_value_id = htab_create (23, vn_constant_hash, vn_constant_eq,
|
||||
free);
|
||||
|
||||
constant_value_ids = BITMAP_ALLOC (NULL);
|
||||
|
||||
next_dfs_num = 1;
|
||||
|
||||
next_value_id = 1;
|
||||
|
||||
vn_ssa_aux_table = VEC_alloc (vn_ssa_aux_t, heap, num_ssa_names + 1);
|
||||
/* VEC_alloc doesn't actually grow it to the right size, it just
|
||||
preallocates the space to do so. */
|
||||
VEC_safe_grow (vn_ssa_aux_t, heap, vn_ssa_aux_table, num_ssa_names + 1);
|
||||
VEC_safe_grow_cleared (vn_ssa_aux_t, heap, vn_ssa_aux_table, num_ssa_names + 1);
|
||||
gcc_obstack_init (&vn_ssa_aux_obstack);
|
||||
|
||||
shared_lookup_phiargs = NULL;
|
||||
@ -2180,6 +2365,7 @@ init_scc_vn (void)
|
||||
{
|
||||
VN_INFO_GET (name)->valnum = VN_TOP;
|
||||
VN_INFO (name)->expr = name;
|
||||
VN_INFO (name)->value_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2206,6 +2392,8 @@ free_scc_vn (void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
htab_delete (constant_to_value_id);
|
||||
BITMAP_FREE (constant_value_ids);
|
||||
VEC_free (tree, heap, shared_lookup_phiargs);
|
||||
VEC_free (tree, gc, shared_lookup_vops);
|
||||
VEC_free (vn_reference_op_s, heap, shared_lookup_references);
|
||||
@ -2215,8 +2403,7 @@ free_scc_vn (void)
|
||||
{
|
||||
tree name = ssa_name (i);
|
||||
if (name
|
||||
&& SSA_NAME_VALUE (name)
|
||||
&& TREE_CODE (SSA_NAME_VALUE (name)) == VALUE_HANDLE)
|
||||
&& SSA_NAME_VALUE (name))
|
||||
SSA_NAME_VALUE (name) = NULL;
|
||||
if (name
|
||||
&& VN_INFO (name)->needs_insertion)
|
||||
@ -2237,6 +2424,91 @@ free_scc_vn (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the value ids in the valid/optimistic hash tables. */
|
||||
|
||||
static void
|
||||
set_hashtable_value_ids (void)
|
||||
{
|
||||
htab_iterator hi;
|
||||
vn_nary_op_t vno;
|
||||
vn_reference_t vr;
|
||||
vn_phi_t vp;
|
||||
|
||||
/* Now set the value ids of the things we had put in the hash
|
||||
table. */
|
||||
|
||||
FOR_EACH_HTAB_ELEMENT (valid_info->nary,
|
||||
vno, vn_nary_op_t, hi)
|
||||
{
|
||||
if (vno->result)
|
||||
{
|
||||
if (TREE_CODE (vno->result) == SSA_NAME)
|
||||
vno->value_id = VN_INFO (vno->result)->value_id;
|
||||
else if (is_gimple_min_invariant (vno->result))
|
||||
vno->value_id = get_or_alloc_constant_value_id (vno->result);
|
||||
}
|
||||
}
|
||||
|
||||
FOR_EACH_HTAB_ELEMENT (optimistic_info->nary,
|
||||
vno, vn_nary_op_t, hi)
|
||||
{
|
||||
if (vno->result)
|
||||
{
|
||||
if (TREE_CODE (vno->result) == SSA_NAME)
|
||||
vno->value_id = VN_INFO (vno->result)->value_id;
|
||||
else if (is_gimple_min_invariant (vno->result))
|
||||
vno->value_id = get_or_alloc_constant_value_id (vno->result);
|
||||
}
|
||||
}
|
||||
|
||||
FOR_EACH_HTAB_ELEMENT (valid_info->phis,
|
||||
vp, vn_phi_t, hi)
|
||||
{
|
||||
if (vp->result)
|
||||
{
|
||||
if (TREE_CODE (vp->result) == SSA_NAME)
|
||||
vp->value_id = VN_INFO (vp->result)->value_id;
|
||||
else if (is_gimple_min_invariant (vp->result))
|
||||
vp->value_id = get_or_alloc_constant_value_id (vp->result);
|
||||
}
|
||||
}
|
||||
FOR_EACH_HTAB_ELEMENT (optimistic_info->phis,
|
||||
vp, vn_phi_t, hi)
|
||||
{
|
||||
if (vp->result)
|
||||
{
|
||||
if (TREE_CODE (vp->result) == SSA_NAME)
|
||||
vp->value_id = VN_INFO (vp->result)->value_id;
|
||||
else if (is_gimple_min_invariant (vp->result))
|
||||
vp->value_id = get_or_alloc_constant_value_id (vp->result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FOR_EACH_HTAB_ELEMENT (valid_info->references,
|
||||
vr, vn_reference_t, hi)
|
||||
{
|
||||
if (vr->result)
|
||||
{
|
||||
if (TREE_CODE (vr->result) == SSA_NAME)
|
||||
vr->value_id = VN_INFO (vr->result)->value_id;
|
||||
else if (is_gimple_min_invariant (vr->result))
|
||||
vr->value_id = get_or_alloc_constant_value_id (vr->result);
|
||||
}
|
||||
}
|
||||
FOR_EACH_HTAB_ELEMENT (optimistic_info->references,
|
||||
vr, vn_reference_t, hi)
|
||||
{
|
||||
if (vr->result)
|
||||
{
|
||||
if (TREE_CODE (vr->result) == SSA_NAME)
|
||||
vr->value_id = VN_INFO (vr->result)->value_id;
|
||||
else if (is_gimple_min_invariant (vr->result))
|
||||
vr->value_id = get_or_alloc_constant_value_id (vr->result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do SCCVN. Returns true if it finished, false if we bailed out
|
||||
due to resource constraints. */
|
||||
|
||||
@ -2245,7 +2517,8 @@ run_scc_vn (bool may_insert_arg)
|
||||
{
|
||||
size_t i;
|
||||
tree param;
|
||||
|
||||
bool changed = true;
|
||||
|
||||
may_insert = may_insert_arg;
|
||||
|
||||
init_scc_vn ();
|
||||
@ -2276,6 +2549,45 @@ run_scc_vn (bool may_insert_arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the value ids. */
|
||||
|
||||
for (i = 1; i < num_ssa_names; ++i)
|
||||
{
|
||||
tree name = ssa_name (i);
|
||||
vn_ssa_aux_t info;
|
||||
if (!name)
|
||||
continue;
|
||||
info = VN_INFO (name);
|
||||
if (info->valnum == name)
|
||||
info->value_id = get_next_value_id ();
|
||||
else if (is_gimple_min_invariant (info->valnum))
|
||||
info->value_id = get_or_alloc_constant_value_id (info->valnum);
|
||||
}
|
||||
|
||||
/* Propagate until they stop changing. */
|
||||
while (changed)
|
||||
{
|
||||
changed = false;
|
||||
for (i = 1; i < num_ssa_names; ++i)
|
||||
{
|
||||
tree name = ssa_name (i);
|
||||
vn_ssa_aux_t info;
|
||||
if (!name)
|
||||
continue;
|
||||
info = VN_INFO (name);
|
||||
if (TREE_CODE (info->valnum) == SSA_NAME
|
||||
&& info->valnum != name
|
||||
&& TREE_CODE (info->valnum) == SSA_NAME
|
||||
&& info->value_id != VN_INFO (info->valnum)->value_id)
|
||||
{
|
||||
changed = true;
|
||||
info->value_id = VN_INFO (info->valnum)->value_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_hashtable_value_ids ();
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Value numbers:\n");
|
||||
@ -2300,3 +2612,83 @@ run_scc_vn (bool may_insert_arg)
|
||||
may_insert = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return the maximum value id we have ever seen. */
|
||||
|
||||
unsigned int
|
||||
get_max_value_id (void)
|
||||
{
|
||||
return next_value_id;
|
||||
}
|
||||
|
||||
/* Return the next unique value id. */
|
||||
|
||||
unsigned int
|
||||
get_next_value_id (void)
|
||||
{
|
||||
return next_value_id++;
|
||||
}
|
||||
|
||||
|
||||
/* Compare two expressions E1 and E2 and return true if they are
|
||||
equal. */
|
||||
|
||||
bool
|
||||
expressions_equal_p (tree e1, tree e2)
|
||||
{
|
||||
tree te1, te2;
|
||||
|
||||
if (e1 == e2)
|
||||
return true;
|
||||
|
||||
te1 = TREE_TYPE (e1);
|
||||
te2 = TREE_TYPE (e2);
|
||||
|
||||
if (TREE_CODE (e1) == TREE_LIST && TREE_CODE (e2) == TREE_LIST)
|
||||
{
|
||||
tree lop1 = e1;
|
||||
tree lop2 = e2;
|
||||
for (lop1 = e1, lop2 = e2;
|
||||
lop1 || lop2;
|
||||
lop1 = TREE_CHAIN (lop1), lop2 = TREE_CHAIN (lop2))
|
||||
{
|
||||
if (!lop1 || !lop2)
|
||||
return false;
|
||||
if (!expressions_equal_p (TREE_VALUE (lop1), TREE_VALUE (lop2)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (TREE_CODE (e1) == TREE_CODE (e2)
|
||||
&& operand_equal_p (e1, e2, OEP_PURE_SAME))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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),
|
||||
operand_build_cmp);
|
||||
}
|
||||
|
||||
/* Sort the VUSE array so that we can do equality comparisons
|
||||
quicker on two vuse vecs. */
|
||||
|
||||
void
|
||||
sort_vuses_heap (VEC (tree,heap) *vuses)
|
||||
{
|
||||
if (VEC_length (tree, vuses) > 1)
|
||||
qsort (VEC_address (tree, vuses),
|
||||
VEC_length (tree, vuses),
|
||||
sizeof (tree),
|
||||
operand_build_cmp);
|
||||
}
|
||||
|
@ -24,6 +24,87 @@
|
||||
/* TOP of the VN lattice. */
|
||||
extern tree VN_TOP;
|
||||
|
||||
/* N-ary operations in the hashtable consist of length operands, an
|
||||
opcode, and a type. Result is the value number of the operation,
|
||||
and hashcode is stored to avoid having to calculate it
|
||||
repeatedly. */
|
||||
|
||||
typedef struct vn_nary_op_s
|
||||
{
|
||||
/* Unique identify that all expressions with the same value have. */
|
||||
unsigned int value_id;
|
||||
ENUM_BITFIELD(tree_code) opcode : 16;
|
||||
unsigned length : 16;
|
||||
hashval_t hashcode;
|
||||
tree result;
|
||||
tree type;
|
||||
tree op[4];
|
||||
} *vn_nary_op_t;
|
||||
typedef const struct vn_nary_op_s *const_vn_nary_op_t;
|
||||
|
||||
/* Phi nodes in the hashtable consist of their non-VN_TOP phi
|
||||
arguments, and the basic block the phi is in. Result is the value
|
||||
number of the operation, and hashcode is stored to avoid having to
|
||||
calculate it repeatedly. Phi nodes not in the same block are never
|
||||
considered equivalent. */
|
||||
|
||||
typedef struct vn_phi_s
|
||||
{
|
||||
/* Unique identifier that all expressions with the same value have. */
|
||||
unsigned int value_id;
|
||||
hashval_t hashcode;
|
||||
VEC (tree, heap) *phiargs;
|
||||
basic_block block;
|
||||
tree result;
|
||||
} *vn_phi_t;
|
||||
typedef const struct vn_phi_s *const_vn_phi_t;
|
||||
|
||||
/* Reference operands only exist in reference operations structures.
|
||||
They consist of an opcode, type, and some number of operands. For
|
||||
a given opcode, some, all, or none of the operands may be used.
|
||||
The operands are there to store the information that makes up the
|
||||
portion of the addressing calculation that opcode performs. */
|
||||
|
||||
typedef struct vn_reference_op_struct
|
||||
{
|
||||
enum tree_code opcode;
|
||||
tree type;
|
||||
tree op0;
|
||||
tree op1;
|
||||
tree op2;
|
||||
} vn_reference_op_s;
|
||||
typedef vn_reference_op_s *vn_reference_op_t;
|
||||
typedef const vn_reference_op_s *const_vn_reference_op_t;
|
||||
|
||||
DEF_VEC_O(vn_reference_op_s);
|
||||
DEF_VEC_ALLOC_O(vn_reference_op_s, heap);
|
||||
|
||||
/* A reference operation in the hashtable is representation as a
|
||||
collection of vuses, representing the memory state at the time of
|
||||
the operation, and a collection of operands that make up the
|
||||
addressing calculation. If two vn_reference_t's have the same set
|
||||
of operands, they access the same memory location. We also store
|
||||
the resulting value number, and the hashcode. The vuses are
|
||||
always stored in order sorted by ssa name version. */
|
||||
|
||||
typedef struct vn_reference_s
|
||||
{
|
||||
/* Unique identifier that all expressions with the same value have. */
|
||||
unsigned int value_id;
|
||||
hashval_t hashcode;
|
||||
VEC (tree, gc) *vuses;
|
||||
VEC (vn_reference_op_s, heap) *operands;
|
||||
tree result;
|
||||
} *vn_reference_t;
|
||||
typedef const struct vn_reference_s *const_vn_reference_t;
|
||||
|
||||
typedef struct vn_constant_s
|
||||
{
|
||||
unsigned int value_id;
|
||||
hashval_t hashcode;
|
||||
tree constant;
|
||||
} *vn_constant_t;
|
||||
|
||||
typedef struct vn_ssa_aux
|
||||
{
|
||||
/* Value number. This may be an SSA name or a constant. */
|
||||
@ -31,6 +112,9 @@ typedef struct vn_ssa_aux
|
||||
/* Representative expression, if not a direct constant. */
|
||||
tree expr;
|
||||
|
||||
/* Unique identifier that all expressions with the same value have. */
|
||||
unsigned int value_id;
|
||||
|
||||
/* SCC information. */
|
||||
unsigned int dfsnum;
|
||||
unsigned int low;
|
||||
@ -57,12 +141,31 @@ extern vn_ssa_aux_t VN_INFO_GET (tree);
|
||||
bool run_scc_vn (bool);
|
||||
void free_scc_vn (void);
|
||||
void switch_to_PRE_table (void);
|
||||
tree vn_nary_op_lookup (tree);
|
||||
void vn_nary_op_insert (tree, tree);
|
||||
tree vn_reference_lookup (tree, VEC (tree, gc) *, bool);
|
||||
void vn_reference_insert (tree, tree, VEC (tree, gc) *);
|
||||
tree vn_nary_op_lookup (tree, vn_nary_op_t *);
|
||||
tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
|
||||
tree, tree, tree, tree, tree,
|
||||
vn_nary_op_t *);
|
||||
vn_nary_op_t vn_nary_op_insert (tree, tree);
|
||||
vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
|
||||
tree, tree, tree, tree,
|
||||
tree, tree, unsigned int);
|
||||
tree vn_reference_lookup_pieces (VEC (tree, gc) *,
|
||||
VEC (vn_reference_op_s, heap) *,
|
||||
vn_reference_t *);
|
||||
tree vn_reference_lookup (tree, VEC (tree, gc) *, bool, vn_reference_t *);
|
||||
vn_reference_t vn_reference_insert (tree, tree, VEC (tree, gc) *);
|
||||
vn_reference_t vn_reference_insert_pieces (VEC (tree, gc) *,
|
||||
VEC (vn_reference_op_s, heap) *,
|
||||
tree, unsigned int);
|
||||
|
||||
hashval_t vn_nary_op_compute_hash (const vn_nary_op_t);
|
||||
int vn_nary_op_eq (const void *, const void *);
|
||||
hashval_t vn_reference_compute_hash (const vn_reference_t);
|
||||
int vn_reference_eq (const void *, const void *);
|
||||
unsigned int get_max_value_id (void);
|
||||
unsigned int get_next_value_id (void);
|
||||
unsigned int get_or_alloc_constant_value_id (tree);
|
||||
bool value_id_constant_p (unsigned int);
|
||||
VEC (tree, gc) *shared_vuses_from_stmt (tree);
|
||||
VEC (tree, gc) *copy_vuses_from_stmt (tree);
|
||||
|
||||
|
||||
#endif /* TREE_SSA_SCCVN_H */
|
||||
|
@ -313,7 +313,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
|
||||
copy[i++] = use;
|
||||
if (TREE_CODE (use) == SSA_NAME)
|
||||
tmp = SSA_NAME_VALUE (use);
|
||||
if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
|
||||
if (tmp)
|
||||
SET_USE (use_p, tmp);
|
||||
}
|
||||
|
||||
@ -407,14 +407,14 @@ simplify_control_stmt_condition (edge e,
|
||||
if (TREE_CODE (op0) == SSA_NAME)
|
||||
{
|
||||
tree tmp = SSA_NAME_VALUE (op0);
|
||||
if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
|
||||
if (tmp)
|
||||
op0 = tmp;
|
||||
}
|
||||
|
||||
if (TREE_CODE (op1) == SSA_NAME)
|
||||
{
|
||||
tree tmp = SSA_NAME_VALUE (op1);
|
||||
if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
|
||||
if (tmp)
|
||||
op1 = tmp;
|
||||
}
|
||||
|
||||
|
406
gcc/tree-vn.c
406
gcc/tree-vn.c
@ -1,406 +0,0 @@
|
||||
/* Value Numbering routines for tree expressions.
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software
|
||||
Foundation, Inc.
|
||||
Contributed by Daniel Berlin <dan@dberlin.org>, Steven Bosscher
|
||||
<stevenb@suse.de> and Diego Novillo <dnovillo@redhat.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tm.h"
|
||||
#include "ggc.h"
|
||||
#include "tree.h"
|
||||
#include "tree-flow.h"
|
||||
#include "hashtab.h"
|
||||
#include "langhooks.h"
|
||||
#include "tree-pass.h"
|
||||
#include "tree-dump.h"
|
||||
#include "diagnostic.h"
|
||||
#include "tree-ssa-sccvn.h"
|
||||
|
||||
/* Most of this is PRE specific. The real grunt work is done in
|
||||
tree-ssa-sccvn.c. This is where the lookup and insertion
|
||||
functions, etc, can be found. */
|
||||
|
||||
/* Create and return a new value handle node of type TYPE. */
|
||||
|
||||
tree
|
||||
make_value_handle (tree type)
|
||||
{
|
||||
static unsigned int id = 0;
|
||||
tree vh;
|
||||
|
||||
vh = build0 (VALUE_HANDLE, type);
|
||||
VALUE_HANDLE_ID (vh) = id++;
|
||||
return vh;
|
||||
}
|
||||
|
||||
/* Compare two expressions E1 and E2 and return true if they are
|
||||
equal. */
|
||||
|
||||
bool
|
||||
expressions_equal_p (tree e1, tree e2)
|
||||
{
|
||||
tree te1, te2;
|
||||
|
||||
if (e1 == e2)
|
||||
return true;
|
||||
|
||||
te1 = TREE_TYPE (e1);
|
||||
te2 = TREE_TYPE (e2);
|
||||
|
||||
if (TREE_CODE (e1) == TREE_LIST && TREE_CODE (e2) == TREE_LIST)
|
||||
{
|
||||
tree lop1 = e1;
|
||||
tree lop2 = e2;
|
||||
for (lop1 = e1, lop2 = e2;
|
||||
lop1 || lop2;
|
||||
lop1 = TREE_CHAIN (lop1), lop2 = TREE_CHAIN (lop2))
|
||||
{
|
||||
if (!lop1 || !lop2)
|
||||
return false;
|
||||
if (!expressions_equal_p (TREE_VALUE (lop1), TREE_VALUE (lop2)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (TREE_CODE (e1) == TREE_CODE (e2)
|
||||
&& operand_equal_p (e1, e2, OEP_PURE_SAME))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the value handle for expression E to value V. */
|
||||
|
||||
void
|
||||
set_value_handle (tree e, tree v)
|
||||
{
|
||||
if (TREE_CODE (e) == SSA_NAME)
|
||||
SSA_NAME_VALUE (e) = v;
|
||||
else if (EXPR_P (e) || DECL_P (e) || TREE_CODE (e) == TREE_LIST
|
||||
|| GIMPLE_STMT_P (e)
|
||||
|| TREE_CODE (e) == CONSTRUCTOR)
|
||||
get_tree_common_ann (e)->value_handle = v;
|
||||
else
|
||||
/* Do nothing. Constants are their own value handles. */
|
||||
gcc_assert (is_gimple_min_invariant (e));
|
||||
}
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
||||
/* 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),
|
||||
operand_build_cmp);
|
||||
}
|
||||
|
||||
/* Sort the VUSE array so that we can do equality comparisons
|
||||
quicker on two vuse vecs. */
|
||||
|
||||
void
|
||||
sort_vuses_heap (VEC (tree,heap) *vuses)
|
||||
{
|
||||
if (VEC_length (tree, vuses) > 1)
|
||||
qsort (VEC_address (tree, vuses),
|
||||
VEC_length (tree, vuses),
|
||||
sizeof (tree),
|
||||
operand_build_cmp);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
switch (TREE_CODE_CLASS (TREE_CODE (expr)))
|
||||
{
|
||||
case tcc_comparison:
|
||||
case tcc_binary:
|
||||
vn_nary_op_insert (expr, val);
|
||||
break;
|
||||
case tcc_unary:
|
||||
vn_nary_op_insert (expr, val);
|
||||
break;
|
||||
/* In the case of array-refs of constants, for example, we can
|
||||
end up with no vuses. */
|
||||
case tcc_reference:
|
||||
vn_reference_insert (expr, val, NULL);
|
||||
break;
|
||||
/* The *only* time CALL_EXPR should appear here is
|
||||
when it has no vuses. */
|
||||
case tcc_vl_exp:
|
||||
case tcc_exceptional:
|
||||
case tcc_expression:
|
||||
case tcc_declaration:
|
||||
if (TREE_CODE (expr) == CALL_EXPR || DECL_P (expr))
|
||||
{
|
||||
vn_reference_insert (expr, val, NULL);
|
||||
break;
|
||||
}
|
||||
else if (TREE_CODE (expr) == SSA_NAME)
|
||||
{
|
||||
SSA_NAME_VALUE (expr) = val;
|
||||
break;
|
||||
}
|
||||
switch (TREE_CODE (expr))
|
||||
{
|
||||
case ADDR_EXPR:
|
||||
case TRUTH_AND_EXPR:
|
||||
case TRUTH_OR_EXPR:
|
||||
case TRUTH_XOR_EXPR:
|
||||
case TRUTH_NOT_EXPR:
|
||||
vn_nary_op_insert (expr, val);
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
set_value_handle (expr, val);
|
||||
if (TREE_CODE (val) == VALUE_HANDLE)
|
||||
add_to_value (val, expr);
|
||||
}
|
||||
|
||||
/* Insert EXPR into the value numbering tables with value VAL, and
|
||||
add expression EXPR to the value set for value VAL. VUSES
|
||||
represents the virtual use operands associated with EXPR. It is
|
||||
used when computing a hash value for EXPR. */
|
||||
|
||||
void
|
||||
vn_add_with_vuses (tree expr, tree val, VEC (tree, gc) *vuses)
|
||||
{
|
||||
if (!vuses)
|
||||
{
|
||||
vn_add (expr, val);
|
||||
return;
|
||||
}
|
||||
vn_reference_insert (expr, val, vuses);
|
||||
|
||||
set_value_handle (expr, val);
|
||||
if (TREE_CODE (val) == VALUE_HANDLE)
|
||||
add_to_value (val, expr);
|
||||
}
|
||||
|
||||
/* Lookup EXPR in the value numbering tables and return the result, if
|
||||
we have one. */
|
||||
|
||||
tree
|
||||
vn_lookup (tree expr)
|
||||
{
|
||||
/* Constants are their own value. */
|
||||
if (is_gimple_min_invariant (expr) || TREE_CODE (expr) == FIELD_DECL)
|
||||
return expr;
|
||||
|
||||
switch (TREE_CODE_CLASS (TREE_CODE (expr)))
|
||||
{
|
||||
case tcc_comparison:
|
||||
case tcc_binary:
|
||||
return vn_nary_op_lookup (expr);
|
||||
case tcc_unary:
|
||||
return vn_nary_op_lookup (expr);
|
||||
break;
|
||||
/* In the case of array-refs of constants, for example, we can
|
||||
end up with no vuses. */
|
||||
case tcc_reference:
|
||||
return vn_reference_lookup (expr, NULL, false);
|
||||
break;
|
||||
/* It is possible to have CALL_EXPR with no vuses for things
|
||||
like "cos", and these will fall into vn_lookup. */
|
||||
case tcc_vl_exp:
|
||||
case tcc_exceptional:
|
||||
case tcc_expression:
|
||||
case tcc_declaration:
|
||||
if (TREE_CODE (expr) == CALL_EXPR || DECL_P (expr))
|
||||
return vn_reference_lookup (expr, NULL, false);
|
||||
else if (TREE_CODE (expr) == SSA_NAME)
|
||||
return SSA_NAME_VALUE (expr);
|
||||
switch (TREE_CODE (expr))
|
||||
{
|
||||
case ADDR_EXPR:
|
||||
case TRUTH_AND_EXPR:
|
||||
case TRUTH_OR_EXPR:
|
||||
case TRUTH_XOR_EXPR:
|
||||
case TRUTH_NOT_EXPR:
|
||||
return vn_nary_op_lookup (expr);
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search in the value numbering tables for an existing instance of
|
||||
expression EXPR, and return its value, or NULL if none has been set. STMT
|
||||
represents the stmt associated with EXPR. It is used when computing the
|
||||
hash value for EXPR for reference operations. */
|
||||
|
||||
tree
|
||||
vn_lookup_with_stmt (tree expr, tree stmt)
|
||||
{
|
||||
if (stmt == NULL)
|
||||
return vn_lookup (expr);
|
||||
|
||||
/* Constants are their own value. */
|
||||
if (is_gimple_min_invariant (expr) || TREE_CODE (expr) == FIELD_DECL)
|
||||
return expr;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!vuses || !VEC_length (tree, vuses))
|
||||
return vn_lookup (expr);
|
||||
|
||||
if (is_gimple_min_invariant (expr) || TREE_CODE (expr) == FIELD_DECL)
|
||||
return expr;
|
||||
|
||||
/* We may not walk the use-def chains here as the alias oracle cannot
|
||||
properly deal with VALUE_HANDLE tree nodes we feed it here. */
|
||||
return vn_reference_lookup (expr, vuses, false);
|
||||
}
|
||||
|
||||
static tree
|
||||
create_value_handle_for_expr (tree expr, VEC(tree, gc) *vuses)
|
||||
{
|
||||
tree v;
|
||||
|
||||
v = make_value_handle (TREE_TYPE (expr));
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
print_creation_to_file (v, expr, vuses);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Like vn_lookup, but creates a new value for the operation if one
|
||||
does not exist. */
|
||||
|
||||
tree
|
||||
vn_lookup_or_add (tree expr)
|
||||
{
|
||||
tree v = vn_lookup (expr);
|
||||
|
||||
if (v == NULL_TREE)
|
||||
{
|
||||
v = create_value_handle_for_expr (expr, NULL);
|
||||
vn_add (expr, v);
|
||||
}
|
||||
else
|
||||
set_value_handle (expr, v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Like vn_lookup, but handles reference operations as well by using
|
||||
STMT to get the set of vuses. */
|
||||
|
||||
tree
|
||||
vn_lookup_or_add_with_stmt (tree expr, tree stmt)
|
||||
{
|
||||
tree v;
|
||||
if (!stmt)
|
||||
return vn_lookup_or_add (expr);
|
||||
|
||||
v = vn_lookup_with_stmt (expr, stmt);
|
||||
if (v == NULL_TREE)
|
||||
{
|
||||
VEC (tree, gc) *vuses = copy_vuses_from_stmt (stmt);
|
||||
v = create_value_handle_for_expr (expr, vuses);
|
||||
vn_add_with_vuses (expr, v, vuses);
|
||||
}
|
||||
else
|
||||
set_value_handle (expr, v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (!vuses || VEC_length (tree, vuses) == 0)
|
||||
return vn_lookup_or_add (expr);
|
||||
|
||||
v = vn_lookup_with_vuses (expr, vuses);
|
||||
if (v == NULL_TREE)
|
||||
{
|
||||
v = create_value_handle_for_expr (expr, vuses);
|
||||
vn_add_with_vuses (expr, v, vuses);
|
||||
}
|
||||
else
|
||||
set_value_handle (expr, v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
@ -462,7 +462,6 @@ tree_code_size (enum tree_code code)
|
||||
|
||||
case STATEMENT_LIST: return sizeof (struct tree_statement_list);
|
||||
case BLOCK: return sizeof (struct tree_block);
|
||||
case VALUE_HANDLE: return sizeof (struct tree_value_handle);
|
||||
case CONSTRUCTOR: return sizeof (struct tree_constructor);
|
||||
|
||||
default:
|
||||
@ -2387,7 +2386,6 @@ tree_node_structure (const_tree t)
|
||||
case BLOCK: return TS_BLOCK;
|
||||
case CONSTRUCTOR: return TS_CONSTRUCTOR;
|
||||
case TREE_BINFO: return TS_BINFO;
|
||||
case VALUE_HANDLE: return TS_VALUE_HANDLE;
|
||||
case OMP_CLAUSE: return TS_OMP_CLAUSE;
|
||||
|
||||
default:
|
||||
@ -3639,7 +3637,7 @@ build_decl_attribute_variant (tree ddecl, tree attribute)
|
||||
|
||||
|
||||
/* Produce good hash value combining VAL and VAL2. */
|
||||
static inline hashval_t
|
||||
hashval_t
|
||||
iterative_hash_hashval_t (hashval_t val, hashval_t val2)
|
||||
{
|
||||
/* the golden ratio; an arbitrary value. */
|
||||
@ -5358,7 +5356,6 @@ iterative_hash_expr (const_tree t, hashval_t val)
|
||||
return iterative_hash_expr (TREE_VECTOR_CST_ELTS (t), val);
|
||||
|
||||
case SSA_NAME:
|
||||
case VALUE_HANDLE:
|
||||
/* we can just compare by pointer. */
|
||||
return iterative_hash_pointer (t, val);
|
||||
|
||||
|
@ -925,12 +925,6 @@ DEFTREECODE (POLYNOMIAL_CHREC, "polynomial_chrec", tcc_expression, 3)
|
||||
Use the interface in tree-iterator.h to access this node. */
|
||||
DEFTREECODE (STATEMENT_LIST, "statement_list", tcc_exceptional, 0)
|
||||
|
||||
/* Value handles. Artificial nodes to represent expressions in
|
||||
partial redundancy elimination (tree-ssa-pre.c). These nodes are
|
||||
used for expression canonicalization. If two expressions compute
|
||||
the same value, they will be assigned the same value handle. */
|
||||
DEFTREECODE (VALUE_HANDLE, "value_handle", tcc_exceptional, 0)
|
||||
|
||||
/* Predicate assertion. Artificial expression generated by the optimizers
|
||||
to keep track of predicate values. This expression may only appear on
|
||||
the RHS of assignments.
|
||||
|
22
gcc/tree.h
22
gcc/tree.h
@ -3492,26 +3492,6 @@ struct tree_statement_list
|
||||
struct tree_statement_list_node *tail;
|
||||
};
|
||||
|
||||
#define VALUE_HANDLE_ID(NODE) \
|
||||
(VALUE_HANDLE_CHECK (NODE)->value_handle.id)
|
||||
|
||||
#define VALUE_HANDLE_EXPR_SET(NODE) \
|
||||
(VALUE_HANDLE_CHECK (NODE)->value_handle.expr_set)
|
||||
|
||||
/* Defined and used in tree-ssa-pre.c. */
|
||||
|
||||
struct tree_value_handle GTY(())
|
||||
{
|
||||
struct tree_common common;
|
||||
|
||||
/* The set of expressions represented by this handle. */
|
||||
struct bitmap_set * GTY ((skip)) expr_set;
|
||||
|
||||
/* Unique ID for this value handle. IDs are handed out in a
|
||||
conveniently dense form starting at 0, so that we can make
|
||||
bitmaps of value handles. */
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
/* Define the overall contents of a tree node.
|
||||
It may be any of the structures declared above
|
||||
@ -3552,7 +3532,6 @@ union tree_node GTY ((ptr_alias (union lang_tree_node),
|
||||
struct tree_binfo GTY ((tag ("TS_BINFO"))) binfo;
|
||||
struct tree_statement_list GTY ((tag ("TS_STATEMENT_LIST"))) stmt_list;
|
||||
struct gimple_stmt GTY ((tag ("TS_GIMPLE_STATEMENT"))) gstmt;
|
||||
struct tree_value_handle GTY ((tag ("TS_VALUE_HANDLE"))) value_handle;
|
||||
struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor;
|
||||
struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag;
|
||||
struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
|
||||
@ -4964,6 +4943,7 @@ extern int tree_log2 (const_tree);
|
||||
extern int tree_floor_log2 (const_tree);
|
||||
extern int simple_cst_equal (const_tree, const_tree);
|
||||
extern hashval_t iterative_hash_expr (const_tree, hashval_t);
|
||||
extern hashval_t iterative_hash_hashval_t (hashval_t, hashval_t);
|
||||
extern int compare_tree_int (const_tree, unsigned HOST_WIDE_INT);
|
||||
extern int type_list_equal (const_tree, const_tree);
|
||||
extern int chain_member (const_tree, const_tree);
|
||||
|
@ -59,7 +59,6 @@ DEFTREESTRUCT(TS_BLOCK, "block")
|
||||
DEFTREESTRUCT(TS_BINFO, "binfo")
|
||||
DEFTREESTRUCT(TS_STATEMENT_LIST, "statement list")
|
||||
DEFTREESTRUCT(TS_GIMPLE_STATEMENT, "gimple statement")
|
||||
DEFTREESTRUCT(TS_VALUE_HANDLE, "value handle")
|
||||
DEFTREESTRUCT(TS_CONSTRUCTOR, "constructor")
|
||||
DEFTREESTRUCT(TS_MEMORY_TAG, "memory tag")
|
||||
DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")
|
||||
|
Loading…
Reference in New Issue
Block a user