RISC-V: Add naked function support.
authorKito Cheng <kito.cheng@gmail.com>
Wed, 10 Jan 2018 23:00:38 +0000 (23:00 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Wed, 10 Jan 2018 23:00:38 +0000 (15:00 -0800)
2018-01-10  Kito Cheng  <kito.cheng@gmail.com>

gcc/
* config/riscv/riscv-protos.h (riscv_output_return): New.
* config/riscv/riscv.c (struct machine_function): New naked_p field.
(riscv_attribute_table, riscv_output_return),
(riscv_handle_fndecl_attribute, riscv_naked_function_p),
(riscv_allocate_stack_slots_for_args, riscv_warn_func_return): New.
(riscv_compute_frame_info): Only compute frame->mask if not a naked
function.
(riscv_expand_prologue): Add early return for naked function.
(riscv_expand_epilogue): Likewise.
(riscv_function_ok_for_sibcall): Return false for naked function.
(riscv_set_current_function): New.
(TARGET_SET_CURRENT_FUNCTION, TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS),
(TARGET_ATTRIBUTE_TABLE, TARGET_WARN_FUNC_RETURN): New.
* config/riscv/riscv.md (simple_return): Call riscv_output_return.
* doc/extend.texi (RISC-V Function Attributes): New.

Co-Authored-By: Jim Wilson <jimw@sifive.com>
From-SVN: r256462

gcc/ChangeLog
gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv.c
gcc/config/riscv/riscv.md
gcc/doc/extend.texi

index 9e7590526e0434e89b92ef7cdf853810d1b3b7f6..3662659fee064b15a26dceb45338836a77de86fb 100644 (file)
@@ -1,3 +1,22 @@
+2018-01-10  Kito Cheng  <kito.cheng@gmail.com>
+           Jim Wilson  <jimw@sifive.com>
+
+       * config/riscv/riscv-protos.h (riscv_output_return): New.
+       * config/riscv/riscv.c (struct machine_function): New naked_p field.
+       (riscv_attribute_table, riscv_output_return),
+       (riscv_handle_fndecl_attribute, riscv_naked_function_p),
+       (riscv_allocate_stack_slots_for_args, riscv_warn_func_return): New.
+       (riscv_compute_frame_info): Only compute frame->mask if not a naked
+       function.
+       (riscv_expand_prologue): Add early return for naked function.
+       (riscv_expand_epilogue): Likewise.
+       (riscv_function_ok_for_sibcall): Return false for naked function.
+       (riscv_set_current_function): New.
+       (TARGET_SET_CURRENT_FUNCTION, TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS),
+       (TARGET_ATTRIBUTE_TABLE, TARGET_WARN_FUNC_RETURN): New.
+       * config/riscv/riscv.md (simple_return): Call riscv_output_return.
+       * doc/extend.texi (RISC-V Function Attributes): New.
+
 2018-01-10  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        * config/rs6000/rs6000.c (is_complex_IBM_long_double): Explicitly
index 1cf016d850b936c19c7693d94d011b006dcfc04c..0538ede77e48e4bffe8f250fda4b656946b96fc8 100644 (file)
@@ -54,6 +54,7 @@ extern bool riscv_split_64bit_move_p (rtx, rtx);
 extern void riscv_split_doubleword_move (rtx, rtx);
 extern const char *riscv_output_move (rtx, rtx);
 extern const char *riscv_output_gpr_save (unsigned);
+extern const char *riscv_output_return ();
 #ifdef RTX_CODE
 extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx);
 extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx);
index b6270f7bfd7ff30659d7238941171af8bd2dcb00..d260c0ebae148d4caaeca2c14c0251f073c4443f 100644 (file)
@@ -127,6 +127,9 @@ struct GTY(())  machine_function {
      This area is allocated by the callee at the very top of the frame.  */
   int varargs_size;
 
+  /* True if current function is a naked function.  */
+  bool naked_p;
+
   /* The current frame information, calculated by riscv_compute_frame_info.  */
   struct riscv_frame_info frame;
 };
@@ -269,6 +272,23 @@ static const struct riscv_tune_info optimize_size_tune_info = {
   false,                                       /* slow_unaligned_access */
 };
 
+static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
+
+/* Defining target-specific uses of __attribute__.  */
+static const struct attribute_spec riscv_attribute_table[] =
+{
+  /* Syntax: { name, min_len, max_len, decl_required, type_required,
+              function_type_required, affects_type_identity, handler,
+              exclude } */
+
+  /* The attribute telling no prologue/epilogue.  */
+  { "naked",   0,  0, true, false, false, false,
+    riscv_handle_fndecl_attribute, NULL },
+
+  /* The last attribute spec is set to be NULL.  */
+  { NULL,      0,  0, false, false, false, false, NULL, NULL }
+};
+
 /* A table describing all the processors GCC knows about.  */
 static const struct riscv_cpu_info riscv_cpu_info_table[] = {
   { "rocket", &rocket_tune_info },
@@ -1827,6 +1847,16 @@ riscv_output_move (rtx dest, rtx src)
     }
   gcc_unreachable ();
 }
+
+const char *
+riscv_output_return ()
+{
+  if (cfun->machine->naked_p)
+    return "";
+
+  return "ret";
+}
+
 \f
 /* Return true if CMP1 is a suitable second operand for integer ordering
    test CODE.  See also the *sCC patterns in riscv.md.  */
@@ -2647,6 +2677,50 @@ riscv_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
     cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD;
 }
 
+/* Handle an attribute requiring a FUNCTION_DECL;
+   arguments as in struct attribute_spec.handler.  */
+static tree
+riscv_handle_fndecl_attribute (tree *node, tree name,
+                              tree args ATTRIBUTE_UNUSED,
+                              int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return true if func is a naked function.  */
+static bool
+riscv_naked_function_p (tree func)
+{
+  tree func_decl = func;
+  if (func == NULL_TREE)
+    func_decl = current_function_decl;
+  return NULL_TREE != lookup_attribute ("naked", DECL_ATTRIBUTES (func_decl));
+}
+
+/* Implement TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS.  */
+static bool
+riscv_allocate_stack_slots_for_args ()
+{
+  /* Naked functions should not allocate stack slots for arguments.  */
+  return !riscv_naked_function_p (current_function_decl);
+}
+
+/* Implement TARGET_WARN_FUNC_RETURN.  */
+static bool
+riscv_warn_func_return (tree decl)
+{
+  /* Naked functions are implemented entirely in assembly, including the
+     return sequence, so suppress warnings about this.  */
+  return !riscv_naked_function_p (decl);
+}
+
 /* Implement TARGET_EXPAND_BUILTIN_VA_START.  */
 
 static void
@@ -3202,23 +3276,26 @@ riscv_compute_frame_info (void)
   frame = &cfun->machine->frame;
   memset (frame, 0, sizeof (*frame));
 
-  /* Find out which GPRs we need to save.  */
-  for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
-    if (riscv_save_reg_p (regno))
-      frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
-
-  /* If this function calls eh_return, we must also save and restore the
-     EH data registers.  */
-  if (crtl->calls_eh_return)
-    for (i = 0; (regno = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
-      frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
-
-  /* Find out which FPRs we need to save.  This loop must iterate over
-     the same space as its companion in riscv_for_each_saved_reg.  */
-  if (TARGET_HARD_FLOAT)
-    for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
-      if (riscv_save_reg_p (regno))
-       frame->fmask |= 1 << (regno - FP_REG_FIRST), num_f_saved++;
+  if (!cfun->machine->naked_p)
+    {
+      /* Find out which GPRs we need to save.  */
+      for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+       if (riscv_save_reg_p (regno))
+         frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
+
+      /* If this function calls eh_return, we must also save and restore the
+        EH data registers.  */
+      if (crtl->calls_eh_return)
+       for (i = 0; (regno = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
+         frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
+
+      /* Find out which FPRs we need to save.  This loop must iterate over
+        the same space as its companion in riscv_for_each_saved_reg.  */
+      if (TARGET_HARD_FLOAT)
+       for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
+         if (riscv_save_reg_p (regno))
+           frame->fmask |= 1 << (regno - FP_REG_FIRST), num_f_saved++;
+    }
 
   /* At the bottom of the frame are any outgoing stack arguments. */
   offset = crtl->outgoing_args_size;
@@ -3488,6 +3565,14 @@ riscv_expand_prologue (void)
   unsigned mask = frame->mask;
   rtx insn;
 
+  if (cfun->machine->naked_p)
+    {
+      if (flag_stack_usage_info)
+       current_function_static_stack_size = 0;
+
+      return;
+    }
+
   if (flag_stack_usage_info)
     current_function_static_stack_size = size;
 
@@ -3600,6 +3685,15 @@ riscv_expand_epilogue (bool sibcall_p)
   bool need_barrier_p = (get_frame_size ()
                         + cfun->machine->frame.arg_pointer_offset) != 0;
 
+  if (cfun->machine->naked_p)
+    {
+      gcc_assert (!sibcall_p);
+
+      emit_jump_insn (gen_return ());
+
+      return;
+    }
+
   if (!sibcall_p && riscv_can_use_return_insn ())
     {
       emit_jump_insn (gen_return ());
@@ -4183,9 +4277,27 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
   if (TARGET_SAVE_RESTORE)
     return false;
 
+  /* Don't use sibcall for naked function.  */
+  if (cfun->machine->naked_p)
+    return false;
+
   return true;
 }
 
+/* Implement `TARGET_SET_CURRENT_FUNCTION'.  */
+/* Sanity cheching for above function attributes.  */
+static void
+riscv_set_current_function (tree decl)
+{
+  if (decl == NULL_TREE
+      || current_function_decl == NULL_TREE
+      || current_function_decl == error_mark_node
+      || !cfun->machine)
+    return;
+
+  cfun->machine->naked_p = riscv_naked_function_p (decl);
+}
+
 /* Implement TARGET_CANNOT_COPY_INSN_P.  */
 
 static bool
@@ -4241,6 +4353,9 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL riscv_function_ok_for_sibcall
 
+#undef  TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION riscv_set_current_function
+
 #undef TARGET_REGISTER_MOVE_COST
 #define TARGET_REGISTER_MOVE_COST riscv_register_move_cost
 #undef TARGET_MEMORY_MOVE_COST
@@ -4276,6 +4391,8 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
 
 #undef TARGET_SETUP_INCOMING_VARARGS
 #define TARGET_SETUP_INCOMING_VARARGS riscv_setup_incoming_varargs
+#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
+#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS riscv_allocate_stack_slots_for_args
 #undef TARGET_STRICT_ARGUMENT_NAMING
 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
 #undef TARGET_MUST_PASS_IN_STACK
@@ -4377,6 +4494,12 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
 #undef TARGET_CONSTANT_ALIGNMENT
 #define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment
 
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE riscv_attribute_table
+
+#undef TARGET_WARN_FUNC_RETURN
+#define TARGET_WARN_FUNC_RETURN riscv_warn_func_return
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
index 99341fa00b459d4dba9808245af302660bc8b0e9..bffe78dd837f62da2e2ec17f3aa79697753f0e3f 100644 (file)
 (define_insn "simple_return"
   [(simple_return)]
   ""
-  "ret"
+{
+  return riscv_output_return ();
+}
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")])
 
index 5f0f4b86cb28149159c8daee45d6628c6e43742a..84640f4fde6431fcbda6580dbc86646d6f2dc6c2 100644 (file)
@@ -2319,6 +2319,7 @@ GCC plugins may provide their own attributes.
 * Nios II Function Attributes::
 * Nvidia PTX Function Attributes::
 * PowerPC Function Attributes::
+* RISC-V Function Attributes::
 * RL78 Function Attributes::
 * RX Function Attributes::
 * S/390 Function Attributes::
@@ -5093,6 +5094,24 @@ function that has different target options than the caller, unless the
 callee has a subset of the target options of the caller.
 @end table
 
+@node RISC-V Function Attributes
+@subsection RISC-V Function Attributes
+
+These function attributes are supported by the RISC-V back end:
+
+@table @code
+@item naked
+@cindex @code{naked} function attribute, RISC-V
+This attribute allows the compiler to construct the
+requisite function declaration, while allowing the body of the
+function to be assembly code. The specified function will not have
+prologue/epilogue sequences generated by the compiler. Only basic
+@code{asm} statements can safely be included in naked functions
+(@pxref{Basic Asm}). While using extended @code{asm} or a mixture of
+basic @code{asm} and C code may appear to work, they cannot be
+depended upon to work reliably and are not supported.
+@end table
+
 @node RL78 Function Attributes
 @subsection RL78 Function Attributes