/* Reload pseudo regs into hard regs for insns that require hard regs.
- Copyright (C) 1987-2019 Free Software Foundation, Inc.
+ Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GCC.
#include "except.h"
#include "dumpfile.h"
#include "rtl-iter.h"
+#include "function-abi.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
This is only valid if reg_reloaded_contents is set and valid. */
static HARD_REG_SET reg_reloaded_dead;
-/* Indicate whether the register's current value is one that is not
- safe to retain across a call, even for registers that are normally
- call-saved. This is only meaningful for members of reg_reloaded_valid. */
-static HARD_REG_SET reg_reloaded_call_part_clobbered;
-
/* Number of spill-regs so far; number of valid elements of spill_regs. */
static int n_spills;
static void delete_address_reloads (rtx_insn *, rtx_insn *);
static void delete_address_reloads_1 (rtx_insn *, rtx, rtx_insn *);
static void inc_for_reload (rtx, rtx, rtx, poly_int64);
-static void add_auto_inc_notes (rtx_insn *, rtx);
static void substitute (rtx *, const_rtx, rtx);
static bool gen_reload_chain_without_interm_reg_p (int, int);
static int reloads_conflict (int, int);
if (crtl->saves_all_registers)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
+ if (! crtl->abi->clobbers_full_reg_p (i)
+ && ! fixed_regs[i]
+ && ! LOCAL_REGNO (i))
df_set_regs_ever_live (i, true);
/* Find all the pseudo registers that didn't get hard regs
rtx t = XVECEXP (pat, 0, i);
if (GET_CODE (t) == CLOBBER && STACK_REG_P (XEXP (t, 0)))
SET_HARD_REG_BIT (clobbered, REGNO (XEXP (t, 0)));
- /* CLOBBER_HIGH is only supported for LRA. */
- gcc_assert (GET_CODE (t) != CLOBBER_HIGH);
}
/* Get the operand values and constraints out of the insn. */
{
/* End of one alternative - mark the regs in the current
class, and reset the class. */
- IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
+ allowed |= reg_class_contents[cls];
cls = NO_REGS;
p++;
if (c == '#')
/* Those of the registers which are clobbered, but allowed by the
constraints, must be usable as reload registers. So clear them
out of the life information. */
- AND_HARD_REG_SET (allowed, clobbered);
+ allowed &= clobbered;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (allowed, i))
{
HARD_REG_SET used_by_pseudos2;
reg_set_iterator rsi;
- COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set);
+ bad_spill_regs = fixed_reg_set;
memset (spill_cost, 0, sizeof spill_cost);
memset (spill_add_cost, 0, sizeof spill_add_cost);
REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout);
REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
- IOR_HARD_REG_SET (bad_spill_regs, used_by_pseudos);
- IOR_HARD_REG_SET (bad_spill_regs, used_by_pseudos2);
+ bad_spill_regs |= used_by_pseudos;
+ bad_spill_regs |= used_by_pseudos2;
/* Now find out which pseudos are allocated to it, and update
hard_reg_n_uses. */
static int regno_pseudo_regs[FIRST_PSEUDO_REGISTER];
static int best_regno_pseudo_regs[FIRST_PSEUDO_REGISTER];
- COPY_HARD_REG_SET (not_usable, bad_spill_regs);
- IOR_HARD_REG_SET (not_usable, bad_spill_regs_global);
- IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->rclass]);
+ not_usable = (bad_spill_regs
+ | bad_spill_regs_global
+ | ~reg_class_contents[rl->rclass]);
CLEAR_HARD_REG_SET (used_by_other_reload);
for (k = 0; k < order; k++)
&& (inv_reg_alloc_order[regno]
< inv_reg_alloc_order[best_reg])
#else
- && call_used_regs[regno]
- && ! call_used_regs[best_reg]
+ && crtl->abi->clobbers_full_reg_p (regno)
+ && !crtl->abi->clobbers_full_reg_p (best_reg)
#endif
))
{
}
}
- COPY_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local);
- IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local);
+ chain->used_spill_regs = used_spill_regs_local;
+ used_spill_regs |= used_spill_regs_local;
memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
}
case SYMBOL_REF:
case CODE_LABEL:
case PC:
- case CC0:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
structure of the insn in a way that reload can't handle.
We special-case the commonest situation in
eliminate_regs_in_insn, so just replace a PLUS with a
- PLUS here, unless inside a MEM. */
- if (mem_mode != 0
+ PLUS here, unless inside a MEM. In DEBUG_INSNs, it is
+ always ok to replace a PLUS with just a REG. */
+ if ((mem_mode != 0 || (insn && DEBUG_INSN_P (insn)))
&& CONST_INT_P (XEXP (x, 1))
&& known_eq (INTVAL (XEXP (x, 1)), -ep->previous_offset))
return ep->to_rtx;
return x;
case CLOBBER:
- case CLOBBER_HIGH:
case ASM_OPERANDS:
gcc_assert (insn && DEBUG_INSN_P (insn));
break;
case SYMBOL_REF:
case CODE_LABEL:
case PC:
- case CC0:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
elimination_effects (XEXP (x, 0), mem_mode);
return;
- case CLOBBER_HIGH:
- /* CLOBBER_HIGH is only supported for LRA. */
- return;
-
case SET:
/* Check for setting a register that we know about. */
if (REG_P (SET_DEST (x)))
if (dest == hard_frame_pointer_rtx)
return;
- /* CLOBBER_HIGH is only supported for LRA. */
- gcc_assert (GET_CODE (x) != CLOBBER_HIGH);
-
for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
if (reg_eliminate[i].can_eliminate && dest == reg_eliminate[i].to_rtx
&& (GET_CODE (x) != SET
HARD_REG_SET to_spill;
CLEAR_HARD_REG_SET (to_spill);
update_eliminables (&to_spill);
- AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill);
+ used_spill_regs &= ~to_spill;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (to_spill, i))
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi)
{
- IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
- chain->used_spill_regs);
+ pseudo_forbidden_regs[i] |= chain->used_spill_regs;
}
EXECUTE_IF_SET_IN_REG_SET
(&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
{
- IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
- chain->used_spill_regs);
+ pseudo_forbidden_regs[i] |= chain->used_spill_regs;
}
}
{
REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout);
REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
- IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
+ used_by_pseudos |= used_by_pseudos2;
compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout);
compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set);
may be not included in the value calculated here because
of possible removing caller-saves insns (see function
delete_caller_save_insns. */
- COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
- AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
+ chain->used_spill_regs = ~used_by_pseudos & used_spill_regs;
}
}
case SYMBOL_REF:
case LABEL_REF:
CASE_CONST_ANY:
- case CC0:
case PC:
case USE:
case CLOBBER:
- case CLOBBER_HIGH:
return;
case SUBREG:
reg_last_reload_reg = XCNEWVEC (rtx, max_regno);
INIT_REG_SET (®_has_output_reload);
CLEAR_HARD_REG_SET (reg_reloaded_valid);
- CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered);
set_initial_elim_offsets ();
be partially clobbered by the call. */
else if (CALL_P (insn))
{
- AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
- AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+ reg_reloaded_valid
+ &= ~insn_callee_abi (insn).full_and_partial_reg_clobbers ();
/* If this is a call to a setjmp-type function, we must not
reuse any reload reg contents across the call; that will
to be forgotten later. */
static void
-forget_old_reloads_1 (rtx x, const_rtx setter,
- void *data)
+forget_old_reloads_1 (rtx x, const_rtx, void *data)
{
unsigned int regno;
unsigned int nr;
if (!REG_P (x))
return;
- /* CLOBBER_HIGH is only supported for LRA. */
- gcc_assert (setter == NULL_RTX || GET_CODE (setter) != CLOBBER_HIGH);
-
regno = REGNO (x);
if (regno >= FIRST_PSEUDO_REGISTER)
{
HARD_REG_SET tmp;
REG_SET_TO_HARD_REG_SET (tmp, &chain->live_throughout);
- IOR_HARD_REG_SET (reg_used_in_insn, tmp);
+ reg_used_in_insn |= tmp;
REG_SET_TO_HARD_REG_SET (tmp, &chain->dead_or_set);
- IOR_HARD_REG_SET (reg_used_in_insn, tmp);
+ reg_used_in_insn |= tmp;
compute_use_by_pseudos (®_used_in_insn, &chain->live_throughout);
compute_use_by_pseudos (®_used_in_insn, &chain->dead_or_set);
}
CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
}
- COMPL_HARD_REG_SET (reload_reg_unavailable, chain->used_spill_regs);
+ reload_reg_unavailable = ~chain->used_spill_regs;
CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
/* Do output reloading for reload RL, which is for the insn described by
CHAIN and has the number J.
??? At some point we need to support handling output reloads of
- JUMP_INSNs or insns that set cc0. */
+ JUMP_INSNs. */
static void
do_output_reload (class insn_chain *chain, struct reload *rl, int j)
{
: out_regno + k);
reg_reloaded_insn[regno + k] = insn;
SET_HARD_REG_BIT (reg_reloaded_valid, regno + k);
- if (targetm.hard_regno_call_part_clobbered (NULL,
- regno + k,
- mode))
- SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
- regno + k);
- else
- CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
- regno + k);
}
}
}
: in_regno + k);
reg_reloaded_insn[regno + k] = insn;
SET_HARD_REG_BIT (reg_reloaded_valid, regno + k);
- if (targetm.hard_regno_call_part_clobbered (NULL,
- regno + k,
- mode))
- SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
- regno + k);
- else
- CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
- regno + k);
}
}
}
reg_reloaded_insn[src_regno + k] = store_insn;
CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + k);
SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k);
- if (targetm.hard_regno_call_part_clobbered
- (NULL, src_regno + k, mode))
- SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
- src_regno + k);
- else
- CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
- src_regno + k);
SET_HARD_REG_BIT (reg_is_output_reload, src_regno + k);
if (note)
SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
}
}
}
- IOR_HARD_REG_SET (reg_reloaded_dead, reg_reloaded_died);
+ reg_reloaded_dead |= reg_reloaded_died;
}
\f
/* Go through the motions to emit INSN and test if it is strictly valid.
emit_insn (gen_sub2_insn (reloadreg, inc));
}
}
-\f
-static void
-add_auto_inc_notes (rtx_insn *insn, rtx x)
-{
- enum rtx_code code = GET_CODE (x);
- const char *fmt;
- int i, j;
-
- if (code == MEM && auto_inc_p (XEXP (x, 0)))
- {
- add_reg_note (insn, REG_INC, XEXP (XEXP (x, 0), 0));
- return;
- }
-
- /* Scan all the operand sub-expressions. */
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- add_auto_inc_notes (insn, XEXP (x, i));
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- add_auto_inc_notes (insn, XVECEXP (x, i, j));
- }
-}