[PATCH][mem-ref2] Handle different canonicalizations of memory in SCCVN
Richard Guenther
rguenther@suse.de
Wed Jun 16 12:26:00 GMT 2010
This patch brings a significant reduction in optimization testcase
fails. The VN code needs some TLC still, but the current state
serves as a nice baseline for followup patches.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applie to the branch.
+FAIL: gfortran.dg/dynamic_dispatch_6.f03 -O2 execution test
now fails - I suppose Fortran does sth funny.
Richard.
2010-06-16 Richard Guenther <rguenther@suse.de>
* tree-ssa-sccvn.h (struct vn_reference_op_struct): Add
a field to store the constant offset this op applies.
* tree-ssa-sscvn.c (vn_reference_compute_hash): Hash
fields that only adjust the offset by a constant by
aggregating them and hashing the offset. Do not hash
*& combinations.
(vn_reference_eq): Adjust comparison accordingly. Make sure
accesses are of the same size first.
(copy_reference_ops_from_ref): Compute and remember constant
offsets.
(copy_reference_ops_from_call): Likewise.
* tree-ssa-pre.c (insert_into_preds_of_block): Properly
initialize avail.
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c (revision 160753)
--- gcc/tree-ssa-sccvn.c (working copy)
*************** vn_reference_compute_hash (const vn_refe
*** 431,439 ****
hashval_t result = 0;
int i;
vn_reference_op_t vro;
for (i = 0; VEC_iterate (vn_reference_op_s, vr1->operands, i, vro); i++)
! result = vn_reference_op_compute_hash (vro, result);
if (vr1->vuse)
result += SSA_NAME_VERSION (vr1->vuse);
--- 431,471 ----
hashval_t result = 0;
int i;
vn_reference_op_t vro;
+ HOST_WIDE_INT off = -1;
+ bool deref = false;
for (i = 0; VEC_iterate (vn_reference_op_s, vr1->operands, i, vro); i++)
! {
! if (vro->opcode == MEM_REF)
! deref = true;
! else if (vro->opcode != ADDR_EXPR)
! deref = false;
! if (vro->off != -1)
! {
! if (off == -1)
! off = 0;
! off += vro->off;
! }
! else
! {
! if (off != -1
! && off != 0)
! result = iterative_hash_hashval_t (off, result);
! off = -1;
! if (deref
! && vro->opcode == ADDR_EXPR)
! {
! if (vro->op0)
! {
! tree op = TREE_OPERAND (vro->op0, 0);
! result = iterative_hash_hashval_t (TREE_CODE (op), result);
! result = iterative_hash_expr (op, result);
! }
! }
! else
! result = vn_reference_op_compute_hash (vro, result);
! }
! }
if (vr1->vuse)
result += SSA_NAME_VERSION (vr1->vuse);
*************** vn_reference_compute_hash (const vn_refe
*** 446,453 ****
int
vn_reference_eq (const void *p1, const void *p2)
{
! int i;
! vn_reference_op_t vro;
const_vn_reference_t const vr1 = (const_vn_reference_t) p1;
const_vn_reference_t const vr2 = (const_vn_reference_t) p2;
--- 478,484 ----
int
vn_reference_eq (const void *p1, const void *p2)
{
! unsigned i, j;
const_vn_reference_t const vr1 = (const_vn_reference_t) p1;
const_vn_reference_t const vr2 = (const_vn_reference_t) p2;
*************** vn_reference_eq (const void *p1, const v
*** 466,482 ****
if (vr1->operands == vr2->operands)
return true;
! /* We require that address operands be canonicalized in a way that
! two memory references will have the same operands if they are
! equivalent. */
! if (VEC_length (vn_reference_op_s, vr1->operands)
! != VEC_length (vn_reference_op_s, vr2->operands))
return false;
! for (i = 0; VEC_iterate (vn_reference_op_s, vr1->operands, i, vro); i++)
! if (!vn_reference_op_eq (VEC_index (vn_reference_op_s, vr2->operands, i),
! vro))
! return false;
return true;
}
--- 497,554 ----
if (vr1->operands == vr2->operands)
return true;
! if (!expressions_equal_p (TYPE_SIZE (vr1->type), TYPE_SIZE (vr2->type)))
return false;
! i = 0;
! j = 0;
! do
! {
! HOST_WIDE_INT off1 = 0, off2 = 0;
! vn_reference_op_t vro1, vro2;
! vn_reference_op_s tem1, tem2;
! bool deref1 = false, deref2 = false;
! for (; VEC_iterate (vn_reference_op_s, vr1->operands, i, vro1); i++)
! {
! if (vro1->opcode == MEM_REF)
! deref1 = true;
! if (vro1->off == -1)
! break;
! off1 += vro1->off;
! }
! for (; VEC_iterate (vn_reference_op_s, vr2->operands, j, vro2); j++)
! {
! if (vro2->opcode == MEM_REF)
! deref2 = true;
! if (vro2->off == -1)
! break;
! off2 += vro2->off;
! }
! if (off1 != off2)
! return false;
! if (deref1 && vro1->opcode == ADDR_EXPR)
! {
! memset (&tem1, 0, sizeof (tem1));
! tem1.op0 = TREE_OPERAND (vro1->op0, 0);
! tem1.type = TREE_TYPE (tem1.op0);
! tem1.opcode = TREE_CODE (tem1.op0);
! vro1 = &tem1;
! }
! if (deref2 && vro2->opcode == ADDR_EXPR)
! {
! memset (&tem2, 0, sizeof (tem2));
! tem2.op0 = TREE_OPERAND (vro2->op0, 0);
! tem2.type = TREE_TYPE (tem2.op0);
! tem2.opcode = TREE_CODE (tem2.op0);
! vro2 = &tem2;
! }
! if (!vn_reference_op_eq (vro1, vro2))
! return false;
! ++j;
! ++i;
! }
! while (VEC_length (vn_reference_op_s, vr1->operands) != i
! || VEC_length (vn_reference_op_s, vr2->operands) != j);
return true;
}
*************** copy_reference_ops_from_ref (tree ref, V
*** 503,508 ****
--- 575,581 ----
temp.op0 = TMR_INDEX (ref);
temp.op1 = TMR_STEP (ref);
temp.op2 = TMR_OFFSET (ref);
+ temp.off = -1;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
memset (&temp, 0, sizeof (temp));
*************** copy_reference_ops_from_ref (tree ref, V
*** 510,515 ****
--- 583,589 ----
temp.opcode = TREE_CODE (base);
temp.op0 = base;
temp.op1 = TMR_ORIGINAL (ref);
+ temp.off = -1;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
return;
}
*************** copy_reference_ops_from_ref (tree ref, V
*** 524,542 ****
/* We do not care for spurious type qualifications. */
temp.type = TYPE_MAIN_VARIANT (TREE_TYPE (ref));
temp.opcode = TREE_CODE (ref);
switch (temp.opcode)
{
case ALIGN_INDIRECT_REF:
/* The only operand is the address, which gets its own
vn_reference_op_s structure. */
! break;
case MISALIGNED_INDIRECT_REF:
temp.op0 = TREE_OPERAND (ref, 1);
break;
case MEM_REF:
/* The base address gets its own vn_reference_op_s structure. */
temp.op0 = TREE_OPERAND (ref, 1);
break;
case BIT_FIELD_REF:
/* Record bits and position. */
--- 598,620 ----
/* We do not care for spurious type qualifications. */
temp.type = TYPE_MAIN_VARIANT (TREE_TYPE (ref));
temp.opcode = TREE_CODE (ref);
+ temp.off = -1;
switch (temp.opcode)
{
case ALIGN_INDIRECT_REF:
/* The only operand is the address, which gets its own
vn_reference_op_s structure. */
! break;
case MISALIGNED_INDIRECT_REF:
temp.op0 = TREE_OPERAND (ref, 1);
+ temp.off = 0;
break;
case MEM_REF:
/* The base address gets its own vn_reference_op_s structure. */
temp.op0 = TREE_OPERAND (ref, 1);
+ if (host_integerp (TREE_OPERAND (ref, 1), 0))
+ temp.off = TREE_INT_CST_LOW (TREE_OPERAND (ref, 1));
break;
case BIT_FIELD_REF:
/* Record bits and position. */
*************** copy_reference_ops_from_ref (tree ref, V
*** 561,566 ****
--- 639,663 ----
&& integer_zerop (DECL_FIELD_BIT_OFFSET (temp.op0))
&& host_integerp (DECL_SIZE (temp.op0), 0))
temp.op0 = DECL_SIZE (temp.op0);
+ {
+ tree this_offset = component_ref_field_offset (ref);
+ if (this_offset
+ && TREE_CODE (this_offset) == INTEGER_CST)
+ {
+ tree bit_offset = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1));
+ if (TREE_INT_CST_LOW (bit_offset) % BITS_PER_UNIT == 0)
+ {
+ double_int off
+ = double_int_add (tree_to_double_int (this_offset),
+ double_int_sdiv
+ (tree_to_double_int (bit_offset),
+ uhwi_to_double_int (BITS_PER_UNIT),
+ TRUNC_DIV_EXPR));
+ if (double_int_fits_in_shwi_p (off))
+ temp.off = off.low;
+ }
+ }
+ }
break;
case ARRAY_RANGE_REF:
case ARRAY_REF:
*************** copy_reference_ops_from_ref (tree ref, V
*** 569,574 ****
--- 666,683 ----
/* Always record lower bounds and element size. */
temp.op1 = array_ref_low_bound (ref);
temp.op2 = array_ref_element_size (ref);
+ if (TREE_CODE (temp.op0) == INTEGER_CST
+ && TREE_CODE (temp.op1) == INTEGER_CST
+ && TREE_CODE (temp.op2) == INTEGER_CST)
+ {
+ double_int off = tree_to_double_int (temp.op0);
+ off = double_int_add (off,
+ double_int_neg
+ (tree_to_double_int (temp.op1)));
+ off = double_int_mul (off, tree_to_double_int (temp.op2));
+ if (double_int_fits_in_shwi_p (off))
+ temp.off = off.low;
+ }
break;
case STRING_CST:
case INTEGER_CST:
*************** copy_reference_ops_from_ref (tree ref, V
*** 595,603 ****
ref in the chain of references (IE they require an
operand), so we don't have to put anything
for op* as it will be handled by the iteration */
- case IMAGPART_EXPR:
case REALPART_EXPR:
case VIEW_CONVERT_EXPR:
break;
default:
gcc_unreachable ();
--- 704,716 ----
ref in the chain of references (IE they require an
operand), so we don't have to put anything
for op* as it will be handled by the iteration */
case REALPART_EXPR:
case VIEW_CONVERT_EXPR:
+ temp.off = 0;
+ break;
+ case IMAGPART_EXPR:
+ /* This is only interesting for its constant offset. */
+ temp.off = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (ref)));
break;
default:
gcc_unreachable ();
*************** copy_reference_ops_from_call (gimple cal
*** 798,803 ****
--- 911,917 ----
temp.opcode = CALL_EXPR;
temp.op0 = gimple_call_fn (call);
temp.op1 = gimple_call_chain (call);
+ temp.off = -1;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
/* Copy the call arguments. As they can be references as well,
Index: gcc/tree-ssa-sccvn.h
===================================================================
*** gcc/tree-ssa-sccvn.h (revision 160753)
--- gcc/tree-ssa-sccvn.h (working copy)
*************** typedef const struct vn_phi_s *const_vn_
*** 72,77 ****
--- 72,79 ----
typedef struct vn_reference_op_struct
{
enum tree_code opcode;
+ /* Constant offset this op adds or -1 if it is variable. */
+ HOST_WIDE_INT off;
tree type;
tree op0;
tree op1;
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c (revision 160753)
--- gcc/tree-ssa-pre.c (working copy)
*************** insert_into_preds_of_block (basic_block
*** 3332,3337 ****
--- 3332,3339 ----
avail[bprime->index] = get_or_alloc_expr_for_name (forcedexpr);
}
}
+ else
+ avail[bprime->index] = get_or_alloc_expr_for_constant (builtexpr);
}
}
else if (eprime->kind == NAME)
More information about the Gcc-patches
mailing list