[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