This replaces uses of last_stmt where we do not require debug skipping

Message ID 20230421135306.0536913456@imap2.suse-dmz.suse.de
State Accepted
Headers
Series This replaces uses of last_stmt where we do not require debug skipping |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Richard Biener April 21, 2023, 1:53 p.m. UTC
  There are quite some cases which want to access the control stmt
ending a basic-block.  Since there cannot be debug stmts after
such stmt there's no point in using last_stmt which skips debug
stmts and can be a compile-time hog for larger testcases.

This is a first batch of changes, a second is to come next week.
It relies on the previously posted/pushed operator* support for
stmt iterators and safe_is_a for some of the replacements.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

I'll leave this for comments in case there are any and will push
on Monday.

Richard.

	* gimple-ssa-split-paths.cc (is_feasible_trace): Avoid
	last_stmt.
	* graphite-scop-detection.cc (single_pred_cond_non_loop_exit):
	Likewise.
	* ipa-fnsummary.cc (set_cond_stmt_execution_predicate): Likewise.
	(set_switch_stmt_execution_predicate): Likewise.
	(phi_result_unknown_predicate): Likewise.
	* ipa-prop.cc (compute_complex_ancestor_jump_func): Likewise.
	(ipa_analyze_indirect_call_uses): Likewise.
	* predict.cc (predict_iv_comparison): Likewise.
	(predict_extra_loop_exits): Likewise.
	(predict_loops): Likewise.
	(tree_predict_by_opcode): Likewise.
	* gimple-predicate-analysis.cc (predicate::init_from_control_deps):
	Likewise.
	* gimple-pretty-print.cc (dump_implicit_edges): Likewise.
	* tree-ssa-phiopt.cc (tree_ssa_phiopt_worker): Likewise.
	(replace_phi_edge_with_variable): Likewise.
	(two_value_replacement): Likewise.
	(value_replacement): Likewise.
	(minmax_replacement): Likewise.
	(spaceship_replacement): Likewise.
	(cond_removal_in_builtin_zero_pattern): Likewise.
	* tree-ssa-reassoc.cc (maybe_optimize_range_tests): Likewise.
	* tree-ssa-sccvn.cc (vn_phi_eq): Likewise.
	(vn_phi_lookup): Likewise.
	(vn_phi_insert): Likewise.
	* tree-ssa-structalias.cc (compute_points_to_sets): Likewise.
	* tree-ssa-threadbackwards.cc (back_threader::maybe_thread_block):
	Likewise.
	(back_threader_profitability::possibly_profitable_path_p):
	Likewise.
	* tree-ssa-threadedge.cc (jump_threader::thread_outgoing_edges):
	Likewise.
	* tree-switch-conversion.cc (pass_convert_switch::execute):
	Likewise.
	(pass_lower_switch<O0>::execute): Likewise.
	* tree-tailcall.cc (tree_optimize_tail_calls_1): Likewise.
	* tree-vect-loop-manip.cc (vect_loop_versioning): Likewise.
	* tree-vect-slp.cc (vect_slp_function): Likewise.
	* tree-vect-stmts.cc (cfun_returns): Likewise.
	* tree-vectorizer.cc (vect_loop_vectorized_call): Likewise.
	(vect_loop_dist_alias_call): Likewise.
---
 gcc/gimple-predicate-analysis.cc |  2 +-
 gcc/gimple-pretty-print.cc       |  5 +----
 gcc/gimple-ssa-split-paths.cc    |  5 ++---
 gcc/graphite-scop-detection.cc   |  9 ++-------
 gcc/ipa-fnsummary.cc             | 15 +++++----------
 gcc/ipa-prop.cc                  |  9 ++++-----
 gcc/predict.cc                   | 25 +++++++++----------------
 gcc/tree-ssa-phiopt.cc           | 32 ++++++++++++++------------------
 gcc/tree-ssa-reassoc.cc          |  2 +-
 gcc/tree-ssa-sccvn.cc            |  8 ++++----
 gcc/tree-ssa-structalias.cc      |  2 +-
 gcc/tree-ssa-threadbackward.cc   |  4 ++--
 gcc/tree-ssa-threadedge.cc       |  4 +---
 gcc/tree-switch-conversion.cc    |  9 +++------
 gcc/tree-tailcall.cc             | 11 ++---------
 gcc/tree-vect-loop-manip.cc      |  2 +-
 gcc/tree-vect-slp.cc             |  2 +-
 gcc/tree-vect-stmts.cc           |  2 +-
 gcc/tree-vectorizer.cc           | 11 ++++-------
 19 files changed, 59 insertions(+), 100 deletions(-)
  

Patch

diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc
index 094e8c7aff3..c89a5b1653a 100644
--- a/gcc/gimple-predicate-analysis.cc
+++ b/gcc/gimple-predicate-analysis.cc
@@ -1830,7 +1830,7 @@  predicate::init_from_control_deps (const vec<edge> *dep_chains,
 		}
 	    }
 	  /* Get the conditional controlling the bb exit edge.  */
-	  gimple *cond_stmt = last_stmt (guard_bb);
+	  gimple *cond_stmt = *gsi_last_bb (guard_bb);
 	  if (gimple_code (cond_stmt) == GIMPLE_COND)
 	    {
 	      /* The true edge corresponds to the uninteresting condition.
diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc
index 300e9d7ed1e..e46f7d5f55a 100644
--- a/gcc/gimple-pretty-print.cc
+++ b/gcc/gimple-pretty-print.cc
@@ -3004,11 +3004,8 @@  dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent,
 		     dump_flags_t flags)
 {
   edge e;
-  gimple *stmt;
-
-  stmt = last_stmt (bb);
 
-  if (stmt && gimple_code (stmt) == GIMPLE_COND)
+  if (safe_is_a <gcond *> (*gsi_last_bb (bb)))
     {
       edge true_edge, false_edge;
 
diff --git a/gcc/gimple-ssa-split-paths.cc b/gcc/gimple-ssa-split-paths.cc
index 44d87c24f60..5896f4d9b64 100644
--- a/gcc/gimple-ssa-split-paths.cc
+++ b/gcc/gimple-ssa-split-paths.cc
@@ -267,8 +267,7 @@  is_feasible_trace (basic_block bb)
   if (single_pred_p (pred2) && single_pred (pred2) == pred1
       && num_stmts_in_pred2 == 0)
     {
-      gimple *cond_stmt = last_stmt (pred1);
-      if (cond_stmt && gimple_code (cond_stmt) == GIMPLE_COND)
+      if (gcond *cond_stmt = dyn_cast <gcond *> (*gsi_last_bb (pred1)))
 	{
 	  tree lhs = gimple_cond_lhs (cond_stmt);
 	  tree rhs = gimple_cond_rhs (cond_stmt);
@@ -369,7 +368,7 @@  is_feasible_trace (basic_block bb)
      an equivalence from to the joiner.  */
   bool found_cprop_opportunity = false;
   basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb);
-  gcond *cond = as_a <gcond *> (last_stmt (dom));
+  gcond *cond = as_a <gcond *> (*gsi_last_bb (dom));
   if (gimple_cond_code (cond) == EQ_EXPR
       || gimple_cond_code (cond) == NE_EXPR)
     for (unsigned i = 0; i < 2; ++i)
diff --git a/gcc/graphite-scop-detection.cc b/gcc/graphite-scop-detection.cc
index 99551990e54..48b3d62c2cf 100644
--- a/gcc/graphite-scop-detection.cc
+++ b/gcc/graphite-scop-detection.cc
@@ -277,17 +277,12 @@  single_pred_cond_non_loop_exit (basic_block bb)
 {
   if (single_pred_p (bb))
     {
-      edge e = single_pred_edge (bb);
-      basic_block pred = e->src;
-      gimple *stmt;
+      basic_block pred = single_pred (bb);
 
       if (loop_depth (pred->loop_father) > loop_depth (bb->loop_father))
 	return NULL;
 
-      stmt = last_stmt (pred);
-
-      if (stmt && gimple_code (stmt) == GIMPLE_COND)
-	return as_a<gcond *> (stmt);
+      return safe_dyn_cast <gcond *> (*gsi_last_bb (pred));
     }
 
   return NULL;
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index 8217039b548..d4b2a073240 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -1558,7 +1558,6 @@  set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 				   class ipa_node_params *params_summary,
 				   basic_block bb)
 {
-  gimple *last;
   tree op, op2;
   int index;
   struct agg_position_info aggpos;
@@ -1569,8 +1568,8 @@  set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   tree param_type;
   expr_eval_ops param_ops;
 
-  last = last_stmt (bb);
-  if (!last || gimple_code (last) != GIMPLE_COND)
+  gcond *last = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
+  if (!last)
     return;
   if (!is_gimple_ip_invariant (gimple_cond_rhs (last)))
     return;
@@ -1652,7 +1651,6 @@  set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 				     class ipa_node_params *params_summary,
 				     basic_block bb)
 {
-  gimple *lastg;
   tree op;
   int index;
   struct agg_position_info aggpos;
@@ -1663,10 +1661,9 @@  set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   tree param_type;
   expr_eval_ops param_ops;
 
-  lastg = last_stmt (bb);
-  if (!lastg || gimple_code (lastg) != GIMPLE_SWITCH)
+  gswitch *last = safe_dyn_cast <gswitch *> (*gsi_last_bb (bb));
+  if (!last)
     return;
-  gswitch *last = as_a <gswitch *> (lastg);
   op = gimple_switch_index (last);
   if (!decompose_param_expr (fbi, last, op, &index, &param_type, &aggpos,
 			     &param_ops))
@@ -2309,7 +2306,6 @@  phi_result_unknown_predicate (ipa_func_body_info *fbi,
   edge e;
   edge_iterator ei;
   basic_block first_bb = NULL;
-  gimple *stmt;
 
   if (single_pred_p (bb))
     {
@@ -2340,9 +2336,8 @@  phi_result_unknown_predicate (ipa_func_body_info *fbi,
   if (!first_bb)
     return false;
 
-  stmt = last_stmt (first_bb);
+  gcond *stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (first_bb));
   if (!stmt
-      || gimple_code (stmt) != GIMPLE_COND
       || !is_gimple_ip_invariant (gimple_cond_rhs (stmt)))
     return false;
 
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index c0143e90cd3..a55cc72b0fd 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -1531,7 +1531,7 @@  compute_complex_ancestor_jump_func (struct ipa_func_body_info *fbi,
 				    gcall *call, gphi *phi)
 {
   HOST_WIDE_INT offset;
-  gimple *assign, *cond;
+  gimple *assign;
   basic_block phi_bb, assign_bb, cond_bb;
   tree tmp, parm, expr, obj;
   int index, i;
@@ -1564,9 +1564,8 @@  compute_complex_ancestor_jump_func (struct ipa_func_body_info *fbi,
     return;
 
   cond_bb = single_pred (assign_bb);
-  cond = last_stmt (cond_bb);
+  gcond *cond = safe_dyn_cast <gcond *> (*gsi_last_bb (cond_bb));
   if (!cond
-      || gimple_code (cond) != GIMPLE_COND
       || gimple_cond_code (cond) != NE_EXPR
       || gimple_cond_lhs (cond) != parm
       || !integer_zerop (gimple_cond_rhs (cond)))
@@ -2681,8 +2680,8 @@  ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
   /* Third, let's see that the branching is done depending on the least
      significant bit of the pfn. */
 
-  gimple *branch = last_stmt (bb);
-  if (!branch || gimple_code (branch) != GIMPLE_COND)
+  gcond *branch = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
+  if (!branch)
     return;
 
   if ((gimple_cond_code (branch) != NE_EXPR
diff --git a/gcc/predict.cc b/gcc/predict.cc
index a0dc409648f..4a686b08f36 100644
--- a/gcc/predict.cc
+++ b/gcc/predict.cc
@@ -1685,7 +1685,6 @@  predict_iv_comparison (class loop *loop, basic_block bb,
 		       enum tree_code loop_bound_code,
 		       int loop_bound_step)
 {
-  gimple *stmt;
   tree compare_var, compare_base;
   enum tree_code compare_code;
   tree compare_step_var;
@@ -1695,10 +1694,10 @@  predict_iv_comparison (class loop *loop, basic_block bb,
   if (predicted_by_loop_heuristics_p (bb))
     return;
 
-  stmt = last_stmt (bb);
-  if (!stmt || gimple_code (stmt) != GIMPLE_COND)
+  gcond *stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
+  if (!stmt)
     return;
-  if (!is_comparison_with_loop_invariant_p (as_a <gcond *> (stmt),
+  if (!is_comparison_with_loop_invariant_p (stmt,
 					    loop, &compare_var,
 					    &compare_code,
 					    &compare_step_var,
@@ -1877,13 +1876,8 @@  predict_extra_loop_exits (class loop *loop, edge exit_edge)
   gimple *lhs_def_stmt;
   gphi *phi_stmt;
   tree cmp_rhs, cmp_lhs;
-  gimple *last;
-  gcond *cmp_stmt;
 
-  last = last_stmt (exit_edge->src);
-  if (!last)
-    return;
-  cmp_stmt = dyn_cast <gcond *> (last);
+  gcond *cmp_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (exit_edge->src));
   if (!cmp_stmt)
     return;
 
@@ -2104,9 +2098,8 @@  predict_loops (void)
 	    stmt = as_a <gcond *> (nb_iter->stmt);
 	    break;
 	  }
-      if (!stmt && last_stmt (loop->header)
-	  && gimple_code (last_stmt (loop->header)) == GIMPLE_COND)
-	stmt = as_a <gcond *> (last_stmt (loop->header));
+      if (!stmt)
+	stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (loop->header));
       if (stmt)
 	is_comparison_with_loop_invariant_p (stmt, loop,
 					     &loop_bound_var,
@@ -2195,7 +2188,6 @@  predict_loops (void)
 	      && single_succ_p (preheader_edge->src))
 	    preheader_edge = single_pred_edge (preheader_edge->src);
 
-	  gimple *stmt = last_stmt (preheader_edge->src);
 	  /* Pattern match fortran loop preheader:
 	     _16 = BUILTIN_EXPECT (_15, 1, PRED_FORTRAN_LOOP_PREHEADER);
 	     _17 = (logical(kind=4)) _16;
@@ -2208,8 +2200,9 @@  predict_loops (void)
 	     headers produced by fortran frontend and in this case we want
 	     to predict paths leading to this preheader.  */
 
+	  gcond *stmt
+	    = safe_dyn_cast <gcond *> (*gsi_last_bb (preheader_edge->src));
 	  if (stmt
-	      && gimple_code (stmt) == GIMPLE_COND
 	      && gimple_cond_code (stmt) == NE_EXPR
 	      && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME
 	      && integer_zerop (gimple_cond_rhs (stmt)))
@@ -2676,7 +2669,6 @@  get_predictor_value (br_predictor predictor, HOST_WIDE_INT probability)
 static void
 tree_predict_by_opcode (basic_block bb)
 {
-  gimple *stmt = last_stmt (bb);
   edge then_edge;
   tree op0, op1;
   tree type;
@@ -2686,6 +2678,7 @@  tree_predict_by_opcode (basic_block bb)
   enum br_predictor predictor;
   HOST_WIDE_INT probability;
 
+  gimple *stmt = *gsi_last_bb (bb);
   if (!stmt)
     return;
 
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 945507be11e..894b6409ae1 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -137,7 +137,6 @@  tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p)
 
   for (i = 0; i < n; i++)
     {
-      gimple *cond_stmt;
       gphi *phi;
       basic_block bb1, bb2;
       edge e1, e2;
@@ -146,10 +145,9 @@  tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p)
 
       bb = bb_order[i];
 
-      cond_stmt = last_stmt (bb);
       /* Check to see if the last statement is a GIMPLE_COND.  */
-      if (!cond_stmt
-          || gimple_code (cond_stmt) != GIMPLE_COND)
+      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
+      if (!cond_stmt)
         continue;
 
       e1 = EDGE_SUCC (bb, 0);
@@ -413,7 +411,7 @@  replace_phi_edge_with_variable (basic_block cond_block,
       /* If there are other edges into the middle block make
 	 CFG cleanup deal with the edge removal to avoid
 	 updating dominators here in a non-trivial way.  */
-      gcond *cond = as_a <gcond *> (last_stmt (cond_block));
+      gcond *cond = as_a <gcond *> (*gsi_last_bb (cond_block));
       if (keep_edge->flags & EDGE_FALSE_VALUE)
 	gimple_cond_make_false (cond);
       else if (keep_edge->flags & EDGE_TRUE_VALUE)
@@ -660,7 +658,7 @@  two_value_replacement (basic_block cond_bb, basic_block middle_bb,
   if (!empty_block_p (middle_bb))
     return false;
 
-  gimple *stmt = last_stmt (cond_bb);
+  gcond *stmt = as_a <gcond *> (*gsi_last_bb (cond_bb));
   tree lhs = gimple_cond_lhs (stmt);
   tree rhs = gimple_cond_rhs (stmt);
 
@@ -1288,7 +1286,6 @@  value_replacement (basic_block cond_bb, basic_block middle_bb,
 		   edge e0, edge e1, gphi *phi, tree arg0, tree arg1)
 {
   gimple_stmt_iterator gsi;
-  gimple *cond;
   edge true_edge, false_edge;
   enum tree_code code;
   bool empty_or_with_defined_p = true;
@@ -1323,7 +1320,7 @@  value_replacement (basic_block cond_bb, basic_block middle_bb,
 	empty_or_with_defined_p = false;
     }
 
-  cond = last_stmt (cond_bb);
+  gcond *cond = as_a <gcond *> (*gsi_last_bb (cond_bb));
   code = gimple_cond_code (cond);
 
   /* This transformation is only valid for equality comparisons.  */
@@ -1831,7 +1828,7 @@  minmax_replacement (basic_block cond_bb, basic_block middle_bb, basic_block alt_
   if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type))
     return false;
 
-  gcond *cond = as_a <gcond *> (last_stmt (cond_bb));
+  gcond *cond = as_a <gcond *> (*gsi_last_bb (cond_bb));
   enum tree_code cmp = gimple_cond_code (cond);
   tree rhs = gimple_cond_rhs (cond);
 
@@ -2573,7 +2570,7 @@  spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
   if (!empty_block_p (middle_bb))
     return false;
 
-  gcond *cond1 = as_a <gcond *> (last_stmt (cond_bb));
+  gcond *cond1 = as_a <gcond *> (*gsi_last_bb (cond_bb));
   enum tree_code cmp1 = gimple_cond_code (cond1);
   switch (cmp1)
     {
@@ -2615,8 +2612,8 @@  spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
   tree arg2 = gimple_phi_arg_def (phi, cond2_phi_edge->dest_idx);
   if (!tree_fits_shwi_p (arg2))
     return false;
-  gimple *cond2 = last_stmt (cond2_bb);
-  if (cond2 == NULL || gimple_code (cond2) != GIMPLE_COND)
+  gcond *cond2 = safe_dyn_cast <gcond *> (*gsi_last_bb (cond2_bb));
+  if (!cond2)
     return false;
   enum tree_code cmp2 = gimple_cond_code (cond2);
   tree lhs2 = gimple_cond_lhs (cond2);
@@ -2672,7 +2669,7 @@  spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
   tree arg3 = arg2;
   basic_block cond3_bb = cond2_bb;
   edge cond3_phi_edge = cond2_phi_edge;
-  gimple *cond3 = cond2;
+  gcond *cond3 = cond2;
   enum tree_code cmp3 = cmp2;
   tree lhs3 = lhs2;
   tree rhs3 = rhs2;
@@ -2732,8 +2729,8 @@  spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
       else
 	cond3_phi_edge = EDGE_SUCC (cond3_bb, 0);
       arg3 = gimple_phi_arg_def (phi, cond3_phi_edge->dest_idx);
-      cond3 = last_stmt (cond3_bb);
-      if (cond3 == NULL || gimple_code (cond3) != GIMPLE_COND)
+      cond3 = safe_dyn_cast <gcond *> (*gsi_last_bb (cond3_bb));
+      if (!cond3)
 	return false;
       cmp3 = gimple_cond_code (cond3);
       lhs3 = gimple_cond_lhs (cond3);
@@ -2975,7 +2972,6 @@  cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
 				      edge e1, edge e2, gphi *phi,
 				      tree arg0, tree arg1)
 {
-  gimple *cond;
   gimple_stmt_iterator gsi, gsi_from;
   gimple *call;
   gimple *cast = NULL;
@@ -3081,11 +3077,11 @@  cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
       arg = gimple_assign_rhs1 (cast);
     }
 
-  cond = last_stmt (cond_bb);
+  gcond *cond = dyn_cast <gcond *> (*gsi_last_bb (cond_bb));
 
   /* Cond_bb has a check for b_4 [!=|==] 0 before calling the popcount/clz/ctz
      builtin.  */
-  if (gimple_code (cond) != GIMPLE_COND
+  if (!cond
       || (gimple_cond_code (cond) != NE_EXPR
 	  && gimple_cond_code (cond) != EQ_EXPR)
       || !integer_zerop (gimple_cond_rhs (cond))
diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc
index 067a3f07f7e..e795bdc0db4 100644
--- a/gcc/tree-ssa-reassoc.cc
+++ b/gcc/tree-ssa-reassoc.cc
@@ -5094,7 +5094,7 @@  maybe_optimize_range_tests (gimple *stmt)
 	      && bbinfo[idx].op == NULL_TREE
 	      && ops[bbinfo[idx].first_idx]->op != NULL_TREE)
 	    {
-	      gcond *cond_stmt = as_a <gcond *> (last_stmt (bb));
+	      gcond *cond_stmt = as_a <gcond *> (*gsi_last_bb (bb));
 
 	      if (idx > max_idx)
 		max_idx = idx;
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 7fa2a154e84..94b793e1caf 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -4757,8 +4757,8 @@  vn_phi_eq (const_vn_phi_t const vp1, const_vn_phi_t const vp2)
 				 && EDGE_COUNT (idom2->succs) == 2);
 
 	    /* Verify the controlling stmt is the same.  */
-	    gcond *last1 = as_a <gcond *> (last_stmt (idom1));
-	    gcond *last2 = as_a <gcond *> (last_stmt (idom2));
+	    gcond *last1 = as_a <gcond *> (*gsi_last_bb (idom1));
+	    gcond *last2 = as_a <gcond *> (*gsi_last_bb (idom2));
 	    bool inverted_p;
 	    if (! cond_stmts_equal_p (last1, vp1->cclhs, vp1->ccrhs,
 				      last2, vp2->cclhs, vp2->ccrhs,
@@ -4859,7 +4859,7 @@  vn_phi_lookup (gimple *phi, bool backedges_varying_p)
     {
       basic_block idom1 = get_immediate_dominator (CDI_DOMINATORS, vp1->block);
       if (EDGE_COUNT (idom1->succs) == 2)
-	if (gcond *last1 = safe_dyn_cast <gcond *> (last_stmt (idom1)))
+	if (gcond *last1 = safe_dyn_cast <gcond *> (*gsi_last_bb (idom1)))
 	  {
 	    /* ???  We want to use SSA_VAL here.  But possibly not
 	       allow VN_TOP.  */
@@ -4914,7 +4914,7 @@  vn_phi_insert (gimple *phi, tree result, bool backedges_varying_p)
     {
       basic_block idom1 = get_immediate_dominator (CDI_DOMINATORS, vp1->block);
       if (EDGE_COUNT (idom1->succs) == 2)
-	if (gcond *last1 = safe_dyn_cast <gcond *> (last_stmt (idom1)))
+	if (gcond *last1 = safe_dyn_cast <gcond *> (*gsi_last_bb (idom1)))
 	  {
 	    /* ???  We want to use SSA_VAL here.  But possibly not
 	       allow VN_TOP.  */
diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc
index 47808a3d813..56021c59cb9 100644
--- a/gcc/tree-ssa-structalias.cc
+++ b/gcc/tree-ssa-structalias.cc
@@ -7568,7 +7568,7 @@  compute_points_to_sets (void)
   edge_iterator ei;
   edge e;
   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-    if (greturn *ret = safe_dyn_cast <greturn *> (last_stmt (e->src)))
+    if (greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src)))
       {
 	tree val = gimple_return_retval (ret);
 	/* ???  Easy to handle simple indirections with some work.
diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc
index fcbb95b08be..962b33d88da 100644
--- a/gcc/tree-ssa-threadbackward.cc
+++ b/gcc/tree-ssa-threadbackward.cc
@@ -512,7 +512,7 @@  back_threader::maybe_thread_block (basic_block bb)
   if (EDGE_COUNT (bb->succs) <= 1)
     return;
 
-  gimple *stmt = last_stmt (bb);
+  gimple *stmt = *gsi_last_bb (bb);
   if (!stmt)
     return;
 
@@ -718,7 +718,7 @@  back_threader_profitability::possibly_profitable_path_p
 	     going to be able to eliminate its branch.  */
 	  if (j > 0)
 	    {
-	      gimple *last = last_stmt (bb);
+	      gimple *last = *gsi_last_bb (bb);
 	      if (last
 		  && (gimple_code (last) == GIMPLE_SWITCH
 		      || gimple_code (last) == GIMPLE_GOTO))
diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc
index 3805d92241e..72a7d4d14d8 100644
--- a/gcc/tree-ssa-threadedge.cc
+++ b/gcc/tree-ssa-threadedge.cc
@@ -1193,7 +1193,6 @@  void
 jump_threader::thread_outgoing_edges (basic_block bb)
 {
   int flags = (EDGE_IGNORE | EDGE_COMPLEX | EDGE_ABNORMAL);
-  gimple *last;
 
   if (!flag_thread_jumps)
     return;
@@ -1204,8 +1203,7 @@  jump_threader::thread_outgoing_edges (basic_block bb)
      will be traversed when the incoming edge from BB is traversed.  */
   if (single_succ_to_potentially_threadable_block (bb))
     thread_across_edge (single_succ_edge (bb));
-  else if ((last = last_stmt (bb))
-	   && gimple_code (last) == GIMPLE_COND
+  else if (safe_is_a <gcond *> (*gsi_last_bb (bb))
 	   && EDGE_COUNT (bb->succs) == 2
 	   && (EDGE_SUCC (bb, 0)->flags & flags) == 0
 	   && (EDGE_SUCC (bb, 1)->flags & flags) == 0)
diff --git a/gcc/tree-switch-conversion.cc b/gcc/tree-switch-conversion.cc
index c08c22039c9..dfdcd79bb40 100644
--- a/gcc/tree-switch-conversion.cc
+++ b/gcc/tree-switch-conversion.cc
@@ -2489,8 +2489,7 @@  pass_convert_switch::execute (function *fun)
 
   FOR_EACH_BB_FN (bb, fun)
   {
-    gimple *stmt = last_stmt (bb);
-    if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
+    if (gswitch *stmt = safe_dyn_cast <gswitch *> (*gsi_last_bb (bb)))
       {
 	if (dump_file)
 	  {
@@ -2504,7 +2503,7 @@  pass_convert_switch::execute (function *fun)
 	  }
 
 	switch_conversion sconv;
-	sconv.expand (as_a <gswitch *> (stmt));
+	sconv.expand (stmt);
 	cfg_altered |= sconv.m_cfg_altered;
 	if (!sconv.m_reason)
 	  {
@@ -2594,9 +2593,7 @@  pass_lower_switch<O0>::execute (function *fun)
 
   FOR_EACH_BB_FN (bb, fun)
     {
-      gimple *stmt = last_stmt (bb);
-      gswitch *swtch;
-      if (stmt && (swtch = dyn_cast<gswitch *> (stmt)))
+      if (gswitch *swtch = safe_dyn_cast <gswitch *> (*gsi_last_bb (bb)))
 	{
 	  if (!O0)
 	    group_case_labels_stmt (swtch);
diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc
index 217357e09c0..04355dfcf44 100644
--- a/gcc/tree-tailcall.cc
+++ b/gcc/tree-tailcall.cc
@@ -1105,7 +1105,6 @@  tree_optimize_tail_calls_1 (bool opt_tailcalls)
   bool changed = false;
   basic_block first = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
   tree param;
-  gimple *stmt;
   edge_iterator ei;
 
   if (!suitable_for_tail_opt_p ())
@@ -1117,10 +1116,7 @@  tree_optimize_tail_calls_1 (bool opt_tailcalls)
     {
       /* Only traverse the normal exits, i.e. those that end with return
 	 statement.  */
-      stmt = last_stmt (e->src);
-
-      if (stmt
-	  && gimple_code (stmt) == GIMPLE_RETURN)
+      if (safe_is_a <greturn *> (*gsi_last_bb (e->src)))
 	find_tail_calls (e->src, &tailcalls);
     }
 
@@ -1201,10 +1197,7 @@  tree_optimize_tail_calls_1 (bool opt_tailcalls)
       /* Modify the remaining return statements.  */
       FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
 	{
-	  stmt = last_stmt (e->src);
-
-	  if (stmt
-	      && gimple_code (stmt) == GIMPLE_RETURN)
+	  if (safe_is_a <greturn *> (*gsi_last_bb (e->src)))
 	    adjust_return_value (e->src, m_acc, a_acc);
 	}
     }
diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
index f60fa50e8f4..44bd5f2c805 100644
--- a/gcc/tree-vect-loop-manip.cc
+++ b/gcc/tree-vect-loop-manip.cc
@@ -3572,7 +3572,7 @@  vect_loop_versioning (loop_vec_info loop_vinfo,
     {
       gcc_assert (scalar_loop);
       condition_bb = gimple_bb (loop_vectorized_call);
-      cond = as_a <gcond *> (last_stmt (condition_bb));
+      cond = as_a <gcond *> (*gsi_last_bb (condition_bb));
       gimple_cond_set_condition_from_tree (cond, cond_expr);
       update_stmt (cond);
 
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index d73deaecce0..b299e209b5b 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -7692,7 +7692,7 @@  vect_slp_function (function *fun)
       /* When we have a stmt ending this block and defining a
 	 value we have to insert on edges when inserting after it for
 	 a vector containing its definition.  Avoid this for now.  */
-      if (gimple *last = last_stmt (bb))
+      if (gimple *last = *gsi_last_bb (bb))
 	if (gimple_get_lhs (last)
 	    && is_ctrl_altering_stmt (last))
 	  {
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 6b7dbfd4a23..272839a658c 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -912,7 +912,7 @@  cfun_returns (tree decl)
   edge e;
   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
     {
-      greturn *ret = safe_dyn_cast <greturn *> (last_stmt (e->src));
+      greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src));
       if (!ret)
 	continue;
       if (gimple_return_retval (ret) == decl)
diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc
index 89cd0b88b61..a048e9d8917 100644
--- a/gcc/tree-vectorizer.cc
+++ b/gcc/tree-vectorizer.cc
@@ -852,7 +852,7 @@  vect_loop_vectorized_call (class loop *loop, gcond **cond)
   gimple *g;
   do
     {
-      g = last_stmt (bb);
+      g = *gsi_last_bb (bb);
       if ((g && gimple_code (g) == GIMPLE_COND)
 	  || !single_succ_p (bb))
 	break;
@@ -888,8 +888,6 @@  vect_loop_dist_alias_call (class loop *loop, function *fun)
   basic_block bb;
   basic_block entry;
   class loop *outer, *orig;
-  gimple_stmt_iterator gsi;
-  gimple *g;
 
   if (loop->orig_loop_num == 0)
     return NULL;
@@ -914,16 +912,15 @@  vect_loop_dist_alias_call (class loop *loop, function *fun)
   for (; bb != entry && flow_bb_inside_loop_p (outer, bb);
        bb = get_immediate_dominator (CDI_DOMINATORS, bb))
     {
-      g = last_stmt (bb);
-      if (g == NULL || gimple_code (g) != GIMPLE_COND)
+      gimple_stmt_iterator gsi = gsi_last_bb (bb);
+      if (!safe_is_a <gcond *> (*gsi))
 	continue;
 
-      gsi = gsi_for_stmt (g);
       gsi_prev (&gsi);
       if (gsi_end_p (gsi))
 	continue;
 
-      g = gsi_stmt (gsi);
+      gimple *g = gsi_stmt (gsi);
       /* The guarding internal function call must have the same distribution
 	 alias id.  */
       if (gimple_call_internal_p (g, IFN_LOOP_DIST_ALIAS)