[NDS32] Refine call and return patterns.
authorChung-Ju Wu <jasonwucj@gmail.com>
Fri, 6 Apr 2018 18:27:51 +0000 (18:27 +0000)
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>
Fri, 6 Apr 2018 18:27:51 +0000 (18:27 +0000)
gcc/
* config/nds32/nds32-md-auxiliary.c (nds32_output_return,
nds32_output_call, nds32_symbol_binds_local_p): New functions.
* config/nds32/nds32-protos.h (nds32_output_call,
nds32_output_return): Declare.
* config/nds32/nds32.md: Refine all the call and return patterns.

Co-Authored-By: Kito Cheng <kito.cheng@gmail.com>
From-SVN: r259186

gcc/ChangeLog
gcc/config/nds32/nds32-md-auxiliary.c
gcc/config/nds32/nds32-protos.h
gcc/config/nds32/nds32.md

index c82d2bc57f874fe4c566fa7516436d279211276e..a261a45986dc7141ff0a1e96447496553eb71820 100644 (file)
@@ -1,3 +1,12 @@
+2018-04-06  Chung-Ju Wu  <jasonwucj@gmail.com>
+           Kito Cheng  <kito.cheng@gmail.com>
+
+       * config/nds32/nds32-md-auxiliary.c (nds32_output_return,
+       nds32_output_call, nds32_symbol_binds_local_p): New functions.
+       * config/nds32/nds32-protos.h (nds32_output_call,
+       nds32_output_return): Declare.
+       * config/nds32/nds32.md: Refine all the call and return patterns.
+
 2018-04-06  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/85252
index dca1c9f959bbbddc821e858081981cc3bb0adc61..01ce38b5980a1ae89d48f7be9b01f6c8ed38a64e 100644 (file)
@@ -1938,6 +1938,48 @@ nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
   return "";
 }
 
+/* Function to output return operation.  */
+const char *
+nds32_output_return (void)
+{
+  /* A string pattern for output_asm_insn().  */
+  char pattern[100];
+  /* The operands array which will be used in output_asm_insn().  */
+  rtx operands[2];
+  /* For stack v3pop:
+     operands[0]: Re
+     operands[1]: imm8u */
+  int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
+  int sp_adjust;
+
+  /* Set operands[0].  */
+  operands[0] = gen_rtx_REG (SImode, re_callee_saved);
+
+  /* Check if we can generate 'pop25 Re,imm8u',
+     otherwise, generate 'pop25 Re,0'.
+     We have to consider alloca issue as well.
+     If the function does call alloca(), the stack pointer is not fixed.
+     In that case, we cannot use 'pop25 Re,imm8u' directly.
+     We have to caculate stack pointer from frame pointer
+     and then use 'pop25 Re,0'.  */
+  sp_adjust = cfun->machine->local_size
+    + cfun->machine->out_args_size
+    + cfun->machine->callee_saved_area_gpr_padding_bytes
+    + cfun->machine->callee_saved_fpr_regs_size;
+  if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
+      && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
+      && !cfun->calls_alloca)
+    operands[1] = GEN_INT (sp_adjust);
+  else
+    operands[1] = GEN_INT (0);
+
+  /* Create assembly code pattern.  */
+  snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
+  /* We use output_asm_insn() to output assembly code by ourself.  */
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
 /* Function to generate PC relative jump table.
    Refer to nds32.md for more details.
 
@@ -2681,6 +2723,56 @@ nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands)
   return "";
 }
 
+/* Return true if SYMBOL_REF X binds locally.  */
+
+static bool
+nds32_symbol_binds_local_p (const_rtx x)
+{
+  return (SYMBOL_REF_DECL (x)
+         ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
+         : SYMBOL_REF_LOCAL_P (x));
+}
+
+const char *
+nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call,
+                  const char *call, bool align_p)
+{
+  char pattern[100];
+  bool noreturn_p;
+
+  if (GET_CODE (symbol) == CONST)
+    {
+      symbol= XEXP (symbol, 0);
+
+      if (GET_CODE (symbol) == PLUS)
+        symbol = XEXP (symbol, 0);
+    }
+
+  gcc_assert (GET_CODE (symbol) == SYMBOL_REF
+             || REG_P (symbol));
+
+  if (nds32_long_call_p (symbol))
+    strcpy (pattern, long_call);
+  else
+    strcpy (pattern, call);
+
+  if (align_p)
+    strcat (pattern, "\n\t.align 2");
+
+  noreturn_p = find_reg_note (insn, REG_NORETURN, NULL_RTX) != NULL_RTX;
+
+  if (noreturn_p)
+    {
+      if (TARGET_16_BIT)
+       strcat (pattern, "\n\tnop16");
+      else
+       strcat (pattern, "\n\tnop");
+    }
+
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
 /* Spilt a doubleword instrucion to two single word instructions.  */
 void
 nds32_spilt_doubleword (rtx *operands, bool load_p)
index aebec3b0b3472067d5099c87eda0186872466390..0b460dadec9f38a0d9601fe72e3b2b0bb23f95f1 100644 (file)
@@ -172,11 +172,15 @@ extern const char *nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *
                                                                      rtx *);
 extern const char *nds32_output_cbranchsi4_greater_less_zero (rtx_insn *, rtx *);
 
+extern const char *nds32_output_call (rtx, rtx *, rtx,
+                                     const char *, const char *, bool);
+
 
 /* Auxiliary functions to output stack push/pop instruction.  */
 
 extern const char *nds32_output_stack_push (rtx);
 extern const char *nds32_output_stack_pop (rtx);
+extern const char *nds32_output_return (void);
 
 /* Auxiliary functions to split double word RTX pattern.  */
 
index cb42d04773adf79e02c96602ec9643df5e316292..67d0d5f075500ace132dd514a3faf817f2ab8fc0 100644 (file)
   ""
 )
 
-(define_insn "*call_register"
-  [(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r"))
-                   (match_operand 1))
-             (clobber (reg:SI LP_REGNUM))
-             (clobber (reg:SI TA_REGNUM))])]
-  ""
-  "@
-  jral5\t%0
-  jral\t%0"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
-
-(define_insn "*call_immediate"
-  [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
+(define_insn "call_internal"
+  [(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i"))
                    (match_operand 1))
              (clobber (reg:SI LP_REGNUM))
              (clobber (reg:SI TA_REGNUM))])]
   ""
 {
-  if (TARGET_CMODEL_LARGE)
-    return "bal\t%0";
-  else
-    return "jal\t%0";
+  switch (which_alternative)
+    {
+    case 0:
+      if (TARGET_16_BIT)
+       return "jral5\t%0";
+      else
+       return "jral\t%0";
+    case 1:
+      return nds32_output_call (insn, operands, operands[0],
+                               "bal\t%0", "jal\t%0", false);
+    default:
+      gcc_unreachable ();
+    }
 }
-  [(set_attr "type"   "branch")
-   (set (attr "length")
-       (if_then_else (match_test "TARGET_CMODEL_LARGE")
-                     (const_int 12)
-                     (const_int 4)))])
-
+  [(set_attr "enabled" "yes")
+   (set_attr "type" "branch")
+   (set_attr_alternative "length"
+     [
+       ;; Alternative 0
+       (if_then_else (match_test "TARGET_16_BIT")
+                    (const_int 2)
+                    (const_int 4))
+       ;; Alternative 1
+       (if_then_else (match_test "nds32_long_call_p (operands[0])")
+                    (const_int 12)
+                    (const_int 4))
+     ])]
+)
 
 ;; Subroutine call instruction returning a value.
 ;;   operands[0]: It is the hard regiser in which the value is returned.
                         (match_operand 2)))
              (clobber (reg:SI LP_REGNUM))
              (clobber (reg:SI TA_REGNUM))])]
-  ""
-  ""
-)
+  "")
 
-(define_insn "*call_value_register"
+(define_insn "call_value_internal"
   [(parallel [(set (match_operand 0)
-                  (call (mem (match_operand:SI 1 "register_operand" "r, r"))
+                  (call (mem (match_operand:SI 1 "nds32_call_address_operand" "r, i"))
                         (match_operand 2)))
              (clobber (reg:SI LP_REGNUM))
              (clobber (reg:SI TA_REGNUM))])]
   ""
-  "@
-  jral5\t%1
-  jral\t%1"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (TARGET_16_BIT)
+       return "jral5\t%1";
+      else
+       return "jral\t%1";
+    case 1:
+      return nds32_output_call (insn, operands, operands[1],
+                               "bal\t%1", "jal\t%1", false);
+    default:
+      gcc_unreachable ();
+    }
+}
+  [(set_attr "enabled" "yes")
+   (set_attr "type" "branch")
+   (set_attr_alternative "length"
+     [
+       ;; Alternative 0
+       (if_then_else (match_test "TARGET_16_BIT")
+                    (const_int 2)
+                    (const_int 4))
+       ;; Alternative 1
+       (if_then_else (match_test "nds32_long_call_p (operands[1])")
+                    (const_int 12)
+                    (const_int 4))
+     ])]
+)
 
-(define_insn "*call_value_immediate"
-  [(parallel [(set (match_operand 0)
-                  (call (mem (match_operand:SI 1 "immediate_operand" "i"))
-                        (match_operand 2)))
-             (clobber (reg:SI LP_REGNUM))
-             (clobber (reg:SI TA_REGNUM))])]
+;; Call subroutine returning any type.
+
+(define_expand "untyped_call"
+  [(parallel [(call (match_operand 0 "" "")
+                   (const_int 0))
+             (match_operand 1 "" "")
+             (match_operand 2 "" "")])]
   ""
 {
-  if (TARGET_CMODEL_LARGE)
-    return "bal\t%1";
-  else
-    return "jal\t%1";
-}
-  [(set_attr "type"   "branch")
-   (set (attr "length")
-       (if_then_else (match_test "TARGET_CMODEL_LARGE")
-                     (const_int 12)
-                     (const_int 4)))])
+  int i;
 
+  emit_call_insn (gen_call (operands[0], const0_rtx));
+
+  for (i = 0; i < XVECLEN (operands[2], 0); i++)
+    {
+      rtx set = XVECEXP (operands[2], 0, i);
+      emit_move_insn (SET_DEST (set), SET_SRC (set));
+    }
+
+  /* The optimizer does not know that the call sets the function value
+     registers we stored in the result block.  We avoid problems by
+     claiming that all hard registers are used and clobbered at this
+     point.  */
+  emit_insn (gen_blockage ());
+  DONE;
+})
 
 ;; ----------------------------------------------------------------------------
 
 ;; Use this pattern to expand a return instruction
 ;; with simple_return rtx if no epilogue is required.
 (define_expand "return"
-  [(simple_return)]
+  [(parallel [(return)
+              (clobber (reg:SI FP_REGNUM))])]
   "nds32_can_use_return_insn ()"
-  ""
-)
+{
+  /* Emit as the simple return.  */
+  if (cfun->machine->naked_p
+      && (cfun->machine->va_args_size == 0))
+    {
+      emit_jump_insn (gen_return_internal ());
+      DONE;
+    }
+})
 
 ;; This pattern is expanded only by the shrink-wrapping optimization
 ;; on paths where the function prologue has not been executed.
   ""
 )
 
+(define_insn "*nds32_return"
+  [(parallel [(return)
+   (clobber (reg:SI FP_REGNUM))])]
+  ""
+{
+  return nds32_output_return ();
+}
+  [(set_attr "type" "branch")
+   (set_attr "enabled" "yes")
+   (set_attr "length" "4")])
+
 (define_insn "return_internal"
   [(simple_return)]
   ""