public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Committed 0/3] IBM zSystems: Add -mpreserve-args option
@ 2023-02-01  8:04 Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 1/3] New reg note REG_CFA_NORESTORE Andreas Krebbel
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Andreas Krebbel @ 2023-02-01  8:04 UTC (permalink / raw)
  To: gcc-patches

This adds support for preserving the content of parameter registers to
the stack and emit CFI for it. This useful for applications which want
to implement their own stack unwinding and need access to function
arguments without having to rely on debug information.

With the -mpreserve-args option GPRs and FPRs are save to the stack
slots which are reserved for stdargs in the register save area.

The introduction of REG_CFA_NORESTORE is a common code change which
has been approved last year already.

Bootstrapped and regtested on s390x. Committed to mainline. 

Andreas Krebbel (3):
  New reg note REG_CFA_NORESTORE
  IBM zSystems: Make stack_tie to work with hard frame pointer
  IBM zSystems: Save argument registers to the stack -mpreserve-args

 gcc/config/s390/s390.cc                       | 271 ++++++++++++------
 gcc/config/s390/s390.md                       |   5 +-
 gcc/config/s390/s390.opt                      |   4 +
 gcc/dwarf2cfi.cc                              |  15 +-
 gcc/reg-notes.def                             |   5 +
 .../gcc.target/s390/preserve-args-1.c         |  17 ++
 .../gcc.target/s390/preserve-args-2.c         |  19 ++
 .../gcc.target/s390/preserve-args-3.c         |  19 ++
 8 files changed, 265 insertions(+), 90 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-1.c
 create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-2.c
 create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-3.c

-- 
2.39.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] New reg note REG_CFA_NORESTORE
  2023-02-01  8:04 [Committed 0/3] IBM zSystems: Add -mpreserve-args option Andreas Krebbel
@ 2023-02-01  8:04 ` Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 2/3] IBM zSystems: Make stack_tie to work with hard frame-pointer Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 3/3] IBM zSystems: Save argument registers to the stack -mpreserve-args Andreas Krebbel
  2 siblings, 0 replies; 4+ messages in thread
From: Andreas Krebbel @ 2023-02-01  8:04 UTC (permalink / raw)
  To: gcc-patches

This patch introduces a new reg note which can be used to tell the CFI
verification in dwarf2cfi that a register is stored without intending
to restore from it.

This is useful when storing e.g. register contents to the stack and
generate CFI for it although the register is not really supposed to be
restored.

gcc/ChangeLog:

	* dwarf2cfi.cc (dwarf2out_frame_debug_cfa_restore): Add
	EMIT_CFI parameter.
	(dwarf2out_frame_debug): Add case for REG_CFA_NORESTORE.
	* reg-notes.def (REG_CFA_NOTE): New reg note definition.
---
 gcc/dwarf2cfi.cc  | 15 ++++++++++-----
 gcc/reg-notes.def |  5 +++++
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/gcc/dwarf2cfi.cc b/gcc/dwarf2cfi.cc
index 1c70bd83f28..57283c10a29 100644
--- a/gcc/dwarf2cfi.cc
+++ b/gcc/dwarf2cfi.cc
@@ -1496,10 +1496,12 @@ dwarf2out_frame_debug_cfa_val_expression (rtx set)
   update_row_reg_save (cur_row, dwf_regno (dest), cfi);
 }
 
-/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note.  */
+/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE
+   note. When called with EMIT_CFI set to false emitting a CFI
+   statement is suppressed.  */
 
 static void
-dwarf2out_frame_debug_cfa_restore (rtx reg)
+dwarf2out_frame_debug_cfa_restore (rtx reg, bool emit_cfi)
 {
   gcc_assert (REG_P (reg));
 
@@ -1507,7 +1509,8 @@ dwarf2out_frame_debug_cfa_restore (rtx reg)
   if (!span)
     {
       unsigned int regno = dwf_regno (reg);
-      add_cfi_restore (regno);
+      if (emit_cfi)
+	add_cfi_restore (regno);
       update_row_reg_save (cur_row, regno, NULL);
     }
   else
@@ -1522,7 +1525,8 @@ dwarf2out_frame_debug_cfa_restore (rtx reg)
 	  reg = XVECEXP (span, 0, par_index);
 	  gcc_assert (REG_P (reg));
 	  unsigned int regno = dwf_regno (reg);
-	  add_cfi_restore (regno);
+	  if (emit_cfi)
+	    add_cfi_restore (regno);
 	  update_row_reg_save (cur_row, regno, NULL);
 	}
     }
@@ -2309,6 +2313,7 @@ dwarf2out_frame_debug (rtx_insn *insn)
 	break;
 
       case REG_CFA_RESTORE:
+      case REG_CFA_NO_RESTORE:
 	n = XEXP (note, 0);
 	if (n == NULL)
 	  {
@@ -2317,7 +2322,7 @@ dwarf2out_frame_debug (rtx_insn *insn)
 	      n = XVECEXP (n, 0, 0);
 	    n = XEXP (n, 0);
 	  }
-	dwarf2out_frame_debug_cfa_restore (n);
+	dwarf2out_frame_debug_cfa_restore (n, REG_NOTE_KIND (note) == REG_CFA_RESTORE);
 	handled_one = true;
 	break;
 
diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
index 23de1f13ee9..1f74a605b3e 100644
--- a/gcc/reg-notes.def
+++ b/gcc/reg-notes.def
@@ -157,6 +157,11 @@ REG_CFA_NOTE (CFA_VAL_EXPRESSION)
    first pattern is the register to be restored.  */
 REG_CFA_NOTE (CFA_RESTORE)
 
+/* Like CFA_RESTORE but without actually emitting CFI.  This can be
+   used to tell the verification infrastructure that a register is
+   saved without intending to restore it.  */
+REG_CFA_NOTE (CFA_NO_RESTORE)
+
 /* Attached to insns that are RTX_FRAME_RELATED_P, marks insn that sets
    vDRAP from DRAP.  If vDRAP is a register, vdrap_reg is initalized
    to the argument, if it is a MEM, it is ignored.  */
-- 
2.39.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] IBM zSystems: Make stack_tie to work with hard frame-pointer
  2023-02-01  8:04 [Committed 0/3] IBM zSystems: Add -mpreserve-args option Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 1/3] New reg note REG_CFA_NORESTORE Andreas Krebbel
@ 2023-02-01  8:04 ` Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 3/3] IBM zSystems: Save argument registers to the stack -mpreserve-args Andreas Krebbel
  2 siblings, 0 replies; 4+ messages in thread
From: Andreas Krebbel @ 2023-02-01  8:04 UTC (permalink / raw)
  To: gcc-patches

With this patch a scheduling barrier is created to prevent the insn
setting up the frame-pointer and instructions which save GPRs to the
stack to be swapped.  Otherwise broken CFI information would be
generated since the stack save insns would use a base register which
is not currently declared as holding the CFA.

Without -mpreserve-args this did not happen because the store multiple
we used for saving the GPRs would also cover the frame-pointer
register and therefore creates a dependency on the frame-pointer
hardreg. However, with this patch the stack_tie is emitted regardless
of -mpreserve-args since this in general appears to be the safer
approach.

	* config/s390/s390.cc (save_gprs): Use gen_frame_mem.
	(restore_gprs): Likewise.
	(s390_emit_stack_tie): Make the stack_tie to be dependent on the
	frame pointer if a frame-pointer is used.
	(s390_emit_prologue): Emit stack_tie when frame-pointer is needed.
	* config/s390/s390.md (stack_tie): Add a register operand and
	rename to ...
	(@stack_tie<mode>): ... this.
---
 gcc/config/s390/s390.cc | 17 ++++++++---------
 gcc/config/s390/s390.md |  5 +++--
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index a9bb610385b..4db5677ce29 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -10898,9 +10898,7 @@ save_gprs (rtx base, int offset, int first, int last)
   int i;
 
   addr = plus_constant (Pmode, base, offset);
-  addr = gen_rtx_MEM (Pmode, addr);
-
-  set_mem_alias_set (addr, get_frame_alias_set ());
+  addr = gen_frame_mem (Pmode, addr);
 
   /* Special-case single register.  */
   if (first == last)
@@ -11012,8 +11010,7 @@ restore_gprs (rtx base, int offset, int first, int last)
   rtx addr, insn;
 
   addr = plus_constant (Pmode, base, offset);
-  addr = gen_rtx_MEM (Pmode, addr);
-  set_mem_alias_set (addr, get_frame_alias_set ());
+  addr = gen_frame_mem (Pmode, addr);
 
   /* Special-case single register.  */
   if (first == last)
@@ -11062,10 +11059,11 @@ s390_load_got (void)
 static void
 s390_emit_stack_tie (void)
 {
-  rtx mem = gen_frame_mem (BLKmode,
-			   gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
-
-  emit_insn (gen_stack_tie (mem));
+  rtx mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
+  if (frame_pointer_needed)
+    emit_insn (gen_stack_tie (Pmode, mem, hard_frame_pointer_rtx));
+  else
+    emit_insn (gen_stack_tie (Pmode, mem, stack_pointer_rtx));
 }
 
 /* Copy GPRS into FPR save slots.  */
@@ -11676,6 +11674,7 @@ s390_emit_prologue (void)
 
   if (frame_pointer_needed)
     {
+      s390_emit_stack_tie ();
       insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 4828aa08be6..00d39608e1d 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -11590,9 +11590,10 @@
 ; This is used in s390_emit_prologue in order to prevent insns
 ; adjusting the stack pointer to be moved over insns writing stack
 ; slots using a copy of the stack pointer in a different register.
-(define_insn "stack_tie"
+(define_insn "@stack_tie<mode>"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
-        (unspec:BLK [(match_dup 0)] UNSPEC_TIE))]
+        (unspec:BLK [(match_dup 0)
+		     (match_operand:P 1 "register_operand" "r")] UNSPEC_TIE))]
   ""
   ""
   [(set_attr "length" "0")])
-- 
2.39.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] IBM zSystems: Save argument registers to the stack -mpreserve-args
  2023-02-01  8:04 [Committed 0/3] IBM zSystems: Add -mpreserve-args option Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 1/3] New reg note REG_CFA_NORESTORE Andreas Krebbel
  2023-02-01  8:04 ` [PATCH 2/3] IBM zSystems: Make stack_tie to work with hard frame-pointer Andreas Krebbel
@ 2023-02-01  8:04 ` Andreas Krebbel
  2 siblings, 0 replies; 4+ messages in thread
From: Andreas Krebbel @ 2023-02-01  8:04 UTC (permalink / raw)
  To: gcc-patches

This adds support for preserving the content of parameter registers to
the stack and emit CFI for it. This useful for applications which want
to implement their own stack unwinding and need access to function
arguments without having to rely on debug information.

With the -mpreserve-args option GPRs and FPRs are save to the stack
slots which are reserved for stdargs in the register save area.

gcc/ChangeLog:

	* config/s390/s390.cc (s390_restore_gpr_p): New function.
	(s390_preserve_gpr_arg_in_range_p): New function.
	(s390_preserve_gpr_arg_p): New function.
	(s390_preserve_fpr_arg_p): New function.
	(s390_register_info_stdarg_fpr): Rename to ...
	(s390_register_info_arg_fpr): ... this. Add -mpreserve-args handling.
	(s390_register_info_stdarg_gpr): Rename to ...
	(s390_register_info_arg_gpr): ... this. Add -mpreserve-args handling.
	(s390_register_info): Use the renamed functions above.
	(s390_optimize_register_info): Likewise.
	(save_fpr): Generate CFI for -mpreserve-args.
	(save_gprs): Generate CFI for -mpreserve-args. Drop return value.
	(s390_emit_prologue): Adjust to changed calling convention of save_gprs.
	(s390_optimize_prologue): Likewise.
	* config/s390/s390.opt: New option -mpreserve-args

gcc/testsuite/ChangeLog:

	* gcc.target/s390/preserve-args-1.c: New test.
	* gcc.target/s390/preserve-args-2.c: New test.
---
 gcc/config/s390/s390.cc                       | 254 +++++++++++++-----
 gcc/config/s390/s390.opt                      |   4 +
 .../gcc.target/s390/preserve-args-1.c         |  17 ++
 .../gcc.target/s390/preserve-args-2.c         |  19 ++
 .../gcc.target/s390/preserve-args-3.c         |  19 ++
 5 files changed, 239 insertions(+), 74 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-1.c
 create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-2.c
 create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-3.c

diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index 4db5677ce29..708b48b5ab6 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -411,6 +411,45 @@ struct s390_address
 #define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2)
 #define VEC_ARG_NUM_REG 8
 
+/* Return TRUE if GPR REGNO is supposed to be restored in the function
+   epilogue.  */
+static inline bool
+s390_restore_gpr_p (int regno)
+{
+  return (cfun_frame_layout.first_restore_gpr != -1
+	  && regno >= cfun_frame_layout.first_restore_gpr
+	  && regno <= cfun_frame_layout.last_restore_gpr);
+}
+
+/* Return TRUE if any of the registers in range [FIRST, LAST] is saved
+   because of -mpreserve-args.  */
+static inline bool
+s390_preserve_gpr_arg_in_range_p (int first, int last)
+{
+  int num_arg_regs = MIN (crtl->args.info.gprs + cfun->va_list_gpr_size,
+			  GP_ARG_NUM_REG);
+  return (num_arg_regs
+	  && s390_preserve_args_p
+	  && first <= GPR2_REGNUM + num_arg_regs - 1
+	  && last >= GPR2_REGNUM);
+}
+
+static inline bool
+s390_preserve_gpr_arg_p (int regno)
+{
+  return s390_preserve_gpr_arg_in_range_p (regno, regno);
+}
+
+static inline bool
+s390_preserve_fpr_arg_p (int regno)
+{
+  int num_arg_regs = MIN (crtl->args.info.fprs + cfun->va_list_fpr_size,
+			  FP_ARG_NUM_REG);
+  return (s390_preserve_args_p
+	  && regno <= FPR0_REGNUM + num_arg_regs - 1
+	  && regno >= FPR0_REGNUM);
+}
+
 /* A couple of shortcuts.  */
 #define CONST_OK_FOR_J(x) \
 	CONST_OK_FOR_CONSTRAINT_P((x), 'J', "J")
@@ -9893,61 +9932,89 @@ s390_register_info_gprtofpr ()
 }
 
 /* Set the bits in fpr_bitmap for FPRs which need to be saved due to
-   stdarg.
+   stdarg or -mpreserve-args.
    This is a helper routine for s390_register_info.  */
-
 static void
-s390_register_info_stdarg_fpr ()
+s390_register_info_arg_fpr ()
 {
   int i;
-  int min_fpr;
-  int max_fpr;
+  int min_stdarg_fpr = INT_MAX, max_stdarg_fpr = -1;
+  int min_preserve_fpr = INT_MAX, max_preserve_fpr = -1;
+  int min_fpr, max_fpr;
 
   /* Save the FP argument regs for stdarg. f0, f2 for 31 bit and
      f0-f4 for 64 bit.  */
-  if (!cfun->stdarg
-      || !TARGET_HARD_FLOAT
-      || !cfun->va_list_fpr_size
-      || crtl->args.info.fprs >= FP_ARG_NUM_REG)
-    return;
+  if (cfun->stdarg
+      && TARGET_HARD_FLOAT
+      && cfun->va_list_fpr_size
+      && crtl->args.info.fprs < FP_ARG_NUM_REG)
+    {
+      min_stdarg_fpr = crtl->args.info.fprs;
+      max_stdarg_fpr = min_stdarg_fpr + cfun->va_list_fpr_size - 1;
+      if (max_stdarg_fpr >= FP_ARG_NUM_REG)
+	max_stdarg_fpr = FP_ARG_NUM_REG - 1;
+
+      /* FPR argument regs start at f0.  */
+      min_stdarg_fpr += FPR0_REGNUM;
+      max_stdarg_fpr += FPR0_REGNUM;
+    }
 
-  min_fpr = crtl->args.info.fprs;
-  max_fpr = min_fpr + cfun->va_list_fpr_size - 1;
-  if (max_fpr >= FP_ARG_NUM_REG)
-    max_fpr = FP_ARG_NUM_REG - 1;
+  if (s390_preserve_args_p && crtl->args.info.fprs)
+    {
+      min_preserve_fpr = FPR0_REGNUM;
+      max_preserve_fpr = MIN (FPR0_REGNUM + FP_ARG_NUM_REG - 1,
+			      FPR0_REGNUM + crtl->args.info.fprs - 1);
+    }
 
-  /* FPR argument regs start at f0.  */
-  min_fpr += FPR0_REGNUM;
-  max_fpr += FPR0_REGNUM;
+  min_fpr = MIN (min_stdarg_fpr, min_preserve_fpr);
+  max_fpr = MAX (max_stdarg_fpr, max_preserve_fpr);
+
+  if (max_fpr == -1)
+    return;
 
   for (i = min_fpr; i <= max_fpr; i++)
     cfun_set_fpr_save (i);
 }
 
+
 /* Reserve the GPR save slots for GPRs which need to be saved due to
-   stdarg.
+   stdarg or -mpreserve-args.
    This is a helper routine for s390_register_info.  */
 
 static void
-s390_register_info_stdarg_gpr ()
+s390_register_info_arg_gpr ()
 {
   int i;
-  int min_gpr;
-  int max_gpr;
+  int min_stdarg_gpr = INT_MAX, max_stdarg_gpr = -1;
+  int min_preserve_gpr = INT_MAX, max_preserve_gpr = -1;
+  int min_gpr, max_gpr;
 
-  if (!cfun->stdarg
-      || !cfun->va_list_gpr_size
-      || crtl->args.info.gprs >= GP_ARG_NUM_REG)
-    return;
+  if (cfun->stdarg
+      && cfun->va_list_gpr_size
+      && crtl->args.info.gprs < GP_ARG_NUM_REG)
+    {
+      min_stdarg_gpr = crtl->args.info.gprs;
+      max_stdarg_gpr = min_stdarg_gpr + cfun->va_list_gpr_size - 1;
+      if (max_stdarg_gpr >= GP_ARG_NUM_REG)
+	max_stdarg_gpr = GP_ARG_NUM_REG - 1;
+
+      /* GPR argument regs start at r2.  */
+      min_stdarg_gpr += GPR2_REGNUM;
+      max_stdarg_gpr += GPR2_REGNUM;
+    }
+
+  if (s390_preserve_args_p && crtl->args.info.gprs)
+    {
+      min_preserve_gpr = GPR2_REGNUM;
+      max_preserve_gpr = MIN (GPR6_REGNUM,
+			      GPR2_REGNUM + crtl->args.info.gprs - 1);
+    }
 
-  min_gpr = crtl->args.info.gprs;
-  max_gpr = min_gpr + cfun->va_list_gpr_size - 1;
-  if (max_gpr >= GP_ARG_NUM_REG)
-    max_gpr = GP_ARG_NUM_REG - 1;
+  min_gpr = MIN (min_stdarg_gpr, min_preserve_gpr);
+  max_gpr = MAX (max_stdarg_gpr, max_preserve_gpr);
 
-  /* GPR argument regs start at r2.  */
-  min_gpr += GPR2_REGNUM;
-  max_gpr += GPR2_REGNUM;
+  if (max_gpr == -1)
+    return;
 
   /* If r6 was supposed to be saved into an FPR and now needs to go to
      the stack for vararg we have to adjust the restore range to make
@@ -10079,14 +10146,14 @@ s390_register_info ()
     if (clobbered_regs[i] && !call_used_regs[i])
       cfun_gpr_save_slot (i) = SAVE_SLOT_STACK;
 
-  s390_register_info_stdarg_fpr ();
+  s390_register_info_arg_fpr ();
   s390_register_info_gprtofpr ();
   s390_register_info_set_ranges ();
-  /* stdarg functions might need to save GPRs 2 to 6.  This might
-     override the GPR->FPR save decision made by
-     s390_register_info_gprtofpr for r6 since vararg regs must go to
-     the stack.  */
-  s390_register_info_stdarg_gpr ();
+
+  /* Forcing argument registers to be saved on the stack might
+     override the GPR->FPR save decision for r6 so this must come
+     last.  */
+  s390_register_info_arg_gpr ();
 }
 
 /* Return true if REGNO is a global register, but not one
@@ -10141,7 +10208,7 @@ s390_optimize_register_info ()
       cfun_gpr_save_slot (i) = SAVE_SLOT_NONE;
 
   s390_register_info_set_ranges ();
-  s390_register_info_stdarg_gpr ();
+  s390_register_info_arg_gpr ();
 }
 
 /* Fill cfun->machine with info about frame of current function.  */
@@ -10864,14 +10931,28 @@ static rtx
 save_fpr (rtx base, int offset, int regnum)
 {
   rtx addr;
+  rtx insn;
+
   addr = gen_rtx_MEM (DFmode, plus_constant (Pmode, base, offset));
 
-  if (regnum >= 16 && regnum <= (16 + FP_ARG_NUM_REG))
+  if (regnum >= FPR0_REGNUM && regnum <= (FPR0_REGNUM + FP_ARG_NUM_REG))
     set_mem_alias_set (addr, get_varargs_alias_set ());
   else
     set_mem_alias_set (addr, get_frame_alias_set ());
 
-  return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum));
+  insn = emit_move_insn (addr, gen_rtx_REG (DFmode, regnum));
+
+  if (!call_used_regs[regnum] || s390_preserve_fpr_arg_p (regnum))
+    RTX_FRAME_RELATED_P (insn) = 1;
+
+  if (s390_preserve_fpr_arg_p (regnum) && !cfun_fpr_save_p (regnum))
+    {
+      rtx reg = gen_rtx_REG (DFmode, regnum);
+      add_reg_note (insn, REG_CFA_NO_RESTORE, reg);
+      add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (addr, reg));
+    }
+
+  return insn;
 }
 
 /* Emit insn to restore fpr REGNUM from offset OFFSET relative
@@ -10891,10 +10972,11 @@ restore_fpr (rtx base, int offset, int regnum)
    the register save area located at offset OFFSET
    relative to register BASE.  */
 
-static rtx
-save_gprs (rtx base, int offset, int first, int last)
+static void
+save_gprs (rtx base, int offset, int first, int last, rtx_insn *before = NULL)
 {
   rtx addr, insn, note;
+  rtx_insn *out_insn;
   int i;
 
   addr = plus_constant (Pmode, base, offset);
@@ -10910,7 +10992,15 @@ save_gprs (rtx base, int offset, int first, int last)
 
       if (!global_not_special_regno_p (first))
 	RTX_FRAME_RELATED_P (insn) = 1;
-      return insn;
+
+      if (s390_preserve_gpr_arg_p (first) && !s390_restore_gpr_p (first))
+	{
+	  rtx reg = gen_rtx_REG (Pmode, first);
+	  add_reg_note (insn, REG_CFA_NO_RESTORE, reg);
+	  add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (addr, reg));
+	}
+
+      goto emit;
     }
 
 
@@ -10939,7 +11029,12 @@ save_gprs (rtx base, int offset, int first, int last)
      set, even if it does not.  Therefore we emit a new pattern
      without those registers as REG_FRAME_RELATED_EXPR note.  */
 
-  if (first >= 6 && !global_not_special_regno_p (first))
+  /* In these cases all of the sets are marked as frame related:
+     1. call-save GPR saved and restored
+     2. argument GPR saved because of -mpreserve-args */
+  if ((first >= GPR6_REGNUM && !global_not_special_regno_p (first))
+      || s390_preserve_gpr_arg_in_range_p (first, last))
+
     {
       rtx pat = PATTERN (insn);
 
@@ -10950,6 +11045,24 @@ save_gprs (rtx base, int offset, int first, int last)
 	  RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
 
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* For the -mpreserve-args register saves no restore operations
+	 will be emitted. CFI checking would complain about this. We
+	 manually generate the REG_CFA notes here to be able to mark
+	 those operations with REG_CFA_NO_RESTORE.  */
+      if (s390_preserve_gpr_arg_in_range_p (first, last))
+	{
+	  for (int regno = first; regno <= last; regno++)
+	    {
+	      rtx reg = gen_rtx_REG (Pmode, regno);
+	      rtx reg_addr = plus_constant (Pmode, base,
+					    offset + (regno - first) * UNITS_PER_LONG);
+	      if (!s390_restore_gpr_p (regno))
+		add_reg_note (insn, REG_CFA_NO_RESTORE, reg);
+	      add_reg_note (insn, REG_CFA_OFFSET,
+			    gen_rtx_SET (gen_frame_mem (Pmode, reg_addr), reg));
+	    }
+	}
     }
   else if (last >= 6)
     {
@@ -10960,7 +11073,7 @@ save_gprs (rtx base, int offset, int first, int last)
 	  break;
 
       if (start > last)
-	return insn;
+	goto emit;
 
       addr = plus_constant (Pmode, base,
 			    offset + (start - first) * UNITS_PER_LONG);
@@ -10978,7 +11091,7 @@ save_gprs (rtx base, int offset, int first, int last)
 	  add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
 	  RTX_FRAME_RELATED_P (insn) = 1;
 
-	  return insn;
+	  goto emit;
 	}
 
       note = gen_store_multiple (gen_rtx_MEM (Pmode, addr),
@@ -10997,9 +11110,15 @@ save_gprs (rtx base, int offset, int first, int last)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  return insn;
+ emit:
+  if (before != NULL_RTX)
+    out_insn = emit_insn_before (insn, before);
+  else
+    out_insn = emit_insn (insn);
+  INSN_ADDRESSES_NEW (out_insn, -1);
 }
 
+
 /* Generate insn to restore registers FIRST to LAST from
    the register save area located at offset OFFSET
    relative to register BASE.  */
@@ -11423,12 +11542,12 @@ s390_emit_prologue (void)
   /* Save call saved gprs.  */
   if (cfun_frame_layout.first_save_gpr != -1)
     {
-      insn = save_gprs (stack_pointer_rtx,
-			cfun_frame_layout.gprs_offset +
-			UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr
-					  - cfun_frame_layout.first_save_gpr_slot),
-			cfun_frame_layout.first_save_gpr,
-			cfun_frame_layout.last_save_gpr);
+      save_gprs (stack_pointer_rtx,
+		 cfun_frame_layout.gprs_offset +
+		 UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr
+				   - cfun_frame_layout.first_save_gpr_slot),
+		 cfun_frame_layout.first_save_gpr,
+		 cfun_frame_layout.last_save_gpr);
 
       /* This is not 100% correct.  If we have more than one register saved,
 	 then LAST_PROBE_OFFSET can move even closer to sp.  */
@@ -11436,8 +11555,6 @@ s390_emit_prologue (void)
 	= (cfun_frame_layout.gprs_offset +
 	   UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr
 			     - cfun_frame_layout.first_save_gpr_slot));
-
-      emit_insn (insn);
     }
 
   /* Dummy insn to mark literal pool slot.  */
@@ -11467,15 +11584,10 @@ s390_emit_prologue (void)
     {
       if (cfun_fpr_save_p (i))
 	{
-	  insn = save_fpr (stack_pointer_rtx, offset, i);
+	  save_fpr (stack_pointer_rtx, offset, i);
 	  if (offset < last_probe_offset)
 	    last_probe_offset = offset;
 	  offset += 8;
-
-	  /* If f4 and f6 are call clobbered they are saved due to
-	     stdargs and therefore are not frame related.  */
-	  if (!call_used_regs[i])
-	    RTX_FRAME_RELATED_P (insn) = 1;
 	}
       else if (!TARGET_PACKED_STACK || call_used_regs[i])
 	offset += 8;
@@ -11491,11 +11603,10 @@ s390_emit_prologue (void)
       for (i = FPR15_REGNUM; i >= FPR8_REGNUM && offset >= 0; i--)
 	if (cfun_fpr_save_p (i))
 	  {
-	    insn = save_fpr (stack_pointer_rtx, offset, i);
+	    save_fpr (stack_pointer_rtx, offset, i);
 	    if (offset < last_probe_offset)
 	      last_probe_offset = offset;
 
-	    RTX_FRAME_RELATED_P (insn) = 1;
 	    offset -= 8;
 	  }
       if (offset >= cfun_frame_layout.f8_offset)
@@ -11663,7 +11774,6 @@ s390_emit_prologue (void)
 
 	    insn = save_fpr (temp_reg, offset, i);
 	    offset += 8;
-	    RTX_FRAME_RELATED_P (insn) = 1;
 	    add_reg_note (insn, REG_FRAME_RELATED_EXPR,
 			  gen_rtx_SET (gen_rtx_MEM (DFmode, addr),
 				       gen_rtx_REG (DFmode, i)));
@@ -14158,15 +14268,11 @@ s390_optimize_prologue (void)
 	    continue;
 
 	  if (cfun_frame_layout.first_save_gpr != -1)
-	    {
-	      rtx s_pat = save_gprs (base,
-				     off + (cfun_frame_layout.first_save_gpr
-					    - first) * UNITS_PER_LONG,
-				     cfun_frame_layout.first_save_gpr,
-				     cfun_frame_layout.last_save_gpr);
-	      new_insn = emit_insn_before (s_pat, insn);
-	      INSN_ADDRESSES_NEW (new_insn, -1);
-	    }
+	    save_gprs (base,
+		       off + (cfun_frame_layout.first_save_gpr
+			      - first) * UNITS_PER_LONG,
+		       cfun_frame_layout.first_save_gpr,
+		       cfun_frame_layout.last_save_gpr, insn);
 
 	  remove_insn (insn);
 	  continue;
diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt
index 57d1b95bd65..344aa551f44 100644
--- a/gcc/config/s390/s390.opt
+++ b/gcc/config/s390/s390.opt
@@ -325,3 +325,7 @@ purposes.
 munroll-only-small-loops
 Target Undocumented Var(unroll_only_small_loops) Init(0) Save
 ; Use conservative small loop unrolling.
+
+mpreserve-args
+Target Var(s390_preserve_args_p) Init(0)
+Store all argument registers on the stack.
diff --git a/gcc/testsuite/gcc.target/s390/preserve-args-1.c b/gcc/testsuite/gcc.target/s390/preserve-args-1.c
new file mode 100644
index 00000000000..24dcf547432
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/preserve-args-1.c
@@ -0,0 +1,17 @@
+/* Functional tests for the -mpreserve-args cmdline option.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z900 -mpreserve-args" } */
+
+
+int
+foo (int a, int b, int c, double d, double e)
+{
+  return a + c + (int)d + (int)e;
+}
+
+/* { dg-final { scan-assembler "stmg\t%r2,%r4,\[0-9\]*\\(%r15\\)" { target lp64 } } } */
+/* { dg-final { scan-assembler "stm\t%r2,%r4,\[0-9\]*\\(%r15\\)" { target { ! lp64 } } } } */
+
+/* { dg-final { scan-assembler "std\t%f0,\[0-9\]*\\(%r15\\)" } } */
+/* { dg-final { scan-assembler "std\t%f2,\[0-9\]*\\(%r15\\)" } } */
diff --git a/gcc/testsuite/gcc.target/s390/preserve-args-2.c b/gcc/testsuite/gcc.target/s390/preserve-args-2.c
new file mode 100644
index 00000000000..006aad9c371
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/preserve-args-2.c
@@ -0,0 +1,19 @@
+/* This test requires special handling of a GPR which is saved because
+   of -mpreserve-args but not restored.  dwarf2cfi used to ICE for
+   this in maybe_record_trace_start.  The solution was to introduce a
+   REG_CFA_NORESTORE reg note.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=z900 -mpreserve-args" } */
+
+void *foo (void *);
+void bar ();
+int x;
+void *
+baz (void *y)
+{
+  if (__builtin_expect (x, 0))
+    return foo (y);
+  bar ();
+  return foo (y);
+}
diff --git a/gcc/testsuite/gcc.target/s390/preserve-args-3.c b/gcc/testsuite/gcc.target/s390/preserve-args-3.c
new file mode 100644
index 00000000000..f4b135ab8e6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/preserve-args-3.c
@@ -0,0 +1,19 @@
+/* Functional tests for the -mpreserve-args cmdline option.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z900 -mpreserve-args" } */
+
+#include <stdarg.h>
+int
+foo (int a, int, int c, double d, ...)
+{
+  va_list argp;
+  va_start(argp, d);
+  return a + c + va_arg(argp, int) + va_arg(argp, int) + (int)va_arg(argp, double);
+}
+
+/* { dg-final { scan-assembler "stmg\t%r2,%r15,\[0-9\]*\\(%r15\\)" { target lp64 } } } */
+/* { dg-final { scan-assembler "stm\t%r2,%r15,\[0-9\]*\\(%r15\\)" { target { ! lp64 } } } } */
+
+/* { dg-final { scan-assembler "std\t%f0,\[0-9\]*\\(%r15\\)" } } */
+/* { dg-final { scan-assembler "std\t%f2,\[0-9\]*\\(%r15\\)" } } */
-- 
2.39.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-02-01  8:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-01  8:04 [Committed 0/3] IBM zSystems: Add -mpreserve-args option Andreas Krebbel
2023-02-01  8:04 ` [PATCH 1/3] New reg note REG_CFA_NORESTORE Andreas Krebbel
2023-02-01  8:04 ` [PATCH 2/3] IBM zSystems: Make stack_tie to work with hard frame-pointer Andreas Krebbel
2023-02-01  8:04 ` [PATCH 3/3] IBM zSystems: Save argument registers to the stack -mpreserve-args Andreas Krebbel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).