This patch fixes a cases where inconsistent CFI is generated.

After restoring the hard frame pointer (r11) from an FPR we have to
set the CFA register.  In order to be able to set it back to the stack
pointer (r15) we have to make sure that r15 has been restored already.

gcc/ChangeLog:

2019-04-09  Andreas Krebbel  <kreb...@linux.ibm.com>

        PR target/89952
        * config/s390/s390.c (s390_restore_gprs_from_fprs): Restore GPRs
        from FPRs in reverse order.  Generate REG_CFA_DEF_CFA note also
        for restored hard frame pointer.

gcc/testsuite/ChangeLog:

2019-04-09  Andreas Krebbel  <kreb...@linux.ibm.com>

        PR target/89952
        * gcc.target/s390/pr89952.c: New test.
---
 gcc/config/s390/s390.c                  | 14 ++++++++++++--
 gcc/testsuite/gcc.target/s390/pr89952.c | 12 ++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/pr89952.c

diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index e0b62b7..e95ea5b 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -10685,7 +10685,11 @@ s390_restore_gprs_from_fprs (void)
   if (!TARGET_Z10 || !TARGET_HARD_FLOAT || !crtl->is_leaf)
     return;
 
-  for (i = 6; i < 16; i++)
+  /* Restore the GPRs starting with the stack pointer.  That way the
+     stack pointer already has its original value when it comes to
+     restoring the hard frame pointer.  So we can set the cfa reg back
+     to the stack pointer.  */
+  for (i = STACK_POINTER_REGNUM; i >= 6; i--)
     {
       rtx_insn *insn;
 
@@ -10701,7 +10705,13 @@ s390_restore_gprs_from_fprs (void)
 
       df_set_regs_ever_live (i, true);
       add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (DImode, i));
-      if (i == STACK_POINTER_REGNUM)
+
+      /* If either the stack pointer or the frame pointer get restored
+        set the CFA value to its value at function start.  Doing this
+        for the frame pointer results in .cfi_def_cfa_register 15
+        what is ok since if the stack pointer got modified it has
+        been restored already.  */
+      if (i == STACK_POINTER_REGNUM || i == HARD_FRAME_POINTER_REGNUM)
        add_reg_note (insn, REG_CFA_DEF_CFA,
                      plus_constant (Pmode, stack_pointer_rtx,
                                     STACK_POINTER_OFFSET));
diff --git a/gcc/testsuite/gcc.target/s390/pr89952.c 
b/gcc/testsuite/gcc.target/s390/pr89952.c
new file mode 100644
index 0000000..9f48e08
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/pr89952.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=zEC12 -fno-omit-frame-pointer -Os" } */
+
+
+extern void j(int);
+
+void
+d(int e, long f, int g, int h, int i) {
+  if (h == 5 && i >= 4 && i <= 7)
+    h = e;
+  j(h);
+}
-- 
2.7.4

Reply via email to