[PATCH] Extend the middle-end type-system (aka useless_type_conversion_p) (2nd try)
Richard Guenther
rguenther@suse.de
Tue Aug 4 16:04:00 GMT 2009
This implements function and array type comparisons purely in the
middle-end without resorting to the types_compatible langhook.
Bootstrapped and tested on x86_64-unknown-linux-gnu. I'll leave it
for review for a couple of days and will install it if there are no
complaints.
Richard.
2009-08-04 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.
Index: gcc/tree-ssa.c
===================================================================
*** gcc/tree-ssa.c.orig 2009-08-04 14:55:45.000000000 +0200
--- gcc/tree-ssa.c 2009-08-04 15:55:29.000000000 +0200
*************** along with GCC; see the file COPYING3.
*** 26,31 ****
--- 26,32 ----
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
+ #include "target.h"
#include "ggc.h"
#include "langhooks.h"
#include "hard-reg-set.h"
*************** useless_type_conversion_p_1 (tree outer_
*** 871,878 ****
&& 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))
return false;
/* If both the inner and outer types are integral types, then the
--- 872,881 ----
&& 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
*************** useless_type_conversion_p_1 (tree outer_
*** 919,924 ****
--- 922,932 ----
&& 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))
*************** useless_type_conversion_p_1 (tree outer_
*** 948,980 ****
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))
{
! /* Different types of aggregates are incompatible. */
! if (TREE_CODE (inner_type) != TREE_CODE (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)
&& TYPE_DOMAIN (outer_type))
return false;
/* ??? 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;
}
--- 956,1084 ----
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 (!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);
}
return false;
}
Index: gcc/Makefile.in
===================================================================
*** gcc/Makefile.in.orig 2009-08-04 14:55:45.000000000 +0200
--- gcc/Makefile.in 2009-08-04 15:12:52.000000000 +0200
*************** tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $
*** 2193,2199 ****
$(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)
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) \
--- 2193,2199 ----
$(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) $(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) \
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig 2009-07-14 14:46:11.000000000 +0200
--- gcc/tree-ssa-sccvn.c 2009-08-04 16:41:51.000000000 +0200
*************** copy_reference_ops_from_ref (tree ref, V
*** 561,578 ****
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);
break;
case STRING_CST:
case INTEGER_CST:
--- 561,569 ----
case ARRAY_REF:
/* Record index as operand. */
temp.op0 = TREE_OPERAND (ref, 1);
! /* 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:
*************** ao_ref_init_from_vn_reference (ao_ref *r
*** 731,749 ****
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))
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));
offset += hindex;
}
break;
--- 722,738 ----
case ARRAY_RANGE_REF:
case ARRAY_REF:
! /* 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);
! hindex -= TREE_INT_CST_LOW (op->op1);
! hindex *= TREE_INT_CST_LOW (op->op2);
! hindex *= BITS_PER_UNIT;
offset += hindex;
}
break;
*************** vn_reference_fold_indirect (VEC (vn_refe
*** 863,870 ****
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;
VEC_safe_push (vn_reference_op_s, heap, mem, &aref);
}
copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
--- 852,859 ----
if ((dom = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (op->op0, 0))))
&& TYPE_MIN_VALUE (dom))
aref.op0 = TYPE_MIN_VALUE (dom);
! 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);
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig 2009-08-03 10:48:42.000000000 +0200
--- gcc/tree-ssa-pre.c 2009-08-04 16:32:48.000000000 +0200
*************** phi_translate_1 (pre_expr expr, bitmap_s
*** 1600,1605 ****
--- 1600,1608 ----
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)
{
*************** phi_translate_1 (pre_expr expr, bitmap_s
*** 1617,1622 ****
--- 1620,1628 ----
else if (!opresult)
break;
}
+ /* We can't possibly insert these. */
+ else if (op2 && !is_gimple_min_invariant (op2))
+ break;
changed |= op2 != oldop2;
if (!newoperands)
*************** create_component_ref_by_pieces_1 (basic_
*** 2742,2748 ****
pre_expr op1expr;
tree genop2 = currop->op1;
pre_expr op2expr;
! tree genop3;
genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt);
if (!genop0)
--- 2748,2755 ----
pre_expr op1expr;
tree genop2 = currop->op1;
pre_expr op2expr;
! tree genop3 = currop->op2;
! pre_expr op3expr;
genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt);
if (!genop0)
*************** create_component_ref_by_pieces_1 (basic_
*** 2759,2766 ****
if (!genop2)
return NULL_TREE;
}
!
! genop3 = currop->op2;
return build4 (currop->opcode, currop->type, genop0, genop1,
genop2, genop3);
}
--- 2766,2782 ----
if (!genop2)
return NULL_TREE;
}
! 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);
}
More information about the Gcc-patches
mailing list