summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthopre01 <thopre01@138bc75d-0d04-0410-961f-82ee72b054a4>2016-12-09 15:26:17 +0000
committerthopre01 <thopre01@138bc75d-0d04-0410-961f-82ee72b054a4>2016-12-09 15:26:17 +0000
commita8debcf698975c869100f391d6153649757f9915 (patch)
tree57643de118b9279a496bfcf4fda020db34ebcb95
parent6e8509370c759ebf7299c9b5207adf81adc46f16 (diff)
downloadgcc-a8debcf698975c869100f391d6153649757f9915.tar.gz
2016-12-09 Thomas Preud'homme <thomas.preudhomme@arm.com>
Backport from mainline 2016-11-17 Thomas Preud'homme <thomas.preudhomme@arm.com> gcc/ PR target/77933 * config/arm/arm.c (thumb1_expand_prologue): Distinguish between lr being live in the function and lr needing to be saved. Distinguish between already saved pushable registers and registers to push. Check for LR being an available pushable register. gcc/testsuite/ PR target/77933 * gcc.target/arm/pr77933-1.c: New test. * gcc.target/arm/pr77933-2.c: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-6-branch@243490 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/arm/arm.c29
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/gcc.target/arm/pr77933-1.c46
-rw-r--r--gcc/testsuite/gcc.target/arm/pr77933-2.c47
5 files changed, 130 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7622597079a..7d78c39c225 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2016-12-09 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ Backport from mainline
+ 2016-11-17 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ PR target/77933
+ * config/arm/arm.c (thumb1_expand_prologue): Distinguish between lr
+ being live in the function and lr needing to be saved. Distinguish
+ between already saved pushable registers and registers to push.
+ Check for LR being an available pushable register.
+
2016-12-09 Nathan Sidwell <nathan@acm.org>
PR C++/78550
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 83cb13d1195..1dba035c62c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -24710,6 +24710,7 @@ thumb1_expand_prologue (void)
unsigned long live_regs_mask;
unsigned long l_mask;
unsigned high_regs_pushed = 0;
+ bool lr_needs_saving;
func_type = arm_current_func_type ();
@@ -24732,6 +24733,7 @@ thumb1_expand_prologue (void)
offsets = arm_get_frame_offsets ();
live_regs_mask = offsets->saved_regs_mask;
+ lr_needs_saving = live_regs_mask & (1 << LR_REGNUM);
/* Extract a mask of the ones we can give to the Thumb's push instruction. */
l_mask = live_regs_mask & 0x40ff;
@@ -24798,6 +24800,7 @@ thumb1_expand_prologue (void)
{
insn = thumb1_emit_multi_reg_push (l_mask, l_mask);
RTX_FRAME_RELATED_P (insn) = 1;
+ lr_needs_saving = false;
offset = bit_count (l_mask) * UNITS_PER_WORD;
}
@@ -24862,12 +24865,13 @@ thumb1_expand_prologue (void)
be a push of LR and we can combine it with the push of the first high
register. */
else if ((l_mask & 0xff) != 0
- || (high_regs_pushed == 0 && l_mask))
+ || (high_regs_pushed == 0 && lr_needs_saving))
{
unsigned long mask = l_mask;
mask |= (1 << thumb1_extra_regs_pushed (offsets, true)) - 1;
insn = thumb1_emit_multi_reg_push (mask, mask);
RTX_FRAME_RELATED_P (insn) = 1;
+ lr_needs_saving = false;
}
if (high_regs_pushed)
@@ -24885,7 +24889,9 @@ thumb1_expand_prologue (void)
/* Here we need to mask out registers used for passing arguments
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) & 0xff;
+ pushable_regs = l_mask & (~arg_regs_mask);
+ if (lr_needs_saving)
+ pushable_regs &= ~(1 << LR_REGNUM);
if (pushable_regs == 0)
pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
@@ -24893,8 +24899,9 @@ thumb1_expand_prologue (void)
while (high_regs_pushed > 0)
{
unsigned long real_regs_mask = 0;
+ unsigned long push_mask = 0;
- for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
+ for (regno = LR_REGNUM; regno >= 0; regno --)
{
if (pushable_regs & (1 << regno))
{
@@ -24903,6 +24910,7 @@ thumb1_expand_prologue (void)
high_regs_pushed --;
real_regs_mask |= (1 << next_hi_reg);
+ push_mask |= (1 << regno);
if (high_regs_pushed)
{
@@ -24912,23 +24920,20 @@ thumb1_expand_prologue (void)
break;
}
else
- {
- pushable_regs &= ~((1 << regno) - 1);
- break;
- }
+ break;
}
}
/* If we had to find a work register and we have not yet
saved the LR then add it to the list of regs to push. */
- if (l_mask == (1 << LR_REGNUM))
+ if (lr_needs_saving)
{
- pushable_regs |= l_mask;
- real_regs_mask |= l_mask;
- l_mask = 0;
+ push_mask |= 1 << LR_REGNUM;
+ real_regs_mask |= 1 << LR_REGNUM;
+ lr_needs_saving = false;
}
- insn = thumb1_emit_multi_reg_push (pushable_regs, real_regs_mask);
+ insn = thumb1_emit_multi_reg_push (push_mask, real_regs_mask);
RTX_FRAME_RELATED_P (insn) = 1;
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3f3c38b684c..21b6839c592 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2016-12-09 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ Backport from mainline
+ 2016-11-17 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ PR target/77933
+ * gcc.target/arm/pr77933-1.c: New test.
+ * gcc.target/arm/pr77933-2.c: Likewise.
+
2016-12-09 Janus Weil <janus@gcc.gnu.org>
Backport from trunk
diff --git a/gcc/testsuite/gcc.target/arm/pr77933-1.c b/gcc/testsuite/gcc.target/arm/pr77933-1.c
new file mode 100644
index 00000000000..95cf68ea753
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr77933-1.c
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+__attribute__ ((noinline, noclone)) void
+clobber_lr_and_highregs (void)
+{
+ __asm__ volatile ("" : : : "r8", "r9", "lr");
+}
+
+int
+main (void)
+{
+ int ret;
+
+ __asm volatile ("mov\tr4, #0xf4\n\t"
+ "mov\tr5, #0xf5\n\t"
+ "mov\tr6, #0xf6\n\t"
+ "mov\tr7, #0xf7\n\t"
+ "mov\tr0, #0xf8\n\t"
+ "mov\tr8, r0\n\t"
+ "mov\tr0, #0xfa\n\t"
+ "mov\tr10, r0"
+ : : : "r0", "r4", "r5", "r6", "r7", "r8", "r10");
+
+ clobber_lr_and_highregs ();
+
+ __asm volatile ("cmp\tr4, #0xf4\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr5, #0xf5\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr6, #0xf6\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr7, #0xf7\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r8\n\t"
+ "cmp\tr0, #0xf8\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r10\n\t"
+ "cmp\tr0, #0xfa\n\t"
+ "bne\tfail\n\t"
+ "mov\t%0, #1\n"
+ "fail:\n\t"
+ "sub\tr0, #1"
+ : "=r" (ret) : :);
+ return ret;
+}
diff --git a/gcc/testsuite/gcc.target/arm/pr77933-2.c b/gcc/testsuite/gcc.target/arm/pr77933-2.c
new file mode 100644
index 00000000000..9028c4fcab4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr77933-2.c
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { ! { arm_thumb1_ok || arm_thumb2_ok } } } */
+/* { dg-options "-mthumb -O2 -mtpcs-leaf-frame" } */
+
+__attribute__ ((noinline, noclone)) void
+clobber_lr_and_highregs (void)
+{
+ __asm__ volatile ("" : : : "r8", "r9", "lr");
+}
+
+int
+main (void)
+{
+ int ret;
+
+ __asm volatile ("mov\tr4, #0xf4\n\t"
+ "mov\tr5, #0xf5\n\t"
+ "mov\tr6, #0xf6\n\t"
+ "mov\tr7, #0xf7\n\t"
+ "mov\tr0, #0xf8\n\t"
+ "mov\tr8, r0\n\t"
+ "mov\tr0, #0xfa\n\t"
+ "mov\tr10, r0"
+ : : : "r0", "r4", "r5", "r6", "r7", "r8", "r10");
+
+ clobber_lr_and_highregs ();
+
+ __asm volatile ("cmp\tr4, #0xf4\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr5, #0xf5\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr6, #0xf6\n\t"
+ "bne\tfail\n\t"
+ "cmp\tr7, #0xf7\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r8\n\t"
+ "cmp\tr0, #0xf8\n\t"
+ "bne\tfail\n\t"
+ "mov\tr0, r10\n\t"
+ "cmp\tr0, #0xfa\n\t"
+ "bne\tfail\n\t"
+ "mov\t%0, #1\n"
+ "fail:\n\t"
+ "sub\tr0, #1"
+ : "=r" (ret) : :);
+ return ret;
+}