or1k: gcc: Add naked attribute

Message ID CAObF=bqVOu9x=nPLEbu2b0mY1dTQCoc9v7K9R=T8xAeBMT-_OA@mail.gmail.com
State New
Headers
Series or1k: gcc: Add naked attribute |

Commit Message

jesus June 23, 2022, 11:55 p.m. UTC
  Hello.

I have added support for naked functions on the OpenRISC 1200 target
it practically inhibits the generation of a function epilogue and
prologue and will warn about variables that might use the stack (to
prevent unintended code being generated).

As well added a table for attributes where the attribute can only
be applied functions, like in the other backends.

gcc/ChangeLog:

	* config/or1k/or1k.cc (or1k_handle_naked_attribute):
	(has_func_attr): Likewise.
	(callee_saved_regno_p): Likewise.
	(or1k_save_reg): Likewise.
	(or1k_restore_reg): Likewise.
	(or1k_expand_prologue): Likewise.
	(or1k_expand_epilogue): Likewise.
	(or1k_frame_pointer_required): Likewise.
	(TARGET_ATTRIBUTE_TABLE): Define.

---
 gcc/config/or1k/or1k.cc | 58 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 55 insertions(+), 3 deletions(-)
  

Patch

diff --git a/gcc/config/or1k/or1k.cc b/gcc/config/or1k/or1k.cc
index da2f59062ba..c41ac5ab099 100644
--- a/gcc/config/or1k/or1k.cc
+++ b/gcc/config/or1k/or1k.cc
@@ -79,6 +79,41 @@  struct GTY(()) machine_function
   rtx_insn *set_mcount_arg_insn;
 };

+static tree
+or1k_handle_naked_attribute(tree *node, tree name ATTRIBUTE_UNUSED,
+                            tree args ATTRIBUTE_UNUSED,
+                            int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  gcc_assert(DECL_P(*node));
+
+  if (TREE_CODE(*node) != FUNCTION_DECL)
+  {
+    warning(OPT_Wattributes, "%qE attribute only applies to functions",
+            name);
+    *no_add_attrs = true;
+  }
+  return NULL_TREE;
+}
+
+static const struct attribute_spec or1k_attribute_table[] = {
+  { "naked", 0, 0, true, false, false, false,
+    or1k_handle_naked_attribute, NULL },
+
+  /* End element.  */
+  { NULL, 0, 0, false, false, false, false, NULL, NULL }
+};
+
+/* Returns true if the provided function has the specified attribute.  */
+
+static inline bool
+has_func_attr(const_tree decl, const char *func_attr)
+{
+  if (decl == NULL_TREE)
+    decl = current_function_decl;
+
+  return lookup_attribute(func_attr, DECL_ATTRIBUTES(decl)) != NULL_TREE;
+}
+
 /* Zero initialization is OK for all current fields.  */

 static struct machine_function *
@@ -103,6 +138,10 @@  or1k_option_override (void)
 static bool
 callee_saved_regno_p (int regno)
 {
+  /* Naked functions do not save anything, so let's say NO! */
+  if (has_func_attr(NULL_TREE, "naked"))
+    return false;
+
   /* Check call-saved registers.  */
   if (!call_used_or_fixed_reg_p (regno) && df_regs_ever_live_p (regno))
     return true;
@@ -185,6 +224,9 @@  or1k_compute_frame_layout (void)
 static void
 or1k_save_reg (int regno, HOST_WIDE_INT offset)
 {
+  if (has_func_attr(NULL_TREE, "naked"))
+    warning(0, "stack usage on naked function %s", current_function_name());
+
   rtx reg = gen_rtx_REG (Pmode, regno);
   rtx mem = gen_frame_mem (SImode, plus_constant (Pmode, stack_pointer_rtx,
 						  offset));
@@ -198,6 +240,9 @@  or1k_save_reg (int regno, HOST_WIDE_INT offset)
 static rtx
 or1k_restore_reg (int regno, HOST_WIDE_INT offset, rtx cfa_restores)
 {
+  if (has_func_attr(NULL_TREE, "naked"))
+    warning(0, "stack usage on naked function %s", current_function_name());
+
   rtx reg = gen_rtx_REG (Pmode, regno);
   rtx mem = gen_frame_mem (SImode, plus_constant (Pmode, stack_pointer_rtx,
 						  offset));
@@ -217,8 +262,8 @@  or1k_expand_prologue (void)
   if (flag_stack_usage_info)
     current_function_static_stack_size = -sp_offset;

-  /* Early exit for frameless functions.  */
-  if (sp_offset == 0)
+  /* Early exit for frameless functions */
+  if (sp_offset == 0 || has_func_attr(NULL_TREE, "naked"))
     goto fini;

   /* Adjust the stack pointer.  For large stack offsets we will
@@ -325,7 +370,7 @@  or1k_expand_epilogue (void)
   rtx insn, cfa_restores = NULL;

   sp_offset = cfun->machine->total_size;
-  if (sp_offset == 0)
+  if (sp_offset == 0 || has_func_attr(NULL_TREE, "naked"))
     return;

   reg_offset = cfun->machine->local_vars_size + cfun->machine->args_size;
@@ -509,6 +554,10 @@  or1k_return_addr (int, rtx frame)
 static bool
 or1k_frame_pointer_required ()
 {
+  /* Frame pointer is not required for naked functions */
+  if (has_func_attr(NULL_TREE, "naked"))
+    return false;
+
   /* ??? While IRA checks accesses_prior_frames, reload does not.
      We do want the frame pointer for this case.  */
   return (crtl->accesses_prior_frames);
@@ -2212,6 +2261,9 @@  or1k_output_mi_thunk (FILE *file, tree thunk_fndecl,
 #undef  TARGET_HAVE_SPECULATION_SAFE_VALUE
 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed

+#undef  TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE or1k_attribute_table
+
 /* Calling Conventions.  */
 #undef  TARGET_FUNCTION_VALUE
 #define TARGET_FUNCTION_VALUE or1k_function_value