aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2023-10-25 10:39:49 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2023-10-25 10:39:49 +0100
commit01b42e9880838e9e4f9d8b419104e8a53dc4c782 (patch)
treedfcb16ff098296e431a11eea9b7bbe2f7b47ed3f
parent7b2ae64b68132c1c643cb34d58cd5eab6f9de652 (diff)
downloadgcc-01b42e9880838e9e4f9d8b419104e8a53dc4c782.zip
gcc-01b42e9880838e9e4f9d8b419104e8a53dc4c782.tar.gz
gcc-01b42e9880838e9e4f9d8b419104e8a53dc4c782.tar.bz2
rtl-ssa: Ensure global registers are live on exit
RTL-SSA mostly relies on DF for block-level register liveness information, including artificial uses and defs at the beginning and end of blocks. But one case was missing. DF does not add artificial uses of global registers to the beginning or end of a block. Instead it marks them as used within every block when computing LR and LIVE problems. For RTL-SSA, global registers behave like memory, which in turn behaves like gimple vops. We need to ensure that they are live on exit so that final definitions do not appear to be unused. Also, the previous live-on-exit handling only considered the exit block itself. It needs to consider non-local gotos as well, since they jump directly to some code in a parent function and so do not have a path to the exit block. gcc/ * rtl-ssa/blocks.cc (function_info::add_artificial_accesses): Force global registers to be live on exit. Handle any block with zero successors like an exit block.
-rw-r--r--gcc/rtl-ssa/blocks.cc19
1 files changed, 16 insertions, 3 deletions
diff --git a/gcc/rtl-ssa/blocks.cc b/gcc/rtl-ssa/blocks.cc
index ecce7a6..49c0d15 100644
--- a/gcc/rtl-ssa/blocks.cc
+++ b/gcc/rtl-ssa/blocks.cc
@@ -866,11 +866,14 @@ function_info::add_artificial_accesses (build_info &bi, df_ref_flags flags)
start_insn_accesses ();
+ HARD_REG_SET added_regs = {};
FOR_EACH_ARTIFICIAL_USE (ref, cfg_bb->index)
if ((DF_REF_FLAGS (ref) & DF_REF_AT_TOP) == flags)
{
unsigned int regno = DF_REF_REGNO (ref);
machine_mode mode = GET_MODE (DF_REF_REAL_REG (ref));
+ if (HARD_REGISTER_NUM_P (regno))
+ SET_HARD_REG_BIT (added_regs, regno);
// A definition must be available.
gcc_checking_assert (bitmap_bit_p (&lr_info->in, regno)
@@ -879,10 +882,20 @@ function_info::add_artificial_accesses (build_info &bi, df_ref_flags flags)
m_temp_uses.safe_push (create_reg_use (bi, insn, { mode, regno }));
}
- // Track the return value of memory by adding an artificial use of
- // memory at the end of the exit block.
- if (flags == 0 && cfg_bb->index == EXIT_BLOCK)
+ // Ensure that global registers and memory are live at the end of any
+ // block that has no successors, such as the exit block and non-local gotos.
+ // Global registers have to be singled out because they are not part of
+ // the DF artifical use list (they are instead treated as used within
+ // every block).
+ if (flags == 0 && EDGE_COUNT (cfg_bb->succs) == 0)
{
+ for (unsigned int i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (global_regs[i] && !TEST_HARD_REG_BIT (added_regs, i))
+ {
+ auto mode = reg_raw_mode[i];
+ m_temp_uses.safe_push (create_reg_use (bi, insn, { mode, i }));
+ }
+
auto *use = allocate<use_info> (insn, memory, bi.current_mem_value ());
add_use (use);
m_temp_uses.safe_push (use);