]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add tailcall/sibcall support to the H8
authorJeff Law <jlaw@localhost.localdomain>
Mon, 23 Aug 2021 14:33:35 +0000 (10:33 -0400)
committerJeff Law <jlaw@localhost.localdomain>
Mon, 23 Aug 2021 14:37:20 +0000 (10:37 -0400)
gcc/

* config/h8300/h8300-protos.h (h8300_expand_epilogue): Add new
argument.
* config/h8300/jumpcall.md (call, call_value): Restrict to
!SIBLING_CALL_P cases.
(subcall, sibcall_value): New patterns & expanders.
* config/h8300/proepi.md (epilogue): Pass new argument to
h8300_expand_epilogue.
(sibcall_epilogue): New expander.
* config/h8300/h8300.c (h8300_expand_epilogue): Handle sibcall
epilogues too.
(h8300_ok_for_sibcall_p): New function.
(TARGET_FUNCTION_OK_FOR_SIBCALL): define.

gcc/config/h8300/h8300-protos.h
gcc/config/h8300/h8300.c
gcc/config/h8300/jumpcall.md
gcc/config/h8300/proepi.md

index 744337d6667189e19daa54b41a88003ef6a29f85..3d344018ff217bf37d0f8f8efbce3b3f106cef4d 100644 (file)
@@ -94,7 +94,7 @@ extern int h8300_tiny_data_p (tree);
 
 extern int h8300_can_use_return_insn_p (void);
 extern void h8300_expand_prologue (void);
-extern void h8300_expand_epilogue (void);
+extern void h8300_expand_epilogue (bool);
 extern int h8300_current_function_interrupt_function_p (void);
 extern int h8300_current_function_monitor_function_p (void);
 extern int h8300_initial_elimination_offset (int, int);
index 8ccacecba79e1bd30c4089ead96848b18c737809..5f7251ab78d1f5540c369153b90b8192f7995a95 100644 (file)
@@ -874,7 +874,7 @@ h8300_can_use_return_insn_p (void)
 /* Generate RTL code for the function epilogue.  */
 
 void
-h8300_expand_epilogue (void)
+h8300_expand_epilogue (bool sibcall_p)
 {
   int regno;
   int saved_regs;
@@ -919,6 +919,7 @@ h8300_expand_epilogue (void)
          /* See if this pop would be the last insn before the return.
             If so, use rte/l or rts/l instead of pop or ldm.l.  */
          if (TARGET_H8300SX
+             && !sibcall_p
              && !frame_pointer_needed
              && frame_size == 0
              && (saved_regs & ((1 << (regno - n_regs + 1)) - 1)) == 0)
@@ -931,12 +932,12 @@ h8300_expand_epilogue (void)
   /* Pop frame pointer if we had one.  */
   if (frame_pointer_needed)
     {
-      if (TARGET_H8300SX)
+      if (TARGET_H8300SX && !sibcall_p)
        returned_p = true;
       h8300_push_pop (HARD_FRAME_POINTER_REGNUM, 1, true, returned_p);
     }
 
-  if (!returned_p)
+  if (!returned_p && !sibcall_p)
     emit_jump_insn (ret_rtx);
 }
 
@@ -5533,6 +5534,25 @@ h8300_push_rounding (poly_int64 bytes)
 {
   return ((bytes + PARM_BOUNDARY / 8 - 1) & (-PARM_BOUNDARY / 8));
 }
+
+static bool
+h8300_ok_for_sibcall_p (tree fndecl, tree)
+{
+  /* If either the caller or target are special, then assume sibling
+     calls are not OK.  */
+  if (!fndecl
+      || h8300_os_task_function_p (fndecl)
+      || h8300_monitor_function_p (fndecl)
+      || h8300_interrupt_function_p (fndecl)
+      || h8300_saveall_function_p (fndecl)
+      || h8300_os_task_function_p (current_function_decl)
+      || h8300_monitor_function_p (current_function_decl)
+      || h8300_interrupt_function_p (current_function_decl)
+      || h8300_saveall_function_p (current_function_decl))
+    return false;
+
+  return 1;
+}
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -5628,4 +5648,7 @@ h8300_push_rounding (poly_int64 bytes)
 #undef TARGET_FLAGS_REGNUM
 #define TARGET_FLAGS_REGNUM 12
 
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL h8300_ok_for_sibcall_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
index 3e59fee58bdfb0c50297808f1e3ee338ee348070..b59639992a366e0324bb60dbd26820617eb2e696 100644 (file)
 (define_insn "call_insn_<mode>"
   [(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
                 (match_operand:P 1 "general_operand" "g"))]
-  ""
+  "!SIBLING_CALL_P (insn)"
 {
   rtx xoperands[1];
   xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
   [(set (match_operand 0 "" "=r")
        (call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
                      (match_operand:P 2 "general_operand" "g")))]
-  ""
+  "!SIBLING_CALL_P (insn)"
 {
   rtx xoperands[2];
   gcc_assert (GET_MODE (operands[1]) == Pmode);
                      (const_int 2)
                      (const_int 4)))])
 
+(define_expand "sibcall"
+  [(call (match_operand:QI 0 "call_expander_operand" "")
+        (match_operand 1 "general_operand" ""))]
+  ""
+  {
+    if (!register_operand (XEXP (operands[0], 0), Pmode)
+       && GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)
+      XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
+  })
+
+(define_insn "sibcall_insn_<mode>"
+  [(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
+                (match_operand:P 1 "general_operand" "g"))]
+  "SIBLING_CALL_P (insn)"
+{
+  rtx xoperands[1];
+  xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
+  gcc_assert (GET_MODE (operands[0]) == Pmode);
+  if (GET_CODE (XEXP (xoperands[0], 0)) == SYMBOL_REF
+      && (SYMBOL_REF_FLAGS (XEXP (xoperands[0], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+    output_asm_insn ("jmp\\t@%0:8", xoperands);
+  else
+    output_asm_insn ("jmp\\t%0", xoperands);
+  return "";
+}
+  [(set_attr "type" "call")
+   (set (attr "length")
+       (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
+                     (const_int 2)
+                     (const_int 4)))])
+
+;; Call subroutine, returning value in operand 0
+;; (which must be a hard register).
+
+;; ??? Even though we use HImode here, this works on the H8/300H and H8S.
+
+(define_expand "sibcall_value"
+  [(set (match_operand 0 "" "")
+       (call (match_operand:QI 1 "call_expander_operand" "")
+             (match_operand 2 "general_operand" "")))]
+  ""
+  {
+    if (!register_operand (XEXP (operands[1], 0), Pmode)
+       && GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)
+      XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
+  })
+
+(define_insn "sibcall_value_insn_<mode>"
+  [(set (match_operand 0 "" "=r")
+       (call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
+                     (match_operand:P 2 "general_operand" "g")))]
+  "SIBLING_CALL_P (insn)"
+{
+  rtx xoperands[2];
+  gcc_assert (GET_MODE (operands[1]) == Pmode);
+  xoperands[0] = operands[0];
+  xoperands[1] = gen_rtx_MEM (QImode, operands[1]);
+  if (GET_CODE (XEXP (xoperands[1], 0)) == SYMBOL_REF
+      && (SYMBOL_REF_FLAGS (XEXP (xoperands[1], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+    output_asm_insn ("jmp\\t@%1:8", xoperands);
+  else
+    output_asm_insn ("jmp\\t%1", xoperands);
+  return "";
+}
+  [(set_attr "type" "call")
+   (set (attr "length")
+       (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
+                     (const_int 2)
+                     (const_int 4)))])
+
index 44d596824966b01e3a5d79b7ff2dd2cc31044ab7..ab58d02fc7f08bbead9ce8f6b2088248c22fd905 100644 (file)
@@ -98,7 +98,7 @@
   [(return)]
   ""
   {
-    h8300_expand_epilogue ();
+    h8300_expand_epilogue (false);
     DONE;
   })
 
   gcc_unreachable ();
 }
   [(set_attr "length" "20")])
+
+(define_expand "sibcall_epilogue"
+  [(const_int 0)]
+  ""
+  {
+    h8300_expand_epilogue (true);
+    DONE;
+  })