diff options
author | Nick Clifton <nickc@redhat.com> | 2013-09-17 08:15:03 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2013-09-17 08:15:03 +0000 |
commit | cad055a4ba2356bb1cde958dfe41de705e39bfea (patch) | |
tree | 3bb014e5f02dba3bcadfe141ef501c948e46ba81 /gcc | |
parent | deb6c11a73e8d651d367950b5ea35ee5f60c3a85 (diff) | |
download | gcc-cad055a4ba2356bb1cde958dfe41de705e39bfea.zip gcc-cad055a4ba2356bb1cde958dfe41de705e39bfea.tar.gz gcc-cad055a4ba2356bb1cde958dfe41de705e39bfea.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 41 | ||||
-rw-r--r-- | gcc/config/msp430/constraints.md | 2 | ||||
-rw-r--r-- | gcc/config/msp430/msp430-protos.h | 6 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.c | 318 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.h | 6 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.md | 53 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 56 |
7 files changed, 459 insertions, 23 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6c75db0..e63347b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,44 @@ +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 diff --git a/gcc/config/msp430/constraints.md b/gcc/config/msp430/constraints.md index baacf92..ea53481 100644 --- a/gcc/config/msp430/constraints.md +++ b/gcc/config/msp430/constraints.md @@ -70,5 +70,3 @@ (match_test ("IN_RANGE (INTVAL (XEXP (XEXP (op, 0), 1)), -1 << 15, (1 << 15)-1)")))) (match_code "reg" "0") ))) - - diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index df90d95..f116855 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -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 */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 2e6705d..9384d32 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -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 @@ -1092,7 +1374,12 @@ 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)) diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index bf3b15c..0b77c4a 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -1,5 +1,5 @@ /* 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 diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index 4324503..a258867 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -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)" + ) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index cb48220..cb0306b 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -30,7 +30,7 @@ extensions, accepted by GCC in C90 mode and in C++. * Constructing Calls:: Dispatching a call to another function. * Typeof:: @code{typeof}: referring to the type of an expression. * Conditionals:: Omitting the middle operand of a @samp{?:} expression. -* __int128:: 128-bit integers---@code{__int128}. +* __int128:: 128-bit integers---@code{__int128}. * Long Long:: Double-word integers---@code{long long int}. * Complex:: Data types for complex numbers. * Floating Types:: Additional Floating Types. @@ -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 |