Commit 6ab7a3d7 by Jeff Law Committed by Jeff Law

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
parent eb4b92c1
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> 2013-11-12 Teresa Johnson <tejohnson@google.com>
Jan Hubicka <jh@suse.cz> Jan Hubicka <jh@suse.cz>
...@@ -39,17 +39,65 @@ along with GCC; see the file COPYING3. If not see ...@@ -39,17 +39,65 @@ along with GCC; see the file COPYING3. If not see
static bool cfg_altered; 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 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; /* We want the NULL pointer dereference to actually occur so that
gimple stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0); code that wishes to catch the signal can do so.
gimple_seq_add_stmt (&seq, stmt);
gsi_insert_before (si_p, seq, GSI_SAME_STMT);
/* 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);) for (; !gsi_end_p (*si_p);)
{ {
stmt = gsi_stmt (*si_p); stmt = gsi_stmt (*si_p);
...@@ -73,7 +121,8 @@ insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p) ...@@ -73,7 +121,8 @@ insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p)
Return BB'. */ Return BB'. */
basic_block 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; gimple_stmt_iterator si, si2;
edge_iterator ei; edge_iterator ei;
...@@ -133,7 +182,7 @@ isolate_path (basic_block bb, basic_block duplicate, edge e, gimple stmt) ...@@ -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 SI2 points to the duplicate of STMT in DUPLICATE. Insert a trap
before SI2 and remove SI2 and all trailing statements. */ before SI2 and remove SI2 and all trailing statements. */
if (!gsi_end_p (si2)) if (!gsi_end_p (si2))
insert_trap_and_remove_trailing_statements (&si2); insert_trap_and_remove_trailing_statements (&si2, op);
return duplicate; return duplicate;
} }
...@@ -224,7 +273,7 @@ gimple_ssa_isolate_erroneous_paths (void) ...@@ -224,7 +273,7 @@ gimple_ssa_isolate_erroneous_paths (void)
if (infer_nonnull_range (use_stmt, lhs)) if (infer_nonnull_range (use_stmt, lhs))
{ {
duplicate = isolate_path (bb, duplicate, duplicate = isolate_path (bb, duplicate,
e, use_stmt); e, use_stmt, lhs);
/* When we remove an incoming edge, we need to /* When we remove an incoming edge, we need to
reprocess the Ith element. */ reprocess the Ith element. */
...@@ -247,7 +296,8 @@ gimple_ssa_isolate_erroneous_paths (void) ...@@ -247,7 +296,8 @@ gimple_ssa_isolate_erroneous_paths (void)
where a non-NULL value is required. */ where a non-NULL value is required. */
if (infer_nonnull_range (stmt, null_pointer_node)) 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. */ /* And finally, remove all outgoing edges from BB. */
edge e; edge e;
......
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> 2013-11-12 Martin Jambor <mjambor@suse.cz>
PR rtl-optimization/10474 PR rtl-optimization/10474
...@@ -389,7 +394,7 @@ ...@@ -389,7 +394,7 @@
PR fortran/58989 PR fortran/58989
* gfortran.dg/reshape_6.f90: New test. * 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/pr38984.c: Add -fno-isolate-erroneous-paths.
* gcc.dg/tree-ssa/isolate-1.c: New test. * gcc.dg/tree-ssa/isolate-1.c: New test.
......
...@@ -43,12 +43,14 @@ d_type (struct d_info *di) ...@@ -43,12 +43,14 @@ d_type (struct d_info *di)
return ret; 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 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 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 "__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 { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
/* { dg-final { cleanup-tree-dump "isolate-paths" } } */ /* { dg-final { cleanup-tree-dump "isolate-paths" } } */
......
/* { 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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment