This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Fix PR 13347
- From: Diego Novillo <dnovillo at redhat dot com>
- To: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 27 Feb 2004 07:40:42 -0500
- Subject: [tree-ssa] Fix PR 13347
- Organization: Red Hat Canada
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)) \