ChangeLog:
2014-05-17 Ajit Agarwal <ajitkum@xilinx.com> * config/microblaze/microblaze.c (break_handler): New Declaration. (microblaze_break_function_p,microblaze_is_break_handler) : New functions. (compute_frame_size): use of microblaze_break_function_p. Add the test of break_handler. (microblaze_function_prologue) : Add the test of variable break_handler. Check the fnname by BREAK_HANDLER_NAME. (microblaze_function_epilogue) : Add the test of break_handler. (microblaze_globalize_label) : Add the test of break_handler. Check the name by BREAK_HANDLER_NAME. * config/microblaze/microblaze.h (BREAK_HANDLER_NAME) : New macro * config/microblaze/microblaze.md : (*<optab>,<optab>_internal): Add microblaze_is_break_handler () test. (call_internal1,call_value_intern) : Use of microblaze_break_function_p. Use of SYMBOL_REF_DECL. * config/microblaze/microblaze-protos.h (microblaze_break_function_p,microblaze_is_break_handler) : New Declaration. * testsuite/gcc.target/microblaze/others/break_handler.c : New. * doc/extend.texi( MicroBlaze break_handler Functions): Document new MicroBlaze break_handler functions. From-SVN: r210559
This commit is contained in:
parent
a0eaa08ceb
commit
86498dbaae
7 changed files with 118 additions and 14 deletions
|
@ -1,3 +1,31 @@
|
|||
2014-05-17 Ajit Agarwal <ajitkum@xilinx.com>
|
||||
|
||||
* config/microblaze/microblaze.c
|
||||
(break_handler): New Declaration.
|
||||
(microblaze_break_function_p,microblaze_is_break_handler): New.
|
||||
(compute_frame_size): use of microblaze_break_function_p. Add
|
||||
the test of break_handler.
|
||||
(microblaze_function_prologue) : Add the test of variable
|
||||
break_handler. Check the fnname by BREAK_HANDLER_NAME.
|
||||
(microblaze_function_epilogue) : Add the test of break_handler.
|
||||
(microblaze_globalize_label) : Add the test of break_handler. Check the
|
||||
name by BREAK_HANDLER_NAME.
|
||||
|
||||
* config/microblaze/microblaze.h (BREAK_HANDLER_NAME) : New macro
|
||||
|
||||
* config/microblaze/microblaze.md :
|
||||
(*<optab>,<optab>_internal): Add microblaze_is_break_handler () test.
|
||||
(call_internal1,call_value_intern) : Use of microblaze_break_function_p.
|
||||
Use of SYMBOL_REF_DECL.
|
||||
|
||||
* config/microblaze/microblaze-protos.h
|
||||
(microblaze_break_function_p,microblaze_is_break_handler) : New Declaration.
|
||||
|
||||
* testsuite/gcc.target/microblaze/others/break_handler.c : New.
|
||||
|
||||
* doc/extend.texi (MicroBlaze break_handler Functions): Document new
|
||||
MicroBlaze break_handler functions.
|
||||
|
||||
2014-05-17 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* doc/extend.texi (Size of an asm): Move node text according
|
||||
|
|
|
@ -40,10 +40,12 @@ extern void print_operand_address (FILE *, rtx);
|
|||
extern void init_cumulative_args (CUMULATIVE_ARGS *,tree, rtx);
|
||||
extern bool microblaze_legitimate_address_p (enum machine_mode, rtx, bool);
|
||||
extern int microblaze_is_interrupt_variant (void);
|
||||
extern int microblaze_is_break_handler (void);
|
||||
extern int microblaze_break_function_p (tree func);
|
||||
extern rtx microblaze_return_addr (int, rtx);
|
||||
extern int simple_memory_operand (rtx, enum machine_mode);
|
||||
extern int double_memory_operand (rtx, enum machine_mode);
|
||||
|
||||
extern void microblaze_order_regs_for_local_alloc (void);
|
||||
extern int microblaze_regno_ok_for_base_p (int, int);
|
||||
extern HOST_WIDE_INT microblaze_initial_elimination_offset (int, int);
|
||||
extern void microblaze_declare_object (FILE *, const char *, const char *,
|
||||
|
|
|
@ -209,6 +209,7 @@ enum reg_class microblaze_regno_to_class[] =
|
|||
and epilogue and use appropriate interrupt return.
|
||||
save_volatiles - Similar to interrupt handler, but use normal return. */
|
||||
int interrupt_handler;
|
||||
int break_handler;
|
||||
int fast_interrupt;
|
||||
int save_volatiles;
|
||||
|
||||
|
@ -217,6 +218,8 @@ const struct attribute_spec microblaze_attribute_table[] = {
|
|||
affects_type_identity */
|
||||
{"interrupt_handler", 0, 0, true, false, false, NULL,
|
||||
false },
|
||||
{"break_handler", 0, 0, true, false, false, NULL,
|
||||
false },
|
||||
{"fast_interrupt", 0, 0, true, false, false, NULL,
|
||||
false },
|
||||
{"save_volatiles" , 0, 0, true, false, false, NULL,
|
||||
|
@ -1866,7 +1869,18 @@ microblaze_fast_interrupt_function_p (tree func)
|
|||
a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
|
||||
return a != NULL_TREE;
|
||||
}
|
||||
int
|
||||
microblaze_break_function_p (tree func)
|
||||
{
|
||||
tree a;
|
||||
if (!func)
|
||||
return 0;
|
||||
if (TREE_CODE (func) != FUNCTION_DECL)
|
||||
return 0;
|
||||
|
||||
a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
|
||||
return a != NULL_TREE;
|
||||
}
|
||||
/* Return true if FUNC is an interrupt function which uses
|
||||
normal return, indicated by the "save_volatiles" attribute. */
|
||||
|
||||
|
@ -1891,6 +1905,11 @@ microblaze_is_interrupt_variant (void)
|
|||
{
|
||||
return (interrupt_handler || fast_interrupt);
|
||||
}
|
||||
int
|
||||
microblaze_is_break_handler (void)
|
||||
{
|
||||
return break_handler;
|
||||
}
|
||||
|
||||
/* Determine of register must be saved/restored in call. */
|
||||
static int
|
||||
|
@ -1994,9 +2013,14 @@ compute_frame_size (HOST_WIDE_INT size)
|
|||
|
||||
interrupt_handler =
|
||||
microblaze_interrupt_function_p (current_function_decl);
|
||||
break_handler =
|
||||
microblaze_break_function_p (current_function_decl);
|
||||
|
||||
fast_interrupt =
|
||||
microblaze_fast_interrupt_function_p (current_function_decl);
|
||||
save_volatiles = microblaze_save_volatiles (current_function_decl);
|
||||
if (break_handler)
|
||||
interrupt_handler = break_handler;
|
||||
|
||||
gp_reg_size = 0;
|
||||
mask = 0;
|
||||
|
@ -2641,9 +2665,11 @@ microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
|||
{
|
||||
fputs ("\t.ent\t", file);
|
||||
if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
|
||||
fputs ("_interrupt_handler", file);
|
||||
fputs ("_interrupt_handler", file);
|
||||
else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
|
||||
fputs ("_break_handler", file);
|
||||
else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
|
||||
fputs ("_fast_interrupt", file);
|
||||
fputs ("_fast_interrupt", file);
|
||||
else
|
||||
assemble_name (file, fnname);
|
||||
fputs ("\n", file);
|
||||
|
@ -2656,7 +2682,8 @@ microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
|||
|
||||
if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
|
||||
fputs ("_interrupt_handler:\n", file);
|
||||
|
||||
if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
|
||||
fputs ("_break_handler:\n", file);
|
||||
if (!flag_inhibit_size_directive)
|
||||
{
|
||||
/* .frame FRAMEREG, FRAMESIZE, RETREG. */
|
||||
|
@ -2791,6 +2818,7 @@ microblaze_expand_prologue (void)
|
|||
if (flag_stack_usage_info)
|
||||
current_function_static_stack_size = fsiz;
|
||||
|
||||
|
||||
/* If this function is a varargs function, store any registers that
|
||||
would normally hold arguments ($5 - $10) on the stack. */
|
||||
if (((TYPE_ARG_TYPES (fntype) != 0
|
||||
|
@ -2892,8 +2920,10 @@ microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
|
|||
if (!flag_inhibit_size_directive)
|
||||
{
|
||||
fputs ("\t.end\t", file);
|
||||
if (interrupt_handler)
|
||||
if (interrupt_handler && !break_handler)
|
||||
fputs ("_interrupt_handler", file);
|
||||
else if (break_handler)
|
||||
fputs ("_break_handler", file);
|
||||
else
|
||||
assemble_name (file, fnname);
|
||||
fputs ("\n", file);
|
||||
|
@ -3007,6 +3037,8 @@ microblaze_globalize_label (FILE * stream, const char *name)
|
|||
{
|
||||
if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
|
||||
fputs (INTERRUPT_HANDLER_NAME, stream);
|
||||
else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
|
||||
fputs (BREAK_HANDLER_NAME, stream);
|
||||
else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
|
||||
fputs (FAST_INTERRUPT_NAME, stream);
|
||||
fputs ("\n\t.globl\t", stream);
|
||||
|
|
|
@ -263,7 +263,6 @@ extern enum pipeline_type microblaze_pipe;
|
|||
1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
1, 1, 1, 1 \
|
||||
}
|
||||
|
||||
#define GP_REG_FIRST 0
|
||||
#define GP_REG_LAST 31
|
||||
#define GP_REG_NUM (GP_REG_LAST - GP_REG_FIRST + 1)
|
||||
|
@ -763,6 +762,10 @@ extern int fast_interrupt;
|
|||
extern int save_volatiles;
|
||||
|
||||
#define INTERRUPT_HANDLER_NAME "_interrupt_handler"
|
||||
/* The function name for the function tagged with attribute break_handler
|
||||
has been set in the RTL as _break_handler. This function name is used
|
||||
in the generation of directives .ent .end and .global. */
|
||||
#define BREAK_HANDLER_NAME "_break_handler"
|
||||
#define FAST_INTERRUPT_NAME "_fast_interrupt"
|
||||
|
||||
/* The following #defines are used in the headers files. Always retain these. */
|
||||
|
|
|
@ -1945,8 +1945,10 @@
|
|||
(define_insn "*<optab>"
|
||||
[(any_return)]
|
||||
""
|
||||
{
|
||||
if (microblaze_is_interrupt_variant ())
|
||||
{
|
||||
if (microblaze_is_break_handler ())
|
||||
return "rtbd\tr16, 8\;%#";
|
||||
else if (microblaze_is_interrupt_variant ())
|
||||
return "rtid\tr14, 0\;%#";
|
||||
else
|
||||
return "rtsd\tr15, 8\;%#";
|
||||
|
@ -1962,8 +1964,10 @@
|
|||
[(any_return)
|
||||
(use (match_operand:SI 0 "register_operand" ""))]
|
||||
""
|
||||
{
|
||||
if (microblaze_is_interrupt_variant ())
|
||||
{
|
||||
if (microblaze_is_break_handler ())
|
||||
return "rtbd\tr16,8\;%#";
|
||||
else if (microblaze_is_interrupt_variant ())
|
||||
return "rtid\tr14,0 \;%#";
|
||||
else
|
||||
return "rtsd\tr15,8 \;%#";
|
||||
|
@ -2068,8 +2072,14 @@
|
|||
register rtx target2 = gen_rtx_REG (Pmode,
|
||||
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
|
||||
if (GET_CODE (target) == SYMBOL_REF) {
|
||||
gen_rtx_CLOBBER (VOIDmode, target2);
|
||||
return "brlid\tr15,%0\;%#";
|
||||
if (microblaze_break_function_p (SYMBOL_REF_DECL (target))) {
|
||||
gen_rtx_CLOBBER (VOIDmode, target2);
|
||||
return "brki\tr16,%0\;%#";
|
||||
}
|
||||
else {
|
||||
gen_rtx_CLOBBER (VOIDmode, target2);
|
||||
return "brlid\tr15,%0\;%#";
|
||||
}
|
||||
} else if (GET_CODE (target) == CONST_INT)
|
||||
return "la\t%@,r0,%0\;brald\tr15,%@\;%#";
|
||||
else if (GET_CODE (target) == REG)
|
||||
|
@ -2173,13 +2183,15 @@
|
|||
if (GET_CODE (target) == SYMBOL_REF)
|
||||
{
|
||||
gen_rtx_CLOBBER (VOIDmode,target2);
|
||||
if (SYMBOL_REF_FLAGS (target) & SYMBOL_FLAG_FUNCTION)
|
||||
if (microblaze_break_function_p (SYMBOL_REF_DECL (target)))
|
||||
return "brki\tr16,%1\;%#";
|
||||
else if (SYMBOL_REF_FLAGS (target) & SYMBOL_FLAG_FUNCTION)
|
||||
{
|
||||
return "brlid\tr15,%1\;%#";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "bralid\tr15,%1\;%#";
|
||||
return "bralid\tr15,%1\;%#";
|
||||
}
|
||||
}
|
||||
else if (GET_CODE (target) == CONST_INT)
|
||||
|
|
|
@ -3772,6 +3772,18 @@ registers) are saved in the function prologue. If the function is a leaf
|
|||
function, only volatiles used by the function are saved. A normal function
|
||||
return is generated instead of a return from interrupt.
|
||||
|
||||
@item break_handler
|
||||
@cindex break handler functions
|
||||
Use this attribute on the MicroBlaze ports to indicate that
|
||||
the specified function is an break handler. The compiler generates function
|
||||
entry and exit sequences suitable for use in an break handler when this
|
||||
attribute is present. The return from @code{break_handler} is done through
|
||||
the @code{rtbd} instead of @code{rtsd}.
|
||||
|
||||
@smallexample
|
||||
void f () __attribute__ ((break_handler));
|
||||
@end smallexample
|
||||
|
||||
@item section ("@var{section-name}")
|
||||
@cindex @code{section} function attribute
|
||||
Normally, the compiler places the code it generates in the @code{text} section.
|
||||
|
|
15
gcc/testsuite/gcc.target/microblaze/others/break_handler.c
Normal file
15
gcc/testsuite/gcc.target/microblaze/others/break_handler.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
int func () __attribute__ ((break_handler));
|
||||
volatile int intr_occurred;
|
||||
|
||||
int func ()
|
||||
{
|
||||
|
||||
/* { dg-final { scan-assembler "rtbd\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),8" } } */
|
||||
intr_occurred += 1;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
/* { dg-final { scan-assembler "brki\tr16" } } */
|
||||
func();
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue