This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tree-ssa] Fix PR 13347


Much like points-to analysis, SRA ought to be using STRIP_NOPS when
scalarizing structure assignments.  SRA was messing up with
reinterpret_cast<> and structure assignments.  The test case in the PR
does something like:

	fn_type_b g = reinterpret_cast<fn_type_b>(f);

which in GIMPLE is expressed as a type casted structure assignment:

	g = (struct fn_type_b)f;

Both g and f are scalarizable, but since SRA was using
STRIP_USELESS_TYPE_CONVERSION, the type cast was not being removed from
the RHS and SRA was proceeding to emit the scalarized assignments:

	g$__pfn = ((struct fn_type_b)f).__pfn;
	g$__delta = ((struct fn_type_b)f).__delta;

which is absolutely wrong because 'f' was also scalarized.  The right
output should be

	g$__pfn = f$__pfn;
	g$__delta = g$__delta;

STRIP_NOPS is safe in this case, because if a non-scalar type cast has
made it so far into the optimization pipeline, then the two structures
have to be compatible.  Changing SRA to use STRIP_NOPS fixes the PR and
causes no regressions on x86 and x86-64.

The patch also clarifies and reformats some comments in
tree_ssa_useless_type_conversion_1.


Diego.


	PR optimization/13347
	* tree-sra.c (scalarize_structure_assignment): Use STRIP_NOPS
	instead of STRIP_USELESS_TYPE_CONVERSION to remove type casts
	from RHS of the assignment.

	* tree-ssa.c (tree_ssa_useless_type_conversion_1): Reformat
	and rephrase comments.
	* tree.h (STRIP_USELESS_TYPE_CONVERSION): Reformat comment.


Index: tree-sra.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-sra.c,v
retrieving revision 1.1.2.23
diff -d -c -p -r1.1.2.23 tree-sra.c
*** tree-sra.c	26 Feb 2004 05:15:59 -0000	1.1.2.23
--- tree-sra.c	27 Feb 2004 11:21:54 -0000
*************** scalarize_structure_assignment (block_st
*** 445,452 ****
      abort ();
  #endif
  
!   /* Remove unnecessary casts from RHS.  */
!   STRIP_USELESS_TYPE_CONVERSION (rhs);
  
    lhs_ann = DECL_P (lhs) ? var_ann (lhs) : NULL;
    rhs_ann = DECL_P (rhs) ? var_ann (rhs) : NULL;
--- 445,468 ----
      abort ();
  #endif
  
!   /* Remove all type casts from RHS.  This may seem heavy handed but
!      it's actually safe and it is necessary in the presence of C++
!      reinterpret_cast<> where structure assignments of different
!      structures will be present in the IL.  This was the case of PR
!      13347 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13347) which
!      had something like this:
! 
! 	struct A f;
!      	struct B g;
! 	f = (struct A)g;
! 
!      Both 'f' and 'g' were scalarizable, but the presence of the type
!      cast was causing SRA to not replace the RHS of the assignment
!      with g's scalar replacements.  Furthermore, the fact that this
!      assignment reached this point without causing syntax errors means
!      that the type cast is safe and that a field-by-field assignment
!      from 'g' into 'f' is the right thing to do.  */
!   STRIP_NOPS (rhs);
  
    lhs_ann = DECL_P (lhs) ? var_ann (lhs) : NULL;
    rhs_ann = DECL_P (rhs) ? var_ann (rhs) : NULL;
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.206
diff -d -c -p -r1.1.4.206 tree-ssa.c
*** tree-ssa.c	26 Feb 2004 12:59:42 -0000	1.1.4.206
--- tree-ssa.c	27 Feb 2004 11:21:54 -0000
*************** get_def_blocks_for (tree var)
*** 3628,3633 ****
--- 3628,3635 ----
    dm.var = var;
    return (struct def_blocks_d *) htab_find (def_blocks, &dm);
  }
+ 
+ 
  /* Return true if EXPR is a useless type conversion, otherwise return
     false.  */
  
*************** tree_ssa_useless_type_conversion_1 (tree
*** 3641,3681 ****
        || TYPE_MAIN_VARIANT (inner_type) == TYPE_MAIN_VARIANT (outer_type))
      return true;
  
!   /* If the outer type is a (void *), then we can enter the
!      equivalence into the table.  The opposite is not true since
!      that conversion would result in a loss of information if
!      the equivalence was used.  Consider an indirect function call
!      where we need to know the exact type of the function to
!      correctly implement the ABI.  */
!   else if (POINTER_TYPE_P (inner_type) && POINTER_TYPE_P (outer_type)
  	   && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
      return true;
  
    /* Pointers and references are equivalent once we get to GENERIC,
       so strip conversions that just switch between them.  */
!   else if (POINTER_TYPE_P (inner_type) && POINTER_TYPE_P (outer_type)
  	   && (TYPE_MAIN_VARIANT (TREE_TYPE (inner_type))
  	       == TYPE_MAIN_VARIANT (TREE_TYPE (outer_type))))
      return true;
  
!   /* If both the inner and outer types are integral types, then
!      we can enter the equivalence if they have the same mode
!      and signedness and precision (The type _Bool can have size of 4
!      (only happens on powerpc-darwin right now but can happen on any 
       target that defines BOOL_TYPE_SIZE to be INT_TYPE_SIZE) and a
!      precision of 1 while unsigned int is the same expect for a 
!      precision of 4 so testing of precision is necessary).  */
!   else if (INTEGRAL_TYPE_P (inner_type) && INTEGRAL_TYPE_P (outer_type)
  	   && TYPE_MODE (inner_type) == TYPE_MODE (outer_type)
  	   && TREE_UNSIGNED (inner_type) == TREE_UNSIGNED (outer_type)
  	   && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
      return true;
    /* Recurse for complex types.  */
    else if (TREE_CODE (inner_type) == COMPLEX_TYPE
  	   && TREE_CODE (outer_type) == COMPLEX_TYPE
  	   && tree_ssa_useless_type_conversion_1 (TREE_TYPE (outer_type),
  						  TREE_TYPE (inner_type)))
      return true;
    return false;
  }
  
--- 3643,3688 ----
        || TYPE_MAIN_VARIANT (inner_type) == TYPE_MAIN_VARIANT (outer_type))
      return true;
  
!   /* If both types are pointers and the outer type is a (void *), then
!      the conversion is not necessary.  The opposite is not true since
!      that conversion would result in a loss of information if the
!      equivalence was used.  Consider an indirect function call where
!      we need to know the exact type of the function to correctly
!      implement the ABI.  */
!   else if (POINTER_TYPE_P (inner_type)
!            && POINTER_TYPE_P (outer_type)
  	   && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
      return true;
  
    /* Pointers and references are equivalent once we get to GENERIC,
       so strip conversions that just switch between them.  */
!   else if (POINTER_TYPE_P (inner_type)
!            && POINTER_TYPE_P (outer_type)
  	   && (TYPE_MAIN_VARIANT (TREE_TYPE (inner_type))
  	       == TYPE_MAIN_VARIANT (TREE_TYPE (outer_type))))
      return true;
  
!   /* 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.  Note that type _Bool can have size of
!      4 (only happens on powerpc-darwin right now but can happen on any
       target that defines BOOL_TYPE_SIZE to be INT_TYPE_SIZE) and a
!      precision of 1 while unsigned int is the same expect for a
!      precision of 4 so testing of precision is necessary.  */
!   else if (INTEGRAL_TYPE_P (inner_type)
!            && INTEGRAL_TYPE_P (outer_type)
  	   && TYPE_MODE (inner_type) == TYPE_MODE (outer_type)
  	   && TREE_UNSIGNED (inner_type) == TREE_UNSIGNED (outer_type)
  	   && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
      return true;
+ 
    /* Recurse for complex types.  */
    else if (TREE_CODE (inner_type) == COMPLEX_TYPE
  	   && TREE_CODE (outer_type) == COMPLEX_TYPE
  	   && tree_ssa_useless_type_conversion_1 (TREE_TYPE (outer_type),
  						  TREE_TYPE (inner_type)))
      return true;
+ 
    return false;
  }
  
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.173
diff -d -c -p -r1.342.2.173 tree.h
*** tree.h	24 Feb 2004 09:25:32 -0000	1.342.2.173
--- tree.h	27 Feb 2004 11:21:55 -0000
*************** extern void tree_operand_check_failed (i
*** 514,520 ****
  	     == TREE_TYPE (TREE_OPERAND (EXP, 0))))		\
      (EXP) = TREE_OPERAND (EXP, 0)
  
! /* Remove unnecessary type conversions according to tree_ssa_useless_type_conversion.  */
  
  #define STRIP_USELESS_TYPE_CONVERSION(EXP)				\
        while (tree_ssa_useless_type_conversion (EXP))			\
--- 514,521 ----
  	     == TREE_TYPE (TREE_OPERAND (EXP, 0))))		\
      (EXP) = TREE_OPERAND (EXP, 0)
  
! /* Remove unnecessary type conversions according to
!    tree_ssa_useless_type_conversion.  */
  
  #define STRIP_USELESS_TYPE_CONVERSION(EXP)				\
        while (tree_ssa_useless_type_conversion (EXP))			\



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]