https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88440

--- Comment #21 from Richard Biener <rguenth at gcc dot gnu.org> ---
Ick.

static inline void
check_pseudos_live_through_calls (int regno,
                                  HARD_REG_SET last_call_used_reg_set,
                                  rtx_insn *call_insn)
{
...
  for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++)
    if (targetm.hard_regno_call_part_clobbered (call_insn, hr,
                                                PSEUDO_REGNO_MODE (regno)))
      add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs,
                           PSEUDO_REGNO_MODE (regno), hr);

this loop is repeatedly computing an implicit hard-reg set for
which hard-regs are partly clobbered by the call for the _same_
actual instruction since check_pseudos_live_through_calls is called
via

      /* Mark each defined value as live.  We need to do this for
         unused values because they still conflict with quantities
         that are live at the time of the definition.  */
      for (reg = curr_id->regs; reg != NULL; reg = reg->next)
        {
          if (reg->type != OP_IN)
            {
              update_pseudo_point (reg->regno, curr_point, USE_POINT);
              mark_regno_live (reg->regno, reg->biggest_mode);
              check_pseudos_live_through_calls (reg->regno,
                                                last_call_used_reg_set,
                                                call_insn);
...
        }

and

              EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
                {
                  IOR_HARD_REG_SET (lra_reg_info[j].actual_call_used_reg_set,
                                    this_call_used_reg_set);

                  if (flush)
                    check_pseudos_live_through_calls (j,
                                                      last_call_used_reg_set,
                                                      last_call_insn);
                }

and

      /* Mark each used value as live.  */
      for (reg = curr_id->regs; reg != NULL; reg = reg->next)
        if (reg->type != OP_OUT)
          {
            if (reg->type == OP_IN)
              update_pseudo_point (reg->regno, curr_point, USE_POINT);
            mark_regno_live (reg->regno, reg->biggest_mode);
            check_pseudos_live_through_calls (reg->regno,
                                              last_call_used_reg_set,
                                              call_insn);
          }

and

  EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb), FIRST_PSEUDO_REGISTER, j, bi)
    {
      if (sparseset_cardinality (pseudos_live_through_calls) == 0)
        break;
      if (sparseset_bit_p (pseudos_live_through_calls, j))
        check_pseudos_live_through_calls (j, last_call_used_reg_set,
call_insn);
    }

the pseudos mode may change but I guess usually it doesn't.  I also wonder
why the target hook doesn't return a hard-reg-set ...

That said, the above code doesn't scale well with functions with a lot of
calls at least, also the passed call_insn isn't the current insn and
might even be NULL.  All but aarch64 do not even look at the actual instruction
(even more an argument for re-designing the hook with it's use in mind).

I guess an artificial testcase with a lot of calls and a lot of live
pseudos (even single-BB) should show this issue easily.

Samples: 579  of event 'cycles:ppp', Event count (approx.): 257134187434191     
Overhead  Command  Shared Object     Symbol                                     
  22.26%  f951     f951              [.] process_bb_lives
  15.06%  f951     f951              [.] ix86_hard_regno_call_part_clobbered
   8.55%  f951     f951              [.] concat
   6.88%  f951     f951              [.] find_base_term
   3.60%  f951     f951              [.] get_ref_base_and_extent
   3.27%  f951     f951              [.] find_base_term
   2.95%  f951     f951              [.] make_hard_regno_dead

Reply via email to