diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-08-06 11:31:20 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-08-06 11:31:20 +0000 |
commit | 9fa672189b407b95f332b4701d6679f9babca98c (patch) | |
tree | c86db63d8e19ae44aa8456ce2c320f63e0d91839 /gcc | |
parent | e2a00a1652571360504067a525f393cfc63772f6 (diff) | |
download | gcc-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/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-pre.c | 22 | ||||
-rw-r--r-- | gcc/tree-ssa-sccvn.c | 35 | ||||
-rw-r--r-- | gcc/tree-ssa.c | 134 |
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; } |