Ejemplo n.º 1
0
static bool
if_convertible_phi_p (struct loop *loop, basic_block bb, tree phi)
{
  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "-------------------------\n");
      print_generic_stmt (dump_file, phi, TDF_SLIM);
    }

  if (bb != loop->header && PHI_NUM_ARGS (phi) != 2)
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "More than two phi node args.\n");
      return false;
    }

  if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
    {
      imm_use_iterator imm_iter;
      use_operand_p use_p;
      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, PHI_RESULT (phi))
	{
	  if (TREE_CODE (USE_STMT (use_p)) == PHI_NODE)
	    {
	      if (dump_file && (dump_flags & TDF_DETAILS))
		fprintf (dump_file, "Difficult to handle this virtual phi.\n");
	      return false;
	    }
	}
    }
Ejemplo n.º 2
0
void
reserve_phi_args_for_new_edge (basic_block bb)
{
  tree *loc;
  int len = EDGE_COUNT (bb->preds);
  int cap = ideal_phi_node_len (len + 4);

  for (loc = &(bb->phi_nodes);
       *loc;
       loc = &PHI_CHAIN (*loc))
    {
      if (len > PHI_ARG_CAPACITY (*loc))
	{
	  tree old_phi = *loc;

	  resize_phi_node (loc, cap);

	  /* The result of the phi is defined by this phi node.  */
	  SSA_NAME_DEF_STMT (PHI_RESULT (*loc)) = *loc;

	  release_phi_node (old_phi);
	}

      /* We represent a "missing PHI argument" by placing NULL_TREE in
	 the corresponding slot.  If PHI arguments were added
	 immediately after an edge is created, this zeroing would not
	 be necessary, but unfortunately this is not the case.  For
	 example, the loop optimizer duplicates several basic blocks,
	 redirects edges, and then fixes up PHI arguments later in
	 batch.  */
      SET_PHI_ARG_DEF (*loc, len - 1, NULL_TREE);

      PHI_NUM_ARGS (*loc)++;
    }
}
Ejemplo n.º 3
0
void
add_phi_arg (tree phi, tree def, edge e)
{
  basic_block bb = e->dest;

  gcc_assert (bb == bb_for_stmt (phi));

  /* We resize PHI nodes upon edge creation.  We should always have
     enough room at this point.  */
  gcc_assert (PHI_NUM_ARGS (phi) <= PHI_ARG_CAPACITY (phi));

  /* We resize PHI nodes upon edge creation.  We should always have
     enough room at this point.  */
  gcc_assert (e->dest_idx < (unsigned int) PHI_NUM_ARGS (phi));

  /* Copy propagation needs to know what object occur in abnormal
     PHI nodes.  This is a convenient place to record such information.  */
  if (e->flags & EDGE_ABNORMAL)
    {
      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) = 1;
      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
    }

  SET_PHI_ARG_DEF (phi, e->dest_idx, def);
}
Ejemplo n.º 4
0
void
remove_phi_node (tree phi, tree prev)
{
  tree *loc;

  if (prev)
    {
      loc = &PHI_CHAIN (prev);
    }
  else
    {
      for (loc = &(bb_for_stmt (phi)->phi_nodes);
	   *loc != phi;
	   loc = &PHI_CHAIN (*loc))
	;
    }

  /* Remove PHI from the chain.  */
  *loc = PHI_CHAIN (phi);

  /* If we are deleting the PHI node, then we should release the
     SSA_NAME node so that it can be reused.  */
  release_phi_node (phi);
  release_ssa_name (PHI_RESULT (phi));
}
Ejemplo n.º 5
0
edge
ssa_redirect_edge (edge e, basic_block dest)
{
  tree phi;
  tree list = NULL, *last = &list;
  tree src, dst, node;

  /* Remove the appropriate PHI arguments in E's destination block.  */
  for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
    {
      if (PHI_ARG_DEF (phi, e->dest_idx) == NULL_TREE)
	continue;

      src = PHI_ARG_DEF (phi, e->dest_idx);
      dst = PHI_RESULT (phi);
      node = build_tree_list (dst, src);
      *last = node;
      last = &TREE_CHAIN (node);
    }

  e = redirect_edge_succ_nodup (e, dest);
  PENDING_STMT (e) = list;

  return e;
}
Ejemplo n.º 6
0
void
add_phi_arg (gimple phi, tree def, edge e)
{
  basic_block bb = e->dest;

  gcc_assert (bb == gimple_bb (phi));

  /* We resize PHI nodes upon edge creation.  We should always have
     enough room at this point.  */
  gcc_assert (gimple_phi_num_args (phi) <= gimple_phi_capacity (phi));

  /* We resize PHI nodes upon edge creation.  We should always have
     enough room at this point.  */
  gcc_assert (e->dest_idx < gimple_phi_num_args (phi));

  /* Copy propagation needs to know what object occur in abnormal
     PHI nodes.  This is a convenient place to record such information.  */
  if (e->flags & EDGE_ABNORMAL)
    {
      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) = 1;
      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
    }

  SET_PHI_ARG_DEF (phi, e->dest_idx, def);
}
Ejemplo n.º 7
0
static unsigned
get_stmt_uid (tree stmt)
{
  if (TREE_CODE (stmt) == PHI_NODE)
    return SSA_NAME_VERSION (PHI_RESULT (stmt)) + max_stmt_uid;

  return stmt_ann (stmt)->uid;
}
Ejemplo n.º 8
0
static void
add_successor_phi_arg (edge e, tree var, tree phi_arg)
{
  gimple_stmt_iterator gsi;

  for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
    if (PHI_RESULT (gsi_stmt (gsi)) == var)
      break;

  gcc_assert (!gsi_end_p (gsi));
  add_phi_arg (gsi_stmt (gsi), phi_arg, e, UNKNOWN_LOCATION);
}
Ejemplo n.º 9
0
static tree
propagate_through_phis (tree var, edge e)
{
  basic_block dest = e->dest;
  gimple_stmt_iterator gsi;

  for (gsi = gsi_start_phis (dest); !gsi_end_p (gsi); gsi_next (&gsi))
    {
      gimple phi = gsi_stmt (gsi);
      if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var)
        return PHI_RESULT (phi);
    }
  return var;
}
Ejemplo n.º 10
0
static void
output_phi (struct output_block *ob, gimple phi)
{
  unsigned i, len = gimple_phi_num_args (phi);

  streamer_write_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
  streamer_write_uhwi (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));

  for (i = 0; i < len; i++)
    {
      stream_write_tree (ob, gimple_phi_arg_def (phi, i), true);
      streamer_write_uhwi (ob, gimple_phi_arg_edge (phi, i)->src->index);
      lto_output_location (ob, gimple_phi_arg_location (phi, i));
    }
}
Ejemplo n.º 11
0
static void
update_phis_for_loop_copy (struct loop *orig_loop, struct loop *new_loop)
{
  tree new_ssa_name;
  gimple_stmt_iterator si_new, si_orig;
  edge orig_loop_latch = loop_latch_edge (orig_loop);
  edge orig_entry_e = loop_preheader_edge (orig_loop);
  edge new_loop_entry_e = loop_preheader_edge (new_loop);

  /* Scan the phis in the headers of the old and new loops
     (they are organized in exactly the same order).  */
  for (si_new = gsi_start_phis (new_loop->header),
       si_orig = gsi_start_phis (orig_loop->header);
       !gsi_end_p (si_new) && !gsi_end_p (si_orig);
       gsi_next (&si_new), gsi_next (&si_orig))
    {
      tree def;
      source_location locus;
      gimple phi_new = gsi_stmt (si_new);
      gimple phi_orig = gsi_stmt (si_orig);

      /* Add the first phi argument for the phi in NEW_LOOP (the one
	 associated with the entry of NEW_LOOP)  */
      def = PHI_ARG_DEF_FROM_EDGE (phi_orig, orig_entry_e);
      locus = gimple_phi_arg_location_from_edge (phi_orig, orig_entry_e);
      add_phi_arg (phi_new, def, new_loop_entry_e, locus);

      /* Add the second phi argument for the phi in NEW_LOOP (the one
	 associated with the latch of NEW_LOOP)  */
      def = PHI_ARG_DEF_FROM_EDGE (phi_orig, orig_loop_latch);
      locus = gimple_phi_arg_location_from_edge (phi_orig, orig_loop_latch);

      if (TREE_CODE (def) == SSA_NAME)
	{
	  new_ssa_name = get_current_def (def);

	  if (!new_ssa_name)
	    /* This only happens if there are no definitions inside the
	       loop.  Use the phi_result in this case.  */
	    new_ssa_name = PHI_RESULT (phi_new);
	}
      else
	/* Could be an integer.  */
	new_ssa_name = def;

      add_phi_arg (phi_new, new_ssa_name, loop_latch_edge (new_loop), locus);
    }
}
Ejemplo n.º 12
0
static tree
create_tailcall_accumulator (const char *label, basic_block bb, tree init)
{
  tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
  if (POINTER_TYPE_P (ret_type))
    ret_type = sizetype;

  tree tmp = make_temp_ssa_name (ret_type, NULL, label);
  gimple phi;

  phi = create_phi_node (tmp, bb);
  /* RET_TYPE can be a float when -ffast-maths is enabled.  */
  add_phi_arg (phi, fold_convert (ret_type, init), single_pred_edge (bb),
	       UNKNOWN_LOCATION);
  return PHI_RESULT (phi);
}
static void
build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
		 tree tidx)
{
  tree array_type, ctor, decl, value_type, name, fetch;
  gimple load;
  gimple_stmt_iterator gsi;

  gcc_assert (info.default_values[num]);
  value_type = TREE_TYPE (info.default_values[num]);
  array_type = build_array_type (value_type, arr_index_type);

  ctor = build_constructor (array_type, info.constructors[num]);
  TREE_CONSTANT (ctor) = true;

  decl = build_decl (VAR_DECL, NULL_TREE, array_type);
  TREE_STATIC (decl) = 1;
  DECL_INITIAL (decl) = ctor;

  DECL_NAME (decl) = create_tmp_var_name ("CSWTCH");
  DECL_ARTIFICIAL (decl) = 1;
  TREE_CONSTANT (decl) = 1;
  add_referenced_var (decl);
  varpool_mark_needed_node (varpool_node (decl));
  varpool_finalize_decl (decl);
  mark_sym_for_renaming (decl);

  name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL);
  info.target_inbound_names[num] = name;

  fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
		  NULL_TREE);
  load = gimple_build_assign (name, fetch);
  SSA_NAME_DEF_STMT (name) = load;

  gsi = gsi_for_stmt (swtch);
  gsi_insert_before (&gsi, load, GSI_SAME_STMT);
  mark_symbols_for_renaming (load);

  info.arr_ref_last = load;
}
Ejemplo n.º 14
0
static bool
verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
{
  edge e;
  bool err = false;
  unsigned i, phi_num_args = PHI_NUM_ARGS (phi);

  if (EDGE_COUNT (bb->preds) != phi_num_args)
    {
      error ("incoming edge count does not match number of PHI arguments");
      err = true;
      goto error;
    }

  for (i = 0; i < phi_num_args; i++)
    {
      use_operand_p op_p = PHI_ARG_DEF_PTR (phi, i);
      tree op = USE_FROM_PTR (op_p);


      e = EDGE_PRED (bb, i);

      if (op == NULL_TREE)
	{
	  error ("PHI argument is missing for edge %d->%d",
	         e->src->index,
		 e->dest->index);
	  err = true;
	  goto error;
	}

      if (TREE_CODE (op) != SSA_NAME && !is_gimple_min_invariant (op))
	{
	  error ("PHI argument is not SSA_NAME, or invariant");
	  err = true;
	}

      if (TREE_CODE (op) == SSA_NAME)
	err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op_p,
			  phi, e->flags & EDGE_ABNORMAL,
			  !is_gimple_reg (PHI_RESULT (phi)),
			  NULL);

      if (e->dest != bb)
	{
	  error ("wrong edge %d->%d for PHI argument",
	         e->src->index, e->dest->index);
	  err = true;
	}

      if (err)
	{
	  fprintf (stderr, "PHI argument\n");
	  print_generic_stmt (stderr, op, TDF_VOPS);
	  goto error;
	}
    }

error:
  if (err)
    {
      fprintf (stderr, "for PHI node\n");
      print_generic_stmt (stderr, phi, TDF_VOPS);
    }


  return err;
}
static bool
minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                    edge e0, edge e1, gimple phi,
                    tree arg0, tree arg1)
{
    tree result, type;
    gimple cond, new_stmt;
    edge true_edge, false_edge;
    enum tree_code cmp, minmax, ass_code;
    tree smaller, larger, arg_true, arg_false;
    gimple_stmt_iterator gsi, gsi_from;

    type = TREE_TYPE (PHI_RESULT (phi));

    /* The optimization may be unsafe due to NaNs.  */
    if (HONOR_NANS (TYPE_MODE (type)))
        return false;

    cond = last_stmt (cond_bb);
    cmp = gimple_cond_code (cond);
    result = PHI_RESULT (phi);

    /* This transformation is only valid for order comparisons.  Record which
       operand is smaller/larger if the result of the comparison is true.  */
    if (cmp == LT_EXPR || cmp == LE_EXPR)
    {
        smaller = gimple_cond_lhs (cond);
        larger = gimple_cond_rhs (cond);
    }
    else if (cmp == GT_EXPR || cmp == GE_EXPR)
    {
        smaller = gimple_cond_rhs (cond);
        larger = gimple_cond_lhs (cond);
    }
    else
        return false;

    /* We need to know which is the true edge and which is the false
        edge so that we know if have abs or negative abs.  */
    extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);

    /* Forward the edges over the middle basic block.  */
    if (true_edge->dest == middle_bb)
        true_edge = EDGE_SUCC (true_edge->dest, 0);
    if (false_edge->dest == middle_bb)
        false_edge = EDGE_SUCC (false_edge->dest, 0);

    if (true_edge == e0)
    {
        gcc_assert (false_edge == e1);
        arg_true = arg0;
        arg_false = arg1;
    }
    else
    {
        gcc_assert (false_edge == e0);
        gcc_assert (true_edge == e1);
        arg_true = arg1;
        arg_false = arg0;
    }

    if (empty_block_p (middle_bb))
    {
        if (operand_equal_for_phi_arg_p (arg_true, smaller)
                && operand_equal_for_phi_arg_p (arg_false, larger))
        {
            /* Case

               if (smaller < larger)
               rslt = smaller;
               else
               rslt = larger;  */
            minmax = MIN_EXPR;
        }
        else if (operand_equal_for_phi_arg_p (arg_false, smaller)
                 && operand_equal_for_phi_arg_p (arg_true, larger))
            minmax = MAX_EXPR;
        else
            return false;
    }
    else
    {
        /* Recognize the following case, assuming d <= u:

        if (a <= u)
           b = MAX (a, d);
         x = PHI <b, u>

         This is equivalent to

         b = MAX (a, d);
         x = MIN (b, u);  */

        gimple assign = last_and_only_stmt (middle_bb);
        tree lhs, op0, op1, bound;

        if (!assign
                || gimple_code (assign) != GIMPLE_ASSIGN)
            return false;

        lhs = gimple_assign_lhs (assign);
        ass_code = gimple_assign_rhs_code (assign);
        if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
            return false;
        op0 = gimple_assign_rhs1 (assign);
        op1 = gimple_assign_rhs2 (assign);

        if (true_edge->src == middle_bb)
        {
            /* We got here if the condition is true, i.e., SMALLER < LARGER.  */
            if (!operand_equal_for_phi_arg_p (lhs, arg_true))
                return false;

            if (operand_equal_for_phi_arg_p (arg_false, larger))
            {
                /* Case

                if (smaller < larger)
                   {
                     r' = MAX_EXPR (smaller, bound)
                   }
                 r = PHI <r', larger>  --> to be turned to MIN_EXPR.  */
                if (ass_code != MAX_EXPR)
                    return false;

                minmax = MIN_EXPR;
                if (operand_equal_for_phi_arg_p (op0, smaller))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, smaller))
                    bound = op0;
                else
                    return false;

                /* We need BOUND <= LARGER.  */
                if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
                                                    bound, larger)))
                    return false;
            }
            else if (operand_equal_for_phi_arg_p (arg_false, smaller))
            {
                /* Case

                if (smaller < larger)
                   {
                     r' = MIN_EXPR (larger, bound)
                   }
                 r = PHI <r', smaller>  --> to be turned to MAX_EXPR.  */
                if (ass_code != MIN_EXPR)
                    return false;

                minmax = MAX_EXPR;
                if (operand_equal_for_phi_arg_p (op0, larger))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, larger))
                    bound = op0;
                else
                    return false;

                /* We need BOUND >= SMALLER.  */
                if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
                                                    bound, smaller)))
                    return false;
            }
            else
                return false;
        }
        else
        {
            /* We got here if the condition is false, i.e., SMALLER > LARGER.  */
            if (!operand_equal_for_phi_arg_p (lhs, arg_false))
                return false;

            if (operand_equal_for_phi_arg_p (arg_true, larger))
            {
                /* Case

                if (smaller > larger)
                   {
                     r' = MIN_EXPR (smaller, bound)
                   }
                 r = PHI <r', larger>  --> to be turned to MAX_EXPR.  */
                if (ass_code != MIN_EXPR)
                    return false;

                minmax = MAX_EXPR;
                if (operand_equal_for_phi_arg_p (op0, smaller))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, smaller))
                    bound = op0;
                else
                    return false;

                /* We need BOUND >= LARGER.  */
                if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
                                                    bound, larger)))
                    return false;
            }
            else if (operand_equal_for_phi_arg_p (arg_true, smaller))
            {
                /* Case

                if (smaller > larger)
                   {
                     r' = MAX_EXPR (larger, bound)
                   }
                 r = PHI <r', smaller>  --> to be turned to MIN_EXPR.  */
                if (ass_code != MAX_EXPR)
                    return false;

                minmax = MIN_EXPR;
                if (operand_equal_for_phi_arg_p (op0, larger))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, larger))
                    bound = op0;
                else
                    return false;

                /* We need BOUND <= SMALLER.  */
                if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
                                                    bound, smaller)))
                    return false;
            }
            else
                return false;
        }

        /* Move the statement from the middle block.  */
        gsi = gsi_last_bb (cond_bb);
        gsi_from = gsi_last_bb (middle_bb);
        gsi_move_before (&gsi_from, &gsi);
    }

    /* Emit the statement to compute min/max.  */
    result = duplicate_ssa_name (PHI_RESULT (phi), NULL);
    new_stmt = gimple_build_assign_with_ops (minmax, result, arg0, arg1);
    gsi = gsi_last_bb (cond_bb);
    gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);

    replace_phi_edge_with_variable (cond_bb, e1, phi, result);
    return true;
}
static bool
dse_possible_dead_store_p (gimple stmt, gimple *use_stmt)
{
  gimple temp;
  unsigned cnt = 0;

  *use_stmt = NULL;

  /* Find the first dominated statement that clobbers (part of) the
     memory stmt stores to with no intermediate statement that may use
     part of the memory stmt stores.  That is, find a store that may
     prove stmt to be a dead store.  */
  temp = stmt;
  do
    {
      gimple use_stmt;
      imm_use_iterator ui;
      bool fail = false;
      tree defvar;

      /* Limit stmt walking to be linear in the number of possibly
         dead stores.  */
      if (++cnt > 256)
	return false;

      if (gimple_code (temp) == GIMPLE_PHI)
	defvar = PHI_RESULT (temp);
      else
	defvar = gimple_vdef (temp);
      temp = NULL;
      FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar)
	{
	  cnt++;

	  /* If we ever reach our DSE candidate stmt again fail.  We
	     cannot handle dead stores in loops.  */
	  if (use_stmt == stmt)
	    {
	      fail = true;
	      BREAK_FROM_IMM_USE_STMT (ui);
	    }
	  /* In simple cases we can look through PHI nodes, but we
	     have to be careful with loops and with memory references
	     containing operands that are also operands of PHI nodes.
	     See gcc.c-torture/execute/20051110-*.c.  */
	  else if (gimple_code (use_stmt) == GIMPLE_PHI)
	    {
	      if (temp
		  /* Make sure we are not in a loop latch block.  */
		  || gimple_bb (stmt) == gimple_bb (use_stmt)
		  || dominated_by_p (CDI_DOMINATORS,
				     gimple_bb (stmt), gimple_bb (use_stmt))
		  /* We can look through PHIs to regions post-dominating
		     the DSE candidate stmt.  */
		  || !dominated_by_p (CDI_POST_DOMINATORS,
				      gimple_bb (stmt), gimple_bb (use_stmt)))
		{
		  fail = true;
		  BREAK_FROM_IMM_USE_STMT (ui);
		}
	      temp = use_stmt;
	    }
	  /* If the statement is a use the store is not dead.  */
	  else if (ref_maybe_used_by_stmt_p (use_stmt,
					     gimple_assign_lhs (stmt)))
	    {
	      fail = true;
	      BREAK_FROM_IMM_USE_STMT (ui);
	    }
	  /* If this is a store, remember it or bail out if we have
	     multiple ones (the will be in different CFG parts then).  */
	  else if (gimple_vdef (use_stmt))
	    {
	      if (temp)
		{
		  fail = true;
		  BREAK_FROM_IMM_USE_STMT (ui);
		}
	      temp = use_stmt;
	    }
	}

      if (fail)
	return false;

      /* If we didn't find any definition this means the store is dead
         if it isn't a store to global reachable memory.  In this case
	 just pretend the stmt makes itself dead.  Otherwise fail.  */
      if (!temp)
	{
	  if (is_hidden_global_store (stmt))
	    return false;

	  temp = stmt;
	  break;
	}
    }
static bool
abs_replacement (basic_block cond_bb, basic_block middle_bb,
                 edge e0 ATTRIBUTE_UNUSED, edge e1,
                 gimple phi, tree arg0, tree arg1)
{
    tree result;
    gimple new_stmt, cond;
    gimple_stmt_iterator gsi;
    edge true_edge, false_edge;
    gimple assign;
    edge e;
    tree rhs, lhs;
    bool negate;
    enum tree_code cond_code;

    /* If the type says honor signed zeros we cannot do this
       optimization.  */
    if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
        return false;

    /* OTHER_BLOCK must have only one executable statement which must have the
       form arg0 = -arg1 or arg1 = -arg0.  */

    assign = last_and_only_stmt (middle_bb);
    /* If we did not find the proper negation assignment, then we can not
       optimize.  */
    if (assign == NULL)
        return false;

    /* If we got here, then we have found the only executable statement
       in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
       arg1 = -arg0, then we can not optimize.  */
    if (gimple_code (assign) != GIMPLE_ASSIGN)
        return false;

    lhs = gimple_assign_lhs (assign);

    if (gimple_assign_rhs_code (assign) != NEGATE_EXPR)
        return false;

    rhs = gimple_assign_rhs1 (assign);

    /* The assignment has to be arg0 = -arg1 or arg1 = -arg0.  */
    if (!(lhs == arg0 && rhs == arg1)
            && !(lhs == arg1 && rhs == arg0))
        return false;

    cond = last_stmt (cond_bb);
    result = PHI_RESULT (phi);

    /* Only relationals comparing arg[01] against zero are interesting.  */
    cond_code = gimple_cond_code (cond);
    if (cond_code != GT_EXPR && cond_code != GE_EXPR
            && cond_code != LT_EXPR && cond_code != LE_EXPR)
        return false;

    /* Make sure the conditional is arg[01] OP y.  */
    if (gimple_cond_lhs (cond) != rhs)
        return false;

    if (FLOAT_TYPE_P (TREE_TYPE (gimple_cond_rhs (cond)))
            ? real_zerop (gimple_cond_rhs (cond))
            : integer_zerop (gimple_cond_rhs (cond)))
        ;
    else
        return false;

    /* We need to know which is the true edge and which is the false
       edge so that we know if have abs or negative abs.  */
    extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);

    /* For GT_EXPR/GE_EXPR, if the true edge goes to OTHER_BLOCK, then we
       will need to negate the result.  Similarly for LT_EXPR/LE_EXPR if
       the false edge goes to OTHER_BLOCK.  */
    if (cond_code == GT_EXPR || cond_code == GE_EXPR)
        e = true_edge;
    else
        e = false_edge;

    if (e->dest == middle_bb)
        negate = true;
    else
        negate = false;

    result = duplicate_ssa_name (result, NULL);

    if (negate)
    {
        tree tmp = create_tmp_var (TREE_TYPE (result), NULL);
        add_referenced_var (tmp);
        lhs = make_ssa_name (tmp, NULL);
    }
    else
        lhs = result;

    /* Build the modify expression with abs expression.  */
    new_stmt = gimple_build_assign_with_ops (ABS_EXPR, lhs, rhs, NULL);

    gsi = gsi_last_bb (cond_bb);
    gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);

    if (negate)
    {
        /* Get the right GSI.  We want to insert after the recently
        added ABS_EXPR statement (which we know is the first statement
         in the block.  */
        new_stmt = gimple_build_assign_with_ops (NEGATE_EXPR, result, lhs, NULL);

        gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
    }

    replace_phi_edge_with_variable (cond_bb, e1, phi, result);

    /* Note that we optimized this PHI.  */
    return true;
}
Ejemplo n.º 18
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);
}
Ejemplo n.º 19
0
static bool
factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
				   tree arg0, tree arg1)
{
  gimple arg0_def_stmt = NULL, arg1_def_stmt = NULL, new_stmt;
  tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE;
  tree temp, result;
  gphi *newphi;
  gimple_stmt_iterator gsi, gsi_for_def;
  source_location locus = gimple_location (phi);
  enum tree_code convert_code;

  /* Handle only PHI statements with two arguments.  TODO: If all
     other arguments to PHI are INTEGER_CST or if their defining
     statement have the same unary operation, we can handle more
     than two arguments too.  */
  if (gimple_phi_num_args (phi) != 2)
    return false;

  /* First canonicalize to simplify tests.  */
  if (TREE_CODE (arg0) != SSA_NAME)
    {
      std::swap (arg0, arg1);
      std::swap (e0, e1);
    }

  if (TREE_CODE (arg0) != SSA_NAME
      || (TREE_CODE (arg1) != SSA_NAME
	  && TREE_CODE (arg1) != INTEGER_CST))
    return false;

  /* Check if arg0 is an SSA_NAME and the stmt which defines arg0 is
     a conversion.  */
  arg0_def_stmt = SSA_NAME_DEF_STMT (arg0);
  if (!is_gimple_assign (arg0_def_stmt)
      || !gimple_assign_cast_p (arg0_def_stmt))
    return false;

  /* Use the RHS as new_arg0.  */
  convert_code = gimple_assign_rhs_code (arg0_def_stmt);
  new_arg0 = gimple_assign_rhs1 (arg0_def_stmt);
  if (convert_code == VIEW_CONVERT_EXPR)
    new_arg0 = TREE_OPERAND (new_arg0, 0);

  if (TREE_CODE (arg1) == SSA_NAME)
    {
      /* Check if arg1 is an SSA_NAME and the stmt which defines arg1
	 is a conversion.  */
      arg1_def_stmt = SSA_NAME_DEF_STMT (arg1);
      if (!is_gimple_assign (arg1_def_stmt)
	  || gimple_assign_rhs_code (arg1_def_stmt) != convert_code)
	return false;

      /* Use the RHS as new_arg1.  */
      new_arg1 = gimple_assign_rhs1 (arg1_def_stmt);
      if (convert_code == VIEW_CONVERT_EXPR)
	new_arg1 = TREE_OPERAND (new_arg1, 0);
    }
  else
    {
      /* If arg1 is an INTEGER_CST, fold it to new type.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
	  && int_fits_type_p (arg1, TREE_TYPE (new_arg0)))
	{
	  if (gimple_assign_cast_p (arg0_def_stmt))
	    new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
	  else
	    return false;
	}
      else
	return false;
    }

  /*  If arg0/arg1 have > 1 use, then this transformation actually increases
      the number of expressions evaluated at runtime.  */
  if (!has_single_use (arg0)
      || (arg1_def_stmt && !has_single_use (arg1)))
    return false;

  /* If types of new_arg0 and new_arg1 are different bailout.  */
  if (!types_compatible_p (TREE_TYPE (new_arg0), TREE_TYPE (new_arg1)))
    return false;

  /* Create a new PHI stmt.  */
  result = PHI_RESULT (phi);
  temp = make_ssa_name (TREE_TYPE (new_arg0), NULL);
  newphi = create_phi_node (temp, gimple_bb (phi));

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "PHI ");
      print_generic_expr (dump_file, gimple_phi_result (phi), 0);
      fprintf (dump_file,
	       " changed to factor conversion out from COND_EXPR.\n");
      fprintf (dump_file, "New stmt with CAST that defines ");
      print_generic_expr (dump_file, result, 0);
      fprintf (dump_file, ".\n");
    }

  /* Remove the old cast(s) that has single use.  */
  gsi_for_def = gsi_for_stmt (arg0_def_stmt);
  gsi_remove (&gsi_for_def, true);
  if (arg1_def_stmt)
    {
      gsi_for_def = gsi_for_s
static bool
conditional_replacement (basic_block cond_bb, basic_block middle_bb,
                         edge e0, edge e1, gimple phi,
                         tree arg0, tree arg1)
{
    tree result;
    gimple stmt, new_stmt;
    tree cond;
    gimple_stmt_iterator gsi;
    edge true_edge, false_edge;
    tree new_var, new_var2;

    /* FIXME: Gimplification of complex type is too hard for now.  */
    if (TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
            || TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE)
        return false;

    /* The PHI arguments have the constants 0 and 1, then convert
       it to the conditional.  */
    if ((integer_zerop (arg0) && integer_onep (arg1))
            || (integer_zerop (arg1) && integer_onep (arg0)))
        ;
    else
        return false;

    if (!empty_block_p (middle_bb))
        return false;

    /* At this point we know we have a GIMPLE_COND with two successors.
       One successor is BB, the other successor is an empty block which
       falls through into BB.

       There is a single PHI node at the join point (BB) and its arguments
       are constants (0, 1).

       So, given the condition COND, and the two PHI arguments, we can
       rewrite this PHI into non-branching code:

         dest = (COND) or dest = COND'

       We use the condition as-is if the argument associated with the
       true edge has the value one or the argument associated with the
       false edge as the value zero.  Note that those conditions are not
       the same since only one of the outgoing edges from the GIMPLE_COND
       will directly reach BB and thus be associated with an argument.  */

    stmt = last_stmt (cond_bb);
    result = PHI_RESULT (phi);

    /* To handle special cases like floating point comparison, it is easier and
       less error-prone to build a tree and gimplify it on the fly though it is
       less efficient.  */
    cond = fold_build2 (gimple_cond_code (stmt), boolean_type_node,
                        gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));

    /* We need to know which is the true edge and which is the false
       edge so that we know when to invert the condition below.  */
    extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
    if ((e0 == true_edge && integer_zerop (arg0))
            || (e0 == false_edge && integer_onep (arg0))
            || (e1 == true_edge && integer_zerop (arg1))
            || (e1 == false_edge && integer_onep (arg1)))
        cond = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);

    /* Insert our new statements at the end of conditional block before the
       COND_STMT.  */
    gsi = gsi_for_stmt (stmt);
    new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true,
                                        GSI_SAME_STMT);

    if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var)))
    {
        new_var2 = create_tmp_var (TREE_TYPE (result), NULL);
        add_referenced_var (new_var2);
        new_stmt = gimple_build_assign_with_ops (CONVERT_EXPR, new_var2,
                   new_var, NULL);
        new_var2 = make_ssa_name (new_var2, new_stmt);
        gimple_assign_set_lhs (new_stmt, new_var2);
        gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
        new_var = new_var2;
    }

    replace_phi_edge_with_variable (cond_bb, e1, phi, new_var);

    /* Note that we optimized this PHI.  */
    return true;
}
Ejemplo n.º 21
0
static bool
init_dont_simulate_again (void)
{
  basic_block bb;
  block_stmt_iterator bsi;
  tree phi;
  bool saw_a_complex_op = false;

  FOR_EACH_BB (bb)
    {
      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
	DONT_SIMULATE_AGAIN (phi) = !is_complex_reg (PHI_RESULT (phi));

      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
	{
	  tree orig_stmt, stmt, rhs = NULL;
	  bool dsa;

	  orig_stmt = stmt = bsi_stmt (bsi);

	  /* Most control-altering statements must be initially 
	     simulated, else we won't cover the entire cfg.  */
	  dsa = !stmt_ends_bb_p (stmt);

	  switch (TREE_CODE (stmt))
	    {
	    case RETURN_EXPR:
	      /* We don't care what the lattice value of <retval> is,
		 since it's never used as an input to another computation.  */
	      dsa = true;
	      stmt = TREE_OPERAND (stmt, 0);
	      if (!stmt || TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
		break;
	      /* FALLTHRU */

	    case GIMPLE_MODIFY_STMT:
	      dsa = !is_complex_reg (GIMPLE_STMT_OPERAND (stmt, 0));
	      rhs = GIMPLE_STMT_OPERAND (stmt, 1);
	      break;

	    case COND_EXPR:
	      rhs = TREE_OPERAND (stmt, 0);
	      break;

	    default:
	      break;
	    }

	  if (rhs)
	    switch (TREE_CODE (rhs))
	      {
	      case EQ_EXPR:
	      case NE_EXPR:
		rhs = TREE_OPERAND (rhs, 0);
		/* FALLTHRU */

	      case PLUS_EXPR:
	      case MINUS_EXPR:
	      case MULT_EXPR:
	      case TRUNC_DIV_EXPR:
	      case CEIL_DIV_EXPR:
	      case FLOOR_DIV_EXPR:
	      case ROUND_DIV_EXPR:
	      case RDIV_EXPR:
	      case NEGATE_EXPR:
	      case CONJ_EXPR:
		if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE)
		  saw_a_complex_op = true;
		break;

	      case REALPART_EXPR:
	      case IMAGPART_EXPR:
		/* The total store transformation performed during
		   gimplification creates such uninitialized loads
		   and we need to lower the statement to be able
		   to fix things up.  */
		if (TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
		    && ssa_undefined_value_p (TREE_OPERAND (rhs, 0)))
		  saw_a_complex_op = true;
		break;

	      default:
		break;
	      }

	  DONT_SIMULATE_AGAIN (orig_stmt) = dsa;
	}
    }

  return saw_a_complex_op;
}
Ejemplo n.º 22
0
static bool
init_dont_simulate_again (void)
{
  basic_block bb;
  block_stmt_iterator bsi;
  tree phi;
  bool saw_a_complex_op = false;

  FOR_EACH_BB (bb)
    {
      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
	DONT_SIMULATE_AGAIN (phi) = !is_complex_reg (PHI_RESULT (phi));

      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
	{
	  tree orig_stmt, stmt, rhs = NULL;
	  bool dsa;

	  orig_stmt = stmt = bsi_stmt (bsi);

	  /* Most control-altering statements must be initially 
	     simulated, else we won't cover the entire cfg.  */
	  dsa = !stmt_ends_bb_p (stmt);

	  switch (TREE_CODE (stmt))
	    {
	    case RETURN_EXPR:
	      /* We don't care what the lattice value of <retval> is,
		 since it's never used as an input to another computation.  */
	      dsa = true;
	      stmt = TREE_OPERAND (stmt, 0);
	      if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR)
		break;
	      /* FALLTHRU */

	    case MODIFY_EXPR:
	      dsa = !is_complex_reg (TREE_OPERAND (stmt, 0));
	      rhs = TREE_OPERAND (stmt, 1);
	      break;

	    case COND_EXPR:
	      rhs = TREE_OPERAND (stmt, 0);
	      break;

	    default:
	      break;
	    }

	  if (rhs)
	    switch (TREE_CODE (rhs))
	      {
	      case EQ_EXPR:
	      case NE_EXPR:
		rhs = TREE_OPERAND (rhs, 0);
		/* FALLTHRU */

	      case PLUS_EXPR:
	      case MINUS_EXPR:
	      case MULT_EXPR:
	      case TRUNC_DIV_EXPR:
	      case CEIL_DIV_EXPR:
	      case FLOOR_DIV_EXPR:
	      case ROUND_DIV_EXPR:
	      case RDIV_EXPR:
	      case NEGATE_EXPR:
	      case CONJ_EXPR:
		if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE)
		  saw_a_complex_op = true;
		break;

	      default:
		break;
	      }

	  DONT_SIMULATE_AGAIN (orig_stmt) = dsa;
	}
    }

  return saw_a_complex_op;
}