diff options
author | Richard Guenther <rguenther@suse.de> | 2009-08-06 11:31:20 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2009-08-06 11:31:20 +0000 |
commit | e52201b6803177a519fc6dfd36e247b33bea4bac (patch) | |
tree | c86db63d8e19ae44aa8456ce2c320f63e0d91839 /gcc/tree-ssa.c | |
parent | b92fbdd7b3eee74a74f97bf7bc74155186efa1be (diff) | |
download | gcc-e52201b6803177a519fc6dfd36e247b33bea4bac.zip gcc-e52201b6803177a519fc6dfd36e247b33bea4bac.tar.gz gcc-e52201b6803177a519fc6dfd36e247b33bea4bac.tar.bz2 |
tree-ssa.c (useless_type_conversion_p_1): Make function and array type comparisons frontend independent.
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.
From-SVN: r150519
Diffstat (limited to 'gcc/tree-ssa.c')
-rw-r--r-- | gcc/tree-ssa.c | 134 |
1 files changed, 119 insertions, 15 deletions
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 28da94b..0b4cc96 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; } |