xref: /dflybsd-src/contrib/gcc-8.0/gcc/gimple-ssa-isolate-paths.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Detect paths through the CFG which can never be executed in a conforming
238fd1498Szrj    program and isolate them.
338fd1498Szrj 
438fd1498Szrj    Copyright (C) 2013-2018 Free Software Foundation, Inc.
538fd1498Szrj 
638fd1498Szrj This file is part of GCC.
738fd1498Szrj 
838fd1498Szrj GCC is free software; you can redistribute it and/or modify
938fd1498Szrj it under the terms of the GNU General Public License as published by
1038fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
1138fd1498Szrj any later version.
1238fd1498Szrj 
1338fd1498Szrj GCC is distributed in the hope that it will be useful,
1438fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1538fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1638fd1498Szrj GNU General Public License for more details.
1738fd1498Szrj 
1838fd1498Szrj You should have received a copy of the GNU General Public License
1938fd1498Szrj along with GCC; see the file COPYING3.  If not see
2038fd1498Szrj <http://www.gnu.org/licenses/>.  */
2138fd1498Szrj 
2238fd1498Szrj #include "config.h"
2338fd1498Szrj #include "system.h"
2438fd1498Szrj #include "coretypes.h"
2538fd1498Szrj #include "backend.h"
2638fd1498Szrj #include "tree.h"
2738fd1498Szrj #include "gimple.h"
2838fd1498Szrj #include "cfghooks.h"
2938fd1498Szrj #include "tree-pass.h"
3038fd1498Szrj #include "ssa.h"
3138fd1498Szrj #include "diagnostic-core.h"
3238fd1498Szrj #include "fold-const.h"
3338fd1498Szrj #include "gimple-iterator.h"
3438fd1498Szrj #include "gimple-walk.h"
3538fd1498Szrj #include "tree-ssa.h"
3638fd1498Szrj #include "cfgloop.h"
3738fd1498Szrj #include "tree-cfg.h"
3838fd1498Szrj #include "cfganal.h"
3938fd1498Szrj #include "intl.h"
4038fd1498Szrj 
4138fd1498Szrj 
4238fd1498Szrj static bool cfg_altered;
4338fd1498Szrj 
4438fd1498Szrj /* Callback for walk_stmt_load_store_ops.
4538fd1498Szrj 
4638fd1498Szrj    Return TRUE if OP will dereference the tree stored in DATA, FALSE
4738fd1498Szrj    otherwise.
4838fd1498Szrj 
4938fd1498Szrj    This routine only makes a superficial check for a dereference.  Thus,
5038fd1498Szrj    it must only be used if it is safe to return a false negative.  */
5138fd1498Szrj static bool
check_loadstore(gimple * stmt,tree op,tree,void * data)5238fd1498Szrj check_loadstore (gimple *stmt, tree op, tree, void *data)
5338fd1498Szrj {
5438fd1498Szrj   if ((TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF)
5538fd1498Szrj       && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
5638fd1498Szrj     {
5738fd1498Szrj       TREE_THIS_VOLATILE (op) = 1;
5838fd1498Szrj       TREE_SIDE_EFFECTS (op) = 1;
5938fd1498Szrj       update_stmt (stmt);
6038fd1498Szrj       return true;
6138fd1498Szrj     }
6238fd1498Szrj   return false;
6338fd1498Szrj }
6438fd1498Szrj 
6538fd1498Szrj /* Insert a trap after SI and split the block after the trap.  */
6638fd1498Szrj 
6738fd1498Szrj static void
insert_trap(gimple_stmt_iterator * si_p,tree op)6838fd1498Szrj insert_trap (gimple_stmt_iterator *si_p, tree op)
6938fd1498Szrj {
7038fd1498Szrj   /* We want the NULL pointer dereference to actually occur so that
7138fd1498Szrj      code that wishes to catch the signal can do so.
7238fd1498Szrj 
7338fd1498Szrj      If the dereference is a load, then there's nothing to do as the
7438fd1498Szrj      LHS will be a throw-away SSA_NAME and the RHS is the NULL dereference.
7538fd1498Szrj 
7638fd1498Szrj      If the dereference is a store and we can easily transform the RHS,
7738fd1498Szrj      then simplify the RHS to enable more DCE.   Note that we require the
7838fd1498Szrj      statement to be a GIMPLE_ASSIGN which filters out calls on the RHS.  */
7938fd1498Szrj   gimple *stmt = gsi_stmt (*si_p);
8038fd1498Szrj   if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
8138fd1498Szrj       && is_gimple_assign (stmt)
8238fd1498Szrj       && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
8338fd1498Szrj     {
8438fd1498Szrj       /* We just need to turn the RHS into zero converted to the proper
8538fd1498Szrj          type.  */
8638fd1498Szrj       tree type = TREE_TYPE (gimple_assign_lhs (stmt));
8738fd1498Szrj       gimple_assign_set_rhs_code (stmt, INTEGER_CST);
8838fd1498Szrj       gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
8938fd1498Szrj       update_stmt (stmt);
9038fd1498Szrj     }
9138fd1498Szrj 
9238fd1498Szrj   gcall *new_stmt
9338fd1498Szrj     = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
9438fd1498Szrj   gimple_seq seq = NULL;
9538fd1498Szrj   gimple_seq_add_stmt (&seq, new_stmt);
9638fd1498Szrj 
9738fd1498Szrj   /* If we had a NULL pointer dereference, then we want to insert the
9838fd1498Szrj      __builtin_trap after the statement, for the other cases we want
9938fd1498Szrj      to insert before the statement.  */
10038fd1498Szrj   if (walk_stmt_load_store_ops (stmt, (void *)op,
10138fd1498Szrj 			        check_loadstore,
10238fd1498Szrj 				check_loadstore))
10338fd1498Szrj     {
10438fd1498Szrj       gsi_insert_after (si_p, seq, GSI_NEW_STMT);
10538fd1498Szrj       if (stmt_ends_bb_p (stmt))
10638fd1498Szrj 	{
10738fd1498Szrj 	  split_block (gimple_bb (stmt), stmt);
10838fd1498Szrj 	  return;
10938fd1498Szrj 	}
11038fd1498Szrj     }
11138fd1498Szrj   else
11238fd1498Szrj     gsi_insert_before (si_p, seq, GSI_NEW_STMT);
11338fd1498Szrj 
11438fd1498Szrj   split_block (gimple_bb (new_stmt), new_stmt);
11538fd1498Szrj   *si_p = gsi_for_stmt (stmt);
11638fd1498Szrj }
11738fd1498Szrj 
11838fd1498Szrj /* BB when reached via incoming edge E will exhibit undefined behavior
11938fd1498Szrj    at STMT.  Isolate and optimize the path which exhibits undefined
12038fd1498Szrj    behavior.
12138fd1498Szrj 
12238fd1498Szrj    Isolation is simple.  Duplicate BB and redirect E to BB'.
12338fd1498Szrj 
12438fd1498Szrj    Optimization is simple as well.  Replace STMT in BB' with an
12538fd1498Szrj    unconditional trap and remove all outgoing edges from BB'.
12638fd1498Szrj 
12738fd1498Szrj    If RET_ZERO, do not trap, only return NULL.
12838fd1498Szrj 
12938fd1498Szrj    DUPLICATE is a pre-existing duplicate, use it as BB' if it exists.
13038fd1498Szrj 
13138fd1498Szrj    Return BB'.  */
13238fd1498Szrj 
13338fd1498Szrj basic_block
isolate_path(basic_block bb,basic_block duplicate,edge e,gimple * stmt,tree op,bool ret_zero)13438fd1498Szrj isolate_path (basic_block bb, basic_block duplicate,
13538fd1498Szrj 	      edge e, gimple *stmt, tree op, bool ret_zero)
13638fd1498Szrj {
13738fd1498Szrj   gimple_stmt_iterator si, si2;
13838fd1498Szrj   edge_iterator ei;
13938fd1498Szrj   edge e2;
14038fd1498Szrj   bool impossible = true;
14138fd1498Szrj   profile_count count = e->count ();
14238fd1498Szrj 
14338fd1498Szrj   for (si = gsi_start_bb (bb); gsi_stmt (si) != stmt; gsi_next (&si))
14438fd1498Szrj     if (stmt_can_terminate_bb_p (gsi_stmt (si)))
14538fd1498Szrj       {
14638fd1498Szrj 	impossible = false;
14738fd1498Szrj 	break;
14838fd1498Szrj       }
14938fd1498Szrj   force_edge_cold (e, impossible);
15038fd1498Szrj 
15138fd1498Szrj   /* First duplicate BB if we have not done so already and remove all
15238fd1498Szrj      the duplicate's outgoing edges as duplicate is going to unconditionally
15338fd1498Szrj      trap.  Removing the outgoing edges is both an optimization and ensures
15438fd1498Szrj      we don't need to do any PHI node updates.  */
15538fd1498Szrj   if (!duplicate)
15638fd1498Szrj     {
15738fd1498Szrj       duplicate = duplicate_block (bb, NULL, NULL);
15838fd1498Szrj       duplicate->count = profile_count::zero ();
15938fd1498Szrj       if (!ret_zero)
16038fd1498Szrj 	for (ei = ei_start (duplicate->succs); (e2 = ei_safe_edge (ei)); )
16138fd1498Szrj 	  remove_edge (e2);
16238fd1498Szrj     }
16338fd1498Szrj   bb->count -= count;
16438fd1498Szrj 
16538fd1498Szrj   /* Complete the isolation step by redirecting E to reach DUPLICATE.  */
16638fd1498Szrj   e2 = redirect_edge_and_branch (e, duplicate);
16738fd1498Szrj   if (e2)
16838fd1498Szrj     {
16938fd1498Szrj       flush_pending_stmts (e2);
17038fd1498Szrj 
17138fd1498Szrj       /* Update profile only when redirection is really processed.  */
17238fd1498Szrj       bb->count += e->count ();
17338fd1498Szrj     }
17438fd1498Szrj 
17538fd1498Szrj   /* There may be more than one statement in DUPLICATE which exhibits
17638fd1498Szrj      undefined behavior.  Ultimately we want the first such statement in
17738fd1498Szrj      DUPLCIATE so that we're able to delete as much code as possible.
17838fd1498Szrj 
17938fd1498Szrj      So each time we discover undefined behavior in DUPLICATE, search for
18038fd1498Szrj      the statement which triggers undefined behavior.  If found, then
18138fd1498Szrj      transform the statement into a trap and delete everything after the
18238fd1498Szrj      statement.  If not found, then this particular instance was subsumed by
18338fd1498Szrj      an earlier instance of undefined behavior and there's nothing to do.
18438fd1498Szrj 
18538fd1498Szrj      This is made more complicated by the fact that we have STMT, which is in
18638fd1498Szrj      BB rather than in DUPLICATE.  So we set up two iterators, one for each
18738fd1498Szrj      block and walk forward looking for STMT in BB, advancing each iterator at
18838fd1498Szrj      each step.
18938fd1498Szrj 
19038fd1498Szrj      When we find STMT the second iterator should point to STMT's equivalent in
19138fd1498Szrj      duplicate.  If DUPLICATE ends before STMT is found in BB, then there's
19238fd1498Szrj      nothing to do.
19338fd1498Szrj 
19438fd1498Szrj      Ignore labels and debug statements.  */
19538fd1498Szrj   si = gsi_start_nondebug_after_labels_bb (bb);
19638fd1498Szrj   si2 = gsi_start_nondebug_after_labels_bb (duplicate);
19738fd1498Szrj   while (!gsi_end_p (si) && !gsi_end_p (si2) && gsi_stmt (si) != stmt)
19838fd1498Szrj     {
19938fd1498Szrj       gsi_next_nondebug (&si);
20038fd1498Szrj       gsi_next_nondebug (&si2);
20138fd1498Szrj     }
20238fd1498Szrj 
20338fd1498Szrj   /* This would be an indicator that we never found STMT in BB, which should
20438fd1498Szrj      never happen.  */
20538fd1498Szrj   gcc_assert (!gsi_end_p (si));
20638fd1498Szrj 
20738fd1498Szrj   /* If we did not run to the end of DUPLICATE, then SI points to STMT and
20838fd1498Szrj      SI2 points to the duplicate of STMT in DUPLICATE.  Insert a trap
20938fd1498Szrj      before SI2 and remove SI2 and all trailing statements.  */
21038fd1498Szrj   if (!gsi_end_p (si2))
21138fd1498Szrj     {
21238fd1498Szrj       if (ret_zero)
21338fd1498Szrj 	{
21438fd1498Szrj 	  greturn *ret = as_a <greturn *> (gsi_stmt (si2));
21538fd1498Szrj 	  tree zero = build_zero_cst (TREE_TYPE (gimple_return_retval (ret)));
21638fd1498Szrj 	  gimple_return_set_retval (ret, zero);
21738fd1498Szrj 	  update_stmt (ret);
21838fd1498Szrj 	}
21938fd1498Szrj       else
22038fd1498Szrj 	insert_trap (&si2, op);
22138fd1498Szrj     }
22238fd1498Szrj 
22338fd1498Szrj   return duplicate;
22438fd1498Szrj }
22538fd1498Szrj 
22638fd1498Szrj /* Return TRUE if STMT is a div/mod operation using DIVISOR as the divisor.
22738fd1498Szrj    FALSE otherwise.  */
22838fd1498Szrj 
22938fd1498Szrj static bool
is_divmod_with_given_divisor(gimple * stmt,tree divisor)23038fd1498Szrj is_divmod_with_given_divisor (gimple *stmt, tree divisor)
23138fd1498Szrj {
23238fd1498Szrj   /* Only assignments matter.  */
23338fd1498Szrj   if (!is_gimple_assign (stmt))
23438fd1498Szrj     return false;
23538fd1498Szrj 
23638fd1498Szrj   /* Check for every DIV/MOD expression.  */
23738fd1498Szrj   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
23838fd1498Szrj   if (rhs_code == TRUNC_DIV_EXPR
23938fd1498Szrj       || rhs_code == FLOOR_DIV_EXPR
24038fd1498Szrj       || rhs_code == CEIL_DIV_EXPR
24138fd1498Szrj       || rhs_code == EXACT_DIV_EXPR
24238fd1498Szrj       || rhs_code == ROUND_DIV_EXPR
24338fd1498Szrj       || rhs_code == TRUNC_MOD_EXPR
24438fd1498Szrj       || rhs_code == FLOOR_MOD_EXPR
24538fd1498Szrj       || rhs_code == CEIL_MOD_EXPR
24638fd1498Szrj       || rhs_code == ROUND_MOD_EXPR)
24738fd1498Szrj     {
24838fd1498Szrj       /* Pointer equality is fine when DIVISOR is an SSA_NAME, but
24938fd1498Szrj 	 not sufficient for constants which may have different types.  */
25038fd1498Szrj       if (operand_equal_p (gimple_assign_rhs2 (stmt), divisor, 0))
25138fd1498Szrj 	return true;
25238fd1498Szrj     }
25338fd1498Szrj   return false;
25438fd1498Szrj }
25538fd1498Szrj 
25638fd1498Szrj /* NAME is an SSA_NAME that we have already determined has the value 0 or NULL.
25738fd1498Szrj 
25838fd1498Szrj    Return TRUE if USE_STMT uses NAME in a way where a 0 or NULL value results
25938fd1498Szrj    in undefined behavior, FALSE otherwise
26038fd1498Szrj 
26138fd1498Szrj    LOC is used for issuing diagnostics.  This case represents potential
26238fd1498Szrj    undefined behavior exposed by path splitting and that's reflected in
26338fd1498Szrj    the diagnostic.  */
26438fd1498Szrj 
26538fd1498Szrj bool
stmt_uses_name_in_undefined_way(gimple * use_stmt,tree name,location_t loc)26638fd1498Szrj stmt_uses_name_in_undefined_way (gimple *use_stmt, tree name, location_t loc)
26738fd1498Szrj {
26838fd1498Szrj   /* If we are working with a non pointer type, then see
26938fd1498Szrj      if this use is a DIV/MOD operation using NAME as the
27038fd1498Szrj      divisor.  */
27138fd1498Szrj   if (!POINTER_TYPE_P (TREE_TYPE (name)))
27238fd1498Szrj     {
273*58e805e6Szrj       if (!cfun->can_throw_non_call_exceptions)
27438fd1498Szrj 	return is_divmod_with_given_divisor (use_stmt, name);
27538fd1498Szrj       return false;
27638fd1498Szrj     }
27738fd1498Szrj 
27838fd1498Szrj   /* NAME is a pointer, so see if it's used in a context where it must
27938fd1498Szrj      be non-NULL.  */
28038fd1498Szrj   bool by_dereference
28138fd1498Szrj     = infer_nonnull_range_by_dereference (use_stmt, name);
28238fd1498Szrj 
28338fd1498Szrj   if (by_dereference
28438fd1498Szrj       || infer_nonnull_range_by_attribute (use_stmt, name))
28538fd1498Szrj     {
28638fd1498Szrj 
28738fd1498Szrj       if (by_dereference)
28838fd1498Szrj 	{
28938fd1498Szrj 	  warning_at (loc, OPT_Wnull_dereference,
29038fd1498Szrj 		      "potential null pointer dereference");
29138fd1498Szrj 	  if (!flag_isolate_erroneous_paths_dereference)
29238fd1498Szrj 	    return false;
29338fd1498Szrj 	}
29438fd1498Szrj       else
29538fd1498Szrj 	{
29638fd1498Szrj 	  if (!flag_isolate_erroneous_paths_attribute)
29738fd1498Szrj 	    return false;
29838fd1498Szrj 	}
29938fd1498Szrj       return true;
30038fd1498Szrj     }
30138fd1498Szrj   return false;
30238fd1498Szrj }
30338fd1498Szrj 
30438fd1498Szrj /* Return TRUE if USE_STMT uses 0 or NULL in a context which results in
30538fd1498Szrj    undefined behavior, FALSE otherwise.
30638fd1498Szrj 
30738fd1498Szrj    These cases are explicit in the IL.  */
30838fd1498Szrj 
30938fd1498Szrj bool
stmt_uses_0_or_null_in_undefined_way(gimple * stmt)31038fd1498Szrj stmt_uses_0_or_null_in_undefined_way (gimple *stmt)
31138fd1498Szrj {
312*58e805e6Szrj   if (!cfun->can_throw_non_call_exceptions
31338fd1498Szrj       && is_divmod_with_given_divisor (stmt, integer_zero_node))
31438fd1498Szrj     return true;
31538fd1498Szrj 
31638fd1498Szrj   /* By passing null_pointer_node, we can use the
31738fd1498Szrj      infer_nonnull_range functions to detect explicit NULL
31838fd1498Szrj      pointer dereferences and other uses where a non-NULL
31938fd1498Szrj      value is required.  */
32038fd1498Szrj 
32138fd1498Szrj   bool by_dereference
32238fd1498Szrj     = infer_nonnull_range_by_dereference (stmt, null_pointer_node);
32338fd1498Szrj   if (by_dereference
32438fd1498Szrj       || infer_nonnull_range_by_attribute (stmt, null_pointer_node))
32538fd1498Szrj     {
32638fd1498Szrj       if (by_dereference)
32738fd1498Szrj 	{
32838fd1498Szrj 	  location_t loc = gimple_location (stmt);
32938fd1498Szrj 	  warning_at (loc, OPT_Wnull_dereference,
33038fd1498Szrj 		      "null pointer dereference");
33138fd1498Szrj 	  if (!flag_isolate_erroneous_paths_dereference)
33238fd1498Szrj 	    return false;
33338fd1498Szrj 	}
33438fd1498Szrj       else
33538fd1498Szrj 	{
33638fd1498Szrj 	  if (!flag_isolate_erroneous_paths_attribute)
33738fd1498Szrj 	    return false;
33838fd1498Szrj 	}
33938fd1498Szrj       return true;
34038fd1498Szrj     }
34138fd1498Szrj   return false;
34238fd1498Szrj }
34338fd1498Szrj 
34438fd1498Szrj /* Look for PHI nodes which feed statements in the same block where
34538fd1498Szrj    the value of the PHI node implies the statement is erroneous.
34638fd1498Szrj 
34738fd1498Szrj    For example, a NULL PHI arg value which then feeds a pointer
34838fd1498Szrj    dereference.
34938fd1498Szrj 
35038fd1498Szrj    When found isolate and optimize the path associated with the PHI
35138fd1498Szrj    argument feeding the erroneous statement.  */
35238fd1498Szrj static void
find_implicit_erroneous_behavior(void)35338fd1498Szrj find_implicit_erroneous_behavior (void)
35438fd1498Szrj {
35538fd1498Szrj   basic_block bb;
35638fd1498Szrj 
35738fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
35838fd1498Szrj     {
35938fd1498Szrj       gphi_iterator si;
36038fd1498Szrj 
36138fd1498Szrj       /* Out of an abundance of caution, do not isolate paths to a
36238fd1498Szrj 	 block where the block has any abnormal outgoing edges.
36338fd1498Szrj 
36438fd1498Szrj 	 We might be able to relax this in the future.  We have to detect
36538fd1498Szrj 	 when we have to split the block with the NULL dereference and
36638fd1498Szrj 	 the trap we insert.  We have to preserve abnormal edges out
36738fd1498Szrj 	 of the isolated block which in turn means updating PHIs at
36838fd1498Szrj 	 the targets of those abnormal outgoing edges.  */
36938fd1498Szrj       if (has_abnormal_or_eh_outgoing_edge_p (bb))
37038fd1498Szrj 	continue;
37138fd1498Szrj 
37238fd1498Szrj 
37338fd1498Szrj       /* If BB has an edge to itself, then duplication of BB below
37438fd1498Szrj 	 could result in reallocation of BB's PHI nodes.   If that happens
37538fd1498Szrj 	 then the loop below over the PHIs would use the old PHI and
37638fd1498Szrj 	 thus invalid information.  We don't have a good way to know
37738fd1498Szrj 	 if a PHI has been reallocated, so just avoid isolation in
37838fd1498Szrj 	 this case.  */
37938fd1498Szrj       if (find_edge (bb, bb))
38038fd1498Szrj 	continue;
38138fd1498Szrj 
38238fd1498Szrj       /* First look for a PHI which sets a pointer to NULL and which
38338fd1498Szrj  	 is then dereferenced within BB.  This is somewhat overly
38438fd1498Szrj 	 conservative, but probably catches most of the interesting
38538fd1498Szrj 	 cases.   */
38638fd1498Szrj       for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
38738fd1498Szrj 	{
38838fd1498Szrj 	  gphi *phi = si.phi ();
38938fd1498Szrj 	  tree lhs = gimple_phi_result (phi);
39038fd1498Szrj 
39138fd1498Szrj 	  /* PHI produces a pointer result.  See if any of the PHI's
39238fd1498Szrj 	     arguments are NULL.
39338fd1498Szrj 
39438fd1498Szrj 	     When we remove an edge, we want to reprocess the current
39538fd1498Szrj 	     index, hence the ugly way we update I for each iteration.  */
39638fd1498Szrj 	  basic_block duplicate = NULL;
39738fd1498Szrj 	  for (unsigned i = 0, next_i = 0;
39838fd1498Szrj 	       i < gimple_phi_num_args (phi);
39938fd1498Szrj 	       i = next_i)
40038fd1498Szrj 	    {
40138fd1498Szrj 	      tree op = gimple_phi_arg_def (phi, i);
40238fd1498Szrj 	      edge e = gimple_phi_arg_edge (phi, i);
40338fd1498Szrj 	      imm_use_iterator iter;
40438fd1498Szrj 	      gimple *use_stmt;
40538fd1498Szrj 
40638fd1498Szrj 	      next_i = i + 1;
40738fd1498Szrj 
40838fd1498Szrj 	      if (TREE_CODE (op) == ADDR_EXPR)
40938fd1498Szrj 		{
41038fd1498Szrj 		  tree valbase = get_base_address (TREE_OPERAND (op, 0));
41138fd1498Szrj 		  if ((VAR_P (valbase) && !is_global_var (valbase))
41238fd1498Szrj 		      || TREE_CODE (valbase) == PARM_DECL)
41338fd1498Szrj 		    {
41438fd1498Szrj 		      FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
41538fd1498Szrj 			{
41638fd1498Szrj 			  greturn *return_stmt
41738fd1498Szrj 			    = dyn_cast <greturn *> (use_stmt);
41838fd1498Szrj 			  if (!return_stmt)
41938fd1498Szrj 			    continue;
42038fd1498Szrj 
42138fd1498Szrj 			  if (gimple_return_retval (return_stmt) != lhs)
42238fd1498Szrj 			    continue;
42338fd1498Szrj 
42438fd1498Szrj 			  if (warning_at (gimple_location (use_stmt),
42538fd1498Szrj 					  OPT_Wreturn_local_addr,
42638fd1498Szrj 					  "function may return address "
42738fd1498Szrj 					  "of local variable"))
42838fd1498Szrj 			    inform (DECL_SOURCE_LOCATION(valbase),
42938fd1498Szrj 				    "declared here");
43038fd1498Szrj 
43138fd1498Szrj 			  if (gimple_bb (use_stmt) == bb)
43238fd1498Szrj 			    {
43338fd1498Szrj 			      duplicate = isolate_path (bb, duplicate, e,
43438fd1498Szrj 							use_stmt, lhs, true);
43538fd1498Szrj 
43638fd1498Szrj 			      /* When we remove an incoming edge, we need to
43738fd1498Szrj 				 reprocess the Ith element.  */
43838fd1498Szrj 			      next_i = i;
43938fd1498Szrj 			      cfg_altered = true;
44038fd1498Szrj 			    }
44138fd1498Szrj 			}
44238fd1498Szrj 		    }
44338fd1498Szrj 		}
44438fd1498Szrj 
44538fd1498Szrj 	      if (!integer_zerop (op))
44638fd1498Szrj 		continue;
44738fd1498Szrj 
44838fd1498Szrj 	      location_t phi_arg_loc = gimple_phi_arg_location (phi, i);
44938fd1498Szrj 
45038fd1498Szrj 	      /* We've got a NULL PHI argument.  Now see if the
45138fd1498Szrj  	         PHI's result is dereferenced within BB.  */
45238fd1498Szrj 	      FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
45338fd1498Szrj 	        {
45438fd1498Szrj 	          /* We only care about uses in BB.  Catching cases in
45538fd1498Szrj 		     in other blocks would require more complex path
45638fd1498Szrj 		     isolation code.   */
45738fd1498Szrj 		  if (gimple_bb (use_stmt) != bb)
45838fd1498Szrj 		    continue;
45938fd1498Szrj 
46038fd1498Szrj 		  location_t loc = gimple_location (use_stmt)
46138fd1498Szrj 		    ? gimple_location (use_stmt)
46238fd1498Szrj 		    : phi_arg_loc;
46338fd1498Szrj 
46438fd1498Szrj 		  if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
46538fd1498Szrj 		    {
46638fd1498Szrj 		      duplicate = isolate_path (bb, duplicate, e,
46738fd1498Szrj 						use_stmt, lhs, false);
46838fd1498Szrj 
46938fd1498Szrj 		      /* When we remove an incoming edge, we need to
47038fd1498Szrj 			 reprocess the Ith element.  */
47138fd1498Szrj 		      next_i = i;
47238fd1498Szrj 		      cfg_altered = true;
47338fd1498Szrj 		    }
47438fd1498Szrj 		}
47538fd1498Szrj 	    }
47638fd1498Szrj 	}
47738fd1498Szrj     }
47838fd1498Szrj }
47938fd1498Szrj 
48038fd1498Szrj /* Look for statements which exhibit erroneous behavior.  For example
48138fd1498Szrj    a NULL pointer dereference.
48238fd1498Szrj 
48338fd1498Szrj    When found, optimize the block containing the erroneous behavior.  */
48438fd1498Szrj static void
find_explicit_erroneous_behavior(void)48538fd1498Szrj find_explicit_erroneous_behavior (void)
48638fd1498Szrj {
48738fd1498Szrj   basic_block bb;
48838fd1498Szrj 
48938fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
49038fd1498Szrj     {
49138fd1498Szrj       gimple_stmt_iterator si;
49238fd1498Szrj 
49338fd1498Szrj       /* Out of an abundance of caution, do not isolate paths to a
49438fd1498Szrj 	 block where the block has any abnormal outgoing edges.
49538fd1498Szrj 
49638fd1498Szrj 	 We might be able to relax this in the future.  We have to detect
49738fd1498Szrj 	 when we have to split the block with the NULL dereference and
49838fd1498Szrj 	 the trap we insert.  We have to preserve abnormal edges out
49938fd1498Szrj 	 of the isolated block which in turn means updating PHIs at
50038fd1498Szrj 	 the targets of those abnormal outgoing edges.  */
50138fd1498Szrj       if (has_abnormal_or_eh_outgoing_edge_p (bb))
50238fd1498Szrj 	continue;
50338fd1498Szrj 
50438fd1498Szrj       /* Now look at the statements in the block and see if any of
50538fd1498Szrj 	 them explicitly dereference a NULL pointer.  This happens
50638fd1498Szrj 	 because of jump threading and constant propagation.  */
50738fd1498Szrj       for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
50838fd1498Szrj 	{
50938fd1498Szrj 	  gimple *stmt = gsi_stmt (si);
51038fd1498Szrj 
51138fd1498Szrj 	  if (stmt_uses_0_or_null_in_undefined_way (stmt))
51238fd1498Szrj 	    {
51338fd1498Szrj 	      insert_trap (&si, null_pointer_node);
51438fd1498Szrj 	      bb = gimple_bb (gsi_stmt (si));
51538fd1498Szrj 
51638fd1498Szrj 	      /* Ignore any more operands on this statement and
51738fd1498Szrj 		 continue the statement iterator (which should
51838fd1498Szrj 		 terminate its loop immediately.  */
51938fd1498Szrj 	      cfg_altered = true;
52038fd1498Szrj 	      break;
52138fd1498Szrj 	    }
52238fd1498Szrj 
52338fd1498Szrj 	  /* Detect returning the address of a local variable.  This only
52438fd1498Szrj 	     becomes undefined behavior if the result is used, so we do not
52538fd1498Szrj 	     insert a trap and only return NULL instead.  */
52638fd1498Szrj 	  if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
52738fd1498Szrj 	    {
52838fd1498Szrj 	      tree val = gimple_return_retval (return_stmt);
52938fd1498Szrj 	      if (val && TREE_CODE (val) == ADDR_EXPR)
53038fd1498Szrj 		{
53138fd1498Szrj 		  tree valbase = get_base_address (TREE_OPERAND (val, 0));
53238fd1498Szrj 		  if ((VAR_P (valbase) && !is_global_var (valbase))
53338fd1498Szrj 		      || TREE_CODE (valbase) == PARM_DECL)
53438fd1498Szrj 		    {
53538fd1498Szrj 		      /* We only need it for this particular case.  */
53638fd1498Szrj 		      calculate_dominance_info (CDI_POST_DOMINATORS);
53738fd1498Szrj 		      const char* msg;
53838fd1498Szrj 		      bool always_executed = dominated_by_p
53938fd1498Szrj 			(CDI_POST_DOMINATORS,
54038fd1498Szrj 			 single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)), bb);
54138fd1498Szrj 		      if (always_executed)
54238fd1498Szrj 			msg = N_("function returns address of local variable");
54338fd1498Szrj 		      else
54438fd1498Szrj 			msg = N_("function may return address of "
54538fd1498Szrj 				 "local variable");
54638fd1498Szrj 
54738fd1498Szrj 		      if (warning_at (gimple_location (stmt),
54838fd1498Szrj 				      OPT_Wreturn_local_addr, msg))
54938fd1498Szrj 			inform (DECL_SOURCE_LOCATION(valbase), "declared here");
55038fd1498Szrj 		      tree zero = build_zero_cst (TREE_TYPE (val));
55138fd1498Szrj 		      gimple_return_set_retval (return_stmt, zero);
55238fd1498Szrj 		      update_stmt (stmt);
55338fd1498Szrj 		    }
55438fd1498Szrj 		}
55538fd1498Szrj 	    }
55638fd1498Szrj 	}
55738fd1498Szrj     }
55838fd1498Szrj }
55938fd1498Szrj 
56038fd1498Szrj /* Search the function for statements which, if executed, would cause
56138fd1498Szrj    the program to fault such as a dereference of a NULL pointer.
56238fd1498Szrj 
56338fd1498Szrj    Such a program can't be valid if such a statement was to execute
56438fd1498Szrj    according to ISO standards.
56538fd1498Szrj 
56638fd1498Szrj    We detect explicit NULL pointer dereferences as well as those implied
56738fd1498Szrj    by a PHI argument having a NULL value which unconditionally flows into
56838fd1498Szrj    a dereference in the same block as the PHI.
56938fd1498Szrj 
57038fd1498Szrj    In the former case we replace the offending statement with an
57138fd1498Szrj    unconditional trap and eliminate the outgoing edges from the statement's
57238fd1498Szrj    basic block.  This may expose secondary optimization opportunities.
57338fd1498Szrj 
57438fd1498Szrj    In the latter case, we isolate the path(s) with the NULL PHI
57538fd1498Szrj    feeding the dereference.  We can then replace the offending statement
57638fd1498Szrj    and eliminate the outgoing edges in the duplicate.  Again, this may
57738fd1498Szrj    expose secondary optimization opportunities.
57838fd1498Szrj 
57938fd1498Szrj    A warning for both cases may be advisable as well.
58038fd1498Szrj 
58138fd1498Szrj    Other statically detectable violations of the ISO standard could be
58238fd1498Szrj    handled in a similar way, such as out-of-bounds array indexing.  */
58338fd1498Szrj 
58438fd1498Szrj static unsigned int
gimple_ssa_isolate_erroneous_paths(void)58538fd1498Szrj gimple_ssa_isolate_erroneous_paths (void)
58638fd1498Szrj {
58738fd1498Szrj   initialize_original_copy_tables ();
58838fd1498Szrj 
58938fd1498Szrj   /* Search all the blocks for edges which, if traversed, will
59038fd1498Szrj      result in undefined behavior.  */
59138fd1498Szrj   cfg_altered = false;
59238fd1498Szrj 
59338fd1498Szrj   /* First handle cases where traversal of a particular edge
59438fd1498Szrj      triggers undefined behavior.  These cases require creating
59538fd1498Szrj      duplicate blocks and thus new SSA_NAMEs.
59638fd1498Szrj 
59738fd1498Szrj      We want that process complete prior to the phase where we start
59838fd1498Szrj      removing edges from the CFG.  Edge removal may ultimately result in
59938fd1498Szrj      removal of PHI nodes and thus releasing SSA_NAMEs back to the
60038fd1498Szrj      name manager.
60138fd1498Szrj 
60238fd1498Szrj      If the two processes run in parallel we could release an SSA_NAME
60338fd1498Szrj      back to the manager but we could still have dangling references
60438fd1498Szrj      to the released SSA_NAME in unreachable blocks.
60538fd1498Szrj      that any released names not have dangling references in the IL.  */
60638fd1498Szrj   find_implicit_erroneous_behavior ();
60738fd1498Szrj   find_explicit_erroneous_behavior ();
60838fd1498Szrj 
60938fd1498Szrj   free_original_copy_tables ();
61038fd1498Szrj 
61138fd1498Szrj   /* We scramble the CFG and loop structures a bit, clean up
61238fd1498Szrj      appropriately.  We really should incrementally update the
61338fd1498Szrj      loop structures, in theory it shouldn't be that hard.  */
61438fd1498Szrj   free_dominance_info (CDI_POST_DOMINATORS);
61538fd1498Szrj   if (cfg_altered)
61638fd1498Szrj     {
61738fd1498Szrj       free_dominance_info (CDI_DOMINATORS);
61838fd1498Szrj       loops_state_set (LOOPS_NEED_FIXUP);
61938fd1498Szrj       return TODO_cleanup_cfg | TODO_update_ssa;
62038fd1498Szrj     }
62138fd1498Szrj   return 0;
62238fd1498Szrj }
62338fd1498Szrj 
62438fd1498Szrj namespace {
62538fd1498Szrj const pass_data pass_data_isolate_erroneous_paths =
62638fd1498Szrj {
62738fd1498Szrj   GIMPLE_PASS, /* type */
62838fd1498Szrj   "isolate-paths", /* name */
62938fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
63038fd1498Szrj   TV_ISOLATE_ERRONEOUS_PATHS, /* tv_id */
63138fd1498Szrj   ( PROP_cfg | PROP_ssa ), /* properties_required */
63238fd1498Szrj   0, /* properties_provided */
63338fd1498Szrj   0, /* properties_destroyed */
63438fd1498Szrj   0, /* todo_flags_start */
63538fd1498Szrj   0, /* todo_flags_finish */
63638fd1498Szrj };
63738fd1498Szrj 
63838fd1498Szrj class pass_isolate_erroneous_paths : public gimple_opt_pass
63938fd1498Szrj {
64038fd1498Szrj public:
pass_isolate_erroneous_paths(gcc::context * ctxt)64138fd1498Szrj   pass_isolate_erroneous_paths (gcc::context *ctxt)
64238fd1498Szrj     : gimple_opt_pass (pass_data_isolate_erroneous_paths, ctxt)
64338fd1498Szrj   {}
64438fd1498Szrj 
64538fd1498Szrj   /* opt_pass methods: */
clone()64638fd1498Szrj   opt_pass * clone () { return new pass_isolate_erroneous_paths (m_ctxt); }
gate(function *)64738fd1498Szrj   virtual bool gate (function *)
64838fd1498Szrj     {
64938fd1498Szrj       /* If we do not have a suitable builtin function for the trap statement,
65038fd1498Szrj 	 then do not perform the optimization.  */
65138fd1498Szrj       return (flag_isolate_erroneous_paths_dereference != 0
65238fd1498Szrj 	      || flag_isolate_erroneous_paths_attribute != 0
65338fd1498Szrj 	      || warn_null_dereference);
65438fd1498Szrj     }
65538fd1498Szrj 
execute(function *)65638fd1498Szrj   virtual unsigned int execute (function *)
65738fd1498Szrj     {
65838fd1498Szrj       return gimple_ssa_isolate_erroneous_paths ();
65938fd1498Szrj     }
66038fd1498Szrj 
66138fd1498Szrj }; // class pass_isolate_erroneous_paths
66238fd1498Szrj }
66338fd1498Szrj 
66438fd1498Szrj gimple_opt_pass *
make_pass_isolate_erroneous_paths(gcc::context * ctxt)66538fd1498Szrj make_pass_isolate_erroneous_paths (gcc::context *ctxt)
66638fd1498Szrj {
66738fd1498Szrj   return new pass_isolate_erroneous_paths (ctxt);
66838fd1498Szrj }
669