gimple-ssa-isolate-paths.c (check_loadstore): New function.

* gimple-ssa-isolate-paths.c (check_loadstore): New function.
	(insert_trap_and_remove_trailing_statements): New argument OP which
	is the NULL pointer.  Emit the trap after the load/store through
	the NULL pointer.  Simplify the RHS of a store through a NULL pointer
	when trivial to do so.
	(isolate_path): Corresponding changes.
	(gimple_ssa_isolate_erroneous_path): Likewise.

	* gcc.dg/tree-ssa/isolate-1.c: Update expected output.
	* gcc.dg/tree-ssa/isolate-5.c: New test.

From-SVN: r204708
This commit is contained in:
Jeff Law 2013-11-12 09:41:51 -07:00 committed by Jeff Law
parent eb4b92c13b
commit 6ab7a3d7c4
5 changed files with 142 additions and 15 deletions

View File

@ -1,3 +1,13 @@
2013-11-12 Jeff Law <law@redhat.com>
* gimple-ssa-isolate-paths.c (check_loadstore): New function.
(insert_trap_and_remove_trailing_statements): New argument OP which
is the NULL pointer. Emit the trap after the load/store through
the NULL pointer. Simplify the RHS of a store through a NULL pointer
when trivial to do so.
(isolate_path): Corresponding changes.
(gimple_ssa_isolate_erroneous_path): Likewise.
2013-11-12 Teresa Johnson <tejohnson@google.com>
Jan Hubicka <jh@suse.cz>

View File

@ -39,17 +39,65 @@ along with GCC; see the file COPYING3. If not see
static bool cfg_altered;
/* Insert a trap before SI and remove SI and all statements after SI. */
/* Callback for walk_stmt_load_store_ops.
Return TRUE if OP will dereference the tree stored in DATA, FALSE
otherwise.
This routine only makes a superficial check for a dereference. Thus,
it must only be used if it is safe to return a false negative. */
static bool
check_loadstore (gimple stmt ATTRIBUTE_UNUSED, tree op, void *data)
{
if ((TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF)
&& operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
return true;
return false;
}
/* Insert a trap after SI and remove SI and all statements after the trap. */
static void
insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p)
insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p, tree op)
{
gimple_seq seq = NULL;
gimple stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
gimple_seq_add_stmt (&seq, stmt);
gsi_insert_before (si_p, seq, GSI_SAME_STMT);
/* We want the NULL pointer dereference to actually occur so that
code that wishes to catch the signal can do so.
/* Now delete all remaining statements in this block. */
If the dereference is a load, then there's nothing to do as the
LHS will be a throw-away SSA_NAME and the LHS is the NULL dereference.
If the dereference is a store and we can easily transform the RHS,
then simplify the RHS to enable more DCE. */
gimple stmt = gsi_stmt (*si_p);
if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
&& INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
{
/* We just need to turn the RHS into zero converted to the proper
type. */
tree type = TREE_TYPE (gimple_assign_lhs (stmt));
gimple_assign_set_rhs_code (stmt, INTEGER_CST);
gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
update_stmt (stmt);
}
gimple new_stmt
= gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
gimple_seq seq = NULL;
gimple_seq_add_stmt (&seq, new_stmt);
/* If we had a NULL pointer dereference, then we want to insert the
__builtin_trap after the statement, for the other cases we want
to insert before the statement. */
if (walk_stmt_load_store_ops (stmt, (void *)op,
check_loadstore,
check_loadstore))
gsi_insert_after (si_p, seq, GSI_NEW_STMT);
else
gsi_insert_before (si_p, seq, GSI_NEW_STMT);
/* The iterator points to the __builtin_trap. Advance the iterator
and delete everything else in the block. */
gsi_next (si_p);
for (; !gsi_end_p (*si_p);)
{
stmt = gsi_stmt (*si_p);
@ -73,7 +121,8 @@ insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p)
Return BB'. */
basic_block
isolate_path (basic_block bb, basic_block duplicate, edge e, gimple stmt)
isolate_path (basic_block bb, basic_block duplicate,
edge e, gimple stmt, tree op)
{
gimple_stmt_iterator si, si2;
edge_iterator ei;
@ -133,7 +182,7 @@ isolate_path (basic_block bb, basic_block duplicate, edge e, gimple stmt)
SI2 points to the duplicate of STMT in DUPLICATE. Insert a trap
before SI2 and remove SI2 and all trailing statements. */
if (!gsi_end_p (si2))
insert_trap_and_remove_trailing_statements (&si2);
insert_trap_and_remove_trailing_statements (&si2, op);
return duplicate;
}
@ -224,7 +273,7 @@ gimple_ssa_isolate_erroneous_paths (void)
if (infer_nonnull_range (use_stmt, lhs))
{
duplicate = isolate_path (bb, duplicate,
e, use_stmt);
e, use_stmt, lhs);
/* When we remove an incoming edge, we need to
reprocess the Ith element. */
@ -247,7 +296,8 @@ gimple_ssa_isolate_erroneous_paths (void)
where a non-NULL value is required. */
if (infer_nonnull_range (stmt, null_pointer_node))
{
insert_trap_and_remove_trailing_statements (&si);
insert_trap_and_remove_trailing_statements (&si,
null_pointer_node);
/* And finally, remove all outgoing edges from BB. */
edge e;

View File

@ -1,3 +1,8 @@
2013-11-12 Jeff Law <law@redhat.com>
* gcc.dg/tree-ssa/isolate-1.c: Update expected output.
* gcc.dg/tree-ssa/isolate-5.c: New test.
2013-11-12 Martin Jambor <mjambor@suse.cz>
PR rtl-optimization/10474
@ -389,7 +394,7 @@
PR fortran/58989
* gfortran.dg/reshape_6.f90: New test.
2013-10-05 Jeff Law <law@redhat.com>
2013-11-05 Jeff Law <law@redhat.com>
* gcc.dg/pr38984.c: Add -fno-isolate-erroneous-paths.
* gcc.dg/tree-ssa/isolate-1.c: New test.

View File

@ -43,12 +43,14 @@ d_type (struct d_info *di)
return ret;
}
/* We're testing two aspects of isolation here. First that isolation
/* We're testing three aspects of isolation here. First that isolation
occurs, second that if we have two null dereferences in a block that
that we delete everything from the first dereferece to the end of the
block, regardless of which comes first in the immediate use iterator. */
block, regardless of which comes first in the immediate use iterator
and finally that we set the RHS of the store to zero. */
/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
/* { dg-final { scan-tree-dump-times "->type" 1 "isolate-paths"} } */
/* { dg-final { scan-tree-dump-times "->type = 42" 1 "isolate-paths"} } */
/* { dg-final { scan-tree-dump-times "->type = 0" 1 "isolate-paths"} } */
/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
/* { dg-final { cleanup-tree-dump "isolate-paths" } } */

View File

@ -0,0 +1,60 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
struct demangle_component
{
int type;
int zzz;
};
struct d_info
{
struct demangle_component *comps;
int next_comp;
int num_comps;
};
static struct demangle_component *
d_make_empty (struct d_info *di)
{
struct demangle_component *p;
if (di->next_comp >= di->num_comps)
return ((void *)0);
p = &di->comps[di->next_comp];
return p;
}
struct demangle_component *
d_type (struct d_info *di)
{
struct demangle_component *ret;
ret = d_make_empty (di);
foo (ret->type);
bar (ret->zzz);
return ret;
}
/* We're testing two aspects of isolation here. First that isolation
occurs, second that if we have two null dereferences in a block that
that we delete everything from the first dereferece to the end of the
block, regardless of which comes first in the immediate use iterator.
We leave the 0->type in the IL, so expect to see ->type twice. */
/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
/* { dg-final { scan-tree-dump-times "->type" 2 "isolate-paths"} } */
/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
/* { dg-final { cleanup-tree-dump "isolate-paths" } } */