summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa.c
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/tree-ssa.c
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/tree-ssa.c')
-rw-r--r--gcc/tree-ssa.c134
1 files changed, 119 insertions, 15 deletions
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;
}