Hi,
When saving registers, function thumb1_expand_prologue () aims at minimizing the
number of push instructions. One of the optimization it does is to push lr
alongside high register(s) (after having moved them to low register(s)) when
there is no low register to save. The way this is implemented is to add lr to
the list of registers that can be pushed just before the push happens. This
would then push lr and allows it to be used for further push if there was not
enough registers to push all high registers to be pushed.
However, the logic that decides what register to move high registers to before
being pushed only looks at low registers (see for loop initialization). This
means not only that lr is not used for pushing high registers but also that lr
is not removed from the list of registers to be pushed when it's not used. This
extra lr push is not poped in epilogue leading in stack corruption.
This patch changes the loop to iterate over register r0 to lr so as to both fix
the stack corruption and reuse lr to push some high register when possible.
ChangeLog entry are as follow:
*** gcc/ChangeLog ***
2016-11-01 Thomas Preud'homme <thomas.preudho...@arm.com>
PR target/77933
* config/arm/arm.c (thumb1_expand_prologue): Also check for lr being a
pushable register.
*** gcc/testsuite/ChangeLog ***
2016-11-01 Thomas Preud'homme <thomas.preudho...@arm.com>
PR target/77933
* gcc.target/arm/pr77933.c: New test.
Testing: no regression on arm-none-eabi GCC cross-compiler targeting Cortex-M0
Is this ok for trunk?
Best regards,
Thomas
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dd8d5e5db8ca50daab648e58df290969aa794862..22a20caf42389748fc64ee0a3f880c6bea4c8f49 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -24990,7 +24990,7 @@ thumb1_expand_prologue (void)
{
unsigned long real_regs_mask = 0;
- for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
+ for (regno = LR_REGNUM; regno >= 0; regno --)
{
if (pushable_regs & (1 << regno))
{
diff --git a/gcc/testsuite/gcc.target/arm/pr77933.c b/gcc/testsuite/gcc.target/arm/pr77933.c
new file mode 100644
index 0000000000000000000000000000000000000000..cba7e9bb9aa57c6755f79b5ec2ea1a8744e23599
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr77933.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+int
+main (void)
+{
+ __asm__ volatile ("" : : : "r8", "r9", "lr");
+ return 0;
+}