The AMD GCN architecture uses 64-bit pointers, but the scalar registers
are 32-bit wide, so pointers must reside in a pair of registers.
The two hard registers holding the frame pointer are currently fixed,
but if they are changed to unfixed (so that the FP can be eliminated),
GCC would sometimes allocate the second register to a pseudo while the
frame pointer was in use, clobbering the value of the FP and crashing
the program.
GCC currently does not handle multi-register hard frame pointers
properly - no_unit_alloc_regs, regs_ever_live, eliminable_regset and
ira_no_alloc_regs (which gets copied to lra_no_alloc_regs) are only set
for HARD_FRAME_POINTER_REGNUM and not for any subsequent registers that
may be used, which means that the register allocators consider
HARD_FRAME_POINTER_REGNUM+1 free. This patch determines the number of
registers needed to store the frame pointer using hard_regno_nregs, and
sets the required variables for HARD_FRAME_POINTER_REGNUM and however
many adjacent registers are needed (which on most architectures should
be zero).
Bootstrapped on x86_64 and tested with no regressions, which is not
surprising as nothing different happens when the FP fits into a single
register. I believe this is true for the 64-bit variants of the more
popular architectures as well (ARM, RS6000, MIPS, Sparc). Are there any
other architectures similar to GCN (i.e. 64-bit pointers with 32-bit GPRs)?
I have not included any specific testcases for this issue as it can
affect pretty much everything not using -fomit-frame-pointer on AMD GCN.
Okay for trunk?
Kwok Yeung
Add support for using multiple registers to hold the frame pointer
2019-11-02 Kwok Cheung Yeung <k...@codesourcery.com>
gcc/
* ira.c (setup_alloc_regs): Setup no_unit_alloc_regs for
frame pointer in multiple registers.
(ira_setup_eliminable_regset): Setup eliminable_regset,
ira_no_alloc_regs and regs_ever_live for frame pointer in
multiple registers.
diff --git a/gcc/ira.c b/gcc/ira.c
index 9f8da67..25e9359 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -515,7 +515,13 @@ setup_alloc_regs (bool use_hard_frame_p)
#endif
no_unit_alloc_regs = fixed_nonglobal_reg_set;
if (! use_hard_frame_p)
- SET_HARD_REG_BIT (no_unit_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+ {
+ int fp_reg_count = hard_regno_nregs (HARD_FRAME_POINTER_REGNUM,
Pmode);
+ for (int reg = HARD_FRAME_POINTER_REGNUM;
+ reg < HARD_FRAME_POINTER_REGNUM + fp_reg_count;
+ reg++)
+ SET_HARD_REG_BIT (no_unit_alloc_regs, reg);
+ }
setup_class_hard_regs ();
}
@@ -2248,6 +2254,7 @@ ira_setup_eliminable_regset (void)
{
int i;
static const struct {const int from, to; } eliminables[] =
ELIMINABLE_REGS;
+ int fp_reg_count = hard_regno_nregs (HARD_FRAME_POINTER_REGNUM, Pmode);
/* Setup is_leaf as frame_pointer_required may use it. This function
is called by sched_init before ira if scheduling is enabled. */
@@ -2276,7 +2283,8 @@ ira_setup_eliminable_regset (void)
frame pointer in LRA. */
if (frame_pointer_needed)
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true);
+ for (i = 0; i < fp_reg_count; i++)
+ df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM + i, true);
ira_no_alloc_regs = no_unit_alloc_regs;
CLEAR_HARD_REG_SET (eliminable_regset);
@@ -2306,17 +2314,21 @@ ira_setup_eliminable_regset (void)
}
if (!HARD_FRAME_POINTER_IS_FRAME_POINTER)
{
- if (!TEST_HARD_REG_BIT (crtl->asm_clobbers,
HARD_FRAME_POINTER_REGNUM))
- {
- SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
- if (frame_pointer_needed)
- SET_HARD_REG_BIT (ira_no_alloc_regs, HARD_FRAME_POINTER_REGNUM);
- }
- else if (frame_pointer_needed)
- error ("%s cannot be used in %<asm%> here",
- reg_names[HARD_FRAME_POINTER_REGNUM]);
- else
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true);
+ for (i = 0; i < fp_reg_count; i++)
+ if (!TEST_HARD_REG_BIT (crtl->asm_clobbers,
+ HARD_FRAME_POINTER_REGNUM + i))
+ {
+ SET_HARD_REG_BIT (eliminable_regset,
+ HARD_FRAME_POINTER_REGNUM + i);
+ if (frame_pointer_needed)
+ SET_HARD_REG_BIT (ira_no_alloc_regs,
+ HARD_FRAME_POINTER_REGNUM + i);
+ }
+ else if (frame_pointer_needed)
+ error ("%s cannot be used in %<asm%> here",
+ reg_names[HARD_FRAME_POINTER_REGNUM + i]);
+ else
+ df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM + i, true);
}
}