mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-08 09:50:38 +08:00
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
This commit is contained in:
parent
b92fbdd7b3
commit
e52201b680
@ -1,3 +1,20 @@
|
||||
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
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
134
gcc/tree-ssa.c
134
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user