On 12/18/2018 09:32 AM, Mihail Ionescu wrote:
Hi All,
In Thumb mode when the function prologue gets expanded, in case of a
multiple register push, additional mov instructions are generated to
save the high registers which result in lr getting overwritten before
it's value can be used to retrieve the return address.
The fix consists of detecting if lr is alive after the prologue, in
which case, the lr register won't be used as a scratch.
Regression tested on arm-none-eabi.
gcc/ChangeLog:
2018-11-23 Mihail Ionescu <mihail.ione...@arm.com>
PR target/88167
* config/arm/arm.c: Add lr liveness check.
gcc/testsuite/ChangeLog
2018-11-23 Mihail Ionescu <mihail.ione...@arm.com>
PR target/88167
* gcc.target/arm/pr88167.c: New test.
If everything is ok for trunk, could someone commit it on my behalf?
Best regards,
Mihail
Hi All,
Sorry, I forgot to attach the diff.
Regards,
Mihail
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index
8393f0b87f34c04c9dcc89c63d2e9bbd042c969c..b5c5942791530bc83f54ec96ed3c9c3838080e0f
100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -25186,7 +25186,10 @@ thumb1_expand_prologue (void)
even if they can be pushed. This is to avoid using them to stash the
high
registers. Such kind of stash may clobber the use of arguments. */
pushable_regs = l_mask & (~arg_regs_mask);
- if (lr_needs_saving)
+ bool lr_alive = REGNO_REG_SET_P (df_get_live_out (
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)),
LR_REGNUM);
+
+ if (lr_needs_saving || lr_alive)
pushable_regs &= ~(1 << LR_REGNUM);
if (pushable_regs == 0)
diff --git a/gcc/testsuite/gcc.target/arm/pr88167.c
b/gcc/testsuite/gcc.target/arm/pr88167.c
new file mode 100644
index
0000000000000000000000000000000000000000..e0023716e0010ef3f09878fd6fa1a70f727228b4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr88167.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-options "-mcpu=cortex-m0 -O2" } */
+
+__attribute__ ((used))
+void *retaddr;
+
+__attribute__ ((noinline))
+void foo (void) {
+ retaddr = __builtin_return_address (0);
+
+ /* Used for enforcing registers stacking. */
+ asm volatile ("" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12");
+}
+
+/* { dg-final { scan-assembler-not "mov\tlr," } } */