Commit cad055a4 by Nick Clifton Committed by Nick Clifton

msp430-protos.h: Add prototypes for new functions.

	* config/msp430/msp430-protos.h: Add prototypes for new functions.
	* config/msp430/msp430.c (msp430_preserve_reg_p): Add support for
	interrupt handlers.
	(is_attr_func): New function.
	(msp430_is_interrupt_func): New function.
	(is_naked_func): New function.
	(is_reentrant_func): New function.
	(is_critical_func): New function.
	(msp430_start_function): Add annotations for function attributes.
	(msp430_attr): New function.
	(msp430_attribute_table): New.
	(msp430_function_section): New function.
	(TARGET_ASM_FUNCTION_SECTION): Define.
	(msp430_builtin): New enum.
	(msp430_init_builtins): New function.
	(msp430_builtin_devl): New function.
	(msp430_expand_builtin): New function.
	(TARGET_INIT_BUILTINS): Define.
	(TARGET_EXPAND_BUILTINS): Define.
	(TARGET_BUILTIN_DECL): Define.
	(msp430_expand_prologue): Add support for naked, interrupt,
	critical and reentrant functions.
	(msp430_expand_epilogue): Likewise.
	(msp430_print_operand): Handle 'O' character.
	* config/msp430/msp430.h (TARGET_CPU_CPP_BUILTINS): Define
	NO_TRAMPOLINES.
	* config/msp430/msp430.md (unspec): Add UNS_DINT, UNS_EINT,
	UNS_PUSH_INTR, UNS_POP_INTR, UNS_BIC_SR, UNS_BIS_SR.
	(pushm): Use a 'n' rather than an 'i' constraint.
	(msp_return): Add generation of the interrupt return instruction.
	(disable_interrupts): New pattern.
	(enable_interrupts): New pattern.
	(push_intr_state): New pattern.
	(pop_intr_state): New pattern.
	(bic_SR): New pattern.
	(bis_SR): New pattern.
	* doc/extend.texi: Document MSP430 function attributes and builtin
	functions.

From-SVN: r202645
parent deb6c11a
2013-09-17 Nick Clifton <nickc@redhat.com>
* config/msp430/msp430-protos.h: Add prototypes for new functions.
* config/msp430/msp430.c (msp430_preserve_reg_p): Add support for
interrupt handlers.
(is_attr_func): New function.
(msp430_is_interrupt_func): New function.
(is_naked_func): New function.
(is_reentrant_func): New function.
(is_critical_func): New function.
(msp430_start_function): Add annotations for function attributes.
(msp430_attr): New function.
(msp430_attribute_table): New.
(msp430_function_section): New function.
(TARGET_ASM_FUNCTION_SECTION): Define.
(msp430_builtin): New enum.
(msp430_init_builtins): New function.
(msp430_builtin_devl): New function.
(msp430_expand_builtin): New function.
(TARGET_INIT_BUILTINS): Define.
(TARGET_EXPAND_BUILTINS): Define.
(TARGET_BUILTIN_DECL): Define.
(msp430_expand_prologue): Add support for naked, interrupt,
critical and reentrant functions.
(msp430_expand_epilogue): Likewise.
(msp430_print_operand): Handle 'O' character.
* config/msp430/msp430.h (TARGET_CPU_CPP_BUILTINS): Define
NO_TRAMPOLINES.
* config/msp430/msp430.md (unspec): Add UNS_DINT, UNS_EINT,
UNS_PUSH_INTR, UNS_POP_INTR, UNS_BIC_SR, UNS_BIS_SR.
(pushm): Use a 'n' rather than an 'i' constraint.
(msp_return): Add generation of the interrupt return instruction.
(disable_interrupts): New pattern.
(enable_interrupts): New pattern.
(push_intr_state): New pattern.
(pop_intr_state): New pattern.
(bic_SR): New pattern.
(bis_SR): New pattern.
* doc/extend.texi: Document MSP430 function attributes and builtin
functions.
2013-09-17 Richard Biener <rguenther@suse.de>
PR tree-optimization/58432
......
......@@ -70,5 +70,3 @@
(match_test ("IN_RANGE (INTVAL (XEXP (XEXP (op, 0), 1)), -1 << 15, (1 << 15)-1)"))))
(match_code "reg" "0")
)))
......@@ -21,6 +21,7 @@
#ifndef GCC_MSP430_PROTOS_H
#define GCC_MSP430_PROTOS_H
rtx msp430_eh_return_stackadj_rtx (void);
void msp430_expand_eh_return (rtx);
void msp430_expand_epilogue (int);
void msp430_expand_helper (rtx *operands, const char *, bool);
......@@ -32,13 +33,14 @@ int msp430_hard_regno_nregs (int, enum machine_mode);
rtx msp430_incoming_return_addr_rtx (void);
void msp430_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
int msp430_initial_elimination_offset (int, int);
bool msp430_is_interrupt_func (void);
const char * msp430x_logical_shift_right (rtx);
bool msp430_modes_tieable_p (enum machine_mode, enum machine_mode);
void msp430_output_labelref (FILE *, const char *);
void msp430_register_pragmas (void);
rtx msp430_return_addr_rtx (int);
void msp430_split_movsi (rtx *);
rtx msp430_subreg (enum machine_mode, rtx, enum machine_mode, int);
rtx msp430_eh_return_stackadj_rtx (void);
bool msp430_modes_tieable_p (enum machine_mode, enum machine_mode);
void msp430_start_function (FILE *, const char *, tree);
#endif /* GCC_MSP430_PROTOS_H */
......@@ -120,7 +120,7 @@ msp430_option_override (void)
msp430x = true;
if (TARGET_LARGE && !msp430x)
error ("-mlarge requires a 430X-compatible -mcpu=");
error ("-mlarge requires a 430X-compatible -mmcu=");
if (flag_exceptions || flag_non_call_exceptions
|| flag_unwind_tables || flag_asynchronous_unwind_tables)
......@@ -208,10 +208,9 @@ msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED,
/* Implements INITIAL_ELIMINATION_OFFSET. */
int
msp430_initial_elimination_offset (int from ATTRIBUTE_UNUSED,
int to ATTRIBUTE_UNUSED)
msp430_initial_elimination_offset (int from, int to)
{
int rv = 0; /* as if arg to arg */
int rv = 0; /* As if arg to arg. */
msp430_compute_frame_info ();
......@@ -763,6 +762,10 @@ static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED,
| |
| PC from call | (2 bytes for 430, 4 for TARGET_LARGE)
| |
+--------------------+
| SR if this func has|
| been called via an |
| interrupt. |
+--------------------+ <-- SP before prologue, also AP
| |
| Saved Regs | (2 bytes per reg for 430, 4 per for TARGET_LARGE)
......@@ -806,6 +809,12 @@ msp430_preserve_reg_p (int regno)
if (fixed_regs [regno])
return false;
/* Interrupt handlers save all registers they use, even
ones which are call saved. If they call other functions
then *every* register is saved. */
if (msp430_is_interrupt_func ())
return ! crtl->is_leaf || df_regs_ever_live_p (regno);
if (!call_used_regs [regno]
&& df_regs_ever_live_p (regno))
return true;
......@@ -825,7 +834,7 @@ msp430_compute_frame_info (void)
cfun->machine->framesize_locals = get_frame_size ();
cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
for (i = 0; i < 16; i ++)
for (i = 0; i < ARG_POINTER_REGNUM; i ++)
if (msp430_preserve_reg_p (i))
{
cfun->machine->need_to_save [i] = 1;
......@@ -842,6 +851,38 @@ msp430_compute_frame_info (void)
+ cfun->machine->framesize_outgoing);
}
static inline bool
is_attr_func (const char * attr)
{
return lookup_attribute (attr, DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
}
/* Returns true if the current function has the "interrupt" attribute. */
bool
msp430_is_interrupt_func (void)
{
return is_attr_func ("interrupt");
}
static inline bool
is_naked_func (void)
{
return is_attr_func ("naked");
}
static inline bool
is_reentrant_func (void)
{
return is_attr_func ("reentrant");
}
static inline bool
is_critical_func (void)
{
return is_attr_func ("critical");
}
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function
......@@ -851,6 +892,21 @@ msp430_start_function (FILE *outfile, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
int r, n;
fprintf (outfile, "; start of function\n");
if (DECL_ATTRIBUTES (current_function_decl) != NULL_TREE)
{
fprintf (outfile, "; attributes: ");
if (is_naked_func ())
fprintf (outfile, "naked ");
if (msp430_is_interrupt_func ())
fprintf (outfile, "interrupt ");
if (is_reentrant_func ())
fprintf (outfile, "reentrant ");
if (is_critical_func ())
fprintf (outfile, "critical ");
fprintf (outfile, "\n");
}
fprintf (outfile, "; framesize_regs: %d\n", cfun->machine->framesize_regs);
fprintf (outfile, "; framesize_locals: %d\n", cfun->machine->framesize_locals);
fprintf (outfile, "; framesize_outgoing: %d\n", cfun->machine->framesize_outgoing);
......@@ -860,7 +916,7 @@ msp430_start_function (FILE *outfile, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
n = 0;
fprintf (outfile, "; saved regs:");
for (r = 0; r < 16; r++)
for (r = 0; r < ARG_POINTER_REGNUM; r++)
if (cfun->machine->need_to_save [r])
{
fprintf (outfile, " %s", reg_names [r]);
......@@ -899,6 +955,215 @@ increment_stack (HOST_WIDE_INT amount)
}
}
/* Verify MSP430 specific attributes. */
static tree
msp430_attr (tree * node,
tree name,
tree args,
int flags ATTRIBUTE_UNUSED,
bool * no_add_attrs)
{
gcc_assert (DECL_P (* node));
if (args != NULL)
{
tree value = TREE_VALUE (args);
switch (TREE_CODE (value))
{
case STRING_CST:
if ( strcmp (TREE_STRING_POINTER (value), "reset")
&& strcmp (TREE_STRING_POINTER (value), "nmi")
&& strcmp (TREE_STRING_POINTER (value), "watchdog"))
/* Allow the attribute to be added - the linker script
being used may still recognise this name. */
warning (OPT_Wattributes,
"unrecognised interrupt vector argument of %qE attribute",
name);
break;
case INTEGER_CST:
if (TREE_INT_CST_LOW (value) > 31)
/* Allow the attribute to be added - the linker script
being used may still recognise this value. */
warning (OPT_Wattributes,
"numeric argument of %qE attribute must be in range 0..31",
name);
break;
default:
warning (OPT_Wattributes,
"argument of %qE attribute is not a string constant or number",
name);
*no_add_attrs = true;
break;
}
}
if (TREE_CODE (* node) != FUNCTION_DECL)
{
warning (OPT_Wattributes,
"%qE attribute only applies to functions",
name);
* no_add_attrs = true;
}
/* FIXME: We ought to check that the interrupt handler
attribute has been applied to a void function. */
/* FIXME: We should check that reentrant and critical
functions are not naked and that critical functions
are not reentrant. */
return NULL_TREE;
}
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table
/* Table of MSP430-specific attributes. */
const struct attribute_spec msp430_attribute_table[] =
{
/* Name min_len decl_req, fn_type_req, affects_type_identity
max_len, type_req, handler. */
{ "interrupt", 0, 1, true, false, false, msp430_attr, false },
{ "naked", 0, 0, true, false, false, msp430_attr, false },
{ "reentrant", 0, 0, true, false, false, msp430_attr, false },
{ "critical", 0, 0, true, false, false, msp430_attr, false },
{ NULL, 0, 0, false, false, false, NULL, false }
};
void
msp430_start_function (FILE *file, const char *name, tree decl)
{
tree int_attr;
int_attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
if (int_attr != NULL_TREE)
{
tree intr_vector = TREE_VALUE (int_attr);
if (intr_vector != NULL_TREE)
{
char buf[101];
intr_vector = TREE_VALUE (intr_vector);
/* The interrupt attribute has a vector value. Turn this into a
section name, switch to that section and put the address of
the current function into that vector slot. Note msp430_attr()
has already verified the vector name for us. */
if (TREE_CODE (intr_vector) == STRING_CST)
sprintf (buf, "__interrupt_vector_%.80s",
TREE_STRING_POINTER (intr_vector));
else /* TREE_CODE (intr_vector) == INTEGER_CST */
sprintf (buf, "__interrupt_vector_%u",
(unsigned int) TREE_INT_CST_LOW (intr_vector));
switch_to_section (get_section (buf, SECTION_CODE, decl));
fputs ("\t.word\t", file);
assemble_name (file, name);
fputc ('\n', file);
fputc ('\t', file);
}
}
switch_to_section (function_section (decl));
ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
}
static section *
msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit)
{
/* In large mode we must make sure that interrupt handlers are put into
low memory as the vector table only accepts 16-bit addresses. */
if (TARGET_LARGE
&& lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl)))
return get_section (".lowtext", SECTION_CODE | SECTION_WRITE , decl);
/* Otherwise, use the default function section. */
return default_function_section (decl, freq, startup, exit);
}
#undef TARGET_ASM_FUNCTION_SECTION
#define TARGET_ASM_FUNCTION_SECTION msp430_function_section
enum msp430_builtin
{
MSP430_BUILTIN_BIC_SR,
MSP430_BUILTIN_BIS_SR,
MSP430_BUILTIN_max
};
static GTY(()) tree msp430_builtins [(int) MSP430_BUILTIN_max];
static void
msp430_init_builtins (void)
{
tree void_ftype_int = build_function_type_list (void_type_node, integer_type_node, NULL);
msp430_builtins[MSP430_BUILTIN_BIC_SR] =
add_builtin_function ( "__bic_SR_register_on_exit", void_ftype_int,
MSP430_BUILTIN_BIC_SR, BUILT_IN_MD, NULL, NULL_TREE);
msp430_builtins[MSP430_BUILTIN_BIS_SR] =
add_builtin_function ( "__bis_SR_register_on_exit", void_ftype_int,
MSP430_BUILTIN_BIS_SR, BUILT_IN_MD, NULL, NULL_TREE);
}
static tree
msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED)
{
switch (code)
{
case MSP430_BUILTIN_BIC_SR:
case MSP430_BUILTIN_BIS_SR:
return msp430_builtins[code];
default:
return error_mark_node;
}
}
static rtx
msp430_expand_builtin (tree exp,
rtx target ATTRIBUTE_UNUSED,
rtx subtarget ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
if (! msp430_is_interrupt_func ())
{
error ("MSP430 builtin functions only work inside interrupt handlers");
return NULL_RTX;
}
if (! REG_P (arg1) && ! CONSTANT_P (arg1))
arg1 = force_reg (mode, arg1);
switch (fcode)
{
case MSP430_BUILTIN_BIC_SR: emit_insn (gen_bic_SR (arg1)); break;
case MSP430_BUILTIN_BIS_SR: emit_insn (gen_bis_SR (arg1)); break;
default:
internal_error ("bad builtin code");
break;
}
return NULL_RTX;
}
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS msp430_init_builtins
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN msp430_expand_builtin
#undef TARGET_BUILTIN_DECL
#define TARGET_BUILTIN_DECL msp430_builtin_decl
void
msp430_expand_prologue (void)
{
......@@ -911,8 +1176,19 @@ msp430_expand_prologue (void)
rtx sp = stack_pointer_rtx;
rtx p;
if (is_naked_func ())
return;
emit_insn (gen_prologue_start_marker ());
if (is_critical_func ())
{
emit_insn (gen_push_intr_state ());
emit_insn (gen_disable_interrupts ());
}
else if (is_reentrant_func ())
emit_insn (gen_disable_interrupts ());
if (!cfun->machine->computed)
msp430_compute_frame_info ();
......@@ -1009,6 +1285,9 @@ msp430_expand_epilogue (int is_eh)
int fs;
int helper_n = 0;
if (is_naked_func ())
return;
if (cfun->machine->need_to_save [10])
{
/* Check for a helper function. */
......@@ -1070,6 +1349,9 @@ msp430_expand_epilogue (int is_eh)
i += count - 1;
}
else if (i == 11 - helper_n
&& ! msp430_is_interrupt_func ()
&& ! is_reentrant_func ()
&& ! is_critical_func ()
&& crtl->args.pretend_args_size == 0
/* Calling the helper takes as many bytes as the POP;RET sequence. */
&& helper_n != 1
......@@ -1093,6 +1375,11 @@ msp430_expand_epilogue (int is_eh)
if (crtl->args.pretend_args_size)
emit_insn (gen_swap_and_shrink ());
if (is_critical_func ())
emit_insn (gen_pop_intr_state ());
else if (is_reentrant_func ())
emit_insn (gen_enable_interrupts ());
emit_jump_insn (gen_msp_return ());
}
......@@ -1131,12 +1418,15 @@ msp430_expand_eh_return (rtx eh_handler)
}
/* This is a list of MD patterns that implement fixed-count shifts. */
static struct {
static struct
{
const char *name;
int count;
int need_430x;
rtx (*genfunc)(rtx,rtx);
} const_shift_helpers[] = {
}
const_shift_helpers[] =
{
#define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }
CSH ("slli", 1, 1, slli_1),
......@@ -1329,7 +1619,6 @@ msp430_split_movsi (rtx *operands)
}
/* The MSPABI specifies the names of various helper functions, many of
which are compatible with GCC's helpers. This table maps the GCC
name to the MSPABI name. */
......@@ -1600,6 +1889,15 @@ msp430_print_operand (FILE * file, rtx op, int letter)
if (TARGET_LARGE)
fprintf (file, "A");
return;
case 'O':
/* Computes the offset to the top of the stack for the current frame.
This has to be done here rather than in, say, msp430_expand_builtin()
because builtins are expanded before the frame layout is determined. */
fprintf (file, "%d",
msp430_initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM)
- 2);
return ;
}
switch (GET_CODE (op))
......
/* GCC backend definitions for the TI MSP430 Processor
Copyright (C) 2012 Free Software Foundation, Inc.
Copyright (C) 2012-2013 Free Software Foundation, Inc.
Contributed by Red Hat.
This file is part of GCC.
......@@ -29,6 +29,7 @@ extern bool msp430x;
#define TARGET_CPU_CPP_BUILTINS() \
do \
{ \
builtin_define ("NO_TRAMPOLINES"); \
builtin_define ("__MSP430__"); \
if (msp430x) \
{ \
......@@ -281,7 +282,8 @@ enum reg_class
typedef struct {
typedef struct
{
/* These two are the current argument status. */
char reg_used[4];
#define CA_FIRST_REG 12
......
......@@ -38,6 +38,13 @@
UNS_GROW_AND_SWAP
UNS_SWAP_AND_SHRINK
UNS_DINT
UNS_EINT
UNS_PUSH_INTR
UNS_POP_INTR
UNS_BIC_SR
UNS_BIS_SR
])
(include "predicates.md")
......@@ -78,7 +85,7 @@
(define_insn "pushm"
[(unspec_volatile [(match_operand 0 "register_operand" "r")
(match_operand 1 "immediate_operand" "i")] UNS_PUSHM)]
(match_operand 1 "immediate_operand" "n")] UNS_PUSHM)]
""
"PUSHM%B0\t%1, %0"
)
......@@ -950,7 +957,7 @@
(define_insn "msp_return"
[(return)]
""
{ return TARGET_LARGE ? "RETA" : "RET"; }
{ return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
)
;; This pattern is NOT, as expected, a return pattern. It's called
......@@ -1102,7 +1109,6 @@
CMP%X0.W\t%1, %2 { J%R0\t%l3"
)
(define_insn "*bitbranch<mode>4"
[(set (pc) (if_then_else
(ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
......@@ -1158,7 +1164,7 @@
)
;;------------------------------------------------------------
;; zero-extend versions of the above
;; zero-extract versions of the above
(define_insn "*bitbranch<mode>4_z"
[(set (pc) (if_then_else
......@@ -1227,3 +1233,42 @@
"NOP"
)
(define_insn "disable_interrupts"
[(unspec_volatile [(const_int 0)] UNS_DINT)]
""
"DINT"
)
(define_insn "enable_interrupts"
[(unspec_volatile [(const_int 0)] UNS_EINT)]
""
"EINT"
)
(define_insn "push_intr_state"
[(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)]
""
"PUSH\tSR"
)
(define_insn "pop_intr_state"
[(unspec_volatile [(const_int 0)] UNS_POP_INTR)]
""
"POP\tSR"
)
;; Clear bits in the copy of the status register that is currently
;; saved on the stack at the top of the interrupt handler.
(define_insn "bic_SR"
[(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)]
""
"BIC.W\t%0, %O0(SP)"
)
;; Set bits in the copy of the status register that is currently
;; saved on the stack at the top of the interrupt handler.
(define_insn "bis_SR"
[(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)]
""
"BIS.W\t%0, %O0(SP)"
)
......@@ -2813,7 +2813,7 @@ least version 2.20.1), and GNU C library (at least version 2.11.1).
@item interrupt
@cindex interrupt handler functions
Use this attribute on the ARM, AVR, CR16, Epiphany, M32C, M32R/D, m68k, MeP, MIPS,
RL78, RX and Xstormy16 ports to indicate that the specified function is an
MSP430, RL78, RX and Xstormy16 ports to indicate that the specified function is an
interrupt handler. The compiler generates function entry and exit
sequences suitable for use in an interrupt handler when this attribute
is present. With Epiphany targets it may also generate a special section with
......@@ -2844,6 +2844,35 @@ Permissible values for this parameter are: @code{IRQ}, @code{FIQ},
On ARMv7-M the interrupt type is ignored, and the attribute means the function
may be called with a word-aligned stack pointer.
Note, for the MSP430 you can provide an argument to the interrupt
attribute which specifies a name or number. If the argument is a
number it indicates the slot in the interrupt vector table (0 - 31) to
which this handler should be assigned. If the argument is a name it
is treated as a symbolic name for the vector slot. These names should
match up with appropriate entries in the linker script. By default
the names @code{watchdog} for vector 26, @code{nmi} for vector 30 and
@code{reset} for vector 31 are recognised.
You can also use the following function attributes to modify how
normal functions interact with interrupt functions:
@table @code
@item critical
@cindex @code{critical} attribute
Critical functions disable interrupts upon entry and restore the
previous interrupt state upon exit. Critical functions cannot also
have the @code{naked} or @code{reentrant} attributes. They can have
the @code{interrupt} attribute.
@item reentrant
@cindex @code{reentrant} attribute
Reentrant functions disable interrupts upon entry and enable them
upon exit. Reentrant functions cannot also have the @code{naked}
or @code{critical} attributes. They can have the @code{interrupt}
attribute.
@end table
On Epiphany targets one or more optional parameters can be added like this:
@smallexample
......@@ -3143,7 +3172,7 @@ and newer.
@item naked
@cindex function without a prologue/epilogue code
Use this attribute on the ARM, AVR, MCORE, RL78, RX and SPU ports to indicate that
Use this attribute on the ARM, AVR, MCORE, MSP430, RL78, RX and SPU ports to indicate that
the specified function does not need prologue/epilogue sequences generated by
the compiler. It is up to the programmer to provide these sequences. The
only statements that can be safely included in naked functions are
......@@ -8844,6 +8873,7 @@ instructions, but allow the compiler to schedule those calls.
* MIPS Paired-Single Support::
* MIPS Loongson Built-in Functions::
* Other MIPS Built-in Functions::
* MSP430 Built-in Functions::
* picoChip Built-in Functions::
* PowerPC Built-in Functions::
* PowerPC AltiVec/VSX Built-in Functions::
......@@ -11853,6 +11883,26 @@ GCC defines the preprocessor macro @code{___GCC_HAVE_BUILTIN_MIPS_CACHE}
when this function is available.
@end table
@node MSP430 Built-in Functions
@subsection MSP430 Built-in Functions
GCC provides a couple of special builtin functions to aid in the
writing of interrupt handlers in C.
@table @code
@item __bic_SR_register_on_exit (int @var{mask})
This clears the indicated bits in the saved copy of the status register
currently residing on the stack. This only works inside interrupt
handlers and the changes to the status register will only take affect
once the handler returns.
@item __bis_SR_register_on_exit (int @var{mask})
This sets the indicated bits in the saved copy of the status register
currently residing on the stack. This only works inside interrupt
handlers and the changes to the status register will only take affect
once the handler returns.
@end table
@node picoChip Built-in Functions
@subsection picoChip Built-in Functions
......
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