예제 #1
0
bool
gsi_replace (gimple_stmt_iterator *gsi, gimple *stmt, bool update_eh_info)
{
  gimple *orig_stmt = gsi_stmt (*gsi);
  bool require_eh_edge_purge = false;

  if (stmt == orig_stmt)
    return false;

  gcc_assert (!gimple_has_lhs (orig_stmt) || !gimple_has_lhs (stmt)
	      || gimple_get_lhs (orig_stmt) == gimple_get_lhs (stmt));

  gimple_set_location (stmt, gimple_location (orig_stmt));
  gimple_set_bb (stmt, gsi_bb (*gsi));

  /* Preserve EH region information from the original statement, if
     requested by the caller.  */
  if (update_eh_info)
    require_eh_edge_purge = maybe_clean_or_replace_eh_stmt (orig_stmt, stmt);

  gimple_duplicate_stmt_histograms (cfun, stmt, cfun, orig_stmt);

  /* Free all the data flow information for ORIG_STMT.  */
  gimple_set_bb (orig_stmt, NULL);
  gimple_remove_stmt_histograms (cfun, orig_stmt);
  delink_stmt_imm_use (orig_stmt);

  gsi_set_stmt (gsi, stmt);
  gimple_set_modified (stmt, true);
  update_modified_stmt (stmt);
  return require_eh_edge_purge;
}
예제 #2
0
static bool
optimize_tail_call (struct tailcall *t, bool opt_tailcalls)
{
  if (t->tail_recursion)
    {
      eliminate_tail_call (t);
      return true;
    }

  if (opt_tailcalls)
    {
      gimple stmt = gsi_stmt (t->call_gsi);

      gimple_call_set_tail (stmt, true);
      cfun->tail_call_marked = true;
      if (dump_file && (dump_flags & TDF_DETAILS))
        {
	  fprintf (dump_file, "Found tail call ");
	  print_gimple_stmt (dump_file, stmt, 0, dump_flags);
	  fprintf (dump_file, " in bb %i\n", (gsi_bb (t->call_gsi))->index);
	}
    }

  return false;
}
예제 #3
0
static void
gsi_insert_seq_nodes_before (gimple_stmt_iterator *i,
			     gimple_seq_node first,
			     gimple_seq_node last,
			     enum gsi_iterator_update mode)
{
  basic_block bb;
  gimple_seq_node cur = i->ptr;

  gcc_assert (!cur || cur->prev);

  if ((bb = gsi_bb (*i)) != NULL)
    update_bb_for_stmts (first, last, bb);

  /* Link SEQ before CUR in the sequence.  */
  if (cur)
    {
      first->prev = cur->prev;
      if (first->prev->next)
	first->prev->next = first;
      else
	gimple_seq_set_first (i->seq, first);
      last->next = cur;
      cur->prev = last;
    }
  else
    {
      gimple_seq_node itlast = gimple_seq_last (*i->seq);

      /* If CUR is NULL, we link at the end of the sequence (this case happens
	 when gsi_after_labels is called for a basic block that contains only
	 labels, so it returns an iterator after the end of the block, and
	 we need to insert before it; it might be cleaner to add a flag to the
	 iterator saying whether we are at the start or end of the list).  */
      last->next = NULL;
      if (itlast)
	{
	  first->prev = itlast;
	  itlast->next = first;
	}
      else
	gimple_seq_set_first (i->seq, first);
      gimple_seq_set_last (i->seq, last);
    }

  /* Update the iterator, if requested.  */
  switch (mode)
    {
    case GSI_NEW_STMT:
    case GSI_CONTINUE_LINKING:
      i->ptr = first;
      break;
    case GSI_SAME_STMT:
      break;
    default:
      gcc_unreachable ();
    }
}
예제 #4
0
void
gsi_move_to_bb_end (gimple_stmt_iterator *from, basic_block bb)
{
  gimple_stmt_iterator last = gsi_last_bb (bb);
  gcc_checking_assert (gsi_bb (last) == bb);

  /* Have to check gsi_end_p because it could be an empty block.  */
  if (!gsi_end_p (last) && is_ctrl_stmt (gsi_stmt (last)))
    gsi_move_before (from, &last);
  else
    gsi_move_after (from, &last);
}
예제 #5
0
static void
gsi_insert_seq_nodes_after (gimple_stmt_iterator *i,
			    gimple_seq_node first,
			    gimple_seq_node last,
			    enum gsi_iterator_update m)
{
  basic_block bb;
  gimple_seq_node cur = i->ptr;

  gcc_assert (!cur || cur->prev);

  /* If the iterator is inside a basic block, we need to update the
     basic block information for all the nodes between FIRST and LAST.  */
  if ((bb = gsi_bb (*i)) != NULL)
    update_bb_for_stmts (first, last, bb);

  /* Link SEQ after CUR.  */
  if (cur)
    {
      last->next = cur->next;
      if (last->next)
	{
	  last->next->prev = last;
	}
      else
	gimple_seq_set_last (i->seq, last);
      first->prev = cur;
      cur->next = first;
    }
  else
    {
      gcc_assert (!gimple_seq_last (*i->seq));
      last->next = NULL;
      gimple_seq_set_first (i->seq, first);
      gimple_seq_set_last (i->seq, last);
    }

  /* Update the iterator, if requested.  */
  switch (m)
    {
    case GSI_NEW_STMT:
      i->ptr = first;
      break;
    case GSI_CONTINUE_LINKING:
      i->ptr = last;
      break;
    case GSI_SAME_STMT:
      gcc_assert (cur);
      break;
    default:
      gcc_unreachable ();
    }
}
예제 #6
0
static basic_block
hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
			       tree cond, edge e_true,
			       bool update_dominators)
{
  tree tmp;
  gcond *cond_stmt;
  edge e_false;
  basic_block new_bb, split_bb = gsi_bb (*gsip);
  bool dominated_e_true = false;

  gcc_assert (e_true->src == split_bb);

  if (update_dominators
      && get_immediate_dominator (CDI_DOMINATORS, e_true->dest) == split_bb)
    dominated_e_true = true;

  tmp = force_gimple_operand_gsi (gsip, cond, /*simple=*/true, NULL,
				  /*before=*/true, GSI_SAME_STMT);
  cond_stmt = gimple_build_cond_from_tree (tmp, NULL_TREE, NULL_TREE);
  gsi_insert_before (gsip, cond_stmt, GSI_SAME_STMT);

  e_false = split_block (split_bb, cond_stmt);
  new_bb = e_false->dest;
  redirect_edge_pred (e_true, split_bb);

  e_true->flags &= ~EDGE_FALLTHRU;
  e_true->flags |= EDGE_TRUE_VALUE;

  e_false->flags &= ~EDGE_FALLTHRU;
  e_false->flags |= EDGE_FALSE_VALUE;
  e_false->probability = REG_BR_PROB_BASE - e_true->probability;
  e_false->count = split_bb->count - e_true->count;
  new_bb->count = e_false->count;

  if (update_dominators)
    {
      if (dominated_e_true)
	set_immediate_dominator (CDI_DOMINATORS, e_true->dest, split_bb);
      set_immediate_dominator (CDI_DOMINATORS, e_false->dest, split_bb);
    }

  return new_bb;
}
예제 #7
0
static void
eliminate_tail_call (struct tailcall *t)
{
  tree param, rslt;
  gimple stmt, call;
  tree arg;
  size_t idx;
  basic_block bb, first;
  edge e;
  gimple phi;
  gimple_stmt_iterator gsi;
  gimple orig_stmt;

  stmt = orig_stmt = gsi_stmt (t->call_gsi);
  bb = gsi_bb (t->call_gsi);

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "Eliminated tail recursion in bb %d : ",
	       bb->index);
      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
      fprintf (dump_file, "\n");
    }

  gcc_assert (is_gimple_call (stmt));

  first = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));

  /* Remove the code after call_gsi that will become unreachable.  The
     possibly unreachable code in other blocks is removed later in
     cfg cleanup.  */
  gsi = t->call_gsi;
  gsi_next (&gsi);
  while (!gsi_end_p (gsi))
    {
      gimple t = gsi_stmt (gsi);
      /* Do not remove the return statement, so that redirect_edge_and_branch
	 sees how the block ends.  */
      if (gimple_code (t) == GIMPLE_RETURN)
	break;

      gsi_remove (&gsi, true);
      release_defs (t);
    }

  /* Number of executions of function has reduced by the tailcall.  */
  e = single_succ_edge (gsi_bb (t->call_gsi));
  decrease_profile (EXIT_BLOCK_PTR_FOR_FN (cfun), e->count, EDGE_FREQUENCY (e));
  decrease_profile (ENTRY_BLOCK_PTR_FOR_FN (cfun), e->count,
		    EDGE_FREQUENCY (e));
  if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
    decrease_profile (e->dest, e->count, EDGE_FREQUENCY (e));

  /* Replace the call by a jump to the start of function.  */
  e = redirect_edge_and_branch (single_succ_edge (gsi_bb (t->call_gsi)),
				first);
  gcc_assert (e);
  PENDING_STMT (e) = NULL;

  /* Add phi node entries for arguments.  The ordering of the phi nodes should
     be the same as the ordering of the arguments.  */
  for (param = DECL_ARGUMENTS (current_function_decl),
	 idx = 0, gsi = gsi_start_phis (first);
       param;
       param = DECL_CHAIN (param), idx++)
    {
      if (!arg_needs_copy_p (param))
	continue;

      arg = gimple_call_arg (stmt, idx);
      phi = gsi_stmt (gsi);
      gcc_assert (param == SSA_NAME_VAR (PHI_RESULT (phi)));

      add_phi_arg (phi, arg, e, gimple_location (stmt));
      gsi_next (&gsi);
    }

  /* Update the values of accumulators.  */
  adjust_accumulator_values (t->call_gsi, t->mult, t->add, e);

  call = gsi_stmt (t->call_gsi);
  rslt = gimple_call_lhs (call);
  if (rslt != NULL_TREE)
    {
      /* Result of the call will no longer be defined.  So adjust the
	 SSA_NAME_DEF_STMT accordingly.  */
      SSA_NAME_DEF_STMT (rslt) = gimple_build_nop ();
    }

  gsi_remove (&t->call_gsi, true);
  release_defs (call);
}
예제 #8
0
파일: ubsan.c 프로젝트: acoxepochlabs/gcc
void
ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
{
  gimple stmt = gsi_stmt (gsi);
  location_t loc = gimple_location (stmt);
  gcc_assert (gimple_call_num_args (stmt) == 2);
  tree ptr = gimple_call_arg (stmt, 0);
  tree ckind = gimple_call_arg (stmt, 1);

  basic_block cur_bb = gsi_bb (gsi);

  /* Split the original block holding the pointer dereference.  */
  edge e = split_block (cur_bb, stmt);

  /* Get a hold on the 'condition block', the 'then block' and the
     'else block'.  */
  basic_block cond_bb = e->src;
  basic_block fallthru_bb = e->dest;
  basic_block then_bb = create_empty_bb (cond_bb);
  add_bb_to_loop (then_bb, cond_bb->loop_father);
  loops_state_set (LOOPS_NEED_FIXUP);

  /* Make an edge coming from the 'cond block' into the 'then block';
     this edge is unlikely taken, so set up the probability accordingly.  */
  e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
  e->probability = PROB_VERY_UNLIKELY;

  /* Connect 'then block' with the 'else block'.  This is needed
     as the ubsan routines we call in the 'then block' are not noreturn.
     The 'then block' only has one outcoming edge.  */
  make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);

  /* Set up the fallthrough basic block.  */
  e = find_edge (cond_bb, fallthru_bb);
  e->flags = EDGE_FALSE_VALUE;
  e->count = cond_bb->count;
  e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY;

  /* Update dominance info for the newly created then_bb; note that
     fallthru_bb's dominance info has already been updated by
     split_bock.  */
  if (dom_info_available_p (CDI_DOMINATORS))
    set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);

  /* Put the ubsan builtin call into the newly created BB.  */
  gimple g;
  if (flag_sanitize_undefined_trap_on_error)
    g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
  else
    {
      enum built_in_function bcode
	= flag_sanitize_recover
	  ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH
	  : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
      tree fn = builtin_decl_implicit (bcode);
      const struct ubsan_mismatch_data m
	= { build_zero_cst (pointer_sized_int_node), ckind };
      tree data
	= ubsan_create_data ("__ubsan_null_data", &loc, &m,
			     ubsan_type_descriptor (TREE_TYPE (ptr),
						    UBSAN_PRINT_POINTER),
			     NULL_TREE);
      data = build_fold_addr_expr_loc (loc, data);
      g = gimple_build_call (fn, 2, data,
			     build_zero_cst (pointer_sized_int_node));
    }
  gimple_set_location (g, loc);
  gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
  gsi_insert_after (&gsi2, g, GSI_NEW_STMT);

  /* Unlink the UBSAN_NULLs vops before replacing it.  */
  unlink_stmt_vdef (stmt);

  g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
			 NULL_TREE, NULL_TREE);
  gimple_set_location (g, loc);

  /* Replace the UBSAN_NULL with a GIMPLE_COND stmt.  */
  gsi_replace (&gsi, g, false);
}