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:
Daniel Berlin 2008-07-08 16:11:06 +00:00 committed by Daniel Berlin
parent 771578a0df
commit c91457541d
20 changed files with 2409 additions and 2014 deletions

View File

@ -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

View File

@ -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) \

View File

@ -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)

View 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;
}
}
}
}

View File

@ -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" } } */

View 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" } } */

View 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" } } */

View 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" } } */

View File

@ -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 */

View File

@ -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);

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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 (&current_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 (&current_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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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")