aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2019-05-09 16:00:23 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2019-05-09 16:00:23 +0000
commit4456525c4ebf97649f4976b4981318fba4564c31 (patch)
tree8c0fb9f89d43d84ba3d5a6052ee6623895abb4d5 /gcc
parentfd4485aa04b5db3f0fc367ce7aefc8431112e1a1 (diff)
downloadgcc-4456525c4ebf97649f4976b4981318fba4564c31.zip
gcc-4456525c4ebf97649f4976b4981318fba4564c31.tar.gz
gcc-4456525c4ebf97649f4976b4981318fba4564c31.tar.bz2
[arm] PR target/90405 fix regression for thumb1 with -mtpcs-leaf-frame
-mtpcs-leaf-frame causes an APCS-style backtrace frame to be created on the stack. This should probably be deprecated, but it did reveal an issue with the patch I committed previously to improve the code generation when pushing high registers, in that thumb_find_work_register had a different idea as to which registers were available as scratch registers. The new code actually does a better job of finding a viable work register and doesn't rely so much on assumptions about the ABI, so it seems better to adapt thumb_find_work_register to the new approach. This way we can eliminate some rather crufty code. gcc: PR target/90405 * config/arm/arm.c (callee_saved_reg_p): Move before thumb_find_work_register. (thumb1_prologue_unused_call_clobbered_lo_regs): Move before thumb_find_work_register. Only call df_get_live_out once. (thumb1_epilogue_unused_call_clobbered_lo_regs): Likewise. (thumb_find_work_register): Use thumb1_prologue_unused_call_clobbered_lo_regs instead of ad hoc algorithms to locate a spare call clobbered reg. gcc/testsuite: PR target/90405 * gcc.target/arm/pr90405.c: New test. From-SVN: r271036
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/config/arm/arm.c110
2 files changed, 52 insertions, 70 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 126a150..b761d0a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2019-05-09 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/90405
+ * config/arm/arm.c (callee_saved_reg_p): Move before
+ thumb_find_work_register.
+ (thumb1_prologue_unused_call_clobbered_lo_regs): Move before
+ thumb_find_work_register. Only call df_get_live_out once.
+ (thumb1_epilogue_unused_call_clobbered_lo_regs): Likewise.
+ (thumb_find_work_register): Use
+ thumb1_prologue_unused_call_clobbered_lo_regs instead of ad hoc
+ algorithms to locate a spare call clobbered reg.
+
2019-05-09 Martin Liska <mliska@suse.cz>
* gimple-pretty-print.c (dump_binary_rhs): Dump MIN_EXPR
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 91bb651..528752a 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -7638,6 +7638,41 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg,
}
+/* Whether a register is callee saved or not. This is necessary because high
+ registers are marked as caller saved when optimizing for size on Thumb-1
+ targets despite being callee saved in order to avoid using them. */
+#define callee_saved_reg_p(reg) \
+ (!call_used_regs[reg] \
+ || (TARGET_THUMB1 && optimize_size \
+ && reg >= FIRST_HI_REGNUM && reg <= LAST_HI_REGNUM))
+
+/* Return a mask for the call-clobbered low registers that are unused
+ at the end of the prologue. */
+static unsigned long
+thumb1_prologue_unused_call_clobbered_lo_regs (void)
+{
+ unsigned long mask = 0;
+ bitmap prologue_live_out = df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+ for (int reg = FIRST_LO_REGNUM; reg <= LAST_LO_REGNUM; reg++)
+ if (!callee_saved_reg_p (reg) && !REGNO_REG_SET_P (prologue_live_out, reg))
+ mask |= 1 << (reg - FIRST_LO_REGNUM);
+ return mask;
+}
+
+/* Similarly for the start of the epilogue. */
+static unsigned long
+thumb1_epilogue_unused_call_clobbered_lo_regs (void)
+{
+ unsigned long mask = 0;
+ bitmap epilogue_live_in = df_get_live_in (EXIT_BLOCK_PTR_FOR_FN (cfun));
+
+ for (int reg = FIRST_LO_REGNUM; reg <= LAST_LO_REGNUM; reg++)
+ if (!callee_saved_reg_p (reg) && !REGNO_REG_SET_P (epilogue_live_in, reg))
+ mask |= 1 << (reg - FIRST_LO_REGNUM);
+ return mask;
+}
+
/* Find a spare register to use during the prolog of a function. */
static int
@@ -7645,45 +7680,16 @@ thumb_find_work_register (unsigned long pushed_regs_mask)
{
int reg;
+ unsigned long unused_regs
+ = thumb1_prologue_unused_call_clobbered_lo_regs ();
+
/* Check the argument registers first as these are call-used. The
register allocation order means that sometimes r3 might be used
but earlier argument registers might not, so check them all. */
- for (reg = LAST_ARG_REGNUM; reg >= 0; reg --)
- if (!df_regs_ever_live_p (reg))
+ for (reg = LAST_LO_REGNUM; reg >= FIRST_LO_REGNUM; reg--)
+ if (unused_regs & (1 << (reg - FIRST_LO_REGNUM)))
return reg;
- /* Before going on to check the call-saved registers we can try a couple
- more ways of deducing that r3 is available. The first is when we are
- pushing anonymous arguments onto the stack and we have less than 4
- registers worth of fixed arguments(*). In this case r3 will be part of
- the variable argument list and so we can be sure that it will be
- pushed right at the start of the function. Hence it will be available
- for the rest of the prologue.
- (*): ie crtl->args.pretend_args_size is greater than 0. */
- if (cfun->machine->uses_anonymous_args
- && crtl->args.pretend_args_size > 0)
- return LAST_ARG_REGNUM;
-
- /* The other case is when we have fixed arguments but less than 4 registers
- worth. In this case r3 might be used in the body of the function, but
- it is not being used to convey an argument into the function. In theory
- we could just check crtl->args.size to see how many bytes are
- being passed in argument registers, but it seems that it is unreliable.
- Sometimes it will have the value 0 when in fact arguments are being
- passed. (See testcase execute/20021111-1.c for an example). So we also
- check the args_info.nregs field as well. The problem with this field is
- that it makes no allowances for arguments that are passed to the
- function but which are not used. Hence we could miss an opportunity
- when a function has an unused argument in r3. But it is better to be
- safe than to be sorry. */
- if (! cfun->machine->uses_anonymous_args
- && crtl->args.size >= 0
- && crtl->args.size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
- && (TARGET_AAPCS_BASED
- ? crtl->args.info.aapcs_ncrn < 4
- : crtl->args.info.nregs < 4))
- return LAST_ARG_REGNUM;
-
/* Otherwise look for a call-saved register that is going to be pushed. */
for (reg = LAST_LO_REGNUM; reg > LAST_ARG_REGNUM; reg --)
if (pushed_regs_mask & (1 << reg))
@@ -19441,13 +19447,6 @@ output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
fputs ("\"\n", stream);
}
-/* Whether a register is callee saved or not. This is necessary because high
- registers are marked as caller saved when optimizing for size on Thumb-1
- targets despite being callee saved in order to avoid using them. */
-#define callee_saved_reg_p(reg) \
- (!call_used_regs[reg] \
- || (TARGET_THUMB1 && optimize_size \
- && reg >= FIRST_HI_REGNUM && reg <= LAST_HI_REGNUM))
/* Compute the register save mask for registers 0 through 12
inclusive. This code is used by arm_compute_save_core_reg_mask (). */
@@ -19670,35 +19669,6 @@ arm_compute_save_core_reg_mask (void)
return save_reg_mask;
}
-/* Return a mask for the call-clobbered low registers that are unused
- at the end of the prologue. */
-static unsigned long
-thumb1_prologue_unused_call_clobbered_lo_regs (void)
-{
- unsigned long mask = 0;
-
- for (int reg = 0; reg <= LAST_LO_REGNUM; reg++)
- if (!callee_saved_reg_p (reg)
- && !REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
- reg))
- mask |= 1 << reg;
- return mask;
-}
-
-/* Similarly for the start of the epilogue. */
-static unsigned long
-thumb1_epilogue_unused_call_clobbered_lo_regs (void)
-{
- unsigned long mask = 0;
-
- for (int reg = 0; reg <= LAST_LO_REGNUM; reg++)
- if (!callee_saved_reg_p (reg)
- && !REGNO_REG_SET_P (df_get_live_in (EXIT_BLOCK_PTR_FOR_FN (cfun)),
- reg))
- mask |= 1 << reg;
- return mask;
-}
-
/* Compute a bit mask of which core registers need to be
saved on the stack for the current function. */
static unsigned long