aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple.c
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2013-09-12 13:03:18 +0000
committerAndrew Macleod <amacleod@gcc.gnu.org>2013-09-12 13:03:18 +0000
commit7a300452804d7f1d6f71d9cba31c5476ab2f2766 (patch)
tree7595bbd037949c5a99e1f26512698945a837ee12 /gcc/gimple.c
parent33605886ff20aeffb08529e2d571fff5483e650e (diff)
downloadgcc-7a300452804d7f1d6f71d9cba31c5476ab2f2766.zip
gcc-7a300452804d7f1d6f71d9cba31c5476ab2f2766.tar.gz
gcc-7a300452804d7f1d6f71d9cba31c5476ab2f2766.tar.bz2
tree-ssa.h: New.
* tree-ssa.h: New. Move content from tree-flow.h and tree-flow-inline.h. * tree-flow.h (_edge_var_map, edge_var_map_vector): Move to tree-ssa.h. Move prototypes belonging to tree-ssa.c. * tree-flow-inline.h (redirect_edge_var_map_def, redirect_edge_var_map_result, redirect_edge_var_map_location): Move to tree-ssa.h. * gimple.h: Adjust prototypes. * tree-ssa.c (useless_type_conversion_p, types_compatible_p): Move to... * gimple.c (useless_type_conversion_p, types_compatible_p): Here. * tree.h: Move prototype to tree-ssa.h. * gengtype.c (open_base_files): Replace tree-flow.h with tree-ssa.h. * Makefile.in: (TREE_SSA_H, TREE_FLOW_H): Adjust dependencies. * alias.c, asan.c, builtins.c, calls.c, cfgexpand.c, cfghooks.c, cfgloop.c, cfgloopmanip.c, cgraph.c, cgraphbuild.c, cgraphclones.c, cgraphunit.c, dse.c, except.c, expr.c, final.c, fold-const.c, ggc-page.c, gimple-fold.c, gimple-iterator.c, gimple-low.c, gimple-pretty-print.c, gimple-ssa-strength-reduction.c, gimple-streamer-in.c, gimple-streamer-out.c, gimple.c, gimplify.c, graphite-blocking.c, graphite-clast-to-gimple.c, graphite-dependences.c, graphite-interchange.c, graphite-optimize-isl.c, graphite-poly.c, graphite-scop-detection.c, graphite-sese-to-poly.c, graphite.c, ipa-cp.c, ipa-inline-analysis.c, ipa-inline-transform.c, ipa-inline.c, ipa-prop.c, ipa-pure-const.c, ipa-reference.c, ipa-split.c, ipa-utils.c, loop-init.c, lto-cgraph.c, lto-section-in.c, lto-section-out.c, lto-streamer-in.c, lto-streamer-out.c, lto-streamer.c, omp-low.c, passes.c, predict.c, print-tree.c, profile.c, sese.c, targhooks.c, tracer.c, trans-mem.c, tree-call-cdce.c, tree-cfg.c, tree-cfgcleanup.c, tree-chrec.c, tree-complex.c, tree-data-ref.c, tree-dfa.c, tree-eh.c, tree-emutls.c, tree-if-conv.c, tree-inline.c, tree-into-ssa.c, tree-loop-distribution.c, tree-mudflap.c, tree-nested.c, tree-nrv.c, tree-object-size.c, tree-optimize.c, tree-outof-ssa.c, tree-parloops.c, tree-phinodes.c, tree-predcom.c, tree-pretty-print.c, tree-profile.c, tree-scalar-evolution.c, tree-sra.c, tree-ssa*.c, tree-stdarg.c, tree-streamer-in.c, tree-switch-conversion.c, tree-tailcall.c, tree-vect-data-refs.c, tree-vect-generic.c, tree-vect-loop-manip.c, tree-vect-loop.c, tree-vect-patterns.c, tree-vect-slp.c, tree-vect-stmts.c, tree-vectorizer.c, tree-vrp.c, tsan.c, value-prof.c, var-tracking.c, varpool.c, vtable-verify.c: Replace tree-flow.h with tree-ssa.h From-SVN: r202523
Diffstat (limited to 'gcc/gimple.c')
-rw-r--r--gcc/gimple.c258
1 files changed, 257 insertions, 1 deletions
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 4dbcdda..59fcf43 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "basic-block.h"
#include "gimple.h"
#include "diagnostic.h"
-#include "tree-flow.h"
+#include "tree-ssa.h"
#include "value-prof.h"
#include "flags.h"
#include "alias.h"
@@ -4324,4 +4324,260 @@ build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
return build_type_cast (to_type, gimple_assign_lhs (op), mode);
}
+
+/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
+ useless type conversion, otherwise return false.
+
+ This function implicitly defines the middle-end type system. With
+ the notion of 'a < b' meaning that useless_type_conversion_p (a, b)
+ holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds,
+ the following invariants shall be fulfilled:
+
+ 1) useless_type_conversion_p is transitive.
+ If a < b and b < c then a < c.
+
+ 2) useless_type_conversion_p is not symmetric.
+ From a < b does not follow a > b.
+
+ 3) Types define the available set of operations applicable to values.
+ A type conversion is useless if the operations for the target type
+ is a subset of the operations for the source type. For example
+ casts to void* are useless, casts from void* are not (void* can't
+ be dereferenced or offsetted, but copied, hence its set of operations
+ is a strict subset of that of all other data pointer types). Casts
+ to const T* are useless (can't be written to), casts from const T*
+ to T* are not. */
+
+bool
+useless_type_conversion_p (tree outer_type, tree inner_type)
+{
+ /* Do the following before stripping toplevel qualifiers. */
+ if (POINTER_TYPE_P (inner_type)
+ && POINTER_TYPE_P (outer_type))
+ {
+ /* Do not lose casts between pointers to different address spaces. */
+ if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
+ != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
+ return false;
+ }
+
+ /* From now on qualifiers on value types do not matter. */
+ inner_type = TYPE_MAIN_VARIANT (inner_type);
+ outer_type = TYPE_MAIN_VARIANT (outer_type);
+
+ if (inner_type == outer_type)
+ return true;
+
+ /* If we know the canonical types, compare them. */
+ if (TYPE_CANONICAL (inner_type)
+ && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
+ return true;
+
+ /* 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
+ conversion is not necessary if they have the same mode and
+ signedness and precision, and both or neither are boolean. */
+ if (INTEGRAL_TYPE_P (inner_type)
+ && INTEGRAL_TYPE_P (outer_type))
+ {
+ /* Preserve changes in signedness or precision. */
+ if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
+ || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+ return false;
+
+ /* Preserve conversions to/from BOOLEAN_TYPE if types are not
+ of precision one. */
+ if (((TREE_CODE (inner_type) == BOOLEAN_TYPE)
+ != (TREE_CODE (outer_type) == BOOLEAN_TYPE))
+ && TYPE_PRECISION (outer_type) != 1)
+ return false;
+
+ /* We don't need to preserve changes in the types minimum or
+ maximum value in general as these do not generate code
+ unless the types precisions are different. */
+ return true;
+ }
+
+ /* Scalar floating point types with the same mode are compatible. */
+ else if (SCALAR_FLOAT_TYPE_P (inner_type)
+ && SCALAR_FLOAT_TYPE_P (outer_type))
+ return true;
+
+ /* Fixed point types with the same mode are compatible. */
+ else if (FIXED_POINT_TYPE_P (inner_type)
+ && FIXED_POINT_TYPE_P (outer_type))
+ return true;
+
+ /* We need to take special care recursing to pointed-to types. */
+ else if (POINTER_TYPE_P (inner_type)
+ && POINTER_TYPE_P (outer_type))
+ {
+ /* Do not lose casts to function pointer types. */
+ if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
+ && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
+ return false;
+
+ /* We do not care for const qualification of the pointed-to types
+ as const qualification has no semantic value to the middle-end. */
+
+ /* Otherwise pointers/references are equivalent. */
+ return true;
+ }
+
+ /* Recurse for complex types. */
+ else if (TREE_CODE (inner_type) == COMPLEX_TYPE
+ && TREE_CODE (outer_type) == COMPLEX_TYPE)
+ return useless_type_conversion_p (TREE_TYPE (outer_type),
+ TREE_TYPE (inner_type));
+
+ /* Recurse for vector types with the same number of subparts. */
+ else if (TREE_CODE (inner_type) == VECTOR_TYPE
+ && TREE_CODE (outer_type) == VECTOR_TYPE
+ && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
+ return useless_type_conversion_p (TREE_TYPE (outer_type),
+ TREE_TYPE (inner_type));
+
+ else if (TREE_CODE (inner_type) == ARRAY_TYPE
+ && TREE_CODE (outer_type) == ARRAY_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 (!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 (!prototype_p (outer_type))
+ return true;
+
+ /* If the unqualified 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
+ (TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)),
+ TYPE_MAIN_VARIANT (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 comp_type_attributes (outer_type, inner_type) != 0;
+
+ return true;
+ }
+
+ /* For aggregates we rely on TYPE_CANONICAL exclusively and require
+ explicit conversions for types involving to be structurally
+ compared types. */
+ else if (AGGREGATE_TYPE_P (inner_type)
+ && TREE_CODE (inner_type) == TREE_CODE (outer_type))
+ return false;
+
+ return false;
+}
+
+/* Return true if a conversion from either type of TYPE1 and TYPE2
+ to the other is not required. Otherwise return false. */
+
+bool
+types_compatible_p (tree type1, tree type2)
+{
+ return (type1 == type2
+ || (useless_type_conversion_p (type1, type2)
+ && useless_type_conversion_p (type2, type1)));
+}
+
+
#include "gt-gimple.h"