of the entry edges and the exit edges.  */
  int m_entry_freq, m_exit_freq;
};

/* Return the cost of storing the register on entry to the loop and
   loading it back on exit from the loop.  This is the cost to use if
   the register is spilled within the loop but is successfully allocated
   in the parent loop.  */
inline int
ira_loop_border_costs::spill_inside_loop_cost () const
{
  return (m_entry_freq * ira_memory_move_cost[m_mode][m_class][0]
	  + m_exit_freq * ira_memory_move_cost[m_mode][m_class][1]);
}

/* Return the cost of loading the register on entry to the loop and
   storing it back on exit from the loop.  This is the cost to use if
   the register is successfully allocated within the loop but is spilled
   in the parent loop.  */
inline int
ira_loop_border_costs::spill_outside_loop_cost () const
{
  return (m_entry_freq * ira_memory_move_cost[m_mode][m_class][1]
	  + m_exit_freq * ira_memory_move_cost[m_mode][m_class][0]);
}

/* Return the cost of moving the pseudo register between different hard
   registers on entry and exit from the loop.  This is the cost to use
   if the register is successfully allocated within both this loop and
   the parent loop, but the allocations for the loops differ.  */
inline int
ira_loop_border_costs::move_between_loops_cost () const
{
  ira_init_register_move_cost_if_necessary (m_mode);
  auto move_cost = ira_register_move_cost[m_mode][m_class][m_class];
  return move_cost * (m_entry_freq + m_exit_freq);
}

/* Return true if subloops that contain allocnos for A's register can
   use a different assignment from A.  ALLOCATED_P is true for the case
   in which allocation succeeded for A.  EXCLUDE_OLD_RELOAD is true if
   we should always return false for non-LRA targets.  (This is a hack
   and should be removed along with old reload.)  */
inline bool
ira_subloop_allocnos_can_differ_p (ira_allocno_t a, bool allocated_p = true,
				   bool exclude_old_reload = true)
{
  if (exclude_old_reload && !ira_use_lra_p)
    return false;

  auto regno = ALLOCNO_REGNO (a);

  if (pic_offset_table_rtx != NULL
      && regno == (int) REGNO (pic_offset_table_rtx))
    return false;

  ira_assert (regno < ira_reg_equiv_len);
  if (ira_equiv_no_lvalue_p (regno))
    return false;

  /* Avoid overlapping multi-registers.  Moves between them might result
     in wrong code generation.  */
  if (allocated_p)
    {
      auto pclass = ira_pressure_class_translate[ALLOCNO_CLASS (a)];
      if (ira_reg_class_max_nregs[pclass][ALLOCNO_MODE (a)] > 1)
	return false;
    }

  return true;
}

/* Return true if we should treat A and SUBLOOP_A as belonging to a
   single region.  */
inline bool
ira_single_region_allocno_p (ira_allocno_t a, ira_allocno_t subloop_a)
{
  if (flag_ira_region != IRA_REGION_MIXED)
    return false;

  if (ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P (subloop_a))
    return false;

  auto rclass = ALLOCNO_CLASS (a);
  auto pclass = ira_pressure_class_translate[rclass];
  auto loop_used_regs = ALLOCNO_LOOP_TREE_NODE (a)->reg_pressure[pclass];
  return loop_used_regs <= ira_class_hard_regs_num[pclass];
}

/* Return the set of all hard registers that conflict with A.  */
inline HARD_REG_SET
ira_total_conflict_hard_regs (ira_allocno_t a)
{
  auto obj_0 = ALLOCNO_OBJECT (a, 0);
  HARD_REG_SET conflicts = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj_0);
  for (int i = 1; i < ALLOCNO_NUM_OBJECTS (a); i++)
    conflicts |= OBJECT_TOTAL_CONFLICT_HARD_REGS (ALLOCNO_OBJECT (a, i));
  return conflicts;
}

/* Return the cost of saving a caller-saved register before each call
   in A's live range and restoring the same register after each call.  */
inline int
ira_caller_save_cost (ira_allocno_t a)
{
  auto mode = ALLOCNO_MODE (a);
  auto rclass = ALLOCNO_CLASS (a);
  return (ALLOCNO_CALL_FREQ (a)
	  * (ira_memory_move_cost[mode][rclass][0]
	     + ira_memory_move_cost[mode][rclass][1]));
}

/* A and SUBLOOP_A are allocnos for the same pseudo register, with A's
   loop immediately enclosing SUBLOOP_A's loop.  If we allocate to A a
   hard register R that is clobbered by a call in SUBLOOP_A, decide
   which of the following approaches should be used for handling the
   conflict:

   (1) Spill R on entry to SUBLOOP_A's loop, assign memory to SUBLOOP_A,
       and restore R on exit from SUBLOOP_A's loop.

   (2) Spill R before each necessary call in SUBLOOP_A's live range and
       restore R after each such call.

   Return true if (1) is better than (2).  SPILL_COST is the cost of
   doing (1).  */
inline bool
ira_caller_save_loop_spill_p (ira_allocno_t a, ira_allocno_t subloop_a,
			      int spill_cost)
{
  if (!ira_subloop_allocnos_can_differ_p (a))
    return false;

  /* Calculate the cost of saving a call-clobbered register
     before each call and restoring it afterwards.  */
  int call_cost = ira_caller_save_cost (subloop_a);
  return call_cost && call_cost >= spill_cost;
}

#endif /* GCC_IRA_INT_H */
