[Committed] S/390: PR91035 Fix call to __morestack

Message ID 20191010091124.16164-1-krebbel@linux.ibm.com
State New
Headers show
Series
  • [Committed] S/390: PR91035 Fix call to __morestack
Related show

Commit Message

Andreas Krebbel Oct. 10, 2019, 9:11 a.m.
For the call to __morestack we use a special ABI in the S/390 back-end
which requires us to emit a parameter block to the .rodata section
which contains the label whereto __morestack needs to return.  The
parameter block needs to be explicit in RTL since we also need the
address of it loaded into r1 in order to pass its address to
__morestack.  In order to express correctly what __morestack does its
RTX also contained the return label. Hence we had the return label to
occur twice in the insn stream.  This is problematic when it comes to
redirecting edges.  The correlation between these two occurrences of
the label cannot be expressed so when doing a redirect only the label
in the jump RTX gets modified while the parameter block label stays as
is.

The patch avoids having two instancs of the label by merging the
parameter block generation and the __morestack call RTX into one. By
doing this I could also get rid of the unspec which was required for
the parameter block generation so far.

gcc/ChangeLog:

2019-10-10  Andreas Krebbel  <krebbel@linux.ibm.com>

	PR target/91035
	* config/s390/s390-protos.h (s390_output_split_stack_data): Add
	prototype.
	* config/s390/s390.md (UNSPECV_SPLIT_STACK_DATA): Remove.
	("split_stack_data", "split_stack_call")
	("split_stack_call_<mode>", "split_stack_cond_call")
	("split_stack_cond_call_<mode>"): Remove.
	("@split_stack_call<mode>", "@split_stack_cond_call<mode>"): New
	insn definition.
	* config/s390/s390.c (s390_output_split_stack_data): New function.
	(s390_expand_split_stack_prologue): Use the merged expander.
---
 gcc/config/s390/s390-protos.h |   1 +
 gcc/config/s390/s390.c        |  78 ++++++++++++++++++------
 gcc/config/s390/s390.md       | 111 +++++++++++-----------------------
 3 files changed, 95 insertions(+), 95 deletions(-)

-- 
2.23.0

Patch

diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index ae70b2fee18..f760f152932 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -146,6 +146,7 @@  extern int s390_branch_condition_mask (rtx);
 extern int s390_compare_and_branch_condition_mask (rtx);
 extern bool s390_extzv_shift_ok (int, int, unsigned HOST_WIDE_INT);
 extern void s390_asm_output_function_label (FILE *, const char *, tree);
+extern void s390_output_split_stack_data (rtx, rtx, rtx, rtx);
 
 enum s390_indirect_branch_type
   {
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 062cbd8099d..8241bd5bbf8 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -11600,6 +11600,44 @@  static GTY(()) rtx morestack_ref;
 
 #define SPLIT_STACK_AVAILABLE 1024
 
+/* Emit the parmblock for __morestack into .rodata section.  It
+   consists of 3 pointer size entries:
+   - frame size
+   - size of stack arguments
+   - offset between parm block and __morestack return label  */
+
+void
+s390_output_split_stack_data (rtx parm_block, rtx call_done,
+			      rtx frame_size, rtx args_size)
+{
+  rtx ops[] = { parm_block, call_done };
+
+  switch_to_section (targetm.asm_out.function_rodata_section
+		     (current_function_decl));
+
+  if (TARGET_64BIT)
+    output_asm_insn (".align\t8", NULL);
+  else
+    output_asm_insn (".align\t4", NULL);
+
+  (*targetm.asm_out.internal_label) (asm_out_file, "L",
+				     CODE_LABEL_NUMBER (parm_block));
+  if (TARGET_64BIT)
+    {
+      output_asm_insn (".quad\t%0", &frame_size);
+      output_asm_insn (".quad\t%0", &args_size);
+      output_asm_insn (".quad\t%1-%0", ops);
+    }
+  else
+    {
+      output_asm_insn (".long\t%0", &frame_size);
+      output_asm_insn (".long\t%0", &args_size);
+      output_asm_insn (".long\t%1-%0", ops);
+    }
+
+  switch_to_section (current_function_section ());
+}
+
 /* Emit -fsplit-stack prologue, which goes before the regular function
    prologue.  */
 
@@ -11677,16 +11715,8 @@  s390_expand_split_stack_prologue (void)
 
   call_done = gen_label_rtx ();
   parm_base = gen_label_rtx ();
-
-  /* Emit the parameter block.  */
-  tmp = gen_split_stack_data (parm_base, call_done,
-			      GEN_INT (frame_size),
-			      GEN_INT (args_size));
-  insn = emit_insn (tmp);
-  add_reg_note (insn, REG_LABEL_OPERAND, call_done);
-  LABEL_NUSES (call_done)++;
-  add_reg_note (insn, REG_LABEL_OPERAND, parm_base);
   LABEL_NUSES (parm_base)++;
+  LABEL_NUSES (call_done)++;
 
   /* %r1 = litbase.  */
   insn = emit_move_insn (r1, gen_rtx_LABEL_REF (VOIDmode, parm_base));
@@ -11696,15 +11726,29 @@  s390_expand_split_stack_prologue (void)
   /* Now, we need to call __morestack.  It has very special calling
      conventions: it preserves param/return/static chain registers for
      calling main function body, and looks for its own parameters at %r1. */
+  if (cc != NULL)
+    tmp = gen_split_stack_cond_call (Pmode,
+				     morestack_ref,
+				     parm_base,
+				     call_done,
+				     GEN_INT (frame_size),
+				     GEN_INT (args_size),
+				     cc);
+  else
+    tmp = gen_split_stack_call (Pmode,
+				morestack_ref,
+				parm_base,
+				call_done,
+				GEN_INT (frame_size),
+				GEN_INT (args_size));
+
+  insn = emit_jump_insn (tmp);
+  JUMP_LABEL (insn) = call_done;
+  add_reg_note (insn, REG_LABEL_OPERAND, parm_base);
+  add_reg_note (insn, REG_LABEL_OPERAND, call_done);
 
   if (cc != NULL)
     {
-      tmp = gen_split_stack_cond_call (morestack_ref, cc, call_done);
-
-      insn = emit_jump_insn (tmp);
-      JUMP_LABEL (insn) = call_done;
-      LABEL_NUSES (call_done)++;
-
       /* Mark the jump as very unlikely to be taken.  */
       add_reg_br_prob_note (insn,
 			    profile_probability::very_unlikely ());
@@ -11720,10 +11764,6 @@  s390_expand_split_stack_prologue (void)
     }
   else
     {
-      tmp = gen_split_stack_call (morestack_ref, call_done);
-      insn = emit_jump_insn (tmp);
-      JUMP_LABEL (insn) = call_done;
-      LABEL_NUSES (call_done)++;
       emit_barrier ();
     }
 
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index e4516f6c378..01e5cf920cd 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -298,7 +298,6 @@ 
 
    ; Split stack support
    UNSPECV_SPLIT_STACK_CALL
-   UNSPECV_SPLIT_STACK_DATA
 
    UNSPECV_OSC_BREAK
   ])
@@ -12000,99 +11999,59 @@ 
   DONE;
 })
 
-;; __morestack parameter block for split stack prologue.  Parameters are:
-;; parameter block label, label to be called by __morestack, frame size,
-;; stack parameter size.
+;; Call to __morestack used by the split stack support
 
-(define_insn "split_stack_data"
-  [(unspec_volatile [(match_operand 0 "" "X")
-		     (match_operand 1 "" "X")
-		     (match_operand 2 "const_int_operand" "X")
-		     (match_operand 3 "const_int_operand" "X")]
-		    UNSPECV_SPLIT_STACK_DATA)]
-  ""
-{
-  switch_to_section (targetm.asm_out.function_rodata_section
-		 (current_function_decl));
+; The insn has 3 parts:
+; 1. A jump to the call done label. The jump will be done as part of
+;    __morestack and will not be explicitly emitted to the insn stream.
+; 2. The call of __morestack including a use for r1 which is supposed to
+;    point to the parameter block for __morestack.
+; 3. 3 USES whose values together with the call done label will be
+;    used to emit the parameter block to the .rodata section. This
+;    needs to be tied into the same insn as 1. since the call done
+;    label is emitted also as part of the parm block.  In order to
+;    allow the edge to the BB with the call done label to be
+;    redirected both need to make use of the same label_ref.
 
-  if (TARGET_64BIT)
-    output_asm_insn (".align\t8", operands);
-  else
-    output_asm_insn (".align\t4", operands);
-  (*targetm.asm_out.internal_label) (asm_out_file, "L",
-				     CODE_LABEL_NUMBER (operands[0]));
-  if (TARGET_64BIT)
-    {
-      output_asm_insn (".quad\t%2", operands);
-      output_asm_insn (".quad\t%3", operands);
-      output_asm_insn (".quad\t%1-%0", operands);
-    }
-  else
-    {
-      output_asm_insn (".long\t%2", operands);
-      output_asm_insn (".long\t%3", operands);
-      output_asm_insn (".long\t%1-%0", operands);
-    }
-
-  switch_to_section (current_function_section ());
-  return "";
-}
-  [(set_attr "length" "0")])
-
-
-;; A jg with minimal fuss for use in split stack prologue.
-
-(define_expand "split_stack_call"
-  [(match_operand 0 "bras_sym_operand" "X")
-   (match_operand 1 "" "")]
-  ""
-{
-  if (TARGET_64BIT)
-    emit_jump_insn (gen_split_stack_call_di (operands[0], operands[1]));
-  else
-    emit_jump_insn (gen_split_stack_call_si (operands[0], operands[1]));
-  DONE;
-})
-
-(define_insn "split_stack_call_<mode>"
-  [(set (pc) (label_ref (match_operand 1 "" "")))
+(define_insn "@split_stack_call<mode>"
+  [(set (pc) (label_ref (match_operand 2 "" "")))     ; call done label
    (set (reg:P 1) (unspec_volatile [(match_operand 0 "bras_sym_operand" "X")
 				    (reg:P 1)]
-				   UNSPECV_SPLIT_STACK_CALL))]
+				   UNSPECV_SPLIT_STACK_CALL))
+   (use (label_ref (match_operand 1 "" "X")))         ; parm block label
+   (use (match_operand 3 "const_int_operand" "X"))    ; frame size
+   (use (match_operand 4 "const_int_operand" "X"))]   ; arg size
   ""
-  "jg\t%0"
+{
+  s390_output_split_stack_data (operands[1], operands[2], operands[3], operands[4]);
+  return "jg\t%0";
+}
   [(set_attr "op_type" "RIL")
    (set_attr "type"  "branch")])
 
-;; Also a conditional one.
-
-(define_expand "split_stack_cond_call"
-  [(match_operand 0 "bras_sym_operand" "X")
-   (match_operand 1 "" "")
-   (match_operand 2 "" "")]
-  ""
-{
-  if (TARGET_64BIT)
-    emit_jump_insn (gen_split_stack_cond_call_di (operands[0], operands[1], operands[2]));
-  else
-    emit_jump_insn (gen_split_stack_cond_call_si (operands[0], operands[1], operands[2]));
-  DONE;
-})
+; As above but with a conditional jump
 
-(define_insn "split_stack_cond_call_<mode>"
+(define_insn "@split_stack_cond_call<mode>"
   [(set (pc)
 	(if_then_else
-	  (match_operand 1 "" "")
-	  (label_ref (match_operand 2 "" ""))
+	  (match_operand 5 "" "")                     ; condition
+	  (label_ref (match_operand 2 "" ""))         ; call done label
 	  (pc)))
    (set (reg:P 1) (unspec_volatile [(match_operand 0 "bras_sym_operand" "X")
 				    (reg:P 1)]
-				   UNSPECV_SPLIT_STACK_CALL))]
+				   UNSPECV_SPLIT_STACK_CALL))
+   (use (label_ref (match_operand 1 "" "X")))         ; parm block label
+   (use (match_operand 3 "const_int_operand" "X"))    ; frame size
+   (use (match_operand 4 "const_int_operand" "X"))]   ; arg size
   ""
-  "jg%C1\t%0"
+{
+  s390_output_split_stack_data (operands[1], operands[2], operands[3], operands[4]);
+  return "jg%C5\t%0";
+}
   [(set_attr "op_type" "RIL")
    (set_attr "type"  "branch")])
 
+
 (define_insn "osc_break"
   [(unspec_volatile [(const_int 0)] UNSPECV_OSC_BREAK)]
   ""