/* Build live ranges for pseudos.
- Copyright (C) 2010-2019 Free Software Foundation, Inc.
+ Copyright (C) 2010-2020 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
#include "sparseset.h"
#include "lra-int.h"
#include "target.h"
+#include "function-abi.h"
/* Program points are enumerated by numbers from range
0..LRA_LIVE_MAX_POINT-1. There are approximately two times more
make_hard_regno_live (int regno)
{
lra_assert (HARD_REGISTER_NUM_P (regno));
- if (TEST_HARD_REG_BIT (hard_regs_live, regno))
+ if (TEST_HARD_REG_BIT (hard_regs_live, regno)
+ || TEST_HARD_REG_BIT (eliminable_regset, regno))
return;
SET_HARD_REG_BIT (hard_regs_live, regno);
sparseset_set_bit (start_living, regno);
static void
make_hard_regno_dead (int regno)
{
+ if (TEST_HARD_REG_BIT (eliminable_regset, regno))
+ return;
+
lra_assert (HARD_REGISTER_NUM_P (regno));
unsigned int i;
EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
mark_pseudo_dead (int regno)
{
lra_assert (!HARD_REGISTER_NUM_P (regno));
- IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live);
+ lra_reg_info[regno].conflict_hard_regs |= hard_regs_live;
if (!sparseset_bit_p (pseudos_live, regno))
return;
/* Structure describing local BB data used for pseudo
live-analysis. */
-struct bb_data_pseudos
+class bb_data_pseudos
{
+public:
/* Basic block about which the below data are. */
basic_block bb;
bitmap_head killed_pseudos; /* pseudos killed in the BB. */
};
/* Array for all BB data. Indexed by the corresponding BB index. */
-typedef struct bb_data_pseudos *bb_data_t;
+typedef class bb_data_pseudos *bb_data_t;
/* All basic block data are referred through the following array. */
static bb_data_t bb_data;
{
bitmap_initialize (&all_hard_regs_bitmap, ®_obstack);
bitmap_set_range (&all_hard_regs_bitmap, 0, FIRST_PSEUDO_REGISTER);
- bb_data = XNEWVEC (struct bb_data_pseudos, last_basic_block_for_fn (cfun));
+ bb_data = XNEWVEC (class bb_data_pseudos, last_basic_block_for_fn (cfun));
bitmap_initialize (&all_blocks, ®_obstack);
basic_block bb;
}
}
-/* Check that REGNO living through calls and setjumps, set up conflict
- regs using LAST_CALL_USED_REG_SET, and clear corresponding bits in
- PSEUDOS_LIVE_THROUGH_CALLS and PSEUDOS_LIVE_THROUGH_SETJUMPS.
- CALL_INSN is a call that is representative of all calls in the region
- described by the PSEUDOS_LIVE_THROUGH_* sets, in terms of the registers
- that it preserves and clobbers. */
+/* Check whether REGNO lives through calls and setjmps and clear
+ the corresponding bits in PSEUDOS_LIVE_THROUGH_CALLS and
+ PSEUDOS_LIVE_THROUGH_SETJUMPS. All calls in the region described
+ by PSEUDOS_LIVE_THROUGH_CALLS have the given ABI. */
static inline void
-check_pseudos_live_through_calls (int regno,
- HARD_REG_SET last_call_used_reg_set,
- rtx_insn *call_insn)
+check_pseudos_live_through_calls (int regno, const function_abi &abi)
{
- int hr;
- rtx_insn *old_call_insn;
-
if (! sparseset_bit_p (pseudos_live_through_calls, regno))
return;
- gcc_assert (call_insn && CALL_P (call_insn));
- old_call_insn = lra_reg_info[regno].call_insn;
- if (!old_call_insn
- || (targetm.return_call_with_max_clobbers
- && targetm.return_call_with_max_clobbers (old_call_insn, call_insn)
- == call_insn))
- lra_reg_info[regno].call_insn = call_insn;
+ machine_mode mode = PSEUDO_REGNO_MODE (regno);
sparseset_clear_bit (pseudos_live_through_calls, regno);
- IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs,
- last_call_used_reg_set);
-
- 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);
+ lra_reg_info[regno].conflict_hard_regs |= abi.mode_clobbers (mode);
if (! sparseset_bit_p (pseudos_live_through_setjumps, regno))
return;
sparseset_clear_bit (pseudos_live_through_setjumps, regno);
static inline bool
reg_early_clobber_p (const struct lra_insn_reg *reg, int n_alt)
{
- return (reg->early_clobber
- && (n_alt == LRA_UNKNOWN_ALT
- || (n_alt != LRA_NON_CLOBBERED_ALT
- && TEST_BIT (reg->early_clobber_alts, n_alt))));
-}
-
-/* Return true if call instructions CALL1 and CALL2 use ABIs that
- preserve the same set of registers. */
-
-static bool
-calls_have_same_clobbers_p (rtx_insn *call1, rtx_insn *call2)
-{
- if (!targetm.return_call_with_max_clobbers)
- return false;
-
- return (targetm.return_call_with_max_clobbers (call1, call2) == call1
- && targetm.return_call_with_max_clobbers (call2, call1) == call2);
+ return (n_alt == LRA_UNKNOWN_ALT
+ ? reg->early_clobber_alts != 0
+ : (n_alt != LRA_NON_CLOBBERED_ALT
+ && TEST_BIT (reg->early_clobber_alts, n_alt)));
}
/* Process insns of the basic block BB to update pseudo live ranges,
rtx_insn *next;
rtx link, *link_loc;
bool need_curr_point_incr;
- HARD_REG_SET last_call_used_reg_set;
- rtx_insn *call_insn = NULL;
- rtx_insn *last_call_insn = NULL;
+ /* Only has a meaningful value once we've seen a call. */
+ function_abi last_call_abi = default_function_abi;
reg_live_out = df_get_live_out (bb);
sparseset_clear (pseudos_live);
sparseset_clear (pseudos_live_through_calls);
sparseset_clear (pseudos_live_through_setjumps);
- CLEAR_HARD_REG_SET (last_call_used_reg_set);
REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
- AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
+ hard_regs_live &= ~eliminable_regset;
EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
{
update_pseudo_point (j, curr_point, USE_POINT);
bool call_p;
int n_alt, dst_regno, src_regno;
rtx set;
- struct lra_insn_reg *reg, *hr;
+ struct lra_insn_reg *reg;
if (!NONDEBUG_INSN_P (curr_insn))
continue;
break;
}
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_IN && !reg->clobber_high)
+ if (reg->type != OP_IN)
{
remove_p = false;
break;
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);
- }
-
- if (!HARD_REGISTER_NUM_P (reg->regno))
- for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next)
- if (hr->clobber_high
- && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)),
- GET_MODE_SIZE (hr->biggest_mode)))
- SET_HARD_REG_BIT (lra_reg_info[reg->regno].conflict_hard_regs,
- hr->regno);
- }
+ if (reg->type != OP_IN)
+ {
+ update_pseudo_point (reg->regno, curr_point, USE_POINT);
+ mark_regno_live (reg->regno, reg->biggest_mode);
+ /* ??? Should be a no-op for unused registers. */
+ check_pseudos_live_through_calls (reg->regno, last_call_abi);
+ }
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
if (reg->type != OP_IN)
if (call_p)
{
- call_insn = curr_insn;
- if (! flag_ipa_ra && ! targetm.return_call_with_max_clobbers)
- COPY_HARD_REG_SET(last_call_used_reg_set, call_used_reg_set);
- else
- {
- HARD_REG_SET this_call_used_reg_set;
- get_call_reg_set_usage (curr_insn, &this_call_used_reg_set,
- call_used_reg_set);
-
- bool flush = (! hard_reg_set_empty_p (last_call_used_reg_set)
- && ( ! hard_reg_set_equal_p (last_call_used_reg_set,
- this_call_used_reg_set)))
- || (last_call_insn && ! calls_have_same_clobbers_p
- (call_insn,
- last_call_insn));
-
- 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);
+ function_abi call_abi = insn_callee_abi (curr_insn);
- if (flush)
- check_pseudos_live_through_calls (j,
- last_call_used_reg_set,
- last_call_insn);
- }
- COPY_HARD_REG_SET(last_call_used_reg_set, this_call_used_reg_set);
- last_call_insn = call_insn;
- }
+ if (last_call_abi != call_abi)
+ EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
+ check_pseudos_live_through_calls (j, last_call_abi);
+
+ last_call_abi = call_abi;
sparseset_ior (pseudos_live_through_calls,
pseudos_live_through_calls, pseudos_live);
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);
+ check_pseudos_live_through_calls (reg->regno, last_call_abi);
}
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
}
if (bb_has_eh_pred (bb))
+ /* Any pseudos that are currently live conflict with the eh_return
+ data registers. For liveness purposes, these registers are set
+ by artificial definitions at the start of the BB, so are not
+ actually live on entry. */
for (j = 0; ; ++j)
{
unsigned int regno = EH_RETURN_DATA_REGNO (j);
if (regno == INVALID_REGNUM)
break;
+
make_hard_regno_live (regno);
+ make_hard_regno_dead (regno);
}
/* Pseudos can't go in stack regs at the start of a basic block that
- is reached by an abnormal edge. Likewise for call clobbered regs,
- because caller-save, fixup_abnormal_edges and possibly the table
- driven EH machinery are not quite ready to handle such pseudos
- live across such edges. */
+ is reached by an abnormal edge. Likewise for registers that are at
+ least partly call clobbered, because caller-save, fixup_abnormal_edges
+ and possibly the table driven EH machinery are not quite ready to
+ handle such pseudos live across such edges. */
if (bb_has_abnormal_pred (bb))
{
+ HARD_REG_SET clobbers;
+
+ CLEAR_HARD_REG_SET (clobbers);
#ifdef STACK_REGS
EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, px)
lra_reg_info[px].no_stack_p = true;
for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++)
- make_hard_regno_live (px);
+ SET_HARD_REG_BIT (clobbers, px);
#endif
/* No need to record conflicts for call clobbered regs if we
have nonlocal labels around, as we don't ever try to
if (!cfun->has_nonlocal_label
&& has_abnormal_call_or_eh_pred_edge_p (bb))
for (px = 0; HARD_REGISTER_NUM_P (px); px++)
- if (call_used_regs[px]
+ if (eh_edge_abi.clobbers_at_least_part_of_reg_p (px)
#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
/* We should create a conflict of PIC pseudo with PIC
hard reg as PIC hard reg can have a wrong value after
&& !HARD_REGISTER_P (pic_offset_table_rtx))
#endif
)
+ SET_HARD_REG_BIT (clobbers, px);
+
+ clobbers &= ~hard_regs_live;
+ for (px = 0; HARD_REGISTER_NUM_P (px); px++)
+ if (TEST_HARD_REG_BIT (clobbers, px))
+ {
make_hard_regno_live (px);
+ make_hard_regno_dead (px);
+ }
}
bool live_change_p = false;
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);
+ check_pseudos_live_through_calls (j, last_call_abi);
}
for (i = 0; HARD_REGISTER_NUM_P (i); ++i)
lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]);
else
lra_reg_info[i].biggest_mode = VOIDmode;
- lra_reg_info[i].call_insn = NULL;
if (!HARD_REGISTER_NUM_P (i)
&& lra_reg_info[i].nrefs != 0)
{