Ejemplo n.º 1
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.º 2
0
void
reserve_phi_args_for_new_edge (basic_block bb)
{
  size_t len = EDGE_COUNT (bb->preds);
  size_t cap = ideal_phi_node_len (len + 4);
  gimple_stmt_iterator gsi;

  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    {
      gimple *loc = gsi_stmt_ptr (&gsi);

      if (len > gimple_phi_capacity (*loc))
	{
	  gimple old_phi = *loc;

	  resize_phi_node (loc, cap);

	  /* The result of the PHI is defined by this PHI node.  */
	  SSA_NAME_DEF_STMT (gimple_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);

      (*loc)->gimple_phi.nargs++;
    }
}
Ejemplo n.º 3
0
void
release_phi_node (gimple phi)
{
  size_t bucket;
  size_t len = gimple_phi_capacity (phi);
  size_t x;

  for (x = 0; x < gimple_phi_num_args (phi); x++)
    {
      use_operand_p  imm;
      imm = gimple_phi_arg_imm_use_ptr (phi, x);
      delink_imm_use (imm);
    }

  bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len;
  bucket -= 2;
  VEC_safe_push (gimple, gc, free_phinodes[bucket], phi);
  free_phinode_count++;
}
Ejemplo n.º 4
0
static gimple
resize_phi_node (gimple phi, size_t len)
{
  size_t old_size, i;
  gimple new_phi;

  gcc_assert (len > gimple_phi_capacity (phi));

  /* The garbage collector will not look at the PHI node beyond the
     first PHI_NUM_ARGS elements.  Therefore, all we have to copy is a
     portion of the PHI node currently in use.  */
  old_size = sizeof (struct gimple_statement_phi)
	     + (gimple_phi_num_args (phi) - 1) * sizeof (struct phi_arg_d);

  new_phi = allocate_phi_node (len);

  memcpy (new_phi, phi, old_size);

  for (i = 0; i < gimple_phi_num_args (new_phi); i++)
    {
      use_operand_p imm, old_imm;
      imm = gimple_phi_arg_imm_use_ptr (new_phi, i);
      old_imm = gimple_phi_arg_imm_use_ptr (phi, i);
      imm->use = gimple_phi_arg_def_ptr (new_phi, i);
      relink_imm_use_stmt (imm, old_imm, new_phi);
    }

  new_phi->gimple_phi.capacity = len;

  for (i = gimple_phi_num_args (new_phi); i < len; i++)
    {
      use_operand_p imm;

      gimple_phi_arg_set_location (new_phi, i, UNKNOWN_LOCATION);
      imm = gimple_phi_arg_imm_use_ptr (new_phi, i);
      imm->use = gimple_phi_arg_def_ptr (new_phi, i);
      imm->prev = NULL;
      imm->next = NULL;
      imm->loc.stmt = new_phi;
    }

  return new_phi;
}
Ejemplo n.º 5
0
static inline gimple
allocate_phi_node (size_t len)
{
  gimple phi;
  size_t bucket = NUM_BUCKETS - 2;
  size_t size = sizeof (struct gimple_statement_phi)
	        + (len - 1) * sizeof (struct phi_arg_d);

  if (free_phinode_count)
    for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
      if (free_phinodes[bucket])
	break;

  /* If our free list has an element, then use it.  */
  if (bucket < NUM_BUCKETS - 2
      && gimple_phi_capacity (VEC_index (gimple, free_phinodes[bucket], 0))
	 >= len)
    {
      free_phinode_count--;
      phi = VEC_pop (gimple, free_phinodes[bucket]);
      if (VEC_empty (gimple, free_phinodes[bucket]))
	VEC_free (gimple, gc, free_phinodes[bucket]);
#ifdef GATHER_STATISTICS
      phi_nodes_reused++;
#endif
    }
  else
    {
      phi = (gimple) ggc_alloc (size);
#ifdef GATHER_STATISTICS
      phi_nodes_created++;
	{
	  enum gimple_alloc_kind kind = gimple_alloc_kind (GIMPLE_PHI);
          gimple_alloc_counts[(int) kind]++;
          gimple_alloc_sizes[(int) kind] += size;
	}
#endif
    }

  return phi;
}
Ejemplo n.º 6
0
static inline gimple_statement_phi *
allocate_phi_node (size_t len)
{
  gimple_statement_phi *phi;
  size_t bucket = NUM_BUCKETS - 2;
  size_t size = sizeof (struct gimple_statement_phi)
	        + (len - 1) * sizeof (struct phi_arg_d);

  if (free_phinode_count)
    for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
      if (free_phinodes[bucket])
	break;

  /* If our free list has an element, then use it.  */
  if (bucket < NUM_BUCKETS - 2
      && gimple_phi_capacity ((*free_phinodes[bucket])[0]) >= len)
    {
      free_phinode_count--;
      phi = as_a <gimple_statement_phi> (free_phinodes[bucket]->pop ());
      if (free_phinodes[bucket]->is_empty ())
	vec_free (free_phinodes[bucket]);
      if (GATHER_STATISTICS)
	phi_nodes_reused++;
    }
  else
    {
      phi = static_cast <gimple_statement_phi *> (
	ggc_internal_alloc_stat (size MEM_STAT_INFO));
      if (GATHER_STATISTICS)
	{
	  enum gimple_alloc_kind kind = gimple_alloc_kind (GIMPLE_PHI);
	  phi_nodes_created++;
	  gimple_alloc_counts[(int) kind]++;
	  gimple_alloc_sizes[(int) kind] += size;
	}
    }

  return phi;
}