@@ -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