Commit 8cad5b14 by Kito Cheng Committed by Jim Wilson

RISC-V: Add naked function support.

	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
parent 3ec62f54
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> 2018-01-10 Michael Meissner <meissner@linux.vnet.ibm.com>
* config/rs6000/rs6000.c (is_complex_IBM_long_double): Explicitly * config/rs6000/rs6000.c (is_complex_IBM_long_double): Explicitly
......
...@@ -54,6 +54,7 @@ extern bool riscv_split_64bit_move_p (rtx, rtx); ...@@ -54,6 +54,7 @@ extern bool riscv_split_64bit_move_p (rtx, rtx);
extern void riscv_split_doubleword_move (rtx, rtx); extern void riscv_split_doubleword_move (rtx, rtx);
extern const char *riscv_output_move (rtx, rtx); extern const char *riscv_output_move (rtx, rtx);
extern const char *riscv_output_gpr_save (unsigned); extern const char *riscv_output_gpr_save (unsigned);
extern const char *riscv_output_return ();
#ifdef RTX_CODE #ifdef RTX_CODE
extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx); extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx);
extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx); extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx);
......
...@@ -127,6 +127,9 @@ struct GTY(()) machine_function { ...@@ -127,6 +127,9 @@ struct GTY(()) machine_function {
This area is allocated by the callee at the very top of the frame. */ This area is allocated by the callee at the very top of the frame. */
int varargs_size; int varargs_size;
/* True if current function is a naked function. */
bool naked_p;
/* The current frame information, calculated by riscv_compute_frame_info. */ /* The current frame information, calculated by riscv_compute_frame_info. */
struct riscv_frame_info frame; struct riscv_frame_info frame;
}; };
...@@ -269,6 +272,23 @@ static const struct riscv_tune_info optimize_size_tune_info = { ...@@ -269,6 +272,23 @@ static const struct riscv_tune_info optimize_size_tune_info = {
false, /* slow_unaligned_access */ 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. */ /* A table describing all the processors GCC knows about. */
static const struct riscv_cpu_info riscv_cpu_info_table[] = { static const struct riscv_cpu_info riscv_cpu_info_table[] = {
{ "rocket", &rocket_tune_info }, { "rocket", &rocket_tune_info },
...@@ -1827,6 +1847,16 @@ riscv_output_move (rtx dest, rtx src) ...@@ -1827,6 +1847,16 @@ riscv_output_move (rtx dest, rtx src)
} }
gcc_unreachable (); gcc_unreachable ();
} }
const char *
riscv_output_return ()
{
if (cfun->machine->naked_p)
return "";
return "ret";
}
/* Return true if CMP1 is a suitable second operand for integer ordering /* Return true if CMP1 is a suitable second operand for integer ordering
test CODE. See also the *sCC patterns in riscv.md. */ 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, ...@@ -2647,6 +2677,50 @@ riscv_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD; 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. */ /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
static void static void
...@@ -3202,23 +3276,26 @@ riscv_compute_frame_info (void) ...@@ -3202,23 +3276,26 @@ riscv_compute_frame_info (void)
frame = &cfun->machine->frame; frame = &cfun->machine->frame;
memset (frame, 0, sizeof (*frame)); memset (frame, 0, sizeof (*frame));
/* Find out which GPRs we need to save. */ if (!cfun->machine->naked_p)
for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) {
if (riscv_save_reg_p (regno)) /* Find out which GPRs we need to save. */
frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++; for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
if (riscv_save_reg_p (regno))
/* If this function calls eh_return, we must also save and restore the frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
EH data registers. */
if (crtl->calls_eh_return) /* If this function calls eh_return, we must also save and restore the
for (i = 0; (regno = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++) EH data registers. */
frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++; if (crtl->calls_eh_return)
for (i = 0; (regno = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
/* Find out which FPRs we need to save. This loop must iterate over frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++;
the same space as its companion in riscv_for_each_saved_reg. */
if (TARGET_HARD_FLOAT) /* Find out which FPRs we need to save. This loop must iterate over
for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) the same space as its companion in riscv_for_each_saved_reg. */
if (riscv_save_reg_p (regno)) if (TARGET_HARD_FLOAT)
frame->fmask |= 1 << (regno - FP_REG_FIRST), num_f_saved++; 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. */ /* At the bottom of the frame are any outgoing stack arguments. */
offset = crtl->outgoing_args_size; offset = crtl->outgoing_args_size;
...@@ -3488,6 +3565,14 @@ riscv_expand_prologue (void) ...@@ -3488,6 +3565,14 @@ riscv_expand_prologue (void)
unsigned mask = frame->mask; unsigned mask = frame->mask;
rtx insn; rtx insn;
if (cfun->machine->naked_p)
{
if (flag_stack_usage_info)
current_function_static_stack_size = 0;
return;
}
if (flag_stack_usage_info) if (flag_stack_usage_info)
current_function_static_stack_size = size; current_function_static_stack_size = size;
...@@ -3600,6 +3685,15 @@ riscv_expand_epilogue (bool sibcall_p) ...@@ -3600,6 +3685,15 @@ riscv_expand_epilogue (bool sibcall_p)
bool need_barrier_p = (get_frame_size () bool need_barrier_p = (get_frame_size ()
+ cfun->machine->frame.arg_pointer_offset) != 0; + 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 ()) if (!sibcall_p && riscv_can_use_return_insn ())
{ {
emit_jump_insn (gen_return ()); emit_jump_insn (gen_return ());
...@@ -4183,9 +4277,27 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, ...@@ -4183,9 +4277,27 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
if (TARGET_SAVE_RESTORE) if (TARGET_SAVE_RESTORE)
return false; return false;
/* Don't use sibcall for naked function. */
if (cfun->machine->naked_p)
return false;
return true; 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. */ /* Implement TARGET_CANNOT_COPY_INSN_P. */
static bool static bool
...@@ -4241,6 +4353,9 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align) ...@@ -4241,6 +4353,9 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
#undef TARGET_FUNCTION_OK_FOR_SIBCALL #undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL riscv_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 #undef TARGET_REGISTER_MOVE_COST
#define TARGET_REGISTER_MOVE_COST riscv_register_move_cost #define TARGET_REGISTER_MOVE_COST riscv_register_move_cost
#undef TARGET_MEMORY_MOVE_COST #undef TARGET_MEMORY_MOVE_COST
...@@ -4276,6 +4391,8 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align) ...@@ -4276,6 +4391,8 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
#undef TARGET_SETUP_INCOMING_VARARGS #undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS riscv_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 #undef TARGET_STRICT_ARGUMENT_NAMING
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
#undef TARGET_MUST_PASS_IN_STACK #undef TARGET_MUST_PASS_IN_STACK
...@@ -4377,6 +4494,12 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align) ...@@ -4377,6 +4494,12 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
#undef TARGET_CONSTANT_ALIGNMENT #undef TARGET_CONSTANT_ALIGNMENT
#define TARGET_CONSTANT_ALIGNMENT riscv_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; struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-riscv.h" #include "gt-riscv.h"
...@@ -1927,7 +1927,9 @@ ...@@ -1927,7 +1927,9 @@
(define_insn "simple_return" (define_insn "simple_return"
[(simple_return)] [(simple_return)]
"" ""
"ret" {
return riscv_output_return ();
}
[(set_attr "type" "jump") [(set_attr "type" "jump")
(set_attr "mode" "none")]) (set_attr "mode" "none")])
......
...@@ -2319,6 +2319,7 @@ GCC plugins may provide their own attributes. ...@@ -2319,6 +2319,7 @@ GCC plugins may provide their own attributes.
* Nios II Function Attributes:: * Nios II Function Attributes::
* Nvidia PTX Function Attributes:: * Nvidia PTX Function Attributes::
* PowerPC Function Attributes:: * PowerPC Function Attributes::
* RISC-V Function Attributes::
* RL78 Function Attributes:: * RL78 Function Attributes::
* RX Function Attributes:: * RX Function Attributes::
* S/390 Function Attributes:: * S/390 Function Attributes::
...@@ -5093,6 +5094,24 @@ function that has different target options than the caller, unless the ...@@ -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. callee has a subset of the target options of the caller.
@end table @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 @node RL78 Function Attributes
@subsection RL78 Function Attributes @subsection RL78 Function Attributes
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment