summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-08-06 11:31:20 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-08-06 11:31:20 +0000
commit9fa672189b407b95f332b4701d6679f9babca98c (patch)
treec86db63d8e19ae44aa8456ce2c320f63e0d91839 /gcc
parente2a00a1652571360504067a525f393cfc63772f6 (diff)
downloadgcc-9fa672189b407b95f332b4701d6679f9babca98c.tar.gz
2009-08-06 Richard Guenther <rguenther@suse.de>
* tree-ssa.c (useless_type_conversion_p_1): Make function and array type comparisons frontend independent. * Makefile.in (tree-ssa.o): Add $(TARGET_H) dependency. * tree-ssa-sccvn.c (copy_reference_ops_from_ref): Always fill out array reference lower bound and element size operands. (ao_ref_init_from_vn_reference): Properly compute the offset for ARRAY_RANGE_REF. (vn_reference_fold_indirect): Fill out array reference lower bound and element size operands. * tree-ssa-pre.c (phi_translate_1): Fail if we have to translate a non gimple valued reference operand which can happen for array reference lower bound or element size. (create_component_ref_by_pieces_1): Properly generate the element size operand for array references. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@150519 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/tree-ssa-pre.c22
-rw-r--r--gcc/tree-ssa-sccvn.c35
-rw-r--r--gcc/tree-ssa.c134
5 files changed, 168 insertions, 42 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2cd266e24d7..97626d63f72 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
2009-08-06 Richard Guenther <rguenther@suse.de>
+ * tree-ssa.c (useless_type_conversion_p_1): Make function and
+ array type comparisons frontend independent.
+ * Makefile.in (tree-ssa.o): Add $(TARGET_H) dependency.
+ * tree-ssa-sccvn.c (copy_reference_ops_from_ref): Always fill
+ out array reference lower bound and element size operands.
+ (ao_ref_init_from_vn_reference): Properly compute the offset
+ for ARRAY_RANGE_REF.
+ (vn_reference_fold_indirect): Fill out array reference lower
+ bound and element size operands.
+ * tree-ssa-pre.c (phi_translate_1): Fail if we have to translate
+ a non gimple valued reference operand which can happen for
+ array reference lower bound or element size.
+ (create_component_ref_by_pieces_1): Properly generate the
+ element size operand for array references.
+
+2009-08-06 Richard Guenther <rguenther@suse.de>
+
PR tree-optimization/40964
* tree.c (iterative_hash_host_wide_int): Export.
* tree.h (iterative_hash_host_wide_int): Declare.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index b43e6ee574f..4df47353b49 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2193,7 +2193,7 @@ tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(TOPLEV_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) langhooks.h $(TREE_PASS_H) $(BASIC_BLOCK_H) $(BITMAP_H) \
$(FLAGS_H) $(GGC_H) hard-reg-set.h $(HASHTAB_H) pointer-set.h \
- $(GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H)
+ $(GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H) $(TARGET_H)
tree-into-ssa.o : tree-into-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h $(DIAGNOSTIC_H) \
$(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 237c250a5f0..c09f3ae901e 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -1600,6 +1600,9 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
else if (!opresult)
break;
}
+ /* We can't possibly insert these. */
+ else if (op1 && !is_gimple_min_invariant (op1))
+ break;
changed |= op1 != oldop1;
if (op2 && TREE_CODE (op2) == SSA_NAME)
{
@@ -1617,6 +1620,9 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
else if (!opresult)
break;
}
+ /* We can't possibly insert these. */
+ else if (op2 && !is_gimple_min_invariant (op2))
+ break;
changed |= op2 != oldop2;
if (!newoperands)
@@ -2742,7 +2748,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
pre_expr op1expr;
tree genop2 = currop->op1;
pre_expr op2expr;
- tree genop3;
+ tree genop3 = currop->op2;
+ pre_expr op3expr;
genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt);
if (!genop0)
@@ -2759,8 +2766,17 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
if (!genop2)
return NULL_TREE;
}
-
- genop3 = currop->op2;
+ if (genop3)
+ {
+ tree elmt_type = TREE_TYPE (TREE_TYPE (genop0));
+ genop3 = size_binop (EXACT_DIV_EXPR, genop3,
+ size_int (TYPE_ALIGN_UNIT (elmt_type)));
+ op3expr = get_or_alloc_expr_for (genop3);
+ genop3 = find_or_generate_expression (block, op3expr, stmts,
+ domstmt);
+ if (!genop3)
+ return NULL_TREE;
+ }
return build4 (currop->opcode, currop->type, genop0, genop1,
genop2, genop3);
}
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 8557b0b07c9..3d814fc2e0b 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -561,18 +561,9 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
case ARRAY_REF:
/* Record index as operand. */
temp.op0 = TREE_OPERAND (ref, 1);
- /* Record even constant lower bounds. */
- if (TREE_OPERAND (ref, 2))
- temp.op1 = TREE_OPERAND (ref, 2);
- else
- {
- tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0)));
- if (domain
- && TYPE_MIN_VALUE (domain)
- && !integer_zerop (TYPE_MIN_VALUE (domain)))
- temp.op1 = TYPE_MIN_VALUE (domain);
- }
- temp.op2 = TREE_OPERAND (ref, 3);
+ /* Always record lower bounds and element size. */
+ temp.op1 = array_ref_low_bound (ref);
+ temp.op2 = array_ref_element_size (ref);
break;
case STRING_CST:
case INTEGER_CST:
@@ -731,19 +722,17 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
case ARRAY_RANGE_REF:
case ARRAY_REF:
- /* Same for ARRAY_REFs. We do not have access to the array
- type here, but we recorded the lower bound in op1. */
- if (op->op2
- || !host_integerp (op->op0, 0)
- || (op->op1 && !host_integerp (op->op1, 0))
- || !host_integerp (TYPE_SIZE (op->type), 1))
+ /* We recorded the lower bound and the element size. */
+ if (!host_integerp (op->op0, 0)
+ || !host_integerp (op->op1, 0)
+ || !host_integerp (op->op2, 0))
max_size = -1;
else
{
HOST_WIDE_INT hindex = TREE_INT_CST_LOW (op->op0);
- if (op->op1)
- hindex -= TREE_INT_CST_LOW (op->op1);
- hindex *= TREE_INT_CST_LOW (TYPE_SIZE (op->type));
+ hindex -= TREE_INT_CST_LOW (op->op1);
+ hindex *= TREE_INT_CST_LOW (op->op2);
+ hindex *= BITS_PER_UNIT;
offset += hindex;
}
break;
@@ -863,8 +852,8 @@ vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
if ((dom = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (op->op0, 0))))
&& TYPE_MIN_VALUE (dom))
aref.op0 = TYPE_MIN_VALUE (dom);
- aref.op1 = NULL_TREE;
- aref.op2 = NULL_TREE;
+ aref.op1 = aref.op0;
+ aref.op2 = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (op->op0)));
VEC_safe_push (vn_reference_op_s, heap, mem, &aref);
}
copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 28da94bb21c..0b4cc964ee7 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
+#include "target.h"
#include "ggc.h"
#include "langhooks.h"
#include "hard-reg-set.h"
@@ -871,8 +872,10 @@ useless_type_conversion_p_1 (tree outer_type, tree inner_type)
&& TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
return true;
- /* Changes in machine mode are never useless conversions. */
- if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type))
+ /* Changes in machine mode are never useless conversions unless we
+ deal with aggregate types in which case we defer to later checks. */
+ if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
+ && !AGGREGATE_TYPE_P (inner_type))
return false;
/* If both the inner and outer types are integral types, then the
@@ -919,6 +922,11 @@ useless_type_conversion_p_1 (tree outer_type, tree inner_type)
&& TYPE_VOLATILE (TREE_TYPE (outer_type)))
return false;
+ /* We require explicit conversions from incomplete target types. */
+ if (!COMPLETE_TYPE_P (TREE_TYPE (inner_type))
+ && COMPLETE_TYPE_P (TREE_TYPE (outer_type)))
+ return false;
+
/* Do not lose casts between pointers that when dereferenced access
memory with different alias sets. */
if (get_deref_alias_set (inner_type) != get_deref_alias_set (outer_type))
@@ -948,33 +956,129 @@ useless_type_conversion_p_1 (tree outer_type, tree inner_type)
return useless_type_conversion_p (TREE_TYPE (outer_type),
TREE_TYPE (inner_type));
- /* For aggregates we may need to fall back to structural equality
- checks. */
- else if (AGGREGATE_TYPE_P (inner_type)
- && AGGREGATE_TYPE_P (outer_type))
+ else if (TREE_CODE (inner_type) == ARRAY_TYPE
+ && TREE_CODE (outer_type) == ARRAY_TYPE)
{
- /* Different types of aggregates are incompatible. */
- if (TREE_CODE (inner_type) != TREE_CODE (outer_type))
+ /* Preserve string attributes. */
+ if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type))
return false;
/* Conversions from array types with unknown extent to
array types with known extent are not useless. */
- if (TREE_CODE (inner_type) == ARRAY_TYPE
- && !TYPE_DOMAIN (inner_type)
+ if (!TYPE_DOMAIN (inner_type)
&& TYPE_DOMAIN (outer_type))
return false;
+ /* Nor are conversions from array types with non-constant size to
+ array types with constant size or to different size. */
+ if (TYPE_SIZE (outer_type)
+ && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST
+ && (!TYPE_SIZE (inner_type)
+ || TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST
+ || !tree_int_cst_equal (TYPE_SIZE (outer_type),
+ TYPE_SIZE (inner_type))))
+ return false;
+
+ /* Check conversions between arrays with partially known extents.
+ If the array min/max values are constant they have to match.
+ Otherwise allow conversions to unknown and variable extents.
+ In particular this declares conversions that may change the
+ mode to BLKmode as useless. */
+ if (TYPE_DOMAIN (inner_type)
+ && TYPE_DOMAIN (outer_type)
+ && TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type))
+ {
+ tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type));
+ tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type));
+ tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type));
+ tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type));
+
+ /* After gimplification a variable min/max value carries no
+ additional information compared to a NULL value. All that
+ matters has been lowered to be part of the IL. */
+ if (inner_min && TREE_CODE (inner_min) != INTEGER_CST)
+ inner_min = NULL_TREE;
+ if (outer_min && TREE_CODE (outer_min) != INTEGER_CST)
+ outer_min = NULL_TREE;
+ if (inner_max && TREE_CODE (inner_max) != INTEGER_CST)
+ inner_max = NULL_TREE;
+ if (outer_max && TREE_CODE (outer_max) != INTEGER_CST)
+ outer_max = NULL_TREE;
+
+ /* Conversions NULL / variable <- cst are useless, but not
+ the other way around. */
+ if (outer_min
+ && (!inner_min
+ || !tree_int_cst_equal (inner_min, outer_min)))
+ return false;
+ if (outer_max
+ && (!inner_max
+ || !tree_int_cst_equal (inner_max, outer_max)))
+ return false;
+ }
+
+ /* Recurse on the element check. */
+ return useless_type_conversion_p (TREE_TYPE (outer_type),
+ TREE_TYPE (inner_type));
+ }
+
+ else if ((TREE_CODE (inner_type) == FUNCTION_TYPE
+ || TREE_CODE (inner_type) == METHOD_TYPE)
+ && TREE_CODE (inner_type) == TREE_CODE (outer_type))
+ {
+ tree outer_parm, inner_parm;
+
+ /* If the return types are not compatible bail out. */
+ if (!useless_type_conversion_p (TREE_TYPE (outer_type),
+ TREE_TYPE (inner_type)))
+ return false;
+
+ /* Method types should belong to a compatible base class. */
+ if (TREE_CODE (inner_type) == METHOD_TYPE
+ && !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type),
+ TYPE_METHOD_BASETYPE (inner_type)))
+ return false;
+
+ /* A conversion to an unprototyped argument list is ok. */
+ if (!TYPE_ARG_TYPES (outer_type))
+ return true;
+
+ /* If the argument types are compatible the conversion is useless. */
+ if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type))
+ return true;
+
+ for (outer_parm = TYPE_ARG_TYPES (outer_type),
+ inner_parm = TYPE_ARG_TYPES (inner_type);
+ outer_parm && inner_parm;
+ outer_parm = TREE_CHAIN (outer_parm),
+ inner_parm = TREE_CHAIN (inner_parm))
+ if (!useless_type_conversion_p (TREE_VALUE (outer_parm),
+ TREE_VALUE (inner_parm)))
+ return false;
+
+ /* If there is a mismatch in the number of arguments the functions
+ are not compatible. */
+ if (outer_parm || inner_parm)
+ return false;
+
+ /* Defer to the target if necessary. */
+ if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type))
+ return targetm.comp_type_attributes (outer_type, inner_type) != 0;
+
+ return true;
+ }
+
+ /* For aggregates we may need to fall back to structural equality
+ checks. */
+ else if (AGGREGATE_TYPE_P (inner_type)
+ && TREE_CODE (inner_type) == TREE_CODE (outer_type))
+ {
/* ??? This seems to be necessary even for aggregates that don't
have TYPE_STRUCTURAL_EQUALITY_P set. */
/* ??? This should eventually just return false. */
return lang_hooks.types_compatible_p (inner_type, outer_type);
}
- /* Also for functions and possibly other types with
- TYPE_STRUCTURAL_EQUALITY_P set. */
- else if (TYPE_STRUCTURAL_EQUALITY_P (inner_type)
- && TYPE_STRUCTURAL_EQUALITY_P (outer_type))
- return lang_hooks.types_compatible_p (inner_type, outer_type);
return false;
}